#include "call.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "parse.h" #include "prv.h" #include "stmt.h" #include #include #include #include static int callpr(const struct lex *l, struct prv *p); static int callp(const struct lex *l, struct prv *p); static int callr(const struct lex *l, struct prv *p); static int callv(const struct lex *l, struct prv *p); static const struct seq seqs[] = { {(const struct step[]){ {ID}, {ID, "with"}, {ID, NULL, 1}, {ID, "returning"}, {ID}, {0}}, .fn = callpr}, {(const struct step[]){ {ID}, {ID, "with"}, {ID, NULL, 1}, {0}}, .fn = callp}, {(const struct step[]){ {ID}, {ID, "returning"}, {ID}, {0}}, .fn = callr}, {(const struct step[]){ {ID}, {0}}, .fn = callv}, {0} }; static int param(const struct lex *l, struct prv *p, const struct tk *tk, struct call *c) { const struct fn *fn = fn_cur(p); const struct stentry *e = fn_var(fn, tk); size_t n = c->nparams + 1; struct callparam *params; if (!e) { errloc(tk, "undefined reference to parameter \"%s\"", tk->s); return -1; } else if (!(params = realloc(c->params, n * sizeof *params))) { perror("realloc(3)"); return -1; } c->params = params; c->params[c->nparams++] = (struct callparam){.entry = e}; return 0; } static int callpr(const struct lex *l, struct prv *p) { const struct tk *tk = p->stk + 2; struct call *c = &stmt_cur(p)->u.call; const struct pr *pr = c->pr; const struct stentry *e; size_t n = 0; while (!kw((tk++)->s)) n++; if (n != pr->nparams) { tk -= 2; errloc(tk, "function \"%s\" expects %zu parameters, " "but %zu were given", c->tk->s, pr->nparams, n); return -1; } else if (!pr->ret) { errloc(tk, "function \"%s\" does not expect any return variable", c->tk->s); return -1; } tk = p->stk + 2; for (size_t i = 0; i < n; i++) if (param(l, p, tk++, c)) return -1; if (!(e = fn_var(fn_cur(p), ++tk))) { errloc(tk, "undefined reference to return variable \"%s\"", tk->s); return -1; } else if (pop(l, p)) return -1; fprintf(stderr, "\t\tadding call to %s with %zu params " "and %s as return variable\n", c->tk->s, n, tk->s); c->ret = e; c->nparams = n; p->stk = ++tk; return 1; } static int callr(const struct lex *l, struct prv *p) { const struct tk *tk = p->stk + 2; const struct fn *fn = fn_cur(p); const struct stentry *e; struct call *c = &stmt_cur(p)->u.call; const struct pr *pr = c->pr; if (!pr->ret) { errloc(tk, "function \"%s\" does not expect any return variable", c->tk->s); return -1; } else if (pr->nparams) { errloc(tk, "function \"%s\" expects %zu parameters, " "but none were given", c->tk->s, pr->nparams); return -1; } else if (!(e = fn_var(fn, tk))) { errloc(tk, "undefined reference to return variable \"%s\"", tk->s); return -1; } else if (pop(l, p)) return -1; fprintf(stderr, "\t\tadding call to %s with %s as return variable\n", c->tk->s, tk->s); c->ret = e; p->stk = ++tk; return 1; } static int callp(const struct lex *l, struct prv *p) { const struct tk *tk = p->stk + 2; struct call *c = &stmt_cur(p)->u.call; const struct pr *pr = c->pr; size_t n = 0; while (!kw((tk++)->s)) n++; if (pr->nparams != n) { errloc(tk, "function \"%s\" expects %zu parameters, " "but %zu were given", c->tk->s, pr->nparams, n); return -1; } tk = p->stk + 2; for (size_t i = 0; i < n; i++) if (param(l, p, tk++, c)) return -1; if (pop(l, p)) return -1; fprintf(stderr, "\t\tadding call to %s with 1 param\n", c->tk->s); p->stk = tk; return 1; } static int callv(const struct lex *l, struct prv *p) { const struct tk *tk = p->stk; struct call *c = &stmt_cur(p)->u.call; const struct pr *pr = c->pr; if (pr->nparams) { errloc(tk, "function \"%s\" expects %zu parameters, " "but none were given", c->tk->s, pr->nparams); return -1; } else if (pop(l, p)) return -1; fprintf(stderr, "\t\tadding call to %s with %s as return variable\n", c->tk->s, tk->s); p->stk = ++tk; return 1; } static const struct pr *find(const struct ast *ast, const char *s) { for (size_t i = 0; i < ast->nfns; i++) { const struct fn *fn = &ast->fns[i]; if (!strcmp(fn->tk->s, s)) return fn->pr; } return NULL; } int call_cgen(const struct call *m, struct cgen *c) { const struct stentry *ret = m->ret; if (ret) printf("%%r =%s ", cgen_sz(ret->t->sz)); printf("call $%s(", m->tk->s); for (size_t i = 0; i < m->nparams; i++) { const struct callparam *cp = &m->params[i]; const struct stentry *e = cp->entry; const char *name = e->tk->s; printf("%s ", cgen_sz(e->t->sz)); if (cgen_global(c->fn, e)) printf("$%s", name); else printf("%%%s_", name); if (i + 1 < m->nparams) fputs(", ", stdout); } puts(")"); if (ret) { const char *name = ret->tk->s; const struct fn *fn = c->fn; const struct param *fnret = fn->pr->ret; size_t sz = ret->t->sz; if (cgen_global(c->fn, ret)) printf("store%s %%r, $%s", cgen_sz(sz), name); else if (fnret && fnret->entry == ret) printf("%%__ret =%s add %%r, 0", cgen_abity(ret->t)); else printf("%%%s_ =%s add %%r, 0", name, cgen_abity(ret->t)); putchar('\n'); } return 0; } void call_free(struct call *c) { if (c) free(c->params); } int call(const struct lex *l, struct prv *p) { const struct tk *tk = p->tk; const struct pr *pr; struct fn *fn = fn_cur(p); size_t n = fn->nstmts +1; struct stmt *stmts; struct pos init = { .seq = seqs, .stseq = seqs, .step = seqs->steps }; /* TODO: function pointers */ if (lex_eof(l, tk)) { errloc(tk - 1, "incomplete call statement"); return -1; } else if (!(pr = find(p->ast, tk->s))) { errloc(tk, "undefined reference to function \"%s\"", tk->s); return -1; } else if (!(stmts = realloc(fn->stmts, n * sizeof *stmts))) { perror("realloc(3)"); return -1; } fn->stmts = stmts; fn->stmts[fn->nstmts++] = (struct stmt) { .type = CALL, .u.call = { .tk = tk, .pr = pr } }; if (push(&init, p)) return -1; p->stk = p->tk; return 1; }