summaryrefslogtreecommitdiff
path: root/call.c
diff options
context:
space:
mode:
Diffstat (limited to 'call.c')
-rw-r--r--call.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/call.c b/call.c
new file mode 100644
index 0000000..ee177b3
--- /dev/null
+++ b/call.c
@@ -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;
+}