#include "td.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "parse.h" #include "prv.h" #include "storage.h" #include "type.h" #include #include #include #include #include static int cid(const struct lex *, struct prv *); static int cnum(const struct lex *, struct prv *); static int end(const struct lex *, struct prv *); static int u(const struct lex *, struct prv *); static int s(const struct lex *, struct prv *); static int c(const struct lex *, struct prv *); static int t(const struct lex *, struct prv *); static int p(const struct lex *, struct prv *); static const struct seq seqs[] = { {(const struct step[]){{ID, "end"}, {0}}, .fn = end}, {(const struct step[]){ {ID}, {ID, "constant"}, {ID, "to"}, {ID}, {0}}, .fn = cid}, {(const struct step[]){ {ID}, {ID, "constant"}, {ID, "to"}, {NUM}, {0}}, .fn = cnum}, {(const struct step[]){{ID}, {ID, "constant"}, {0}}, .fn = c}, {(const struct step[]){{ID}, {ID, "type"}, {ID}, {0}}, .fn = t}, {(const struct step[]){{ID}, {ID, "prototype"}, {0}}, .fn = p}, {(const struct step[]){{ID}, {ID, "union"}, {0}}, .fn = u}, {(const struct step[]){{ID}, {ID, "struct"}, {0}}, .fn = s}, {0} }; static void reset(struct prv *p) { struct pos *pos = &p->pos[p->i]; pos->seq = seqs; pos->step = seqs->steps; p->stk = p->tk; } static int bump(const struct tk *tk, const struct type *t, struct prv *p) { struct tdlevel *l = &p->levels[p->block]; int neg = 0; if (!t->sign) { unsigned long long uv = t->u.c.uv; if (uv + 1 < uv) { errloc(tk, "constant value exceeds maximum (%llu)", ULLONG_MAX); return -1; } l->u.uv = ++uv; } else { long long v = t->u.c.v; if (++v < 0) neg = 1; l->u.v = v; } l->neg = neg; for (size_t i = 0; i < p->block; i++) fputc('\t', stderr); fprintf(stderr, "\t\tnext %s constant value set to ", neg ? "negative" : "positive"); if (neg) fprintf(stderr, "%lld", l->u.v); else fprintf(stderr, "%llu", l->u.uv); fputc('\n', stderr); return 0; } static int cid(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); const struct tk *id = p->stk, *v = p->stk + 3; const struct stentry *e; const struct type *t = type_find(fn, id->s); struct tdlevel *lev = &p->levels[p->block]; struct td *td = fn->td; size_t n = td->ntypes + 1; struct type *types, *nt; if (t) { const struct loc *loc = &t->tk->loc; errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, loc->line, loc->col); return -1; } else if ((e = fn_var(fn, id))) { const struct loc *loc = &e->tk->loc; errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, loc->f, loc->line, loc->col); return -1; } else if ((e = fn_var(fn, v))) { const struct loc *loc = &e->tk->loc; errloc(id, "value \"%s\" (defined at %s:%d:%d) is not a constant", v->s, loc->f, loc->line, loc->col); return -1; } else if (!(t = type_find(fn, v->s))) { errloc(id, "undefined reference to value \"%s\"", v->s); return -1; } else if (t->type != C) { const struct loc *loc = &t->tk->loc; errloc(id, "value \"%s\" (defined at %s:%d:%d) is not a constant", v->s, loc->f, loc->line, loc->col); return -1; } else if (!(types = realloc(td->types, n * sizeof *types))) { perror("realloc(3)"); return -1; } td->types = types; nt = &td->types[td->ntypes++]; *nt = (struct type) { .type = C, .tk = id, .sign = t->sign, .u.c = t->u.c }; lev->neg = t->sign; if (bump(id, t, p)) return -1; for (size_t i = 0; i < p->block; i++) fputc('\t', stderr); fprintf(stderr, "\tadding constant %s to %s (%lld)\n", id->s, v->s, t->u.c.v); reset(p); return 1; } static int cnum(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); const struct tk *id = p->stk, *num = p->stk + 3; const char *name = id->s; const struct stentry *e; struct td *td = fn->td; size_t n = td->ntypes + 1; struct type *types, *nt; struct tdlevel *lev = &p->levels[p->block]; const struct type *t = type_find(fn, name); int sign = *num->s == '-'; unsigned long long uv = 0; long long v; char *end; errno = 0; v = strtoll(num->s, &end, 0); if (sign || errno || *end) { errno = 0; uv = strtoull(num->s, NULL, 0); } if (t) { const struct loc *loc = &t->tk->loc; errloc(id, "type \"%s\" already defined at %s:%d:%d", name, loc->f, loc->line, loc->col); return -1; } else if ((e = fn_var(fn, id))) { const struct loc *loc = &e->tk->loc; errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, loc->f, loc->line, loc->col); return -1; } else if (!(types = realloc(td->types, n * sizeof *types))) { perror("realloc(3)"); return -1; } td->types = types; nt = &td->types[td->ntypes++]; *nt = (struct type) { .type = C, .tk = id, .sign = sign }; if (sign) lev->u.v = nt->u.c.v = v; else lev->u.uv = nt->u.c.uv = uv; lev->neg = sign; for (size_t i = 0; i < p->block; i++) fputc('\t', stderr); fprintf(stderr, "\tadding constant %s to %s\n", id->s, num->s); if (bump(id, nt, p)) return -1; reset(p); return 1; } static int c(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); const struct tk *id = p->stk; const struct stentry *e; const struct type *t = type_find(fn, id->s); struct td *td = fn->td; size_t n = td->ntypes + 1; struct type *types, *nt; const struct tdlevel *lev = &p->levels[p->block]; if (t) { const struct loc *loc = &t->tk->loc; errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, loc->line, loc->col); return -1; } else if ((e = fn_var(fn, id))) { const struct loc *loc = &e->tk->loc; errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, loc->f, loc->line, loc->col); return -1; } else if (!(types = realloc(td->types, n * sizeof *types))) { perror("realloc(3)"); return -1; } td->types = types; nt = &td->types[td->ntypes]; *nt = (struct type) { .type = C, .tk = id, .sign = lev->neg, }; if (nt->sign) nt->u.c.v = lev->u.v; else nt->u.c.uv = lev->u.uv; for (size_t i = 0; i < p->block; i++) fputc('\t', stderr); fprintf(stderr, "\tadding constant %s to ", id->s); if (lev->neg) fprintf(stderr, "%lld", lev->u.v); else fprintf(stderr, "%llu", lev->u.uv); fputc('\n', stderr); if (bump(id, &td->types[td->ntypes++], p)) return -1; reset(p); return 1; } static int end(const struct lex *l, struct prv *p) { const struct tk *tk = p->tk - 1; struct type *t; if (!p->block) { errloc(tk, "unexpected \"end\" statement"); return -1; } else if (!(t = p->nest)) { errloc(tk, "unreachable"); return -1; } switch (t->type) { case U: { const struct u *u = &t->u.u; if (!u->storage->nentries) { errloc(t->tk, "struct \"%s\" has no children", t->tk->s); return -1; } } break; case S: { const struct s *s = &t->u.s; if (!s->storage->nentries) { errloc(t->tk, "struct \"%s\" has no children", t->tk->s); return -1; } } break; default: errloc(tk, "unreachable"); return -1; } p->nest = NULL; p->block--; reset(p); return 1; } static int s(const struct lex *l, struct prv *p) { const struct tk *id = p->stk; struct fn *fn = fn_cur(p); struct td *td = fn->td; size_t nb = p->block + 2, nt = td->ntypes + 1; struct tdlevel *levels; struct type *types, *newt; const struct type *t = type_find(fn, id->s); if (t) { const struct loc *loc = &t->tk->loc; errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, loc->line, loc->col); return -1; } else if (!(types = realloc(td->types, nt * sizeof *types))) { perror("realloc(3)"); return -1; } td->types = types; newt = &td->types[td->ntypes++]; *newt = (struct type) { .type = S, .tk = id }; if (!(levels = realloc(p->levels, nb * sizeof *levels))) { perror("realloc(3)"); return -1; } p->levels = levels; p->levels[++p->block] = (struct tdlevel){0}; p->nest = newt; return storage(l, p, id->s, 0, &newt->u.s.storage); } static int u(const struct lex *l, struct prv *p) { fprintf(stderr, "%s: TODO\n", __func__); return -1; } static int t(const struct lex *l, struct prv *p) { fprintf(stderr, "%s: TODO\n", __func__); return -1; } static int p(const struct lex *l, struct prv *p) { fprintf(stderr, "%s: TODO\n", __func__); return -1; } static void type_free(struct type *t) { switch (t->type) { case U: { struct u *u = &t->u.u; storage_free(u->storage); } break; case S: { struct s *s = &t->u.s; storage_free(s->storage); } break; case C: case P: case T: case BUILTIN: break; } } void td_free(struct td *td) { if (td) { for (size_t i = 0; i < td->ntypes; i++) type_free(&td->types[i]); free(td->types); } free(td); } int td(const struct lex *l, struct prv *p) { const struct tk *tk = p->stk; struct fn *fn = fn_cur(p); struct td *td = NULL, *prev = fn->td; struct tdlevel *levels = NULL; struct pos init = { .seq = seqs, .stseq = seqs, .step = seqs->steps }; if (prev) { const struct loc *loc = &prev->tk->loc; errloc(tk, "types section already defined at %s:%d:%d", loc->f, loc->line, loc->col); goto failure; } else if (!(td = malloc(sizeof *td)) || !(levels = malloc(sizeof *levels))) { perror("malloc(3)"); goto failure; } else if (push(&init, p)) goto failure; *levels = (struct tdlevel){0}; *td = (struct td){.tk = tk}; fn->td = td; p->levels = levels; p->stk = p->tk; return 1; failure: free(levels); free(td); return -1; }