aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 16:35:53 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 16:35:53 +0330
commit6cca028ab8d2f87e7005b8760afde0a8a71a023b (patch)
tree6bf1aa84621374d0ba0bf95a12e0097aeb326688 /src
parentmerge bounds checking (diff)
parenttodo: zc0 gaps done (diff)
merge work/xref: zc0 gaps a-f
Diffstat (limited to 'src')
-rw-r--r--src/tools/zc0.c68
1 files changed, 51 insertions, 17 deletions
diff --git a/src/tools/zc0.c b/src/tools/zc0.c
index af85ff8..664ea79 100644
--- a/src/tools/zc0.c
+++ b/src/tools/zc0.c
@@ -34,7 +34,19 @@ static char module_name[64];
static char *src; static int pos, line = 1, tstart, hdr_start;
/* the signature of the function being defined: its header's source text, for the language server (ZC0DOCS) */
static char sgtext[400], sgname[80];
-static int tk, glue; static int64_t tv; static char ts[4096]; /* current token */
+static int tk, glue; static int64_t tv; /* current token */
+/* the token's text. it grows as a long string literal or name needs; there is no fixed limit */
+static char ts0[4096]; static char *ts = ts0; static size_t tscap = sizeof ts0;
+static void tsroom(size_t n)
+{
+ size_t c = tscap; char *nb;
+ if (n < tscap) return;
+ while (c <= n) c *= 2;
+ nb = ts == ts0 ? malloc(c) : realloc(ts, c);
+ if (!nb) { fprintf(stderr, "zc0: out of memory for a token\n"); exit(1); }
+ if (ts == ts0) memcpy(nb, ts0, sizeof ts0);
+ ts = nb; tscap = c;
+}
static int xf, xs, lvi; /* float, byte string; the plain local it came from, or -1 */
static int64_t *img; static int imgcap, here = GORG;
@@ -133,6 +145,24 @@ static void docblock(void)
while (dn && (dbuf[dn - 1] == ' ' || dbuf[dn - 1] == '\t' || dbuf[dn - 1] == '\r' || dbuf[dn - 1] == '\n')) dn--;
dbuf[dn++] = '\n'; dlast = line; docpending = 1;
}
+/* an integer literal at pos, as the compiler reads it: decimal digits (a leading 0 is
+ not octal: 010 is 10), or 0x and hex digits (0x alone is 0). the value wraps modulo
+ 2^64 instead of saturating. the token text is the literal's source. */
+static void intlit(int base)
+{
+ int p = pos, d; uint64_t u = 0;
+ if (base == 16) pos += 2;
+ for (;;) {
+ int c = (unsigned char)src[pos];
+ if (c >= '0' && c <= '9') d = c - '0';
+ else if (base == 16 && c >= 'a' && c <= 'f') d = c - 'a' + 10;
+ else if (base == 16 && c >= 'A' && c <= 'F') d = c - 'A' + 10;
+ else break;
+ u = u * (uint64_t)base + (uint64_t)d; pos++;
+ }
+ tsroom((size_t)(pos - p) + 1); memcpy(ts, src + p, (size_t)(pos - p)); ts[pos - p] = 0;
+ tv = (int64_t)u; tk = T_NUM;
+}
static void next(void)
{
int ws = 0, i;
@@ -153,7 +183,7 @@ static void next(void)
if (isdigit((unsigned char)src[pos]) || (src[pos] == '.' && isdigit((unsigned char)src[pos + 1]))) {
int p = pos, fl = 0;
if (src[pos] == '0' && (src[pos + 1] == 'x' || src[pos + 1] == 'X')) {
- char *e; tv = (int64_t)strtoll(src + pos, &e, 0); memcpy(ts, src + pos, e - src - pos); ts[e - src - pos] = 0; pos = e - src; tk = T_NUM; return;
+ intlit(16); return;
}
if (src[p] == '.') {
int nch = (unsigned char)src[p + 1];
@@ -186,22 +216,21 @@ static void next(void)
}
b[n] = 0; memcpy(ts, b, (size_t)n + 1); tv = (int64_t)fop_parse(b); tk = T_FLT; return;
}
- { char *e; tv = (int64_t)strtoll(src + pos, &e, 0); memcpy(ts, src + pos, e - src - pos); ts[e - src - pos] = 0; pos = e - src; tk = T_NUM; return; }
+ intlit(10); return;
}
if (isalpha((unsigned char)src[pos]) || src[pos] == '_') {
- i = 0; while (isalnum((unsigned char)src[pos]) || src[pos] == '_') ts[i++] = src[pos++];
+ i = 0; while (isalnum((unsigned char)src[pos]) || src[pos] == '_') { tsroom((size_t)i + 2); ts[i++] = src[pos++]; }
ts[i] = 0;
if (i == 1 && ts[0] == 'b' && src[pos] == '"') {
pos++; i = 0;
while (src[pos] && src[pos] != '"') {
- if (i >= 4095) { die("a byte string literal is at most 4095 bytes; embed larger data"); break; }
- ts[i++] = (char)esc();
+ tsroom((size_t)i + 2); ts[i++] = (char)esc();
}
ts[i] = 0; if (src[pos] == '"') pos++; tk = T_BSTR; return;
}
if (src[pos] == '.' && (!strcmp(ts,"rt") || !strcmp(ts,"run") || !strcmp(ts,"core") || !strcmp(ts,"lsp") || !strcmp(ts,"std") || !strcmp(ts,"icon"))) {
- ts[i++] = src[pos++];
- while (isalnum((unsigned char)src[pos]) || src[pos] == '_') ts[i++] = src[pos++];
+ tsroom((size_t)i + 2); ts[i++] = src[pos++];
+ while (isalnum((unsigned char)src[pos]) || src[pos] == '_') { tsroom((size_t)i + 2); ts[i++] = src[pos++]; }
ts[i] = 0;
}
tk = T_ID; return;
@@ -210,8 +239,7 @@ static void next(void)
if (src[pos] == '"') {
pos++; i = 0;
while (src[pos] && src[pos] != '"') {
- if (i >= 4095) { die("a string literal is at most 4095 bytes"); break; }
- ts[i++] = (char)esc();
+ tsroom((size_t)i + 2); ts[i++] = (char)esc();
}
ts[i] = 0; pos++; tk = T_STR; return;
}
@@ -220,9 +248,10 @@ static void next(void)
for (i = 0; ops2[i]; i++) if (!strncmp(src + pos, ops2[i], 2)) { strcpy(ts, ops2[i]); pos += 2; return; }
ts[0] = src[pos++]; ts[1] = 0;
}
-typedef struct { char *src; int pos, line, tk, glue; int64_t tv; char ts[4096]; int xf, xs; } Lex;
-static void lexsave(Lex *L) { L->src = src; L->pos = pos; L->line = line; L->tk = tk; L->glue = glue; L->tv = tv; memcpy(L->ts, ts, sizeof ts); L->xf = xf; L->xs = xs; }
-static void lexrest(Lex *L) { src = L->src; pos = L->pos; line = L->line; tk = L->tk; glue = L->glue; tv = L->tv; memcpy(ts, L->ts, sizeof ts); xf = L->xf; xs = L->xs; }
+/* a saved lexer position. ts is a copy of the token text (malloc), released by lexrest */
+typedef struct { char *src; int pos, line, tk, glue; int64_t tv; char *ts; size_t tn; int xf, xs; } Lex;
+static void lexsave(Lex *L) { L->src = src; L->pos = pos; L->line = line; L->tk = tk; L->glue = glue; L->tv = tv; L->tn = strlen(ts) + 1; L->ts = malloc(L->tn); if (!L->ts) { fprintf(stderr, "zc0: out of memory\n"); exit(1); } memcpy(L->ts, ts, L->tn); L->xf = xf; L->xs = xs; }
+static void lexrest(Lex *L) { src = L->src; pos = L->pos; line = L->line; tk = L->tk; glue = L->glue; tv = L->tv; tsroom(L->tn); memcpy(ts, L->ts, L->tn); free(L->ts); L->ts = 0; xf = L->xf; xs = L->xs; }
static int is(const char *s) { return (tk == T_OP || tk == T_ID) && !strcmp(ts, s); }
static int accept(const char *s) { if (is(s)) { next(); return 1; } return 0; }
static void expect(const char *s) { if (!accept(s)) { char b[64]; sprintf(b, "expected '%s'", s); die(b); } }
@@ -626,7 +655,7 @@ static void postfix(void)
else if (is("(")) { rval(); n = args(); lit(n); op(O_PICK); op(O_CALL); op(O_SWAP); op(O_DROP); xf = 0; xs = 0; lvi = -1; }
else if (accept("++")) incdec(1, 1);
else if (accept("--")) incdec(1, -1);
- else if (accept("as")) ident();
+ else if (accept("as")) ptype0(); /* the whole type, as the compiler reads it: x as int*, x as char** */
else return;
}
}
@@ -820,7 +849,10 @@ static void fndef(int ret, int rstr) /* rstr: the return type is bstr */
if (!accept(")")) {
do {
t = 0; ptag = 0; pstr[np & 15] = 0;
- if (optype() >= 0) { t = ptag == 1 ? 1 : ptag == 2 ? 2 : 0; pstr[np & 15] = ptstr; } /* the type is read and dropped */
+ if (optype() >= 0) { /* the type is read and dropped */
+ if (ptag == 3) die("a parameter tag is .m or .d"); /* the compiler's message: .u is only a return tag */
+ t = ptag == 1 ? 1 : ptag == 2 ? 2 : 0; pstr[np & 15] = ptstr;
+ }
else if (accept(".")) { /* .m name, .d name */
if (is("m")) t = 1; else if (is("d")) t = 2; else die("a parameter tag is .m or .d");
next();
@@ -980,12 +1012,13 @@ static void embeddecl(int local)
}
} else {
int count; w = embed_width(ty, star);
- if (local) die("zc0 embeds an array at the top level, not in a function");
if (!w) die("embed declares a bstr, a char*, a number or an array of numbers");
if (len % w) die("the embedded file's size is not a whole number of elements");
count = (int)(len / w);
if (arr >= 0 && count > arr) die("the embedded file is larger than the array it is declared as");
if (arr >= 0) count = arr;
+ /* in a function the elements sit in the code, jumped over, and the local holds their address */
+ if (local) { j = here; lit(0); op(O_JMP); }
a = here;
for (i = 0; i < count; i++) {
uint64_t u = 0; int k;
@@ -995,7 +1028,8 @@ static void embeddecl(int local)
emit((int64_t)u);
}
if (!count) emit(0);
- add(n, K_GARR, a);
+ if (local) { setlit(j, here); l = newloc(n); lit(a); laddr(l->slot); op(O_ST); }
+ else add(n, K_GARR, a);
}
free(buf);
}