diff options
| author | 2026-10-14 17:00:26 +0330 | |
|---|---|---|
| committer | 2026-10-14 17:00:26 +0330 | |
| commit | ff16b77d03c997ac4214b5a440c83cd849be7a2d (patch) | |
| tree | 159dd6fc86dbb3dfc0381f109681751085011c77 /src | |
| parent | len: len on a char* is an error with typecheck off too (appendix b.2.14) (diff) | |
| parent | merge work/xref: zc0 u*d redo and follow-ups (diff) | |
Merge branch 'main' into work/spec
Diffstat (limited to 'src')
| -rw-r--r-- | src/tools/zc0.c | 40 |
1 files changed, 26 insertions, 14 deletions
diff --git a/src/tools/zc0.c b/src/tools/zc0.c index 664ea79..6c62abf 100644 --- a/src/tools/zc0.c +++ b/src/tools/zc0.c @@ -48,6 +48,9 @@ static void tsroom(size_t n) ts = nb; tscap = c; } static int xf, xs, lvi; /* float, byte string; the plain local it came from, or -1 */ +/* xro: the value is a local embed array (Loc.ro); lro: the lvalue is one of its elements, which zc0 refuses to write */ +static int xro, lro; +static void rocheck(void); static int64_t *img; static int imgcap, here = GORG; static void emit(int64_t w) { @@ -257,12 +260,8 @@ 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); } } static char *ident(void) { static char b[8][256]; static int k; char *r = b[k++ & 7]; if (tk != T_ID) die("expected a name"); strcpy(r, ts); next(); return r; } /* u, m and d are ordinary names. u*x, m*x and d*x are recasts when the star touches - the letter, which the raw character after the name tells: u * x is a product, and + the letter and no variable of that name is visible, which the raw character after the name tells: u * x is a product, and so is u*=x. the current token is the name, so pos is just past it. */ -static int isrecast(void) -{ - return tk == T_ID && ts[1] == 0 && (ts[0] == 'u' || ts[0] == 'm' || ts[0] == 'd') && src[pos] == '*' && src[pos + 1] != '='; -} /* ---- symbols ---- */ typedef struct { char name[64]; int kind, sig, defd, str; int64_t val; } Sym; /* str: a global holding a byte string, or a function returning one */ @@ -300,9 +299,16 @@ static void fnref(const char *n) /* push a function address, fixing it up later } /* ---- locals ---- */ -typedef struct { char name[64]; int slot, arr, flt, str, dstr; } Loc; /* dstr: declared bstr, so always a byte string */ +typedef struct { char name[64]; int slot, arr, flt, str, dstr, ro; } Loc; /* dstr: declared bstr, so always a byte string; ro: a local embed array, whose elements are in the code */ static Loc lo[1024]; static int nlo, nslot, infn; static Loc *findl(const char *n) { int i; for (i = nlo; i--;) if (!strcmp(lo[i].name, n)) return &lo[i]; return 0; } +static int isrecast(void) +{ + Sym *g; + if (!(tk == T_ID && ts[1] == 0 && (ts[0] == 'u' || ts[0] == 'm' || ts[0] == 'd') && src[pos] == '*' && src[pos + 1] != '=')) return 0; + if (findl(ts)) return 0; /* a visible variable named u, m or d: a product (spec 1.6.3) */ + g = find(ts); return !(g && (g->kind == K_GVAR || g->kind == K_GARR)); +} static void laddr(int k) { lit(ZFP); op(O_LD); if (k) { lit(k); op(O_ADD); } } /* ---- operator tables ---- */ @@ -594,10 +600,11 @@ static int returns_bstr(const char *n) } static int args(void) { int n = 0; expect("("); if (!accept(")")) { do { expr(); rval(); n++; } while (accept(",")); expect(")"); } return n; } static void asmblock(void); +static void rocheck(void) { if (lro) die("a local embed array is part of the code; zc0 does not let a program write it (embed it at the top level)"); } static void primary(void) { char n[64]; Loc *l; Sym *s; - lv = 0; lvi = -1; xf = 0; xs = 0; + lv = 0; lvi = -1; xf = 0; xs = 0; xro = 0; lro = 0; if (tk == T_FLT) { emit(1200); emit(tv); xf = 1; next(); return; } if (tk == T_NUM) { lit(tv); next(); return; } if (tk == T_BSTR) { bstrlit(); xs = 1; return; } @@ -605,7 +612,7 @@ static void primary(void) if (accept("(")) { expr(); expect(")"); return; } if (is("asm")) { next(); asmblock(); return; } strcpy(n, ident()); - if ((l = findl(n))) { laddr(l->slot); lv = !l->arr; if (!l->arr) { xf = l->flt; xs = l->str; lvi = (int)(l - lo); } return; } + if ((l = findl(n))) { laddr(l->slot); lv = !l->arr; if (!l->arr) { xf = l->flt; xs = l->str; lvi = (int)(l - lo); } xro = l->ro; return; } s = find(n); if (s && s->kind == K_CONST) { lit(s->val); return; } if (s && s->kind == K_GVAR) { lit(s->val); lv = 1; xs = s->str; return; } @@ -631,6 +638,7 @@ static void primary(void) static void incdec(int post, int d) { if (!lv) die("++/-- needs an lvalue"); + rocheck(); lv = 0; if (lvi >= 0) lo[lvi].str = lo[lvi].dstr; xs = 0; @@ -643,6 +651,7 @@ static void postfix(void) primary(); for (;;) { if (accept("[")) { + int ro = xro; was = xs; rval(); expr(); rval(); if (was && accept(":")) { expr(); rval(); expect("]"); fnref("slice_s"); op(O_CALL); @@ -651,8 +660,9 @@ static void postfix(void) expect("]"); fnref("at_s"); op(O_CALL); lv = 0; xs = 0; xf = 0; lvi = -1; } else { expect("]"); op(O_ADD); lv = 1; xs = 0; xf = 0; lvi = -1; } + xro = 0; lro = ro; } - 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 (is("(")) { rval(); n = args(); lit(n); op(O_PICK); op(O_CALL); op(O_SWAP); op(O_DROP); xf = 0; xs = 0; lvi = -1; xro = 0; lro = 0; } else if (accept("++")) incdec(1, 1); else if (accept("--")) incdec(1, -1); else if (accept("as")) ptype0(); /* the whole type, as the compiler reads it: x as int*, x as char** */ @@ -668,7 +678,7 @@ static void unary(void) } else if (accept("!")) { unary(); rval(); ftest(); seq_isz(); xf = 0; xs = 0; } else if (accept("~")) { unary(); rval(); lit(-1); op(O_XOR); xf = 0; xs = 0; } - else if (accept("*")) { unary(); rval(); lv = 1; xs = 0; } + else if (accept("*")) { unary(); rval(); lv = 1; xs = 0; xro = 0; lro = 0; } else if (accept("&")) { unary(); if (!lv) die("& needs an lvalue"); lv = 0; xs = 0; } else if (accept("++")) { unary(); incdec(0, 1); } else if (accept("--")) { unary(); incdec(0, -1); } @@ -695,7 +705,7 @@ static void bin(int minp) } else if ((lf || rf) && fis(o)) { fbinop(o, lf, rf); xs = 0; } else { binop(o); xf = 0; xs = 0; } } - lv = 0; lvi = -1; + lv = 0; lvi = -1; xro = 0; lro = 0; } } static void expr(void) @@ -704,11 +714,13 @@ static void expr(void) bin(1); dst = lvi; if (is("=")) { if (!lv) die("assignment needs an lvalue"); + rocheck(); next(); expr(); rval(); op(O_SWAP); lit(1); op(O_PICK); op(O_SWAP); op(O_ST); lv = 0; if (dst >= 0) { lo[dst].flt = xf; lo[dst].str = xs || lo[dst].dstr; } } else if (tk == T_OP && strlen(ts) >= 2 && ts[strlen(ts) - 1] == '=' && strcmp(ts, "==") && strcmp(ts, "!=") && strcmp(ts, "<=") && strcmp(ts, ">=")) { if (!lv) die("assignment needs an lvalue"); + rocheck(); lf = xf; strcpy(o, ts); o[strlen(o) - 1] = 0; next(); lit(0); op(O_PICK); op(O_LD); lv = 0; expr(); rval(); if ((lf || xf) && fis(o)) fbinop(o, lf, xf); @@ -780,7 +792,7 @@ static void stmt(void) else if (is(".")) { next(); ptagname(); nw = 1; } /* a bare tag: .m p = new(3); */ else if (is("embed")) { /* embed "file" as [type] name; makes a local */ Lex L; lexsave(&L); next(); - if (tk == T_STR) { embeddecl(1); return; } + if (tk == T_STR) { free(L.ts); embeddecl(1); return; } /* the saved token is not restored */ lexrest(&L); } if (nw >= 0 || accept("let") || accept("var")) { @@ -953,7 +965,7 @@ static int embed_width(const char *t, int star) } static Loc *newloc(const char *n) { - Loc *l = &lo[nlo++]; strcpy(l->name, n); l->slot = nslot++; l->arr = l->flt = l->str = l->dstr = 0; + Loc *l = &lo[nlo++]; strcpy(l->name, n); l->slot = nslot++; l->arr = l->flt = l->str = l->dstr = l->ro = 0; return l; } static void embeddecl(int local) @@ -1028,7 +1040,7 @@ static void embeddecl(int local) emit((int64_t)u); } if (!count) emit(0); - if (local) { setlit(j, here); l = newloc(n); lit(a); laddr(l->slot); op(O_ST); } + if (local) { setlit(j, here); l = newloc(n); l->ro = 1; lit(a); laddr(l->slot); op(O_ST); } else add(n, K_GARR, a); } free(buf); |
