]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
implemented expression parsing based on precedence climbing / pratt parsing
authorMichael D. Lowis <mike@mdlowis.com>
Thu, 4 Apr 2019 02:50:29 +0000 (22:50 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Thu, 4 Apr 2019 02:50:29 +0000 (22:50 -0400)
example.src
inc/sclpl.h
src/parser.c

index ef80023392aa55f753fb2c1a9c802eb0577f042e..90a6ceee15ef76905e142fd22df133d874ad8fe7 100644 (file)
@@ -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
 }
index 5ff583fe92ffc78688571d276c525f6193bc2ca0..0e9996e2d34e6742073476ce5eb3bbe13a162844 100644 (file)
@@ -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;
index 034ea291c12ea8ef90023953e6a27941880f973f..4a26623cf7a6ff5b04e603a67976ca62a2096fbe 100644 (file)
@@ -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