Add support for evaluating rudamentary expressions
This commit is contained in:
@@ -57,7 +57,11 @@ static void error_msg_print(struct error_msg* msg, bool print_colon)
|
|||||||
if (!msg)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
error_msg_print(msg->next, true);
|
error_msg_print(msg->next, true);
|
||||||
fprintf(stderr, "%s", msg->message);
|
|
||||||
|
if (msg->message) {
|
||||||
|
fprintf(stderr, "%s", msg->message);
|
||||||
|
}
|
||||||
|
|
||||||
if (print_colon) {
|
if (print_colon) {
|
||||||
fprintf(stderr, ": ");
|
fprintf(stderr, ": ");
|
||||||
}
|
}
|
||||||
|
|||||||
114
src/parser.c
114
src/parser.c
@@ -4,6 +4,7 @@
|
|||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
#include "printable.h"
|
#include "printable.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -14,6 +15,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
/* ======= Grammar Rules =======
|
/* ======= Grammar Rules =======
|
||||||
|
|
||||||
statement:
|
statement:
|
||||||
@@ -60,6 +64,22 @@ typedef struct symbol_table {
|
|||||||
Symbol_table_entry* syms;
|
Symbol_table_entry* syms;
|
||||||
} Symbol_table;
|
} 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)
|
static Value* parse_int(Error* err, Token* t)
|
||||||
{
|
{
|
||||||
if (t->type != TOKEN_INTEGER) {
|
if (t->type != TOKEN_INTEGER) {
|
||||||
@@ -72,7 +92,13 @@ static Value* parse_int(Error* err, Token* t)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
v->type = VALUE_INTEGER;
|
v->type = VALUE_INTEGER;
|
||||||
|
assert(errno == 0);
|
||||||
|
errno = 0;
|
||||||
v->i = strtol(t->start, NULL, 10);
|
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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,40 +138,76 @@ static Value* parse_binary_expr(Error* err, Value* lval, Value* rval, Value* op)
|
|||||||
return result;
|
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);
|
mfile_skip(m, isspace);
|
||||||
Token* t = token_read(err, m);
|
Token* t = token_read(err, m);
|
||||||
if (t->type == EOF) {
|
if (t->type == EOF) {
|
||||||
return EOF;
|
return NULL;
|
||||||
} else if (!error_empty(err)) {
|
} else if (!error_empty(err)) {
|
||||||
error_print(err);
|
return NULL;
|
||||||
return EOF;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "unknown error\n");
|
|
||||||
return EOF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* v;
|
Value* result;
|
||||||
|
|
||||||
switch (t->type) {
|
switch (t->type) {
|
||||||
case TOKEN_INTEGER:
|
case TOKEN_INTEGER: {
|
||||||
v = parse_int(err, t);
|
result = parser_handle_binary_expr(err, t, m);
|
||||||
if (!v) {
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
if (!error_empty(err)) {
|
if (!error_empty(err)) {
|
||||||
error_print(err);
|
goto syntax_error;
|
||||||
return EOF;
|
|
||||||
}
|
}
|
||||||
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);
|
token_print(err, t);
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
@@ -168,21 +230,23 @@ int main(int argc, char** argv)
|
|||||||
if (!error_empty(&err)) {
|
if (!error_empty(&err)) {
|
||||||
error_push(&err, "mfile_open");
|
error_push(&err, "mfile_open");
|
||||||
error_print(&err);
|
error_print(&err);
|
||||||
status = EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
error_clear(&err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_clear(&err);
|
|
||||||
while (!mfile_eof(m)) {
|
while (!mfile_eof(m)) {
|
||||||
parser_next(&err, m);
|
parser_next(&err, m);
|
||||||
|
if (!error_empty(&err)) {
|
||||||
|
error_print(&err);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error_clear(&err);
|
|
||||||
mfile_close(&err, m);
|
mfile_close(&err, m);
|
||||||
if (!error_empty(&err)) {
|
if (!error_empty(&err)) {
|
||||||
error_push(&err, "mfile_close");
|
error_push(&err, "mfile_close");
|
||||||
error_print(&err);
|
error_print(&err);
|
||||||
status = EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ int main() {
|
|||||||
|
|
||||||
// generated by main() in printable.h
|
// generated by main() in printable.h
|
||||||
|
|
||||||
static const char * asdasd_printable[256] = {
|
static const char * asdasd_printable[] = {
|
||||||
"<NULL>", "<01>", "<02>", "<03>", "<04>", "<05>", "<06>", "<07>", "<08>",
|
"<NULL>", "<01>", "<02>", "<03>", "<04>", "<05>", "<06>", "<07>", "<08>",
|
||||||
"<09>", "<0a>", "<0b>", "<0c>", "<0d>", "<0e>", "<0f>", "<10>", "<11>",
|
"<09>", "<0a>", "<0b>", "<0c>", "<0d>", "<0e>", "<0f>", "<10>", "<11>",
|
||||||
"<12>", "<13>", "<14>", "<15>", "<16>", "<17>", "<18>", "<19>", "<1a>",
|
"<12>", "<13>", "<14>", "<15>", "<16>", "<17>", "<18>", "<19>", "<1a>",
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
The "quick" brown fox jumps at 8.42 m/h over the lazy dog
|
The "quick" brown fox jumps at 8.42 m/h over the lazy dog
|
||||||
|
|
||||||
10 + 20 = 30
|
10 + 20
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ Token* token_read(Error* err, Mfile* m)
|
|||||||
error_push(err, "failed to allocate token: %s", strerror(errno));
|
error_push(err, "failed to allocate token: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
mfile_skip(m, isspace);
|
||||||
const int c = mfile_curchar(m);
|
const int c = mfile_curchar(m);
|
||||||
|
|
||||||
if (isalpha(c)) {
|
if (isalpha(c)) {
|
||||||
@@ -138,7 +139,7 @@ Token* token_read(Error* err, Mfile* m)
|
|||||||
} else if ( c == EOF ) {
|
} else if ( c == EOF ) {
|
||||||
t->type = EOF;
|
t->type = EOF;
|
||||||
} else {
|
} else {
|
||||||
error_push(err, "unexpected character: %c", PRINTABLE(c));
|
error_push(err, "unexpected character: %s (0x%02x)", PRINTABLE(c), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
|
|||||||
Reference in New Issue
Block a user