diff options
Diffstat (limited to 'td.c')
| -rw-r--r-- | td.c | 506 |
1 files changed, 506 insertions, 0 deletions
@@ -0,0 +1,506 @@ +#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 <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +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; +} |
