aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/analyzer.c30
-rw-r--r--src/codegen.c21
-rw-r--r--src/parser.c25
-rw-r--r--src/parser.h8
4 files changed, 64 insertions, 20 deletions
diff --git a/src/analyzer.c b/src/analyzer.c
index 4a5a2c6..bf77745 100644
--- a/src/analyzer.c
+++ b/src/analyzer.c
@@ -309,13 +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 ASTUNCMPL:
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)
+ if (ast.kinds[i] == ASTUNNEG && (t.kind != TYPE_NUM || !t.issigned))
err("analyzer: Unary negation is reserved for signed numeric types");
+ else if (ast.kinds[i] == ASTUNCMPL && (t.kind != TYPE_NUM || t.isfloat))
+ err("analyzer: Unary negation is reserved for numeric integer types");
types[i] = t;
return ni;
}
@@ -323,7 +326,8 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast,
case ASTBINSUB:
case ASTBINMUL:
case ASTBINDIV:
- case ASTBINMOD: {
+ case ASTBINMOD:
+ case ASTBINXOR: {
idx_t lhs, rhs;
lhs = ast.kids[i].lhs;
rhs = ast.kids[i].rhs;
@@ -338,6 +342,9 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast,
err("analyzer: Remainder is not defined for non-integer types");
if (types[rhs].kind != TYPE_NUM || types[rhs].isfloat)
err("analyzer: Remainder is not defined for non-integer types");
+ } else if (ast.kinds[i] == ASTBINXOR) {
+ if (types[lhs].kind != TYPE_NUM || types[lhs].isfloat)
+ err("analyzer: XOR is not defined for non-integer types");
}
/* In the expression ‘x ⋆ y’ where ⋆ is a binary operator, the
@@ -519,6 +526,12 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
}
}
}
+ case ASTUNCMPL: {
+ idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, ast.kids[i].rhs);
+ if (MPQ_IS_INIT(folds[ast.kids[i].rhs]))
+ err("analyzer: Cannot perform bitwise complement of constant");
+ return ni;
+ }
case ASTUNNEG: {
idx_t rhs = ast.kids[i].rhs;
idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, rhs);
@@ -568,7 +581,14 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
}
return ni;
}
- case ASTBINMOD: {
+ case ASTBINMOD:
+ case ASTBINXOR: {
+ static void (*const mpz_fns[UINT8_MAX])(mpz_t, const mpz_t,
+ const mpz_t) = {
+ ['%'] = mpz_tdiv_q,
+ ['~'] = mpz_xor,
+ };
+
idx_t lhs, rhs;
lhs = ast.kids[i].lhs;
rhs = ast.kids[i].rhs;
@@ -578,8 +598,8 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
if (MPQ_IS_INIT(folds[lhs]) && MPQ_IS_INIT(folds[rhs])) {
mpq_init(folds[i]);
- mpz_tdiv_r(mpq_numref(folds[i]), mpq_numref(folds[lhs]),
- mpq_numref(folds[rhs]));
+ mpz_fns[ast.kinds[i]](mpq_numref(folds[i]), mpq_numref(folds[lhs]),
+ mpq_numref(folds[rhs]));
}
return ni;
}
diff --git a/src/codegen.c b/src/codegen.c
index 188275b..6b5f5e0 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -232,6 +232,13 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv)
*outv = LLVMBuildLoad2(ctx.bob, t, ptrval, "loadtmp");
return fwdnode(ctx.ast, i);
}
+ case ASTUNCMPL: {
+ LLVMValueRef v, minus_one;
+ minus_one = LLVMConstInt(type2llvm(ctx, ctx.types[i]), -1, false);
+ idx_t ni = codegentypedexpr(ctx, ctx.ast.kids[i].rhs, ctx.types[i], &v);
+ *outv = LLVMBuildXor(ctx.bob, v, minus_one, "cmpltmp");
+ return ni;
+ }
case ASTUNNEG: {
LLVMValueRef v;
idx_t ni = codegentypedexpr(ctx, ctx.ast.kids[i].rhs, ctx.types[i], &v);
@@ -239,10 +246,11 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv)
return ni;
}
case ASTBINADD:
- case ASTBINSUB:
- case ASTBINMUL:
case ASTBINDIV:
- case ASTBINMOD: {
+ case ASTBINMOD:
+ case ASTBINMUL:
+ case ASTBINSUB:
+ case ASTBINXOR: {
typedef LLVMValueRef llbfn(LLVMBuilderRef, LLVMValueRef, LLVMValueRef,
const char *);
static const struct binop {
@@ -250,16 +258,17 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv)
const char *name;
} binoptbl[UINT8_MAX] = {
['+'] = {{LLVMBuildAdd, LLVMBuildAdd}, "addtmp"},
- ['-'] = {{LLVMBuildSub, LLVMBuildSub}, "subtmp"},
['*'] = {{LLVMBuildMul, LLVMBuildMul}, "multmp"},
+ ['-'] = {{LLVMBuildSub, LLVMBuildSub}, "subtmp"},
['/'] = {{LLVMBuildUDiv, LLVMBuildSDiv}, "divtmp"},
['%'] = {{LLVMBuildURem, LLVMBuildSRem}, "remtmp"},
+ ['~'] = {{LLVMBuildXor, LLVMBuildXor}, "xortmp"},
};
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);
+ 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.types[i].issigned](ctx.bob, vl, vr, bo.name);
diff --git a/src/parser.c b/src/parser.c
index 6a96154..f0977d4 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -71,8 +71,10 @@ fwdnode(ast_t ast, idx_t i)
case ASTBINMOD:
case ASTBINMUL:
case ASTBINSUB:
+ case ASTBINXOR:
case ASTCDECL:
case ASTFN:
+ case ASTUNCMPL:
case ASTUNNEG:
i = ast.kids[i].rhs;
break;
@@ -263,6 +265,10 @@ parseexpratom(ast_t *ast, lexemes_t toks)
ast->kinds[i] = ASTUNNEG;
ast->kids[i].rhs = parseexpratom(ast, toks);
break;
+ case LEXTILDE:
+ ast->kinds[i] = ASTUNCMPL;
+ ast->kids[i].rhs = parseexpratom(ast, toks);
+ break;
default:
err("parser: Invalid expression leaf");
}
@@ -275,9 +281,10 @@ parseexprinc(ast_t *ast, lexemes_t toks, idx_t lhs, int minprec)
static const int prectbl[UINT8_MAX] = {
['+'] = 1,
['-'] = 1,
+ ['~'] = 1,
+ ['%'] = 2,
['*'] = 2,
['/'] = 2,
- ['%'] = 2,
};
uint8_t op = toks.kinds[toksidx];
@@ -378,18 +385,18 @@ isfunc(lexemes_t toks)
if (toks.kinds[toksidx + 1] == LEXRPAR)
return true;
- for (size_t i = toksidx + 1, nst = 1;; i++) {
+ for (size_t i = toksidx + 1;; i++) {
switch (toks.kinds[i]) {
- case LEXLPAR:
- nst++;
- break;
- case LEXRPAR:
- if (--nst == 0)
- return false;
- break;
case LEXCOLON:
return true;
case LEXEOF:
+ case LEXLPAR:
+ case LEXMINUS:
+ case LEXPERC:
+ case LEXPLUS:
+ case LEXRPAR:
+ case LEXSLASH:
+ case LEXSTAR:
return false;
}
}
diff --git a/src/parser.h b/src/parser.h
index 0a25a4c..3cf4292 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -53,6 +53,10 @@ enum {
‘-rhs’ */
ASTUNNEG,
+ /* Unary complement
+ ‘~rhs’ */
+ ASTUNCMPL,
+
/* NOTE: Ensure that the enumerations defined above this comment do
not exceed 37 — the value of ‘%’ — or they will conflict with the
definitions below. */
@@ -76,6 +80,10 @@ enum {
/* Binary modulus
‘lhs % rhs’ */
ASTBINMOD = '%',
+
+ /* Binary xor
+ ‘lhs ~ rhs’ */
+ ASTBINXOR = '~',
};
#define AST_EMPTY ((idx_t)-1)