diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-05-09 02:56:07 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-05-17 11:13:23 +0200 |
| commit | 527c23b73c8dae16f02cca6f450edb7d8225f60f (patch) | |
| tree | 6b2bfd9e8d814026d6d2c1839d8cfe1bcadc825c /parse.c | |
| download | slcob-master.tar.gz | |
Diffstat (limited to 'parse.c')
| -rw-r--r-- | parse.c | 155 |
1 files changed, 155 insertions, 0 deletions
@@ -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; +} |
