#include "pr.h" #include "dbg.h" #include "errloc.h" #include "fn.h" #include "prv.h" #include "parse.h" #include "stmt.h" #include "storage.h" #include "sym.h" #include #include #include static int etc(const struct lex *, struct prv *); static int using(const struct lex *, struct prv *); static int s_returning(const struct lex *, struct prv *); static const struct seq returning = {(struct step[]){{ID, "returning"}, {0}}, .fn = s_returning}; static const struct seq seqs[] = { {(struct step[]){{ID, "using"}, {0}}, .fn = using}, returning, {0} }; static const struct seq useqs[] = { {(struct step[]){{ID, "etc"}, {0}}, .fn = etc}, returning, {0} }; static const struct tk *findparam(const char *s, const struct pr *pr) { for (size_t i = 0; i < pr->nparams; i++) { const struct param *p = &pr->params[i]; const struct tk *tk = p->tk; if (!strcmp(tk->s, s)) return tk; } return NULL; } static int param(const struct tk *tk, const struct stentry *e, struct pr *pr) { size_t n = pr->nparams + 1; struct param *params = realloc(pr->params, n * sizeof *params); if (!params) { perror("realloc(3)"); return -1; } pr->params = params; pr->params[pr->nparams++] = (struct param){.tk = tk, .entry = e}; return 0; } static int setret(const struct tk *tk, const struct stentry *e, struct pr *pr) { const struct tk *prm = findparam(tk->s, pr); if (prm) { const struct loc *loc = &prm->loc; errloc(tk, "return value \"%s\" already listed as " "parameter at %s:%d:%d", tk->s, loc->f, loc->line, loc->col); return -1; } else if (!(pr->ret = malloc(sizeof *pr->ret))) { perror("malloc(3)"); return -1; } *pr->ret = (struct param){.tk = tk, .entry = e}; return 0; } static int finalize(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); const struct pr *pr = fn->pr; struct pos init = { .name = __func__, .seq = stmts }; if (pr->using && !pr->params) { errloc(p->stk, "missing parameters"); return -1; } else if (pr->returning && !pr->ret) { errloc(p->stk, "missing return variable"); return -1; } else if (p->proto) { if (pop(l, p)) return -1; dbg("\t"); } else if (push(&init, p)) return -1; dbg("\tadd procedure to %s using %zu%s parameters and%s return value\n", fn->tk->s, pr->nparams, pr->variadic ? " variadic" : "", pr->ret ? "" : " no"); p->stk = p->tk; return 0; } static int check(const struct lex *l, struct prv *p, const struct sym *s, int param, const struct stentry **out) { const struct fn *fn = fn_cur(p); const struct tk *tk = s->tk; const struct stentry *e, *gle; const struct storage *lk = fn->lk, *gl = fn->gl; if (s->type != SYM_ID) { errloc(tk, "expected identifier"); return -1; } else if (!lk || !(e = storage_find(tk->s, lk))) { if (param && p->proto) { /* ambiguous syntax: param might be confused * with next custom type. */ p->stk = s->tk; return pop(l, p); } else { errloc(tk, "\"%s\" not in linkage section", tk->s); return -1; } } else if (gl && (gle = storage_find(tk->s, gl))) { const struct loc *loc = &gle->tk->loc; errloc(tk, "\"%s\" also in %s at %d:%d", s, gl->name, loc->line, loc->col); return -1; } *out = e; return 0; } static int usym(const struct lex *l, struct prv *p, const struct sym *s) { const struct tk *tk = s->tk; const struct fn *fn = fn_cur(p); const struct stentry *e = NULL; if (check(l, p, s, 1, &e)) return -1; else if (e) return param(tk, e, fn->pr); return 0; } static int etc(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); struct pr *pr = fn->pr; if (pr->variadic) { errloc(p->stk, "procedure for \"%s\" already set as variadic", fn->tk->s); return -1; } pr->variadic = 1; reset(p); return 0; } static int rsym(const struct lex *l, struct prv *p, const struct sym *s) { const struct tk *tk = s->tk; const struct fn *fn = fn_cur(p); const struct stentry *e = NULL; if (check(l, p, s, 0, &e)) return -1; else if (e) { if (setret(tk, e, fn->pr)) return -1; return pop(l, p); } return 0; } static int s_returning(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); struct pr *pr = fn->pr; const struct tk *r = pr->returning; if (r) { const struct loc *loc = &r->loc; errloc(p->stk, "\"returning\" for \"%s\" already set at %d:%d", fn->tk->s, loc->line, loc->col); return -1; } pr->returning = p->stk; return sym(p, rsym); } static int using(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); struct pr *pr = fn->pr; const struct tk *u = pr->using; struct pos init = { .name = __func__, .seq = useqs }; if (u) { const struct loc *loc = &u->loc; errloc(p->stk, "\"using\" for \"%s\" already set at %d:%d", fn->tk->s, loc->line, loc->col); return -1; } else if (push(&init, p)) return -1; pr->using = p->stk; return sym(p, usym); } void pr_free(struct pr *pr) { if (pr) { free(pr->params); free(pr->ret); } free(pr); } int pr(const struct lex *l, struct prv *p) { const struct tk *tk = p->stk; struct fn *fn = fn_cur(p); struct pos init = { .name = __func__, .seq = seqs, .end = finalize }; if (fn->pr) { const struct loc *loc = &fn->pr->tk->loc; errloc(tk, "procedure already defined at %s:%d:%d", loc->f, loc->line, loc->col); return -1; } else if (!(fn->pr = malloc(sizeof *fn->pr))) { perror("malloc(3)"); return -1; } *fn->pr = (struct pr){.tk = tk}; if (push(&init, p)) return -1; p->stk = p->tk; return 0; }