diff options
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 84 |
1 files changed, 60 insertions, 24 deletions
diff --git a/src/parser.c b/src/parser.c index 69417b2..d71627e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -28,8 +28,13 @@ typedef idx_t parsefn(ast_t *, aux_t *, lexemes_t) static parsefn parseblk, parsefunc, parseproto, parsestmt, parsetype; static idx_t parsedecl(ast_t *, aux_t *, lexemes_t, bool) __attribute__((nonnull)); -static idx_t parseexpr(ast_t *, aux_t *, lexemes_t, int) +static idx_t parseexpr(ast_t *, lexemes_t, int) __attribute__((nonnull)); +static idx_t parseexprinc(ast_t *, lexemes_t, idx_t, int) + __attribute__((nonnull)); +static idx_t parseexpratom(ast_t *, lexemes_t) + __attribute__((nonnull)); +static bool isfunc(lexemes_t); static ast_t mkast(void); @@ -45,14 +50,6 @@ static void astresz(ast_t *ast) /* TODO: Make thread-local? */ static size_t toksidx; -static int prectbl[_LEX_LAST_ENT] = { - ['+'] = 1, - ['-'] = 1, - ['*'] = 2, - ['/'] = 2, - ['%'] = 2, -}; - idx_t fwdnode(ast_t ast, idx_t i) { @@ -70,6 +67,9 @@ fwdnode(ast_t ast, idx_t i) i = ast.kids[i].rhs; break; case ASTBINADD: + case ASTBINDIV: + case ASTBINMOD: + case ASTBINMUL: case ASTBINSUB: case ASTCDECL: case ASTFN: @@ -187,7 +187,8 @@ parsedecl(ast_t *ast, aux_t *aux, lexemes_t toks, bool toplvl) switch (toks.kinds[toksidx]) { case LEXLPAR: - func = true; + if (!(func = isfunc(toks))) + goto not_fn; if (ast->kinds[i] == ASTDECL) err("Cannot assign function to mutable variable"); rhs = parsefunc(ast, aux, toks); @@ -200,7 +201,8 @@ parsedecl(ast_t *ast, aux_t *aux, lexemes_t toks, bool toplvl) aux->buf[j].decl.isundef = true; break; default: - rhs = parseexpr(ast, aux, toks, 1); +not_fn: + rhs = parseexpr(ast, toks, 0); } ast->kids[i].rhs = rhs; @@ -228,8 +230,18 @@ parsefunc(ast_t *ast, aux_t *aux, lexemes_t toks) } idx_t -parseexprunit(ast_t *ast, lexemes_t toks) +parseexpratom(ast_t *ast, lexemes_t toks) { + /* We handle parenthesised expressions up here because we don’t want + to allocate a new AST node for them */ + if (toks.kinds[toksidx] == LEXLPAR) { + toksidx++; + idx_t i = parseexpr(ast, toks, 0); + if (toks.kinds[toksidx++] != LEXRPAR) + err("parser: Expected closing parenthesis after expression"); + return i; + } + idx_t i = astalloc(ast); /* Unary plus is kind of a fake syntactic construct. We just pretend @@ -249,7 +261,7 @@ parseexprunit(ast_t *ast, lexemes_t toks) break; case LEXMINUS: ast->kinds[i] = ASTUNNEG; - ast->kids[i].rhs = parseexprunit(ast, toks); + ast->kids[i].rhs = parseexpratom(ast, toks); break; default: err("parser: Invalid expression leaf"); @@ -258,16 +270,23 @@ parseexprunit(ast_t *ast, lexemes_t toks) } idx_t -parseexprinc(ast_t *ast, aux_t *aux, lexemes_t toks, idx_t lhs, int minprec) +parseexprinc(ast_t *ast, lexemes_t toks, idx_t lhs, int minprec) { + static const int prectbl[UINT8_MAX] = { + ['+'] = 1, + ['-'] = 1, + ['*'] = 2, + ['/'] = 2, + ['%'] = 2, + }; + uint8_t op = toks.kinds[toksidx]; int nxtprec = prectbl[op]; - if (nxtprec != 0) - toksidx++; - if (nxtprec < minprec) + if (nxtprec <= minprec) return lhs; + toksidx++; idx_t i = astalloc(ast); - idx_t rhs = parseexpr(ast, aux, toks, nxtprec); + idx_t rhs = parseexpr(ast, toks, nxtprec); ast->kinds[i] = op; ast->lexemes[i] = toksidx - 1; ast->kids[i].lhs = lhs; @@ -276,13 +295,13 @@ parseexprinc(ast_t *ast, aux_t *aux, lexemes_t toks, idx_t lhs, int minprec) } idx_t -parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks, int minprec) +parseexpr(ast_t *ast, lexemes_t toks, int minprec) { - idx_t lhs = parseexprunit(ast, toks); + idx_t lhs = parseexpratom(ast, toks); for (;;) { - idx_t rhs = parseexprinc(ast, aux, toks, lhs, minprec); - if (rhs == lhs) + idx_t rhs = parseexprinc(ast, toks, lhs, minprec); + if (lhs == rhs) break; lhs = rhs; } @@ -323,8 +342,8 @@ parsestmt(ast_t *ast, aux_t *aux, lexemes_t toks) ast->lexemes[i] = toksidx++; ast->kinds[i] = ASTRET; - idx_t rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, aux, toks, 1) - : AST_EMPTY; + idx_t rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, toks, 0) + : AST_EMPTY; ast->kids[i].rhs = rhs; if (toks.kinds[toksidx++] != LEXSEMI) err("parser: Expected semicolon"); @@ -352,6 +371,23 @@ parsetype(ast_t *ast, aux_t *aux, lexemes_t toks) return i; } +bool +isfunc(lexemes_t toks) +{ + assert(toks.kinds[toksidx] == LEXLPAR); + + if (toks.kinds[toksidx + 1] == LEXRPAR) + return true; + for (size_t i = toksidx + 1;; i++) { + switch (toks.kinds[i]) { + case LEXRPAR: + return false; + case LEXCOLON: + return true; + } + } +} + ast_t mkast(void) { |