aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.c20
-rw-r--r--src/codegen.c24
-rw-r--r--src/parser.c15
-rw-r--r--src/parser.h10
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 = '-',