diff options
Diffstat (limited to 'src/prc1/call.c')
| -rw-r--r-- | src/prc1/call.c | 486 |
1 files changed, 123 insertions, 363 deletions
diff --git a/src/prc1/call.c b/src/prc1/call.c index 21ef4de..f06f25b 100644 --- a/src/prc1/call.c +++ b/src/prc1/call.c @@ -5,263 +5,171 @@ #include "lex.h" #include "lit.h" #include "parse.h" +#include "pr.h" #include "prv.h" #include "stmt.h" +#include "sym.h" #include "type.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 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}, - {ID, "using"}, - {ANY, NULL, 1}, - {ID, "returning"}, - {ID}, - {0}}, .fn = callpr}, - {(struct step[]){ - {ID}, - {ID, "using"}, - {ANY, NULL, 1}, - {0}}, .fn = callp}, - {(struct step[]){ - {ID}, - {ID, "returning"}, - {ID}, - {0}}, .fn = callr}, - {(struct step[]){ - {ID}, - {0}}, .fn = callv}, + {(struct step[]){{ID, "using"}, {0}}, .fn = using}, + returning, {0} }; -static int param(const struct lex *l, struct prv *p, const struct tk *tk, - struct call *c) +static const struct seq useqs[] = { - const struct fn *fn = fn_cur(p); + returning, + {0} +}; + +static int param(const struct lex *l, struct prv *p, const struct sym *s) +{ + struct stmt *stmt = stmt_cur(p); + struct call *c = &stmt->u.call; size_t n = c->nparams + 1; - struct callparam *params; - const struct lit *lit = NULL; - const struct stentry *e = NULL; - const struct type *t = NULL; - int sign = 0; - union callv u = {0}; - - if (tk->type == LIT) - { - if (!(lit = lit_push(tk, p))) - return -1; - } - else if (tk->type == NUM) - { - if ((sign = *tk->s == '-')) - u.v = strtoll(tk->s, NULL, 0); - else - u.uv = strtoull(tk->s, NULL, 0); - } - else if ((t = type_find(fn, tk->s))) - { - if (t->type != C) - { - errloc(tk, "type \"%s\" not a constant", tk->s); - return -1; - } - } - else if (!(e = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to parameter \"%s\"", tk->s); - return -1; - } + struct callparam *params = realloc(c->params, n * sizeof *params); - if (!(params = realloc(c->params, n * sizeof *params))) + if (!params) { perror("realloc(3)"); return -1; } + params[c->nparams++] = (struct callparam){.s = s}; c->params = params; - c->params[c->nparams++] = (struct callparam) - { - .entry = e, - .lit = lit, - .t = t, - .u = u - }; - return 0; } -static int callpr(const struct lex *l, struct prv *p) +static int using(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; + struct pos init = + { + .name = __func__, + .seq = useqs + }; - while (!lex_eof(l, tk) && !kw((tk++)->s)) - n++; + struct stmt *stmt = stmt_cur(p); + struct call *c = &stmt->u.call; + const struct tk *tk = c->pr->tk, *u = c->using; - if (pr->variadic) + if (u) { - if (n < pr->nparams) - { - errloc(tk, "function \"%s\" expects at least %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); - return -1; - } - } - else 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; - } + const struct loc *loc = &u->loc; - if (!pr->ret) - { - errloc(tk, "function \"%s\" does not expect any return variable", - c->tk->s); + errloc(p->stk, "\"using\" for \"%s\" already set at %d:%d", tk->s, + loc->line, loc->col); return -1; } + else if (push(&init, p)) + return -1; - tk = p->stk + 2; + c->using = p->stk; + return sym(p, param); +} - for (size_t i = 0; i < n; i++) - if (param(l, p, tk++, c)) - return -1; +static int setret(const struct lex *l, struct prv *p, const struct sym *s) +{ + struct stmt *stmt = stmt_cur(p); + struct call *c = &stmt->u.call; - if (!(e = fn_var(fn_cur(p), ++tk))) + c->ret = s; + return pop(l, p); +} + +static int s_returning(const struct lex *l, struct prv *p) +{ + struct pos init = { - errloc(tk, "undefined reference to return variable \"%s\"", - tk->s); + .name = __func__, + .seq = useqs + }; + + struct stmt *stmt = stmt_cur(p); + struct call *c = &stmt->u.call; + const struct tk *tk = c->pr->tk, *r = c->returning; + + if (r) + { + const struct loc *loc = &r->loc; + + errloc(p->stk, "\"returning\" for \"%s\" already set at %d:%d", + tk->s, loc->line, loc->col); return -1; } - else if (pop(l, p)) + + if (push(&init, p)) return -1; - dbg("\t\tadding call to %s using %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; + c->returning = p->stk; + return sym(p, setret); } -static int callr(const struct lex *l, struct prv *p) +static int endcall(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 stmt *stmt = stmt_cur(p); + const struct call *c = &stmt->u.call; const struct pr *pr = c->pr; + const struct tk *tk = c->id->tk; + size_t n = c->nparams; - if (!pr->ret) + if (!pr) { - errloc(tk, "function \"%s\" does not expect any return variable", - c->tk->s); + errloc(p->stk - 1, "incomplete \"call\" statement"); return -1; } - else if (pr->nparams) + else if (c->using && !n) { - errloc(tk, "function \"%s\" expects %zu parameters, " - "but none were given", c->tk->s, pr->nparams); + errloc(c->using, "\"using\" without arguments"); return -1; } - else if (!(e = fn_var(fn, tk))) + else if (c->returning && !c->ret) { - errloc(tk, "undefined reference to return variable \"%s\"", tk->s); + errloc(c->using, "\"returning\" without return variable"); return -1; } - else if (pop(l, p)) - return -1; - - dbg("\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 (!lex_eof(l, tk) && !kw((tk++)->s)) - n++; - - if (lex_eof(l, tk)) - tk--; - - if (pr->variadic) + else if (pr->variadic) { if (n < pr->nparams) { - errloc(tk, "function \"%s\" expects at least %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); + errloc(tk, "\"%s\" expects at least %zu parameters, " + "but %zu were given", tk->s, pr->nparams, n); return -1; } } - else if (pr->nparams != n) + else if (n != pr->nparams) { - errloc(tk, "function \"%s\" expects %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); + errloc(tk, "\"%s\" expects %zu parameters, but %zu were given", + 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; - - dbg("\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) + if (!pr->ret && c->ret) { - errloc(tk, "function \"%s\" expects %zu parameters, " - "but none were given", c->tk->s, pr->nparams); + errloc(tk, "function \"%s\" does not expect any return variable", + tk->s); return -1; } - else if (pop(l, p)) - return -1; - dbg("\t\tadding call to %s with %s as return variable\n", c->tk->s, tk->s); - p->stk = ++tk; - return 1; + fprintf(stderr, "%s: TODO\n", __func__); + return -1; } -static const struct pr *find_proto(const struct fn *fn, const char *s) +void call_free(struct call *c) { - const struct type *t = type_find(fn, s); - - if (t && t->type == P) - return t->u.p.fn->pr; - - return NULL; + if (c) + free(c->params); } static const struct pr *find(const struct ast *ast, const char *s) @@ -269,219 +177,71 @@ 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]; - const struct pr *pr; - if ((pr = find_proto(fn, s))) - return pr; - else if (!strcmp(fn->tk->s, s)) + if (!strcmp(fn->tk->s, s)) return fn->pr; } return NULL; } -static int gettmp(char *tmp, size_t n) -{ - size_t j; - - for (j = 0; j < n; j++) - { - char c = tmp[j]; - - if (!c) - return tmp[j] = 'a'; - else if (c != 'z') - return ++(tmp[j]); - } - - return EOF; -} - -static int param_lit(const struct lit *lit, struct cgen *c) -{ - printf("l $%s", lit->name); - return 0; -} - -static int param_id(const struct stentry *e, struct cgen *c, char *tmp, - size_t n) -{ - const char *name = e->tk->s; - const struct type *t = e->t; - - printf("%s ", cgen_sz(t->sz)); - - if (cgen_global(c->fn, e)) - printf("$%s", name); - else if (cgen_abity(t)) - { - if (gettmp(tmp, n) == EOF) - return -1; - - printf("%%%s", tmp); - } - else - printf("%%%s_", name); - - return 0; -} - -static int param_c(const struct type *t, struct cgen *cg) -{ - const union c *c = &t->u.c; - - /* TODO: adapt type to expected param size */ - fputs("l ", stdout); - - if (t->sign) - printf("%lld", c->v); - else - printf("%llu", c->uv); - - return 0; -} - -static int param_num(const struct callparam *cp, struct cgen *c) -{ - const union callv *u = &cp->u; - - /* TODO: adapt type to expected param size */ - fputs("w ", stdout); - - if (cp->sign) - printf("%lld", u->v); - else - printf("%llu", u->uv); - - return 0; -} - -static int param_load(const struct call *m, struct cgen *c) +static int onsym(const struct lex *l, struct prv *p, const struct sym *s) { - char tmp[sizeof "abcdefghijklmnopqrstuvwxyz"] = {0}; + const struct fn *fn = fn_cur(p); + struct stmt *stmt = stmt_cur(p); + struct call *c = &stmt->u.call; + const struct tk *tk = s->tk; + const struct pr *pr = find(p->ast, tk->s); + const struct stentry *e; - for (size_t i = 0; i < m->nparams; i++) + if (pr) + c->pr = pr; + else if (!(e = fn_var(fn, tk))) { - const struct callparam *cp = &m->params[i]; - const struct stentry *e = cp->entry; - - if (!e || cgen_global(c->fn, e) || !cgen_abity(e->t)) - continue; - else if (gettmp(tmp, sizeof tmp - 1) == EOF) - { - fprintf(stderr, "%s: exhausted temporaries\n", __func__); - return -1; - } - - printf("%%%s =%s load%s %%%s_\n", tmp, cgen_sz(e->t->sz), - cgen_load(e->t), e->tk->s); - } - - return 0; -} - -int call_cgen(const struct call *m, struct cgen *c) -{ - char tmps[sizeof "abcdefghijklmnopqrstuvwxyz"] = {0}; - const struct stentry *ret = m->ret; - const char *tmp; - size_t sz; - - if (param_load(m, c)) + errloc(tk, "undefined reference to \"%s\"", tk->s); return -1; - else if (ret) - { - tmp = cgen_tmp((sz = ret->t->sz)); - printf("%%%s =%s ", tmp, cgen_sz(sz)); } - - printf("call $%s(", m->tk->s); - - for (size_t i = 0; i < m->nparams; i++) + else if (e->t->type != P) { - const struct callparam *cp = &m->params[i]; - int var = m->pr->variadic; - - if (cp->lit) - param_lit(cp->lit, c); - else if (cp->entry) - param_id(cp->entry, c, tmps, sizeof tmps - 1); - else if (cp->t) - param_c(cp->t, c); - else - param_num(cp, c); - - if (var && i + 1 == var - 1) - fputs(", ...", stdout); - - if (i + 1 < m->nparams) - fputs(", ", stdout); - } + char *tn = type_name(e->t); - puts(")"); + if (tn) + errloc(tk, "cannot call \"%s\" with type \"%s\"", tk->s, tn); - if (ret) - { - printf("store%s %%%s, ", cgen_sz(sz), tmp); - cgen_printvar(c->fn, ret); - putchar('\n'); + free(tn); + return -1; } + else + c->pr = e->t->u.p.fn->pr; - return 0; -} - -void call_free(struct call *c) -{ - if (c) - free(c->params); + c->id = s; + return pop(l, p); } 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 = { + .name = __func__, .seq = seqs, - .stseq = seqs, - .step = seqs->steps + .end = endcall, }; - /* TODO: function pointers */ + struct fn *fn = fn_cur(p); + size_t n = fn->nstmts + 1; + struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); - 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))) + if (!stmts) { perror("realloc(3)"); return -1; } + stmts[fn->nstmts++] = (struct stmt){.type = CALL, .u.call.tk = p->stk}; 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; + return sym(p, onsym); } |
