From b75cc76276216af71d7bc89c894187df726e4a71 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 28 Jun 2024 13:14:47 +0200 Subject: Prelimiary work on binary expressions --- src/analyzer.c | 36 ++++++++++++++++++++++++++++++++ src/codegen.c | 20 ++++++++++++++++++ src/parser.c | 66 +++++++++++++++++++++++++++++++++++++++++++++------------- src/parser.h | 8 +++++++ 4 files changed, 116 insertions(+), 14 deletions(-) diff --git a/src/analyzer.c b/src/analyzer.c index c74e89f..de4400c 100644 --- a/src/analyzer.c +++ b/src/analyzer.c @@ -319,6 +319,20 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast, types[i] = t; return ni; } + case ASTBINADD: + case ASTBINSUB: + case ASTBINMUL: + case ASTBINDIV: { + idx_t lhs, rhs; + lhs = ast.kids[i].lhs; + rhs = ast.kids[i].rhs; + analyzeexpr(ctx, scps, types, ast, aux, toks, lhs); + idx_t ni = analyzeexpr(ctx, scps, types, ast, aux, toks, rhs); + if (!typecompat(types[lhs], types[rhs])) + err("analyzer: Binary oprand type mismatch"); + types[i] = types[rhs]; + return ni; + } case ASTFN: return analyzefn(ctx, scps, types, ast, aux, toks, i); default: @@ -496,6 +510,28 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types, } return ni; } + case ASTBINADD: + case ASTBINSUB: + case ASTBINMUL: + case ASTBINDIV: { + static void (*const mpq_fns[_AST_LAST_ENT])(mpq_t, const mpq_t, const mpq_t) = { + ['+'] = mpq_add, + ['-'] = mpq_sub, + ['*'] = mpq_mul, + ['/'] = mpq_div, + }; + + idx_t lhs, rhs; + lhs = ast.kids[i].lhs; + rhs = ast.kids[i].rhs; + (void)constfoldexpr(ctx, folds, scps, types, ast, toks, lhs); + idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, rhs); + if (MPQ_IS_INIT(folds[lhs]) && MPQ_IS_INIT(folds[rhs])) { + mpq_init(folds[i]); + mpq_fns[ast.kinds[i]](folds[i], folds[lhs], folds[rhs]); + } + return ni; + } case ASTFN: return constfoldblk(ctx, folds, scps, types, ast, toks, ast.kids[i].rhs); diff --git a/src/codegen.c b/src/codegen.c index 1286131..eb26036 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -14,6 +14,7 @@ #include "analyzer.h" #include "common.h" #include "errors.h" +#include "parser.h" #include "strview.h" #define lengthof(xs) (sizeof(xs) / sizeof(*(xs))) @@ -228,6 +229,25 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv) *outv = LLVMBuildNeg(ctx.bob, v, "negtmp"); return ni; } + case ASTBINADD: + case ASTBINSUB: + case ASTBINMUL: { + typedef LLVMValueRef llbfn(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); + static const struct binop { + llbfn *fn; + const char *name; + } binoptbl[_AST_LAST_ENT] = { + ['+'] = { LLVMBuildAdd, "addtmp" }, + ['-'] = { LLVMBuildSub, "subtmp" }, + ['*'] = { LLVMBuildMul, "multmp" }, + }; + LLVMValueRef vl, vr; + (void)codegentypedexpr(ctx, ctx.ast.kids[i].lhs, ctx.types[i], &vl); + idx_t ni = codegentypedexpr(ctx, ctx.ast.kids[i].rhs, ctx.types[i], &vr); + struct binop bo = binoptbl[ctx.ast.kinds[i]]; + *outv = bo.fn(ctx.bob, vl, vr, bo.name); + return ni; + } default: __builtin_unreachable(); } diff --git a/src/parser.c b/src/parser.c index cb8aa8f..69417b2 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -9,6 +10,7 @@ #include "alloc.h" #include "common.h" #include "errors.h" +#include "lexer.h" #include "parser.h" #include "strview.h" @@ -23,9 +25,11 @@ typedef idx_t parsefn(ast_t *, aux_t *, lexemes_t) __attribute__((nonnull)); -static parsefn parseblk, parseexpr, parsefunc, parseproto, parsestmt, parsetype; +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) + __attribute__((nonnull)); static ast_t mkast(void); @@ -41,6 +45,14 @@ 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) { @@ -188,7 +200,7 @@ 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); + rhs = parseexpr(ast, aux, toks, 1); } ast->kids[i].rhs = rhs; @@ -216,9 +228,8 @@ parsefunc(ast_t *ast, aux_t *aux, lexemes_t toks) } idx_t -parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks) +parseexprunit(ast_t *ast, lexemes_t toks) { - (void)aux; idx_t i = astalloc(ast); /* Unary plus is kind of a fake syntactic construct. We just pretend @@ -229,29 +240,56 @@ parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks) ast->lexemes[i] = toksidx; - switch (toks.kinds[toksidx]) { + switch (toks.kinds[toksidx++]) { case LEXNUM: - toksidx++; ast->kinds[i] = ASTNUMLIT; break; case LEXIDENT: - toksidx++; ast->kinds[i] = ASTIDENT; break; - case LEXMINUS: { - toksidx++; + case LEXMINUS: ast->kinds[i] = ASTUNNEG; - idx_t rhs = parseexpr(ast, aux, toks); - ast->kids[i].rhs = rhs; + ast->kids[i].rhs = parseexprunit(ast, toks); break; - } default: - err("parser: Expected expression"); + err("parser: Invalid expression leaf"); } + return i; +} +idx_t +parseexprinc(ast_t *ast, aux_t *aux, lexemes_t toks, idx_t lhs, int minprec) +{ + uint8_t op = toks.kinds[toksidx]; + int nxtprec = prectbl[op]; + if (nxtprec != 0) + toksidx++; + if (nxtprec < minprec) + return lhs; + idx_t i = astalloc(ast); + idx_t rhs = parseexpr(ast, aux, toks, nxtprec); + ast->kinds[i] = op; + ast->lexemes[i] = toksidx - 1; + ast->kids[i].lhs = lhs; + ast->kids[i].rhs = rhs; return i; } +idx_t +parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks, int minprec) +{ + idx_t lhs = parseexprunit(ast, toks); + + for (;;) { + idx_t rhs = parseexprinc(ast, aux, toks, lhs, minprec); + if (rhs == lhs) + break; + lhs = rhs; + } + + return lhs; +} + idx_t parseproto(ast_t *ast, aux_t *aux, lexemes_t toks) { @@ -285,7 +323,7 @@ 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) + idx_t rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, aux, toks, 1) : AST_EMPTY; ast->kids[i].rhs = rhs; if (toks.kinds[toksidx++] != LEXSEMI) diff --git a/src/parser.h b/src/parser.h index 055350a..9cdf0c4 100644 --- a/src/parser.h +++ b/src/parser.h @@ -66,6 +66,14 @@ enum { ‘lhs - rhs’ */ ASTBINSUB = '-', + /* Binary multiplication + ‘lhs - rhs’ */ + ASTBINMUL = '*', + + /* Binary division + ‘lhs - rhs’ */ + ASTBINDIV = '/', + _AST_LAST_ENT, }; -- cgit v1.2.3