summaryrefslogtreecommitdiff
path: root/parse.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 /parse.c
downloadslcob-8c4f46dca6a1bb02082886beac46cbb8e4cf2bbb.tar.gz
Add project skeleton
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/parse.c b/parse.c
new file mode 100644
index 0000000..fd9adda
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,182 @@
+#include "parse.h"
+#include "div.h"
+#include "errloc.h"
+#include "fn.h"
+#include "lex.h"
+#include "lit.h"
+#include "prv.h"
+#include "type.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+void ast_free(struct ast *ast)
+{
+ struct type *t = ast->types;
+
+ while (t)
+ {
+ struct type *next = t->next;
+
+ type_lfree(t);
+ t = next;
+ }
+
+ for (struct lit *l = ast->lits, *next; l; l = next)
+ {
+ next = l->next;
+ lit_free(l);
+ free(l);
+ }
+
+ for (size_t i = 0; i < ast->nfns; i++)
+ fn_free(&ast->fns[i]);
+
+ free(ast->fns);
+}
+
+static const char *expected(const struct step *s)
+{
+ static const char *tmap[] =
+ {
+ [ID] = "identifier", [LIT] = "literal", [NUM] = "number"
+ };
+
+ return s->id ? s->id : tmap[s->type];
+}
+
+static int iter(const struct lex *l, struct prv *p)
+{
+ struct pos *pos = p->pos;
+ const struct step *s;
+ const struct tk *tk = p->tk;
+
+ if (!pos)
+ return p->entry(l, p);
+
+ pos = &p->pos[p->i];
+
+ if (!(s = pos->step))
+ {
+ if (lex_eof(l, tk))
+ return 0;
+ else if (p->n > 1)
+ return pop(l, p) ? -1 : 1;
+ else
+ {
+ switch (tk->type)
+ {
+ case LIT:
+ errloc(tk, "unexpected literal \"%s\"", tk->s);
+ break;
+ case NUM:
+ errloc(tk, "unexpected number %s", tk->s);
+ break;
+ case ID:
+ errloc(tk, "unexpected %s %s", kw(tk->s) ?
+ "keyword" : "identifier", tk->s);
+ break;
+ case ANY:
+ case UNDEF:
+ errloc(tk, "%s: unreachable", __func__);
+ break;
+ }
+
+ return -1;
+ }
+ }
+ else if (lex_eof(l, tk))
+ {
+ if (p->stk == p->tk)
+ return pop(l, p) ? -1 : 1;
+ else if (s->type)
+ {
+ tk--;
+
+ if (lex_eof(l, p->stk))
+ {
+ errloc(tk, "expected %s", expected(pos->step));
+ return -1;
+ }
+ }
+ }
+
+ if (!s->type)
+ return pos->seq->fn(l, p);
+ else if ((s->type == ID || s->type == ANY) && !s->id && kw(tk->s)
+ && !s->chain)
+ {
+ if (tk != p->stk || !p->n)
+ {
+ errloc(tk, "unexpected keyword %s", tk->s);
+ return -1;
+ }
+ else if (pop(l, p))
+ return -1;
+
+ pos = &p->pos[p->i];
+ }
+ else if ((s->type != tk->type && s->type != ANY)
+ || (s->type == ID && s->id && strcmp(s->id, tk->s))
+ || (s->type == ID && kw(tk->s) && s->chain))
+ {
+ pos->step = (++pos->seq)->steps;
+ p->tk = p->stk;
+ }
+ else
+ {
+ const struct tk *next = tk + 1;
+
+ if (!s->chain)
+ pos->step++;
+ else if (!lex_eof(l, next))
+ {
+ if (s->chain && kw(next->s))
+ pos->step++;
+ }
+ else
+ pos->step++;
+
+ p->tk++;
+ }
+
+ return 1;
+}
+
+static void free_prv(struct prv *p)
+{
+ free(p->tdc);
+ free(p->pos);
+}
+
+static int comm(const struct lex *l, struct ast *ast,
+ int (*entry)(const struct lex *, struct prv *))
+{
+ int ret;
+ struct prv prv =
+ {
+ .ast = ast,
+ .tk = l->tokens,
+ .stk = l->tokens,
+ .entry = entry
+ };
+
+ if (!(prv.stk = prv.tk))
+ return 0;
+
+ while ((ret = iter(l, &prv)) > 0)
+ ;
+
+ free_prv(&prv);
+ return ret;
+}
+
+int parse(const struct lex *l, struct ast *ast)
+{
+ return comm(l, ast, fn);
+}
+
+int parse_im(const struct lex *l, struct ast *ast)
+{
+ return comm(l, ast, div_im);
+}