aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/analyzer.c36
-rw-r--r--src/codegen.c20
-rw-r--r--src/parser.c66
-rw-r--r--src/parser.h8
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 <errno.h>
#include <limits.h>
#include <stdalign.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -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,30 +240,57 @@ 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)
{
idx_t i = astalloc(ast);
@@ -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,
};