diff options
-rw-r--r-- | src/analyzer.c | 35 | ||||
-rw-r--r-- | src/codegen.c | 11 | ||||
-rw-r--r-- | src/common.h | 3 |
3 files changed, 33 insertions, 16 deletions
diff --git a/src/analyzer.c b/src/analyzer.c index 2686e07..fff7716 100644 --- a/src/analyzer.c +++ b/src/analyzer.c @@ -331,8 +331,12 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast, idx_t ni = analyzeexpr(ctx, scps, types, ast, aux, toks, rhs); if (!typecompat(types[lhs], types[rhs])) err("analyzer: Binary oprand type mismatch"); - if (ast.kinds[i] == ASTBINMOD && types[lhs].isfloat) - err("analyzer: Modulus is not defined for floating-point types"); + if (ast.kinds[i] == ASTBINMOD) { + if (types[lhs].kind != TYPE_NUM || types[lhs].isfloat) + 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"); + } types[i] = types[rhs]; return ni; } @@ -488,8 +492,8 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types, MPQCPY(folds[i], folds[expr]); if (!MPQ_IS_INIT(folds[i])) { ctx.si = lvl; - (void)constfolddecl(ctx, folds, scps, types, - ast, toks, sym->i); + (void)constfolddecl(ctx, folds, scps, types, ast, toks, + sym->i); MPQCPY(folds[i], folds[expr]); assert(MPQ_IS_INIT(folds[i])); } @@ -516,16 +520,14 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types, case ASTBINADD: case ASTBINSUB: case ASTBINMUL: - case ASTBINDIV: - case ASTBINMOD: { - static void (*const mpq_fns[UINT8_MAX])(mpq_t, const mpq_t, const mpq_t) = { + case ASTBINDIV: { + static void (*const mpq_fns[UINT8_MAX])(mpq_t, const mpq_t, + const mpq_t) = { ['+'] = mpq_add, ['-'] = mpq_sub, ['*'] = mpq_mul, ['/'] = mpq_div, }; - /* TODO: Support modulus */ - idx_t lhs, rhs; lhs = ast.kids[i].lhs; rhs = ast.kids[i].rhs; @@ -537,6 +539,21 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types, } return ni; } + case ASTBINMOD: { + 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]); + mpz_tdiv_r(mpq_numref(folds[i]), mpq_numref(folds[lhs]), + mpq_numref(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 2f07442..188275b 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -150,13 +150,11 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv) if (!type.issigned && mpq_sgn(ctx.folds[i]) == -1) err("Cannot convert negative value to unsigned type"); - mpz_ptr num, den; - num = mpq_numref(ctx.folds[i]); - den = mpq_denref(ctx.folds[i]); - if (mpz_cmp_ui(den, 1) != 0) - err("Invalid integer"); + if (!MPQ_IS_WHOLE(ctx.folds[i])) + err("codegen: Invalid integer"); int cmp; + mpz_ptr num = mpq_numref(ctx.folds[i]); assert(type.size != 0); /* TODO: Can we make the first branch work when the type has the same size as an unsigned long? */ @@ -243,7 +241,8 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv) case ASTBINADD: case ASTBINSUB: case ASTBINMUL: - case ASTBINDIV: { + case ASTBINDIV: + case ASTBINMOD: { typedef LLVMValueRef llbfn(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); static const struct binop { diff --git a/src/common.h b/src/common.h index 2dffe2a..6285a15 100644 --- a/src/common.h +++ b/src/common.h @@ -17,7 +17,8 @@ # include <stdio.h> #endif -#define MPQ_IS_INIT(x) (mpq_denref(x)->_mp_d != NULL) +#define MPQ_IS_INIT(x) (mpq_denref(x)->_mp_d != NULL) +#define MPQ_IS_WHOLE(x) (mpz_cmp_ui(mpq_denref(x), 1) == 0) /* Some headers like <sys/param.h> may define these */ #ifdef MIN |