summaryrefslogtreecommitdiff
path: root/td.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2026-05-09 02:56:07 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2026-05-31 20:43:27 +0200
commit8c4f46dca6a1bb02082886beac46cbb8e4cf2bbb (patch)
tree2fa198377214bac01713fcfd6004eb7ca3515dfe /td.c
downloadslcob-8c4f46dca6a1bb02082886beac46cbb8e4cf2bbb.tar.gz
Add project skeleton
Diffstat (limited to 'td.c')
-rw-r--r--td.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/td.c b/td.c
new file mode 100644
index 0000000..90ca331
--- /dev/null
+++ b/td.c
@@ -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;
+}