From 21b48d75aac9e57442be97aec7990df992a308d3 Mon Sep 17 00:00:00 2001 From: mike lowis Date: Sun, 18 Apr 2021 21:09:45 -0400 Subject: [PATCH] added rule macro to automatically add tracing code --- cerise/build.sh | 1 + cerise/parser.c | 245 ++++++++++++++++++++++++++++++------------------ 2 files changed, 155 insertions(+), 91 deletions(-) diff --git a/cerise/build.sh b/cerise/build.sh index de92c50..b183a1d 100755 --- a/cerise/build.sh +++ b/cerise/build.sh @@ -3,3 +3,4 @@ ctags -R & cc -g -D CERISE_TESTS -Wall -Wextra --std=c99 -o cerisec-test *.c \ && ./cerisec-test \ && cc -g -Wall -Wextra -Werror --std=c99 -o cerisec *.c +[ $? -gt 0 ] && printf "\a" diff --git a/cerise/parser.c b/cerise/parser.c index 134a50f..7aecee8 100644 --- a/cerise/parser.c +++ b/cerise/parser.c @@ -1,17 +1,19 @@ #include "cerise.h" #include -//#define TRACE +#define TRACE #ifdef TRACE -static int Indent = 0; -#define parse_enter() \ - (printf("%*c-> %s\n", ++Indent * 2, ' ', __func__)) -#define parse_exit() \ - Indent-- -// (printf("%*c<- %s\n", --Indent * 2, ' ', __func__)) + static int Indent = 0; + #define RULE(name) \ + void name##_actual(Parser* p); \ + void name(Parser* p) { \ + printf("%*c-> %s\n", ++Indent * 2, ' ', __func__); \ + name##_actual(p); \ + Indent--; } \ + void name##_actual(Parser* p) #else -#define parse_enter() -#define parse_exit() + #define RULE(name) \ + void name(Parser* p) #endif /* Precedence Table @@ -80,17 +82,17 @@ 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 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) { @@ -138,23 +140,20 @@ static int consume(Parser* p) /* 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) +void import_list(Parser* p); +void declaration_seq(Parser* p); +void statement_seq(Parser* p); +void const_decl(Parser* p); +void expression(Parser* p); +void simple_expr(Parser* p); +void term(Parser* p); +void factor(Parser* p); +void designator(Parser* p); +void qualident(Parser* p); +void expr_list(Parser* p); + +RULE(module) { - parse_enter(); expect(p, MODULE); char* sname = expect_text(p, IDENT); /* TODO: Check that it matches filename here */ @@ -175,12 +174,10 @@ void module(Parser* p) error(p, "Expected module name '%s', recieved '%s' instead", sname, ename); } expect(p, ';'); - parse_exit(); } -static void import_list(Parser* p) +RULE(import_list) { - parse_enter(); expect(p, IMPORT); while (1) { @@ -196,10 +193,9 @@ static void import_list(Parser* p) expect(p, ','); } expect(p, ';'); - parse_exit(); } -static void declaration_seq(Parser* p) +RULE(declaration_seq) { if (accept(p, CONST)) { @@ -218,12 +214,12 @@ static void declaration_seq(Parser* p) } } -static void statement_seq(Parser* p) +RULE(statement_seq) { (void)p; } -static void const_decl(Parser* p) +RULE(const_decl) { while (1) { @@ -238,65 +234,68 @@ static void const_decl(Parser* p) (void)p; } -static void expression(Parser* p) +RULE(expression) { + // expression = SimpleExpression [relation SimpleExpression]. + // relation = "=" | "!=" | "<" | "<=" | ">" | ">=" | "is". + + int ops[] = { EQ, NEQ, '<', LTEQ, '>', GTEQ, IS, 0 }; 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}. + if (matches_oneof(p, ops)) + { + consume(p); + simple_expr(p); + } } -/* - -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] ")" . - -*/ +RULE(simple_expr) +{ + // SimpleExpression = ["+" | "-"] term {AddOperator term}. + // AddOperator = "+" | "-" | "or". + /* first term and +/- */ + if (matches_oneof(p, (int[]){'+', '-', 0})) + { + consume(p); // OP + term(p); + } + else + { + term(p); + } -static void simple_expr(Parser* p) -{ -// if (matches_oneof(p, (int[]){ '+', '-', 0 })) -// { -// consume(p); -//// term(p); -// } - term(p); + /* optional second term and op */ + while (matches_oneof(p, (int[]){'+', '-', OR, 0})) + { + consume(p); + term(p); + } } -static void term(Parser* p) +RULE(term) { + // term = factor {MulOperator factor}. + // MulOperator = "*" | "/" | "and". factor(p); + while (matches_oneof(p, (int[]){'*', '/', AND, 0})) + { + consume(p); + factor(p); + } } -// designator [ActualParameters] -// designator = qualident {selector}. -// selector = "." ident | "[" ExpList "]" | "^" | "(" qualident ")". -// ExpList = expression {"," expression}. -// ActualParameters = "(" [ExpList] ")" . +/* +factor = number + | string + | "nil" + | "true" + | "false" + | designator [ActualParameters] + | "(" expression ")" + | "not" factor. +*/ -static void factor(Parser* p) +RULE(factor) { switch ((int)peek(p)->type) { @@ -319,12 +318,68 @@ static void factor(Parser* p) factor(p); break; - default: - error(p, "not a valid literal/expression"); + case IDENT: + designator(p); +// actual_params(p); + break; + } +} + +/* + designator = qualident {selector}. + selector = "." ident | "[" ExpList "]" | "^" | "(" qualident ")". + ExpList = expression {"," expression}. + qualident = [ident "."] ident. + + ActualParameters = "(" [ExpList] ")" . +*/ +RULE(designator) +{ + qualident(p); + /* selector */ + switch ((int)peek(p)->type) + { + case '.': + expect(p, IDENT); + break; + + case '[': + expr_list(p); + expect(p, ']'); + break; + + case '^': + expect(p, '^'); + break; + + case '(': + qualident(p); + expect(p, ')'); break; } } +RULE(qualident) +{ + expect(p, IDENT); + if (accept(p, '.')) + { + expect(p, IDENT); + } +} + +RULE(expr_list) +{ + while (1) + { + expression(p); + if (!accept(p, ',')) + { + break; + } + } +} + /* Grammar Unit Tests *****************************************************************************/ #ifdef CERISE_TESTS @@ -394,6 +449,14 @@ TEST_SUITE(Grammar) "FOO = not true"); parse_rule(const_decl, "FOO = (not true)"); + parse_rule(const_decl, + "FOO = +1"); + parse_rule(const_decl, + "FOO = -1"); + parse_rule(const_decl, + "FOO = 1 + 1"); + parse_rule(const_decl, + "FOO = 1 + 2 * 4"); } } #endif -- 2.49.0