From 8899b9a5f33c3d69bdd47c03314faedaafc94fd0 Mon Sep 17 00:00:00 2001 From: Ole Morud Date: Fri, 5 Jan 2024 17:48:18 +0100 Subject: [PATCH] Add support for evaluating rudamentary expressions --- src/error.c | 6 ++- src/parser.c | 114 ++++++++++++++++++++++++++++++++++++---------- src/printable.h | 2 +- src/test/test.txt | 2 +- src/tokenizer.c | 3 +- 5 files changed, 98 insertions(+), 29 deletions(-) diff --git a/src/error.c b/src/error.c index a49f3ca..d8e9085 100644 --- a/src/error.c +++ b/src/error.c @@ -57,7 +57,11 @@ static void error_msg_print(struct error_msg* msg, bool print_colon) if (!msg) return; error_msg_print(msg->next, true); - fprintf(stderr, "%s", msg->message); + + if (msg->message) { + fprintf(stderr, "%s", msg->message); + } + if (print_colon) { fprintf(stderr, ": "); } diff --git a/src/parser.c b/src/parser.c index 574da0c..4ed462e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -4,6 +4,7 @@ #include "tokenizer.h" #include "printable.h" +#include #include #include #include @@ -14,6 +15,9 @@ #include #include +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + /* ======= Grammar Rules ======= statement: @@ -60,6 +64,22 @@ typedef struct symbol_table { Symbol_table_entry* syms; } Symbol_table; +static Value* parse_operator(Error* err, Token* t) +{ + if (t->type != TOKEN_OPERATOR) { + error_push(err, "%s: unexpected token type: %s", __func__, token_type_str[t->type]); + return NULL; + } + Value* v = malloc(sizeof *v); + if (!v) { + error_push(err, "%s: failed to allocate value: %s", __func__, strerror(errno)); + return NULL; + } + v->type = VALUE_OPERATOR; + strncpy(v->op, t->start, MIN(t->end - t->start, sizeof(v->op))); + return v; +} + static Value* parse_int(Error* err, Token* t) { if (t->type != TOKEN_INTEGER) { @@ -72,7 +92,13 @@ static Value* parse_int(Error* err, Token* t) return NULL; } v->type = VALUE_INTEGER; + assert(errno == 0); + errno = 0; v->i = strtol(t->start, NULL, 10); + if (errno != 0) { + error_push(err, "%s: failed to parse int: %s", __func__, strerror(errno)); + return NULL; + } return v; } @@ -112,40 +138,76 @@ static Value* parse_binary_expr(Error* err, Value* lval, Value* rval, Value* op) return result; } -static int parser_next(Error* err, Mfile* m) +static Value* parser_handle_binary_expr(Error* err, Token* peek, Mfile* m) +{ + Value* lval = parse_int(err, peek); + if (!error_empty(err) || !lval) { + goto generic_error; + } + + Token* op_tok = token_read(err, m); + if (!error_empty(err)) { + goto generic_error; + } else if (op_tok->type != TOKEN_OPERATOR) { + goto syntax_error; + } + + Value* op = parse_operator(err, op_tok); + if (!error_empty(err)) { + goto generic_error; + } + + Token* rval_tok = token_read(err, m); + if (!error_empty(err)) { + goto generic_error; + } else if (rval_tok->type != TOKEN_INTEGER) { + goto syntax_error; + } + Value* rval = parse_int(err, rval_tok); + if (!error_empty(err)) { + goto generic_error; + } + + Value* result = parse_binary_expr(err, lval, rval, op); + if (!error_empty(err)) { + goto generic_error; + } + return result; + +syntax_error: + error_push(err, "%s: syntax error, expected binary expression", __func__); +generic_error: + return NULL; +} + +static Value* parser_next(Error* err, Mfile* m) { mfile_skip(m, isspace); Token* t = token_read(err, m); if (t->type == EOF) { - return EOF; + return NULL; } else if (!error_empty(err)) { - error_print(err); - return EOF; - } else { - fprintf(stderr, "unknown error\n"); - return EOF; + return NULL; } - Value* v; + Value* result; + switch (t->type) { - case TOKEN_INTEGER: - v = parse_int(err, t); - if (!v) { - return EOF; - } + case TOKEN_INTEGER: { + result = parser_handle_binary_expr(err, t, m); if (!error_empty(err)) { - error_print(err); - return EOF; + goto syntax_error; } - printf("\nINT: %ld\n", v->i); - break; - + } + default: syntax_error: { + error_push(err, "syntax error: unexpected token %s", token_type_str[t->type]); + return NULL; + } } token_print(err, t); - return 0; + return result; } - /* ========================================================================= */ int main(int argc, char** argv) @@ -168,21 +230,23 @@ int main(int argc, char** argv) if (!error_empty(&err)) { error_push(&err, "mfile_open"); error_print(&err); - status = EXIT_FAILURE; - error_clear(&err); + return EXIT_FAILURE; } - error_clear(&err); while (!mfile_eof(m)) { parser_next(&err, m); + if (!error_empty(&err)) { + error_print(&err); + return EXIT_FAILURE; + } } - error_clear(&err); + mfile_close(&err, m); if (!error_empty(&err)) { error_push(&err, "mfile_close"); error_print(&err); - status = EXIT_FAILURE; + return EXIT_FAILURE; } return status; diff --git a/src/printable.h b/src/printable.h index bf3bdc6..b1d197e 100644 --- a/src/printable.h +++ b/src/printable.h @@ -62,7 +62,7 @@ int main() { // generated by main() in printable.h -static const char * asdasd_printable[256] = { +static const char * asdasd_printable[] = { "", "<01>", "<02>", "<03>", "<04>", "<05>", "<06>", "<07>", "<08>", "<09>", "<0a>", "<0b>", "<0c>", "<0d>", "<0e>", "<0f>", "<10>", "<11>", "<12>", "<13>", "<14>", "<15>", "<16>", "<17>", "<18>", "<19>", "<1a>", diff --git a/src/test/test.txt b/src/test/test.txt index 525fb6a..0958e07 100644 --- a/src/test/test.txt +++ b/src/test/test.txt @@ -1,3 +1,3 @@ The "quick" brown fox jumps at 8.42 m/h over the lazy dog -10 + 20 = 30 +10 + 20 diff --git a/src/tokenizer.c b/src/tokenizer.c index 6decd5a..e6bc6f0 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -125,6 +125,7 @@ Token* token_read(Error* err, Mfile* m) error_push(err, "failed to allocate token: %s", strerror(errno)); return NULL; } + mfile_skip(m, isspace); const int c = mfile_curchar(m); if (isalpha(c)) { @@ -138,7 +139,7 @@ Token* token_read(Error* err, Mfile* m) } else if ( c == EOF ) { t->type = EOF; } else { - error_push(err, "unexpected character: %c", PRINTABLE(c)); + error_push(err, "unexpected character: %s (0x%02x)", PRINTABLE(c), c); } return t;