commit ba13e1099a3818307a3209e5c329130bde791ff9
parent 28541ae45185f623f7ff4693081ec3144f477858
Author: Eyal Sawady <ecs@d2evs.net>
Date: Tue, 8 Mar 2022 12:15:52 +0000
lex: separate negative literals into two tokens
Fixes some lexer ambiguities and allows negative unsigned constants
Signed-off-by: Eyal Sawady <ecs@d2evs.net>
Diffstat:
9 files changed, 40 insertions(+), 24 deletions(-)
diff --git a/include/qbe.h b/include/qbe.h
@@ -134,6 +134,7 @@ enum qbe_instr {
Q_OR,
Q_REM,
Q_RET,
+ Q_NEG,
Q_SAR,
Q_SHL,
Q_SHR,
diff --git a/src/check.c b/src/check.c
@@ -2633,6 +2633,17 @@ check_expr_unarithm(struct context *ctx,
expr->result = operand->result;
break;
case UN_MINUS:
+ if (operand->result->storage == STORAGE_ICONST) {
+ // Not technically quite right, but we need
+ // operand->result to be lowered with expr->result, and
+ // this is correct enough
+ const struct type *old = operand->result;
+ const struct type *new = type_create_const(
+ STORAGE_ICONST, -old->_const.min,
+ -old->_const.max);
+ lower_const(old, new);
+ }
+ // Fallthrough
case UN_PLUS:
if (!type_is_numeric(operand->result)) {
error(ctx, aexpr->unarithm.operand->loc, expr,
diff --git a/src/eval.c b/src/eval.c
@@ -755,7 +755,11 @@ eval_unarithm(struct context *ctx, struct expression *in, struct expression *out
out->constant.bval = !lvalue.constant.bval;
break;
case UN_MINUS:
- out->constant.ival = -lvalue.constant.ival;
+ if (type_is_float(out->result)) {
+ out->constant.fval = -lvalue.constant.fval;
+ } else {
+ out->constant.ival = -lvalue.constant.ival;
+ }
break;
case UN_PLUS:
out->constant = lvalue.constant;
diff --git a/src/gen.c b/src/gen.c
@@ -2766,8 +2766,7 @@ gen_expr_unarithm(struct gen_context *ctx,
val = gen_expr(ctx, operand);
temp = mktemp(ctx, operand->result, ".%d");
qval = mkqval(ctx, &val), qtmp = mkqval(ctx, &temp);
- struct qbe_value zerol = constl(0);
- pushi(ctx->current, &qtmp, Q_SUB, &zerol, &qval, NULL);
+ pushi(ctx->current, &qtmp, Q_NEG, &qval, NULL);
return temp;
case UN_PLUS:
return gen_expr(ctx, operand);
diff --git a/src/lex.c b/src/lex.c
@@ -279,9 +279,6 @@ static uint32_t
lex_literal(struct lexer *lexer, struct token *out)
{
uint32_t c = next(lexer, &out->loc, true);
- if (c == '-') {
- c = next(lexer, NULL, true);
- }
assert(c != UTF8_INVALID && c <= 0x7F && isdigit(c));
int base = 10;
@@ -434,16 +431,13 @@ finalize:
}
break;
case STORAGE_ICONST:
- if (lexer->buf[0] != '-') {
- uintmax_t uval = strtoumax(lexer->buf, NULL, base);
- for (intmax_t i = 0; i < exponent; i++) {
- uval *= 10;
- }
- if (uval > (uintmax_t)INT64_MAX) {
- out->storage = STORAGE_U64;
- out->uval = uval;
- break;
- }
+ out->uval = strtoumax(lexer->buf, NULL, base);
+ for (intmax_t i = 0; i < exponent; i++) {
+ out->uval *= 10;
+ }
+ if (out->uval > (uintmax_t)INT64_MAX) {
+ out->storage = STORAGE_U64;
+ break;
}
// Fallthrough
case STORAGE_I8:
@@ -451,6 +445,15 @@ finalize:
case STORAGE_I32:
case STORAGE_INT:
case STORAGE_I64:
+ out->uval = strtoumax(lexer->buf, NULL, base);
+ for (intmax_t i = 0; i < exponent; i++) {
+ out->uval *= 10;
+ }
+ if (out->uval == (uintmax_t)INT64_MIN) {
+ // XXX: Hack
+ out->ival = INT64_MIN;
+ break;
+ }
out->ival = strtoimax(lexer->buf, NULL, base);
for (intmax_t i = 0; i < exponent; i++) {
out->ival *= 10;
@@ -816,11 +819,6 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c)
out->token = T_MINUSEQ;
break;
default:
- if (c != UTF8_INVALID && c <= 0x7F && isdigit(c)) {
- push(lexer, c, false);
- push(lexer, '-', false);
- return lex_literal(lexer, out);
- }
push(lexer, c, false);
out->token = T_MINUS;
break;
diff --git a/src/qbe.c b/src/qbe.c
@@ -106,6 +106,7 @@ const char *qbe_instr[Q_LAST_INSTR] = {
[Q_LOADUH] = "loaduh",
[Q_LOADUW] = "loaduw",
[Q_MUL] = "mul",
+ [Q_NEG] = "neg",
[Q_OR] = "or",
[Q_REM] = "rem",
[Q_RET] = "ret",
diff --git a/tests/00-constants.ha b/tests/00-constants.ha
@@ -135,7 +135,7 @@ fn aggregates() void = {
export fn main() void = {
let i1 = 13, i2 = 13i, i3 = 13i8, i4 = 13i16, i5 = 13i32, i6 = 13i64;
let u1 = 13u, u2 = 13z, u3 = 13u8, u4 = 13u16, u5 = 13u32, u6 = 13u64;
- let n = -13;
+ let n1 = -13, n2 = -13u;
let b1 = true, b2 = false;
let p1: nullable *int = null;
let r1 = 'x', r2 = '\x0A', r3 = '\u1234', r4 = '\0', r5 = '\a',
diff --git a/tests/10-binarithms.ha b/tests/10-binarithms.ha
@@ -71,7 +71,7 @@ fn sar_shr() void = {
let x = 1i64;
x <<= 63;
- assert(x == -9223372036854775808);
+ assert(x == -9223372036854775808i64);
x >>= 63;
assert(x == -1);
diff --git a/tests/29-unarithm.ha b/tests/29-unarithm.ha
@@ -14,7 +14,9 @@ fn addr() void = {
let z = &struct { a: int = 42 };
assert(z.a == 42);
let a = -2;
- assert(a == 0i - 2i);
+ assert(a == 0 - 2);
+ let b = 1-1;
+ assert(b == 0);
};
export fn main() void = {