aboutsummaryrefslogtreecommitdiff
path: root/fn.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2026-05-09 02:56:07 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2026-06-21 01:15:38 +0200
commitb25ff71bb198c227b3202ee32a8067cda413bc16 (patch)
tree41d665a87d948c10b17a853220cbcdbaeebf3672 /fn.c
downloadprc-b25ff71bb198c227b3202ee32a8067cda413bc16.tar.gz
Add project skeletonHEADmaster
Diffstat (limited to 'fn.c')
-rw-r--r--fn.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/fn.c b/fn.c
new file mode 100644
index 0000000..261e21e
--- /dev/null
+++ b/fn.c
@@ -0,0 +1,251 @@
+#include "fn.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 "td.h"
+#include "ws.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static int pubfn(const struct lex *l, struct prv *p);
+static int prvfn(const struct lex *l, struct prv *p);
+static int end(const struct lex *l, struct prv *p);
+
+static const struct seq fnseq[] =
+{
+ {(struct step[])
+ {{ID, "public"}, {ID, "function"}, {ID}, {0}}, .fn = pubfn, .end = end},
+ {(struct step[])
+ {{ID, "function"}, {ID}, {0}}, .fn = prvfn, .end = end},
+ {0}
+};
+
+static int end(const struct lex *l, struct prv *p)
+{
+ const struct fn *fn = fn_cur(p);
+
+ if (!fn->pr)
+ {
+ const struct tk *tk = fn->tk, *stk = p->stk;
+
+ if (lex_eof(l, p->stk))
+ errloc(--stk, "function \"%s\" has no body", tk->s);
+ else
+ errloc(p->tk, "incomplete \"%s\"", p->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;
+
+ fprintf(stderr, "adding %s function %s\n",
+ l == STATIC ? "private" : "public", tk->s);
+ return 1;
+}
+
+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;
+}
+
+int fn_cgen(const struct fn *fn, struct cgen *c)
+{
+ const struct pr *pr = fn->pr;
+ const struct param *ret = pr->ret;
+ const struct type *rt = NULL;
+ const char *s = NULL;
+
+ if (fn->gl && gl_cgen(fn->gl, c))
+ return -1;
+
+ switch (fn->linkage)
+ {
+ case STATIC:
+ printf("function ");
+ break;
+ case EXTERNAL:
+ printf("export function ");
+ break;
+ }
+
+ if (ret)
+ {
+ rt = ret->entry->t;
+ s = ret->entry->tk->s;
+ printf("%s ", cgen_abity(ret->entry->t));
+ }
+
+ printf("$%s(", fn->tk->s);
+
+ for (size_t i = 0; i < pr->nparams; i++)
+ {
+ const struct param *p = &pr->params[i];
+
+ printf(" %s", cgen_abity(p->entry->t));
+ printf(" %%__param_%s ", p->tk->s);
+
+ if (i + 1 < pr->nparams)
+ fputs(", ", stdout);
+ }
+
+ puts(") {\n@start");
+
+ for (size_t i = 0; i < pr->nparams; i++)
+ {
+ const struct param *p = &pr->params[i];
+ const struct type *t = p->entry->t;
+ const char *s = p->tk->s;
+
+ printf("%%%s_ =l alloc%zu %zu\n", s, t->align, t->sz);
+ printf("store%s %%__param_%s, %%%s_\n", cgen_sz(t->sz), s, s);
+ }
+
+ if (ret)
+ printf("%%%s_ =l alloc%zu %zu\n", s, rt->align, rt->sz);
+
+ if (fn->ws && ws_cgen(fn->ws, c))
+ return -1;
+
+ for (size_t i = 0; i < fn->nstmts; i++)
+ if (stmt_cgen(&fn->stmts[i], c))
+ return -1;
+
+ if (ret)
+ {
+ const char *t = cgen_tmp(rt->sz);
+
+ printf("%%%s =%s load%s %%%s_\n", t, cgen_sz(rt->sz), cgen_load(rt), s);
+ printf("ret %%%s", t);
+ }
+ else
+ fputs("ret", stdout);
+
+ puts("\n}");
+ return 0;
+}
+
+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]);
+
+ 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);
+}
+
+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 =
+ {
+ .seq = fnseq,
+ .stseq = fnseq,
+ .step = fnseq->steps
+ };
+
+ if (lex_eof(l, p->stk))
+ return 0;
+ else 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 1;
+}