#include "td.h" #include "div.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 #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 a(const struct lex *, struct prv *); static int p(const struct lex *, struct prv *); static const struct seq seqs[] = { {(struct step[]){{ID, "end"}, {0}}, .fn = end}, {(struct step[]){{ID}, {ID, "constant"}, {ID, "to"}, {ID}, {0}}, .fn = cid}, {(struct step[]){{ID}, {ID, "constant"}, {ID, "to"}, {NUM}, {0}}, .fn = cnum}, {(struct step[]){{ID}, {ID, "alias"}, {ID, "of"}, {0}}, .fn = a}, {(struct step[]){{ID}, {ID, "union"}, {0}}, .fn = u}, {(struct step[]){{ID}, {ID, "struct"}, {0}}, .fn = s}, {(struct step[]){{ID}, {ID, "constant"}, {0}}, .fn = c}, {(struct step[]){{ID}, {ID, "prototype"}, {0}}, .fn = p}, {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 tdconstant *tdc = p->tdc; 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; } tdc->u.uv = ++uv; } else { long long v = t->u.c.v; if (++v < 0) neg = 1; tdc->u.v = v; } tdc->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", tdc->u.v); else fprintf(stderr, "%llu", tdc->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 tdconstant *tdc = p->tdc; 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 }; tdc->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 tdconstant *tdc = p->tdc; 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) tdc->u.v = nt->u.c.v = v; else tdc->u.uv = nt->u.c.uv = uv; tdc->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 tdconstant *tdc = p->tdc; 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 = tdc->neg, }; if (nt->sign) nt->u.c.v = tdc->u.v; else nt->u.c.uv = tdc->u.uv; for (size_t i = 0; i < p->block; i++) fputc('\t', stderr); fprintf(stderr, "\tadding constant %s to ", id->s); if (tdc->neg) fprintf(stderr, "%lld", tdc->u.v); else fprintf(stderr, "%llu", tdc->u.uv); fputc('\n', stderr); if (bump(id, &td->types[td->ntypes++], p)) return -1; reset(p); return 1; } static int p(const struct lex *l, struct prv *p) { struct fn *fn = fn_cur(p), *pt = NULL; struct td *td = fn->td; size_t n = td->ntypes + 1; struct type *types; if (!(pt = malloc(sizeof *pt))) { perror("malloc(3)"); goto failure; } *pt = (struct fn){.tk = p->stk, .parent = fn}; if (!(types = realloc(td->types, n * sizeof *types))) { perror("realloc(3)"); goto failure; } types[td->ntypes++] = (struct type) { .type = P, .tk = p->stk, .sz = sizeof (void *), .align = sizeof (void *), .u.p.fn = pt }; td->types = types; p->proto = pt; fprintf(stderr, "\tadding prototype %s\n", p->stk->s); return div_p(l, p); failure: free(pt); return -1; } static int ends(struct type *t) { const struct s *s = &t->u.s; const struct storage *st = s->storage; const struct stentry *e; if (!st->nentries) { errloc(t->tk, "struct \"%s\" has no members", t->tk->s); return -1; } e = &st->entries[st->nentries - 1]; t->align = st->entries->t->align; t->sz = e->offset + e->t->sz; t->sz += t->align - (t->sz % t->align); fprintf(stderr, "\tadding struct %s, size %zu, align %zu\n", t->tk->s, t->sz, t->align); return 0; } static int endu(struct type *t) { const struct u *u = &t->u.u; if (!u->storage->nentries) { errloc(t->tk, "union \"%s\" has no members", t->tk->s); return -1; } return 0; } 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->ag)) { errloc(tk, "unreachable"); return -1; } switch (t->type) { case U: if (endu(t)) return -1; break; case S: if (ends(t)) return -1; break; default: errloc(tk, "unreachable"); return -1; } p->ag = 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 nt = td->ntypes + 1; 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 }; p->ag = newt; p->block++; 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 tt(const struct lex *l, struct prv *p, const struct type *t) { int ret = -1; const struct fn *fn = fn_cur(p); const struct tk *id = p->id; const struct type *tp = type_ufind(fn, id->s); struct td *td = fn->td; size_t n = td->ntypes + 1; struct type *types, *nt; char *s = type_name(t); if (tp) { const struct loc *loc = &tp->tk->loc; errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, loc->line, loc->col); goto end; } else if (pop(l, p)) return -1; else if (!(types = realloc(td->types, n * sizeof *types))) { perror("realloc(3)"); goto end; } td->types = types; nt = &td->types[td->ntypes++]; *nt = (struct type) { .type = T, .tk = id, .u.t.alias = t }; fprintf(stderr, "\tadding %s as alias for %s\n", id->s, s); reset(p); p->id = NULL; ret = 1; end: free(s); return ret; } static int a(const struct lex *l, struct prv *p) { p->id = p->stk; return type(l, p, tt); } 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 tdconstant *tdc = 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)) || !(tdc = malloc(sizeof *tdc))) { perror("malloc(3)"); goto failure; } else if (push(&init, p)) goto failure; *tdc = (struct tdconstant){0}; *td = (struct td){.tk = tk}; fn->td = td; p->tdc = tdc; p->stk = p->tk; return 1; failure: free(tdc); free(td); return -1; }