aboutsummaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 18:25:36 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 18:25:36 +0330
commit08173d7f88f8551caca81594ed8af79d82d3f71f (patch)
treeb6efdbe27675dc8ad6102e637ab9c8d341cf494e /src/tools
parentmerge work/small-oob: bytes test out-of-bounds read (diff)
constant expressions: c precedence and / % ^ (b.1.3); local const usable in constant expressions (b.1.7, b.2.16); zc0 matches
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/zc0.c40
1 files changed, 33 insertions, 7 deletions
diff --git a/src/tools/zc0.c b/src/tools/zc0.c
index 6c62abf..229734c 100644
--- a/src/tools/zc0.c
+++ b/src/tools/zc0.c
@@ -396,16 +396,42 @@ static int64_t cprim(void)
if (tk == T_ID && (s = find(ts)) && (s->kind == K_CONST || (s->kind != K_GVAR && s->defd))) { next(); return s->val; }
die("constant expected"); return 0;
}
-static int64_t cexpr(void)
+/* c precedence (spec 3.14.1): * / % above + -, above << >>, above &, ^, | */
+static int cprec(void)
{
- int64_t v = cprim();
- for (;;) {
- if (accept("+")) v += cprim(); else if (accept("-")) v -= cprim();
- else if (accept("*")) v *= cprim(); else if (accept("|")) v |= cprim();
- else if (accept("&")) v &= cprim(); else if (accept("<<")) v <<= cprim();
- else if (accept(">>")) v >>= cprim(); else return v;
+ if (is("*") || is("/") || is("%")) return 10;
+ if (is("+") || is("-")) return 9;
+ if (is("<<") || is(">>")) return 8;
+ if (is("&")) return 5;
+ if (is("^")) return 4;
+ if (is("|")) return 3;
+ return 0;
+}
+static int64_t cbin(int minp)
+{
+ int64_t v = cprim(), w; int p; char o[3];
+ while ((p = cprec()) && p >= minp) {
+ o[0] = ts[0]; o[1] = ts[1]; o[2] = 0;
+ next(); w = cbin(p + 1);
+ switch (o[0]) {
+ case '*': v *= w; break;
+ case '/': case '%':
+ if (w == 0) { die("division by zero in a constant expression"); return 0; }
+ if (w == -1) v = o[0] == '/' ? (int64_t)(0 - (uint64_t)v) : 0;
+ else v = o[0] == '/' ? v / w : v % w;
+ break;
+ case '+': v += w; break;
+ case '-': v -= w; break;
+ case '<': v = (int64_t)((uint64_t)v << (w & 63)); break;
+ case '>': v >>= (w & 63); break;
+ case '&': v &= w; break;
+ case '^': v ^= w; break;
+ default: v |= w; break;
+ }
}
+ return v;
}
+static int64_t cexpr(void) { return cbin(1); }
/* ---- types ----
zc0 has no types: a type is read and thrown away. all it has to know is the