aboutsummaryrefslogtreecommitdiff
path: root/src/tools/zc0.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/zc0.c')
-rw-r--r--src/tools/zc0.c40
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);