diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-05-09 02:56:07 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-05-31 20:43:27 +0200 |
| commit | 8c4f46dca6a1bb02082886beac46cbb8e4cf2bbb (patch) | |
| tree | 2fa198377214bac01713fcfd6004eb7ca3515dfe /td.c | |
| download | slcob-8c4f46dca6a1bb02082886beac46cbb8e4cf2bbb.tar.gz | |
Add project skeleton
Diffstat (limited to 'td.c')
| -rw-r--r-- | td.c | 569 |
1 files changed, 569 insertions, 0 deletions
@@ -0,0 +1,569 @@ +#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 <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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 p(const struct lex *, struct prv *); +static int t(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, "type"}, {ID, "to"}, {0}}, .fn = t}, + {(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 *), + .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->sz = e->offset + e->t->sz; + fprintf(stderr, "\tadding struct %s, size %zu\n", t->tk->s, t->sz); + 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_find(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 t(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; +} |
