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-17 11:13:23 +0200
commit527c23b73c8dae16f02cca6f450edb7d8225f60f (patch)
tree6b2bfd9e8d814026d6d2c1839d8cfe1bcadc825c /parse.c
downloadslcob-master.tar.gz
Add project skeletonHEADmaster
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/parse.c b/parse.c
new file mode 100644
index 0000000..2867df4
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,155 @@
+#include "parse.h"
+#include "fn.h"
+#include "errloc.h"
+#include "lex.h"
+#include "lit.h"
+#include "prv.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+void ast_free(struct ast *ast)
+{
+ 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 lex_eof(l, tk) ? 0 : fn(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->levels);
+ free(p->pos);
+}
+
+int parse(const struct lex *l, struct ast *ast)
+{
+ int ret;
+ struct prv prv = {0};
+
+ prv.ast = ast;
+
+ if (!(prv.tk = l->tokens))
+ return 0;
+
+ while ((ret = iter(l, &prv)) > 0)
+ ;
+
+ free_prv(&prv);
+ return ret;
+}