diff options
Diffstat (limited to 'call.c')
| -rw-r--r-- | call.c | 318 |
1 files changed, 318 insertions, 0 deletions
@@ -0,0 +1,318 @@ +#include "call.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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; +} |
