#include "fn.h" #include "dbg.h" #include "div.h" #include "errloc.h" #include "gl.h" #include "im.h" #include "parse.h" #include "prv.h" #include "pr.h" #include "stmt.h" #include "storage.h" #include "sym.h" #include "td.h" #include "ws.h" #include #include #include static int pubfn(const struct lex *l, struct prv *p); static int prvfn(const struct lex *l, struct prv *p); static const struct seq fnseq[] = { {(struct step[]){{ID, "public"}, {ID, "function"}, {ID}, {0}}, .fn = pubfn}, {(struct step[]){{ID, "function"}, {ID}, {0}}, .fn = prvfn}, {0} }; int fn_end(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); if (!fn->pr) { const struct tk *tk = fn->tk; const char *s = p->proto ? "prototype" : "function"; errloc(p->stk - 1, "%s \"%s\" has no procedure", s, tk->s); return -1; } else if (fn->nblocks) { const struct tk *tk = lex_eof(l, p->stk) ? p->tk - 1 : p->stk; errloc(tk, "missing \"end\" in function \"%s\"", fn->tk->s); return -1; } return 0; } static const struct tk *findfn(const char *s, const struct ast *ast) { for (size_t i = 0; i < ast->nfns; i++) { const struct tk *tk = ast->fns[i].tk; if (!strcmp(tk->s, s)) return tk; } return NULL; } static int pushfn(const struct tk *tk, const struct lex *lex, struct prv *p, enum linkage l) { const struct tk *def; struct ast *ast = p->ast; size_t n = ast->nfns + 1; struct fn *fns; if ((def = findfn(tk->s, ast))) { const struct loc *loc = &def->loc; errloc(tk, "function \"%s\" already defined at %s:%d:%d", tk->s, loc->f, loc->line, loc->col); return -1; } else if (!(fns = realloc(ast->fns, n * sizeof *fns))) { perror("realloc(3)"); return -1; } fns[ast->nfns++] = (struct fn){.linkage = l, .tk = tk}; ast->fns = fns; if (div_fn(lex, p)) return -1; dbg("add %s function %s\n", l == STATIC ? "private" : "public", tk->s); return 0; } static int pubfn(const struct lex *l, struct prv *p) { return pushfn(p->stk + 2, l, p, EXTERNAL); } static int prvfn(const struct lex *l, struct prv *p) { return pushfn(p->stk + 1, l, p, STATIC); } const struct stentry *fn_var(const struct fn *fn, const struct tk *tk) { const struct storage *lk = fn->lk, *ws = fn->ws, *gl = fn->gl; const struct stentry *e; if ((lk && (e = storage_find(tk->s, lk))) || (ws && (e = storage_find(tk->s, ws))) || (gl && (e = storage_find(tk->s, gl)))) return e; for (size_t i = 0; i < fn->nimps; i++) if ((e = fn_var(fn->imps[i].ast.fns, tk))) return e; return NULL; } void fn_cgen_free(struct fn_cgen *c) { free(c); } void fn_free(struct fn *fn) { for (size_t i = 0; i < fn->nimps; i++) im_free(&fn->imps[i]); for (size_t i = 0; i < fn->nstmts; i++) stmt_free(&fn->stmts[i]); for (struct tmp *t = fn->tmps; t;) { struct tmp *next = t->next; free(t->tk.s); free(t); t = next; } for (struct sym *s = fn->syms; s;) { struct sym *next = s->next; sym_free(s); s = next; } storage_free(fn->lk); storage_free(fn->ws); storage_free(fn->gl); pr_free(fn->pr); td_free(fn->td); free(fn->imps); free(fn->stmts); free(fn->blocks); } struct fn *fn_cur(const struct prv *p) { struct ast *ast = p->ast; if (p->proto) return p->proto; return &ast->fns[p->ast->nfns - 1]; } int fn(const struct lex *l, struct prv *p) { struct pos init = { .name = __func__, .seq = fnseq }; if (lex_eof(l, p->stk + 1)) { errloc(p->stk, "incomplete function statement"); return -1; } else if (push(&init, p)) return -1; p->stk = p->tk; return 0; }