From a8a3f92984afbe4e02a427bfea468ebc2e146a5a Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 28 Jun 2024 23:57:45 +0200 Subject: Implement ~x and x ~ y --- src/analyzer.c | 30 +++++++++++++++++++++++++----- src/codegen.c | 21 +++++++++++++++------ src/parser.c | 25 ++++++++++++++++--------- src/parser.h | 8 ++++++++ 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) -- cgit v1.2.3