aboutsummaryrefslogtreecommitdiff
path: root/src/prc1/sym.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2026-10-01 01:04:30 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2026-10-11 00:14:35 +0200
commit4ce39e4fc1de9536de7dedfe91b6dee38dec76ae (patch)
treef9820f96b8eab624430c3700f32a2878a7036ee2 /src/prc1/sym.c
parent9140988be4e5bb028b7140aca1a67af1370c72a7 (diff)
downloadprc-4ce39e4fc1de9536de7dedfe91b6dee38dec76ae.tar.gz
WIP sym + cgen
Diffstat (limited to 'src/prc1/sym.c')
-rw-r--r--src/prc1/sym.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/src/prc1/sym.c b/src/prc1/sym.c
new file mode 100644
index 0000000..fb67f14
--- /dev/null
+++ b/src/prc1/sym.c
@@ -0,0 +1,478 @@
+#include "sym.h"
+#include "errloc.h"
+#include "fn.h"
+#include "lex.h"
+#include "parse.h"
+#include "prv.h"
+#include "storage.h"
+#include "type.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int addr(const struct lex *, struct prv *);
+static int cnt(const struct lex *, struct prv *);
+static int off(const struct lex *, struct prv *);
+static int szof(const struct lex *, struct prv *);
+static int idof(const struct lex *, struct prv *);
+static int numof(const struct lex *, struct prv *);
+static int cast(const struct lex *, struct prv *);
+static int to(const struct lex *, struct prv *);
+static int lit(const struct lex *, struct prv *);
+static int num(const struct lex *, struct prv *);
+static int id(const struct lex *, struct prv *);
+static int push_to(struct prv *);
+
+static const struct seq seqs[] =
+{
+ {(struct step[]){{ID, "address"}, {ID, "of"}, {0}}, .fn = addr},
+ {(struct step[]){{ID, "contents"}, {ID, "of"}, {0}}, .fn = cnt},
+ {(struct step[]){{ID, "offset"}, {ID, "of"}, {0}}, .fn = off},
+ {(struct step[]){{ID, "size"}, {ID, "of"}, {0}}, .fn = szof},
+ {(struct step[]){{ID, "cast"}, {0}}, .fn = cast},
+ {(struct step[]){{ID}, {ID, "of"}, {0}}, .fn = idof},
+ {(struct step[]){{NUM}, {ID, "of"}, {0}}, .fn = numof},
+ {(struct step[]){{LIT}, {0}}, .fn = lit},
+ {(struct step[]){{NUM}, {0}}, .fn = num},
+ {(struct step[]){{ID}, {0}}, .fn = id},
+ {0}
+};
+
+static const struct seq cast_seqs[] =
+{
+ {(struct step[]){{ID, "to"}, {0}}, .fn = to},
+ {0}
+};
+
+static void queue(struct prv *p, struct sym *s)
+{
+ struct sym *ss = p->s;
+
+ if (!ss)
+ p->s = s;
+ else
+ {
+ while (ss->child)
+ ss = ss->child;
+
+ ss->child = s;
+ s->parent = ss;
+ }
+
+ reset(p);
+}
+
+static int pushsym(struct prv *p, enum symtype t)
+{
+ struct sym *s = malloc(sizeof *s);
+
+ if (!s)
+ {
+ perror("malloc(3)");
+ return -1;
+ }
+
+ *s = (struct sym){.type = t, .tk = p->stk};
+ queue(p, s);
+ return 0;
+}
+
+static int addr(const struct lex *l, struct prv *p)
+{
+ return pushsym(p, SYM_ADDR);
+}
+
+static int cnt(const struct lex *l, struct prv *p)
+{
+ return pushsym(p, SYM_CNT);
+}
+
+static int off(const struct lex *l, struct prv *p)
+{
+ return pushsym(p, SYM_OFF);
+}
+
+static int szof(const struct lex *l, struct prv *p)
+{
+ return pushsym(p, SYM_SZ);
+}
+
+static void insert(struct fn *fn, struct sym *s)
+{
+ struct sym *ss = fn->syms;
+
+ while (ss && ss->next)
+ ss = ss->next;
+
+ if (!ss)
+ fn->syms = s;
+ else
+ ss->next = s;
+}
+
+static int symbol(const struct sym *s)
+{
+ switch (s->type)
+ {
+ case SYM_ID:
+ case SYM_TMP:
+ case SYM_LIT:
+ case SYM_NUM:
+ return 1;
+
+ case SYM_CAST:
+ case SYM_ADDR:
+ case SYM_SZ:
+ case SYM_CNT:
+ case SYM_OFF:
+ break;
+ }
+
+ return 0;
+}
+
+static struct sym *getsym(struct sym *s)
+{
+ for (struct sym *ss = s; ss; ss = ss->child)
+ if (symbol(ss))
+ return ss;
+
+ return NULL;
+}
+
+static int idof(const struct lex *l, struct prv *p)
+{
+ fprintf(stderr, "%s: TODO\n", __func__);
+ reset(p);
+ return -1;
+}
+
+static int numof(const struct lex *l, struct prv *p)
+{
+ fprintf(stderr, "%s: TODO\n", __func__);
+ reset(p);
+ return -1;
+}
+
+static struct sym *inner(struct sym *s)
+{
+ struct sym *ret = NULL;
+
+ for (; s; s = s->child)
+ if (s->type == SYM_CAST && !s->u.t)
+ ret = s;
+
+ return ret;
+}
+
+static struct sym *resolve(const struct sym *s)
+{
+ fprintf(stderr, "%s: TODO\n", __func__);
+ return NULL;
+}
+
+static int run(const struct lex *l, struct prv *p)
+{
+ struct fn *fn = fn_cur(p);
+ struct sym *s = p->s;
+
+ insert(fn, s);
+ p->s = NULL;
+
+ if (getsym(s))
+ return p->sym(l, p, s);
+
+ errloc(p->stk - 1, "expected identifier, literal or number");
+ return -1;
+}
+
+static int totype(const struct lex *l, struct prv *p, const struct type *t)
+{
+ struct sym *s = inner(p->s);
+
+ if (!s || s->u.t)
+ {
+ errloc(p->tk - 1, "incomplete cast");
+ return -1;
+ }
+
+ s->u.t = t;
+
+ if (pop(l, p))
+ return -1;
+
+ return !inner(p->s) && getsym(p->s) ? run(l, p) : 0;
+}
+
+static int to(const struct lex *l, struct prv *p)
+{
+ return type(l, p, totype);
+}
+
+static int endcast(const struct lex *l, struct prv *p)
+{
+ struct sym *s = inner(p->s);
+
+ if (!p->cast--)
+ {
+ errloc(p->tk - 1, "incomplete cast");
+ return -1;
+ }
+ else if (s)
+ {
+ if (lex_eof(l, p->tk))
+ {
+ errloc(p->tk - 1, "incomplete cast");
+ return -1;
+ }
+
+ return push_to(p);
+ }
+
+ return 0;
+}
+
+static int cast(const struct lex *l, struct prv *p)
+{
+ p->cast++;
+ return pushsym(p, SYM_CAST);
+}
+
+static int push_to(struct prv *p)
+{
+ struct pos init =
+ {
+ .name = __func__,
+ .seq = cast_seqs,
+ .end = endcast
+ };
+
+ return push(&init, p);
+}
+
+static int lit(const struct lex *l, struct prv *p)
+{
+ struct sym *cs = inner(p->s);
+
+ if (pushsym(p, SYM_LIT))
+ return -1;
+
+ return cs ? push_to(p) : run(l, p);
+}
+
+static int num(const struct lex *l, struct prv *p)
+{
+ fprintf(stderr, "%s: TODO\n", __func__);
+ reset(p);
+ return -1;
+}
+
+static int id(const struct lex *l, struct prv *p)
+{
+ struct sym *cs = inner(p->s);
+
+ if (pushsym(p, SYM_ID))
+ return -1;
+ else if (cs)
+ return push_to(p);
+
+ p->stk = p->tk;
+ return run(l, p);
+}
+
+void sym_free(struct sym *s)
+{
+ struct sym *ss = s;
+
+ while (ss)
+ {
+ struct sym *child = ss->child;
+
+ free(ss);
+ ss = child;
+ }
+}
+
+int sym_lval(const struct sym *s)
+{
+ int ret = 1;
+
+ while (s)
+ {
+ switch (s->type)
+ {
+ case SYM_OFF:
+ case SYM_SZ:
+ case SYM_LIT:
+ case SYM_NUM:
+ case SYM_TMP:
+ ret = 0;
+ break;
+
+ case SYM_ADDR:
+ if (!s->parent || s->parent->type != SYM_CNT)
+ ret = 0;
+ case SYM_ID:
+ case SYM_CNT:
+ case SYM_CAST:
+ break;
+ }
+
+ s = s->child;
+ }
+
+ return ret;
+}
+
+static int endsym(const struct lex *l, struct prv *p)
+{
+ return p->s ? run(l, p) : 0;
+}
+
+static int invalid(const struct tk *tk, const struct type *a,
+ const struct type *b)
+{
+ static int t[BUILTIN + 1][BUILTIN + 1] =
+ {
+ /* U S C P T PTR ARY BUILTIN */
+ /* U */ {1, 0, 0, 0, 0, 0, 0, 0},
+ /* S */ {0, 1, 0, 0, 0, 0, 0, 0},
+ /* C */ {0, 0, 1, 0, 0, 0, 0, 0},
+ /* P */ {0, 0, 0, 1, 0, 1, 0, 0},
+ /* T */ {0, 0, 0, 0, 1, 0, 0, 0},
+ /* PTR */ {0, 0, 0, 0, 0, 1, 1, 0},
+ /* ARY */ {0, 0, 0, 0, 0, 0, 1, 0},
+ /* BUILTIN */ {0, 0, 0, 0, 0, 0, 0, 1}
+ };
+
+ int valid = t[a->type][b->type];
+
+ if (!valid)
+ {
+ char *s1 = type_name(b), *s2 = type_name(a);
+
+ if (s1 && s2)
+ errloc(tk, "cannot convert \"%s\" to \"%s\"", s1, s2);
+
+ free(s1);
+ free(s2);
+ }
+
+ return !valid;
+}
+
+static const struct type *genlittype(struct prv *p)
+{
+ const struct fn *fn = fn_cur(p);
+ const struct type *byte = type_find(fn, "char");
+ struct type *bytedup = NULL, *t = NULL;
+
+ if (!byte)
+ return NULL;
+ else if (!(bytedup = malloc(sizeof *bytedup))
+ || !(t = malloc(sizeof *t)))
+ {
+ perror("malloc(3)");
+ goto failure;
+ }
+
+ *bytedup = *byte;
+ *t = (struct type)
+ {
+ .type = ARY,
+ .u.ary.etc = 1,
+ .child = bytedup
+ };
+
+ return p->ast->littype = type_insert(p, t);
+
+failure:
+ free(t);
+ free(bytedup);
+ return NULL;
+}
+
+static const struct type *littype(struct prv *p)
+{
+ const struct type *t = p->ast->littype;
+
+ return t ? t : genlittype(p);
+}
+
+const struct type *sym_type(struct prv *p, const struct sym *s)
+{
+ const struct fn *fn = fn_cur(p);
+ const struct type *ret = NULL;
+
+ for (; s; s = s->child)
+ {
+ const struct tk *tk = s->tk;
+
+ switch (s->type)
+ {
+ case SYM_CAST:
+ if (!ret)
+ ret = s->u.t;
+ else if (invalid(tk, ret, s->u.t))
+ return NULL;
+
+ break;
+
+ case SYM_ID:
+ {
+ const struct stentry *e = fn_var(fn, tk);
+ const struct type *t;
+
+ if (!e && !(t = type_ufind(fn, tk->s)))
+ return NULL;
+ else if (e)
+ t = e->t;
+
+ if (!ret)
+ ret = t;
+ else if (invalid(tk, ret, t))
+ return NULL;
+ }
+ break;
+
+ case SYM_LIT:
+ {
+ const struct type *lt = littype(p);
+
+ if (!ret)
+ ret = lt;
+ else if (invalid(tk, ret, lt))
+ return NULL;
+ }
+ break;
+
+ case SYM_ADDR:
+ case SYM_TMP:
+ case SYM_NUM:
+ case SYM_SZ:
+ case SYM_CNT:
+ case SYM_OFF:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int sym_rval(const struct sym *s)
+{
+ return !sym_lval(s);
+}
+
+int sym(struct prv *p, sym_fn fn)
+{
+ struct pos init =
+ {
+ .name = __func__,
+ .seq = seqs,
+ .end = endsym
+ };
+
+ p->stk = p->tk;
+ p->sym = fn;
+ return push(&init, p);
+}