#include "parse.h" #include "div.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "lit.h" #include "sym.h" #include "prv.h" #include "type.h" #include #include #include 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 unexpected(const struct tk *tk) { 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; } 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) { if (lex_eof(l, p->stk)) return 0; return p->entry(l, p) ? -1 : 1; } pos = &p->pos[p->i]; /* no rules have matched the current token */ if (!(s = pos->step)) { if (p->n > 1) return pop(l, p) ? -1 : 1; else if (lex_eof(l, tk)) return 0; else return unexpected(tk); } else if (lex_eof(l, tk)) { /* pop all remaining rules */ 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; } } } /* rule has been completely parsed, execute */ if (!s->type) return pos->seq->fn(l, p) ? -1 : 1; /* skip if: */ else if ( /* rule type does not match */ s->type != tk->type /* ID does not match */ || (s->type == ID && s->id && strcmp(s->id, tk->s)) /* rule does not expect a keyword */ || (s->type == ID && !s->id && kw(tk->s))) { /* move to next rule on no match */ pos->step = (++pos->seq)->steps; p->tk = p->stk; } /* move to next step */ else { pos->step++; if (!lex_eof(l, p->tk)) p->tk++; } return 1; } static void free_prv(struct prv *p) { sym_free(p->s); 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) 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); }