aboutsummaryrefslogtreecommitdiff
path: root/storage.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-06-21 01:15:38 +0200
commitb25ff71bb198c227b3202ee32a8067cda413bc16 (patch)
tree41d665a87d948c10b17a853220cbcdbaeebf3672 /storage.c
downloadprc-master.tar.gz
Add project skeletonHEADmaster
Diffstat (limited to 'storage.c')
-rw-r--r--storage.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/storage.c b/storage.c
new file mode 100644
index 0000000..8ab1ad4
--- /dev/null
+++ b/storage.c
@@ -0,0 +1,217 @@
+#include "storage.h"
+#include "errloc.h"
+#include "fn.h"
+#include "lex.h"
+#include "prv.h"
+#include "type.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int id(const struct lex *l, struct prv *p);
+
+static const struct seq seqs[] =
+{
+ {(struct step[]){{ID}, {0}}, .fn = id},
+ {0}
+};
+
+static int compat(const struct fn *fn, const struct prv *p,
+ const struct tk *name, const struct type *t, const struct type **ot)
+{
+ const struct stentry *oe;
+ const struct fn *top = fn_cur(p);
+
+ /* allow global entries if already found on linkage section
+ * and vice versa, as long as the types are compatible. */
+ if (p->st == top->gl)
+ {
+ for (size_t i = 0; i < fn->nimps; i++)
+ {
+ const struct im *im = &fn->imps[i];
+
+ if (compat(im->ast.fns, p, name, t, ot))
+ return 1;
+ }
+
+ if (fn->lk && (oe = storage_find(name->s, fn->lk)))
+ {
+ if (t == oe->t)
+ return 1;
+
+ *ot = oe->t;
+ return -1;
+ }
+ }
+ else if (p->st == top->lk)
+ {
+ if (fn->gl && (oe = storage_find(name->s, fn->gl)))
+ {
+ if (t == oe->t)
+ return 1;
+
+ *ot = oe->t;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int stpush(const struct lex *l, struct prv *p, const struct tk *name,
+ const struct type *t)
+{
+ int ret = -1;
+ struct stentry *entries;
+ struct storage *st = p->st;
+ size_t n = st->nentries + 1;
+ const struct fn *fn = fn_cur(p);
+ const struct loc *loc = &name->loc;
+ const struct stentry *e;
+ char *tname = type_name(t);
+
+ if (!t->sz && p->st != fn->lk)
+ {
+ errloc(name + 1, "type \"%s\" has null size", tname);
+ goto end;
+ }
+ else if (st->check && (e = fn_var(fn, name)))
+ {
+ const struct loc *loc = &e->tk->loc;
+ const struct type *ot;
+ int ret = compat(fn, p, name, t, &ot);
+
+ if (ret < 0)
+ {
+ errloc(name, "variable \"%s\" (\"%s\") already defined at "
+ "%s:%d:%d with incompatible type (\"%s\")",
+ name->s, type_name(t), loc->f, loc->line, loc->col,
+ type_name(ot));
+ goto end;
+ }
+ else if (!ret)
+ {
+ errloc(name, "variable \"%s\" already defined at %s:%d:%d",
+ name->s, loc->f, loc->line, loc->col);
+ goto end;
+ }
+ }
+
+ /* find var in currently known symbols */
+ for (size_t i = 0; i < st->nentries; i++)
+ {
+ const struct stentry *e = &st->entries[i];
+ const struct tk *tk = e->tk;
+
+ if (!strcmp(name->s, tk->s))
+ {
+ const struct loc *loc = &tk->loc;
+
+ errloc(tk, "variable \"%s\" already defined at %s:%d:%d",
+ tk->s, loc->f, loc->line, loc->col);
+ goto end;
+ }
+ }
+
+ if (pop(l, p))
+ goto end;
+ else if (!(entries = realloc(st->entries, n * sizeof *entries)))
+ {
+ perror("realloc(3)");
+ goto end;
+ }
+
+ if (t->sz)
+ st->offset += st->offset % t->sz;
+
+ entries[st->nentries++] = (struct stentry)
+ {
+ .t = t,
+ .tk = name,
+ .offset = st->offset
+ };
+
+ st->entries = entries;
+ st->offset += t->sz;
+ p->stk = p->tk;
+
+ if (p->proto)
+ fputc('\t', stderr);
+
+ fprintf(stderr, "\tadding %s (%d:%d) to %s, type %s, offset %zu, "
+ "size %zu\n", name->s, loc->line, loc->col, st->name, tname,
+ entries[st->nentries - 1].offset, t->sz);
+ ret = 1;
+end:
+ free(tname);
+ return ret;
+}
+
+static int v(const struct lex *l, struct prv *p, const struct type *t)
+{
+ return stpush(l, p, p->id, t);
+}
+
+static int id(const struct lex *l, struct prv *p)
+{
+ p->id = p->stk;
+ return type(l, p, v);
+}
+
+void storage_free(struct storage *s)
+{
+ if (s)
+ free(s->entries);
+
+ free(s);
+}
+
+const struct stentry *storage_find(const char *name, const struct storage *s)
+{
+ for (size_t i = 0; i < s->nentries; i++)
+ {
+ const struct stentry *e = &s->entries[i];
+
+ if (!strcmp(name, e->tk->s))
+ return e;
+ }
+
+ return NULL;
+}
+
+int storage(const struct lex *l, struct prv *p, const char *name, int check,
+ struct storage **out)
+{
+ struct storage *st = NULL;
+ struct pos init =
+ {
+ .seq = seqs,
+ .stseq = seqs,
+ .step = seqs->steps
+ };
+
+ if (*out)
+ {
+ const struct loc *loc = &(*out)->tk->loc;
+
+ errloc(p->stk, "%s already defined at %s:%d:%d", name, loc->f,
+ loc->line, loc->col);
+ goto failure;
+ }
+ else if (!(st = malloc(sizeof *st)))
+ {
+ perror("malloc(3)");
+ goto failure;
+ }
+ else if (push(&init, p))
+ goto failure;
+
+ *st = (struct storage){.name = name, .tk = p->stk, .check = check};
+ *out = p->st = st;
+ p->stk = p->tk;
+ return 1;
+
+failure:
+ free(st);
+ return -1;
+}