From: mike lowis Date: Sat, 17 Apr 2021 04:00:27 +0000 (-0400) Subject: added parser scaffolding ofr expressions X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=8f39abb092d7983728f81961804990dcc61cb780;p=proto%2Fobnc.git added parser scaffolding ofr expressions --- diff --git a/cerise/cerise.h b/cerise/cerise.h index 714213d..af6cc55 100644 --- a/cerise/cerise.h +++ b/cerise/cerise.h @@ -20,6 +20,7 @@ typedef enum { INT, STRING, BOOL, + REAL, EQ, NEQ, LTEQ, @@ -36,7 +37,6 @@ typedef enum { ELSE, ELSIF, END, - FALSE, FOR, IF, IMPORT, @@ -54,7 +54,6 @@ typedef enum { RETURN, THEN, TO, - TRUE, TYPE, UNTIL, VAR, diff --git a/cerise/lex.c b/cerise/lex.c index 5de2cc8..2f47a53 100644 --- a/cerise/lex.c +++ b/cerise/lex.c @@ -72,7 +72,7 @@ KeywordDef Keywords[] = { { "else", ELSE }, { "elsif", ELSIF }, { "end", END }, - { "false", FALSE }, + { "false", BOOL }, { "for", FOR }, { "if", IF }, { "import", IMPORT }, @@ -90,7 +90,7 @@ KeywordDef Keywords[] = { { "return", RETURN }, { "then", THEN }, { "to", TO }, - { "true", TRUE }, + { "true", BOOL }, { "type", TYPE }, { "until", UNTIL }, { "var", VAR }, @@ -141,6 +141,12 @@ static inline void convert_value(Tok* tok) break; } + case REAL: + { + tok->value.floating = strtod(tok->text, 0); + break; + } + case IDENT: { KeywordDef key = { .keyword = tok->text }; @@ -232,6 +238,12 @@ static inline void readtok(Parser* ctx) case DIGITS: tok->type = INT; for (; Chars[(int)*curr] == DIGITS; curr++); + if (*curr == '.') + { + tok->type = REAL; + curr++; + for (; Chars[(int)*curr] == DIGITS; curr++); + } break; case ALPHA_: @@ -379,7 +391,7 @@ TEST_SUITE(Lexer) { "else", ELSE }, { "elsif", ELSIF }, { "end", END }, - { "false", FALSE }, + { "false", BOOL }, { "for", FOR }, { "if", IF }, { "import", IMPORT }, @@ -397,13 +409,14 @@ TEST_SUITE(Lexer) { "return", RETURN }, { "then", THEN }, { "to", TO }, - { "true", TRUE }, + { "true", BOOL }, { "type", TYPE }, { "until", UNTIL }, { "var", VAR }, { "while", WHILE }, { "foo", IDENT }, { "123", INT }, + { "123.123", REAL }, { "", STRING }, { "", END_FILE }, }; diff --git a/cerise/parser.c b/cerise/parser.c index 9eb79a6..134a50f 100644 --- a/cerise/parser.c +++ b/cerise/parser.c @@ -80,6 +80,18 @@ static bool matches(Parser* p, TokType type) return (peek(p)->type == type); } +//static bool matches_oneof(Parser* p, TokType types[]) +//{ +// for (int i = 0; types[i] != NONE; i++) +// { +// if (matches(p, types[i])) +// { +// return true; +// } +// } +// return false; +//} + static bool accept(Parser* p, TokType type) { if (matches(p, type)) { @@ -113,15 +125,58 @@ static char* expect_text(Parser* p, TokType type) return strdup(expect_val(p, type)->text); } -//static int consume(Parser* p) { -// int type = peek(p)->type; -// if (!accept(p, type)) -// error(p, "Unexpected token"); -// return type; -//} +static int consume(Parser* p) +{ + int type = peek(p)->type; + if (!accept(p, type)) + { + error(p, "Unexpected token"); + } + return type; +} /* Grammar Definition *****************************************************************************/ +void module(Parser* p); +static void import_list(Parser* p); +static void declaration_seq(Parser* p); +static void statement_seq(Parser* p); +static void const_decl(Parser* p); + +static void expression(Parser* p); +static void simple_expr(Parser* p); +static void term(Parser* p); +static void factor(Parser* p); + +//static int RelationOps[] = { EQ, NEQ, '<', LTEQ, '>', GTEQ, IS, 0 }; +//static int AddOps[] = { '+', '-', OR, 0 }; +//static int MulOps[] = { '*', '/', AND, 0 }; + +void module(Parser* p) +{ + parse_enter(); + expect(p, MODULE); + char* sname = expect_text(p, IDENT); + /* TODO: Check that it matches filename here */ + expect(p, ';'); + if (matches(p, IMPORT)) + { + import_list(p); + } + declaration_seq(p); + if (accept(p, BEGIN)) + { + statement_seq(p); + } + expect(p, END); + char* ename = expect_text(p, IDENT); + if (strcmp(sname, ename)) + { + error(p, "Expected module name '%s', recieved '%s' instead", sname, ename); + } + expect(p, ';'); + parse_exit(); +} static void import_list(Parser* p) { @@ -146,7 +201,21 @@ static void import_list(Parser* p) static void declaration_seq(Parser* p) { - (void)p; + if (accept(p, CONST)) + { + const_decl(p); + expect(p, ';'); + } + if (accept(p, TYPE)) + { +// type_decl(p); + expect(p, ';'); + } + if (accept(p, VAR)) + { +// var_decl(p); + expect(p, ';'); + } } static void statement_seq(Parser* p) @@ -154,30 +223,106 @@ static void statement_seq(Parser* p) (void)p; } -void module(Parser* p) +static void const_decl(Parser* p) { - parse_enter(); - expect(p, MODULE); - char* sname = expect_text(p, IDENT); - /* TODO: Check that it matches filename here */ - expect(p, ';'); - if (matches(p, IMPORT)) - { - import_list(p); - } - declaration_seq(p); - if (accept(p, BEGIN)) + while (1) { - statement_seq(p); + /*char* name =*/ expect_text(p, IDENT); + expect(p, '='); + expression(p); + if (!accept(p, ',')) + { + break; + } } - expect(p, END); - char* ename = expect_text(p, IDENT); - if (strcmp(sname, ename)) + (void)p; +} + +static void expression(Parser* p) +{ + simple_expr(p); +// int operators[] = {EQ, NEQ, '<', LTEQ, '>', GTEQ, IS, 0}; +// simple_expr(p); +// if (matches_oneof(p, operators)) +// { +// consume(p); +// simple_expr(p); +// } + +// expression = SimpleExpression [relation SimpleExpression]. +// relation = "=" | "!=" | "<" | "<=" | ">" | ">=" | "is". +// SimpleExpression = ["+" | "-"] term {AddOperator term}. +} + +/* + +expression = SimpleExpression [relation SimpleExpression]. + relation = "=" | "!=" | "<" | "<=" | ">" | ">=" | "is". + +SimpleExpression = ["+" | "-"] term {AddOperator term}. + AddOperator = "+" | "-" | "or". + +term = factor {MulOperator factor}. + MulOperator = "*" | "/" | "div" | "mod" | "and". + +factor = number | string | "nil" | "true" | "false" | designator [ActualParameters] | "(" expression ")" | "not" factor. +designator [ActualParameters] +designator = qualident {selector}. + selector = "." ident | "[" ExpList "]" | "^" | "(" qualident ")". +ExpList = expression {"," expression}. +ActualParameters = "(" [ExpList] ")" . + +*/ + + +static void simple_expr(Parser* p) +{ +// if (matches_oneof(p, (int[]){ '+', '-', 0 })) +// { +// consume(p); +//// term(p); +// } + term(p); +} + +static void term(Parser* p) +{ + factor(p); +} + +// designator [ActualParameters] +// designator = qualident {selector}. +// selector = "." ident | "[" ExpList "]" | "^" | "(" qualident ")". +// ExpList = expression {"," expression}. +// ActualParameters = "(" [ExpList] ")" . + +static void factor(Parser* p) +{ + switch ((int)peek(p)->type) { - error(p, "Expected module name '%s', recieved '%s' instead", sname, ename); + case INT: + case REAL: + case STRING: + case NIL: + case BOOL: + consume(p); + break; + + case '(': + expect(p, '('); + expression(p); + expect(p, ')'); + break; + + case NOT: + consume(p); + factor(p); + break; + + default: + error(p, "not a valid literal/expression"); + break; } - expect(p, ';'); - parse_exit(); } /* Grammar Unit Tests @@ -230,5 +375,25 @@ TEST_SUITE(Grammar) parse_rule(import_list, "import A, B = ModB, C;"); } + + TEST(Should parse constant declarations) + { + parse_rule(const_decl, + "FOO = 123"); + parse_rule(const_decl, + "FOO = 123.123"); + parse_rule(const_decl, + "FOO = \"\""); + parse_rule(const_decl, + "FOO = true"); + parse_rule(const_decl, + "FOO = false"); + parse_rule(const_decl, + "FOO = nil"); + parse_rule(const_decl, + "FOO = not true"); + parse_rule(const_decl, + "FOO = (not true)"); + } } #endif diff --git a/cerise/tests/tokens.txt b/cerise/tests/tokens.txt index d8a921a..f9165fb 100644 --- a/cerise/tests/tokens.txt +++ b/cerise/tests/tokens.txt @@ -59,4 +59,5 @@ var while foo 123 +123.123 ""