From: Michael D. Lowis Date: Thu, 4 Apr 2019 02:50:29 +0000 (-0400) Subject: implemented expression parsing based on precedence climbing / pratt parsing X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=5f5da4c204a53c6c2ce5ca66fab7331bbcb2555a;p=proto%2Fsclpl.git implemented expression parsing based on precedence climbing / pratt parsing --- diff --git a/example.src b/example.src index ef80023..90a6cee 100644 --- a/example.src +++ b/example.src @@ -32,8 +32,7 @@ fun main(args string[]) int { let foo int = 123 var bar int = 123 {123 321} - 123 - (123) + 123 (123) foo() bar(1) baz(1,2) @@ -47,9 +46,9 @@ fun main(args string[]) int { 123 } # UFCS call (call regular function like a method) -# foo.bar() -# foo.bar.baz() + foo.bar() + foo.bar.baz() # Struct/Union field access -# let a int = foo.bar -# let b int = foo.bar.baz + let a int = foo.bar + let b int = foo.bar.baz } diff --git a/inc/sclpl.h b/inc/sclpl.h index 5ff583f..0e9996e 100644 --- a/inc/sclpl.h +++ b/inc/sclpl.h @@ -27,6 +27,7 @@ typedef enum { T_STRING = 256, T_ID, T_INT, T_BOOL, T_CHAR, T_FLOAT, T_REQUIRES, T_PROVIDES, T_LET, T_VAR, T_FUN, T_TYPE, T_STRUCT, T_UNION, T_RETURN, T_IF, T_ELSE, + T_COUNT, T_ERROR = -2, T_END_FILE = -1 } TokType; diff --git a/src/parser.c b/src/parser.c index 034ea29..4a26623 100644 --- a/src/parser.c +++ b/src/parser.c @@ -15,6 +15,8 @@ static AST* expression_block(Parser* p); static AST* if_expression(Parser* p); static AST* identifier(Parser* p); static AST* expr_list(Parser* p, int firstc, int endc); +static AST* prefix_expr(Parser* p); +static AST* binary_expr(Parser* p, AST* left); //#define TRACE #ifdef TRACE @@ -28,51 +30,17 @@ static int Indent = 0; #define parse_exit() #endif -typedef struct { - int precedence; - int token; - AST* (*parse)(Parser* p, AST* expr); -} OpDef_T; - -AST* if_expr(Parser* p, AST* expr); -AST* block_expr(Parser* p, AST* expr); -AST* paren_expr(Parser* p, AST* expr); -AST* binop_expr(Parser* p, AST* expr); -AST* fncall_expr(Parser* p, AST* expr); - -OpDef_T PrefixOps[] = { - { 0, T_IF, if_expr }, /* If expression */ - { 0, '{', block_expr }, /* Expression block */ - { 0, '(', paren_expr }, /* Parenthese grouping */ +uint8_t PrefixOps[T_COUNT] = { + [T_IF] = 1, + ['{'] = 1, + ['('] = 1, }; -OpDef_T InfixOps[] = { - { 0, '.', binop_expr }, /* If expression */ - { 0, '(', fncall_expr }, /* Parenthese grouping */ +uint8_t BinaryOps[T_COUNT] = { + ['.'] = 1, + ['('] = 1, }; -/* Operator Parsing Routines - *****************************************************************************/ -AST* if_expr(Parser* p, AST* expr) { - return NULL; -} - -AST* block_expr(Parser* p, AST* expr) { - return NULL; -} - -AST* paren_expr(Parser* p, AST* expr) { - return NULL; -} - -AST* binop_expr(Parser* p, AST* expr) { - return NULL; -} - -AST* fncall_expr(Parser* p, AST* expr) { - return NULL; -} - /* Parsing Routines *****************************************************************************/ static Tok* peek(Parser* p) { @@ -223,83 +191,80 @@ static AST* func_definition(Parser* p) { return Var(name, func, type, SF_CONSTANT); } -static AST* member_access(Parser* p); -static AST* parenthesized(Parser* p); -static AST* literal(Parser* p); - static AST* expression(Parser* p) { parse_enter(); - AST* exp; - if (matches(p, '{')) { - exp = expression_block(p); - } else if (matches(p, T_IF)) { - exp = if_expression(p); - } else { - exp = member_access(p); - /* check for function call syntax */ - if (matches(p, '(')) - exp = Apply(exp, expr_list(p, '(', ')')); - } - parse_exit(); - return exp; -} - -static AST* member_access(Parser* p) { - parse_enter(); - AST* exp = parenthesized(p); - if (accept(p, '.')) { - AST* field = identifier(p); - // TODO: convert access to an apply or dedicated AST type - } - parse_exit(); - return exp; -} - -static AST* parenthesized(Parser* p) { - parse_enter(); - AST* exp; - if (matches(p, '(')) { - expect(p, '('); - exp = expression(p); - expect(p, ')'); - } else { - exp = literal(p); + int precedence = PrefixOps[peek(p)->type]; + AST* left = prefix_expr(p); + int next = peek(p)->type; + while (BinaryOps[next] && BinaryOps[next] >= precedence) { + left = binary_expr(p, left); + next = peek(p)->type; } parse_exit(); - return exp; + return left; } -static AST* literal(Parser* p) { - parse_enter(); - AST* exp; - if (matches(p, '[')) { - exp = expr_list(p, '[', ']'); - } else if (matches(p, T_ID)) { - exp = identifier(p); - // TODO: Struct init here? - } else { - exp = constant(p); +static AST* prefix_expr(Parser* p) { + AST* tree = NULL; + Tok* tok = peek(p); + switch ((int)tok->type) { + case '(': + expect(p, '('); + tree = expression(p); + expect(p, ')'); + break; + case '[': + tree = expr_list(p, '[', ']'); + break; + case '{': + tree = expression_block(p); + break; + case T_IF: + tree = if_expression(p); + break; + case T_BOOL: + tree = Bool(tok->value.integer); + accept(p, tok->type); + break; + case T_CHAR: + tree = Char(tok->value.integer); + accept(p, tok->type); + break; + case T_STRING: + tree = String(tok->text); + accept(p, tok->type); break; + case T_INT: + tree = Integer(tok->value.integer); + accept(p, tok->type); + break; + case T_FLOAT: + tree = Float(tok->value.floating); + accept(p, tok->type); + break; + case T_ID: + tree = Ident(tok->text); + accept(p, tok->type); + break; + default: + error(p, "expected an expression"); } - parse_exit(); - return exp; + return tree; } -static AST* constant(Parser* p) { - parse_enter(); - AST* tree = NULL; +static AST* binary_expr(Parser* p, AST* left) { + AST* exp = NULL; Tok* tok = peek(p); - switch (tok->type) { - case T_BOOL: tree = Bool(tok->value.integer); break; - case T_CHAR: tree = Char(tok->value.integer); break; - case T_STRING: tree = String(tok->text); break; - case T_INT: tree = Integer(tok->value.integer); break; - case T_FLOAT: tree = Float(tok->value.floating); break; - case T_ID: tree = Ident(tok->text); break; - default: error(p, "expected an expression"); + switch ((int)tok->type) { + case '(': + exp = Apply(left, expr_list(p, '(', ')')); + break; + case '.': + expect(p, '.'); + AST* field = identifier(p); + exp = left; + break; } - accept(p, tok->type); - parse_exit(); - return tree; + return exp; } /* Type Expressions