diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.c | 20 | ||||
-rw-r--r-- | src/codegen.c | 24 | ||||
-rw-r--r-- | src/parser.c | 15 | ||||
-rw-r--r-- | src/parser.h | 10 |
4 files changed, 61 insertions, 8 deletions
diff --git a/src/analyzer.c b/src/analyzer.c index 6e6df9d..c74e89f 100644 --- a/src/analyzer.c +++ b/src/analyzer.c @@ -309,6 +309,16 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast, err("analyzer: Unknown symbol ‘%.*s’", SV_PRI_ARGS(sv)); } + case ASTUNNEG: { + idx_t ni, rhs; + rhs = ast.kids[i].rhs; + ni = analyzeexpr(ctx, scps, types, ast, aux, toks, rhs); + type_t t = types[rhs]; + if (t.kind != TYPE_NUM || !t.issigned) + err("analyzer: Unary negation is reserved for signed numeric types"); + types[i] = t; + return ni; + } case ASTFN: return analyzefn(ctx, scps, types, ast, aux, toks, i); default: @@ -476,6 +486,16 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types, } } } + case ASTUNNEG: { + idx_t rhs = ast.kids[i].rhs; + idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, rhs); + mpq_t *x = folds + rhs; + if (MPQ_IS_INIT(*x)) { + MPQCPY(folds[i], *x); + mpq_neg(folds[i], folds[i]); + } + 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 a9b1430..9e9e329 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -211,13 +211,23 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv) return fwdnode(ctx.ast, i); } - assert(ctx.ast.kinds[i] == ASTIDENT); - - strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]]; - LLVMTypeRef t = type2llvm(ctx, ctx.types[i]); - LLVMValueRef ptrval = symtab_insert(&ctx.scps[ctx.scpi].map, sv, NULL)->v; - *outv = LLVMBuildLoad2(ctx.bob, t, ptrval, "loadtmp"); - return fwdnode(ctx.ast, i); + switch (ctx.ast.kinds[i]) { + case ASTIDENT: { + strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]]; + LLVMTypeRef t = type2llvm(ctx, ctx.types[i]); + LLVMValueRef ptrval = symtab_insert(&ctx.scps[ctx.scpi].map, sv, NULL)->v; + *outv = LLVMBuildLoad2(ctx.bob, t, ptrval, "loadtmp"); + return fwdnode(ctx.ast, i); + } + case ASTUNNEG: { + LLVMValueRef v; + idx_t ni = codegentypedexpr(ctx, ctx.ast.kids[i].rhs, ctx.types[i], &v); + *outv = LLVMBuildNeg(ctx.bob, v, "negtmp"); + return ni; + } + default: + __builtin_unreachable(); + } } idx_t diff --git a/src/parser.c b/src/parser.c index fa1c720..cb8aa8f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -61,6 +61,7 @@ fwdnode(ast_t ast, idx_t i) case ASTBINSUB: case ASTCDECL: case ASTFN: + case ASTUNNEG: i = ast.kids[i].rhs; break; case ASTIDENT: @@ -219,6 +220,13 @@ parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks) { (void)aux; idx_t i = astalloc(ast); + + /* Unary plus is kind of a fake syntactic construct. We just pretend + like it doesn’t exist, but allow it in the syntax to be consistent + with unary negation. */ + while (toks.kinds[toksidx] == LEXPLUS) + toksidx++; + ast->lexemes[i] = toksidx; switch (toks.kinds[toksidx]) { @@ -230,6 +238,13 @@ parseexpr(ast_t *ast, aux_t *aux, lexemes_t toks) toksidx++; ast->kinds[i] = ASTIDENT; break; + case LEXMINUS: { + toksidx++; + ast->kinds[i] = ASTUNNEG; + idx_t rhs = parseexpr(ast, aux, toks); + ast->kids[i].rhs = rhs; + break; + } default: err("parser: Expected expression"); } diff --git a/src/parser.h b/src/parser.h index d8991c0..055350a 100644 --- a/src/parser.h +++ b/src/parser.h @@ -50,11 +50,19 @@ enum { ‘return rhs’ */ ASTRET, + /* Unary negation + ‘-rhs’ */ + ASTUNNEG, + + /* NOTE: Ensure that the enumerations defined above this comment do + not exceed 37 — the value of ‘%’ — or they will conflict with the + definitions below. */ + /* Binary add ‘lhs + rhs’ */ ASTBINADD = '+', - /* Binary sub + /* Binary subtraction ‘lhs - rhs’ */ ASTBINSUB = '-', |