#include <ctype.h>
static so_token so_lexer_string(so_lexer *);
+
static so_token so_lexer_integer(so_lexer *);
+
static so_token so_lexer_bareword(so_lexer *);
-void so_token_deinit(so_token *t)
-{
+void so_token_deinit(so_token *t) {
free(t->lexeme);
t->lexeme = NULL;
t->type = SO_TT_INVALID;
}
-void so_token_type_to_string(so_token_type tt, char buffer[], int size)
-{
- switch (tt)
- {
- case SO_TT_USE:
- strncpy(buffer, "USE", size);
- break;
- case SO_TT_CALL:
- strncpy(buffer, "CALL", size);
- break;
- case SO_TT_BARE:
- strncpy(buffer, "BAREWORD", size);
- break;
- case SO_TT_STRING:
- strncpy(buffer, "STRING", size);
- break;
- case SO_TT_INTEGER:
- strncpy(buffer, "INTEGER", size);
- break;
- case SO_TT_EOF:
- strncpy(buffer, "EOF", size);
- break;
- case SO_TT_INVALID:
- strncpy(buffer, "INVALID", size);
- break;
+void so_token_type_to_string(so_token_type tt, char buffer[], int size) {
+ switch (tt) {
+ case SO_TT_USE:
+ strncpy(buffer, "USE", size);
+ break;
+ case SO_TT_CALL:
+ strncpy(buffer, "CALL", size);
+ break;
+ case SO_TT_BARE:
+ strncpy(buffer, "BAREWORD", size);
+ break;
+ case SO_TT_STRING:
+ strncpy(buffer, "STRING", size);
+ break;
+ case SO_TT_INTEGER:
+ strncpy(buffer, "INTEGER", size);
+ break;
+ case SO_TT_EOL:
+ strncpy(buffer, "EOL", size);
+ break;
+ case SO_TT_EOF:
+ strncpy(buffer, "EOF", size);
+ break;
+ case SO_TT_INVALID:
+ strncpy(buffer, "INVALID", size);
+ break;
}
}
-static char so_lexer_advance(so_lexer *l)
-{
+static char so_lexer_advance(so_lexer *l) {
if (l->current >= l->source_length)
return '\0';
return l->source[l->current++];
}
-static char so_lexer_peek(so_lexer *l)
-{
+static char so_lexer_peek(so_lexer *l) {
if (l->current >= l->source_length)
return '\0';
return l->source[l->current];
}
-static int so_lexer_eof(so_lexer *l)
-{
+static int so_lexer_eof(so_lexer *l) {
return so_lexer_peek(l) == '\0';
}
-void so_lexer_init(so_lexer *l, const char *source)
-{
+void so_lexer_init(so_lexer *l, const char *source) {
l->current = 0;
l->start = 0;
l->source_length = strlen(source);
l->source = source;
}
-void so_lexer_deinit(so_lexer *l)
-{
+void so_lexer_deinit(so_lexer *l) {
l->current = 0;
l->start = 0;
l->source_length = 0;
l->source = NULL;
}
-so_token so_lexer_next_token(so_lexer *l)
-{
+so_token so_lexer_next_token(so_lexer *l) {
l->start = l->current;
char c = so_lexer_advance(l);
if (c == '\0')
return (so_token){.lexeme = strdup("eof"), .type = SO_TT_EOF};
- switch (c)
- {
- case '"':
- return so_lexer_string(l);
- case '\n':
- case ' ':
- return so_lexer_next_token(l);
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return so_lexer_integer(l);
- default:
- return so_lexer_bareword(l);
+ switch (c) {
+ case '"':
+ return so_lexer_string(l);
+ case '\n':
+ return (so_token){.lexeme = strdup("eol"), .type = SO_TT_EOL};
+ case ' ':
+ return so_lexer_next_token(l);
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return so_lexer_integer(l);
+ default:
+ return so_lexer_bareword(l);
}
}
-so_token so_lexer_string(so_lexer *l)
-{
+so_token so_lexer_string(so_lexer *l) {
while (!so_lexer_eof(l) && so_lexer_peek(l) != '"')
so_lexer_advance(l);
- if (so_lexer_peek(l) != '"')
- {
+ if (so_lexer_peek(l) != '"') {
fprintf(stderr, "warning: unterminated string literal at %d\n", l->current);
return (so_token){.lexeme = strdup("invalid"), .type = SO_TT_INVALID};
}
return (so_token){.lexeme = lexeme, .type = SO_TT_STRING};
}
-so_token so_lexer_integer(so_lexer *l)
-{
+so_token so_lexer_integer(so_lexer *l) {
while (!so_lexer_eof(l) && so_lexer_peek(l) >= '0' && so_lexer_peek(l) <= '9')
so_lexer_advance(l);
return (so_token){.lexeme = lexeme, .type = SO_TT_INTEGER};
}
-so_token so_lexer_bareword(so_lexer *l)
-{
+so_token so_lexer_bareword(so_lexer *l) {
while (!so_lexer_eof(l) && !isspace(so_lexer_peek(l)))
so_lexer_advance(l);
#include <string.h>
static void so_parse_call(so_parser *);
+
static void so_parse_load(so_parser *);
+
static so_expr *so_parser_parse_simple_expression(so_parser *);
-static so_token so_parser_advance(so_parser *p)
-{
+static so_token so_parser_advance(so_parser *p) {
p->current = so_lexer_next_token(&p->lexer);
return p->current;
}
-static int so_parser_expect(so_parser *p, so_token_type tt)
-{
- if (p->current.type != tt)
- {
+static int so_parser_expect(so_parser *p, so_token_type tt) {
+ if (p->current.type != tt) {
char buffer[20] = {0};
so_token_type_to_string(tt, buffer, sizeof(buffer));
- fprintf(stderr, "warning: expected a different type of token: %s\n", buffer);
+ fprintf(stderr, "warning: expected a token of type: %s\n", buffer);
return 0;
}
return 1;
}
-static void add_command(so_parser *p, so_expr *e)
-{
- if (p->ncommands >= MAX_COMMANDS)
- {
+static void add_command(so_parser *p, so_expr *e) {
+ if (p->ncommands >= MAX_COMMANDS) {
fprintf(stderr, "warning: maximum number of commands reached\n");
return;
}
p->commands[p->ncommands++] = e;
}
-void so_parser_init(so_parser *p, const char *source)
-{
+void so_parser_init(so_parser *p, const char *source) {
p->source = source;
p->ncommands = 0;
so_lexer_init(&p->lexer, source);
}
-void so_parser_deinit(so_parser *p)
-{
+void so_parser_deinit(so_parser *p) {
p->source = NULL;
p->ncommands = 0;
memset(p->commands, 0, MAX_COMMANDS * sizeof(so_expr *));
so_lexer_deinit(&p->lexer);
}
-void so_parser_parse(so_parser *p)
-{
- while (so_parser_advance(p).type != SO_TT_EOF)
- {
- switch (p->current.type)
- {
- case SO_TT_USE:
- so_parse_load(p);
- break;
- case SO_TT_CALL:
- so_parse_call(p);
- break;
- case SO_TT_EOF:
- so_token_deinit(&p->current);
- return;
- default:
- fprintf(stderr, "warning: invalid start of expression, expected use or call: %s\n", p->current.lexeme);
- so_token_deinit(&p->current);
+void so_parser_parse(so_parser *p) {
+ while (so_parser_advance(p).type != SO_TT_EOF) {
+ switch (p->current.type) {
+ case SO_TT_USE:
+ so_parse_load(p);
+ break;
+ case SO_TT_CALL:
+ so_parse_call(p);
+ break;
+ case SO_TT_EOL: // Happens on an empty line
+ so_token_deinit(&p->current);
+ break;
+ case SO_TT_EOF: // Happens at end of input
+ so_token_deinit(&p->current);
+ return;
+ default:
+ fprintf(stderr, "warning: invalid start of expression, expected use or call: %s\n", p->current.lexeme);
+ so_token_deinit(&p->current);
}
}
so_token_deinit(&p->current);
}
-void so_parse_call(so_parser *p)
-{
- if (!so_parser_expect(p, SO_TT_CALL))
- {
+void so_parse_call(so_parser *p) {
+ if (!so_parser_expect(p, SO_TT_CALL)) {
so_token_deinit(&p->current);
return;
}
so_token_deinit(&p->current);
so_parser_advance(p);
- if (!so_parser_expect(p, SO_TT_BARE))
- {
+ if (!so_parser_expect(p, SO_TT_BARE)) {
so_token_deinit(&p->current);
return;
}
so_expr *args[MAX_CALL_ARGS];
int nargs = 0;
- while (so_parser_advance(p).type != SO_TT_EOF && nargs < MAX_CALL_ARGS)
- {
+ while (so_parser_advance(p).type != SO_TT_EOF && p->current.type != SO_TT_EOL && nargs < MAX_CALL_ARGS) {
so_expr *e = so_parser_parse_simple_expression(p);
- if (e == NULL)
- {
- fprintf(stderr, "warning: expected either a string or a number\n");
+ if (e == NULL) {
+ char type[10] = {0};
+ so_token_type_to_string(p->current.type, type, sizeof(type));
+ fprintf(
+ stderr,
+ "warning: expected either a string or a number, but got %s\n",
+ type);
so_token_deinit(&p->current);
continue;
}
args[nargs++] = e;
}
- if (!so_parser_expect(p, SO_TT_EOF))
- {
- fprintf(stderr, "warning: expected EOF");
+ if (!so_parser_expect(p, SO_TT_EOL)) {
+ fprintf(stderr, "warning: expected an end of line\n");
so_token_deinit(&p->current);
return;
}
so_token_deinit(&name);
}
-void so_parse_load(so_parser *p)
-{
- if (!so_parser_expect(p, SO_TT_USE))
- {
+void so_parse_load(so_parser *p) {
+ if (!so_parser_expect(p, SO_TT_USE)) {
so_token_deinit(&p->current);
return;
}
so_token use = p->current;
so_parser_advance(p);
- if (!so_parser_expect(p, SO_TT_STRING))
- {
+ if (!so_parser_expect(p, SO_TT_STRING)) {
so_token_deinit(&use);
so_token_deinit(&p->current);
return;
}
- so_expr *e = create_load_node(p->current.lexeme);
+ so_token name = p->current;
+ so_parser_advance(p);
+
+ if (!so_parser_expect(p, SO_TT_EOL)) {
+ so_token_deinit(&use);
+ so_token_deinit(&name);
+ so_token_deinit(&p->current);
+ return;
+ }
+
+ so_expr *e = create_load_node(name.lexeme);
add_command(p, e);
so_token_deinit(&use);
+ so_token_deinit(&name);
so_token_deinit(&p->current);
}
-so_expr *so_parser_parse_simple_expression(so_parser *p)
-{
+so_expr *so_parser_parse_simple_expression(so_parser *p) {
so_expr *e = NULL;
- if (p->current.type == SO_TT_STRING)
- {
+ if (p->current.type == SO_TT_STRING) {
e = create_string_node(p->current.lexeme);
so_token_deinit(&p->current);
}
- if (p->current.type == SO_TT_INTEGER)
- {
+ if (p->current.type == SO_TT_INTEGER) {
int n = atoi(p->current.lexeme);
e = create_number_node(n);
so_token_deinit(&p->current);