summaryrefslogtreecommitdiff
path: root/pr.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-05-17 11:13:23 +0200
commit527c23b73c8dae16f02cca6f450edb7d8225f60f (patch)
tree6b2bfd9e8d814026d6d2c1839d8cfe1bcadc825c /pr.c
downloadslcob-master.tar.gz
Add project skeletonHEADmaster
Diffstat (limited to 'pr.c')
-rw-r--r--pr.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/pr.c b/pr.c
new file mode 100644
index 0000000..df2d127
--- /dev/null
+++ b/pr.c
@@ -0,0 +1,289 @@
+#include "pr.h"
+#include "errloc.h"
+#include "fn.h"
+#include "prv.h"
+#include "parse.h"
+#include "stmt.h"
+#include "storage.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int pryy(const struct lex *l, struct prv *p);
+static int pryn(const struct lex *l, struct prv *p);
+static int prny(const struct lex *l, struct prv *p);
+static int prnn(const struct lex *l, struct prv *p);
+
+static const struct seq seqs[] =
+{
+ /* function definition with parameters and return variable */
+ {
+ (const struct step[])
+ {
+ {ID, "with"},
+ {ID, NULL, 1},
+ {ID, "returning"},
+ {ID},
+ {0}
+ },
+ .fn = pryy
+ },
+
+ /* function definition with parameters, no return variable */
+ {
+ (const struct step[])
+ {
+ {ID, "with"},
+ {ID, NULL, 1},
+ {0}
+ },
+
+ .fn = pryn
+ },
+
+ /* function definition with no parameters, with return variable */
+ {
+ (const struct step[])
+ {
+ {ID, "returning"},
+ {ID},
+ {0}
+ },
+
+ .fn = prny
+ },
+
+ {0}
+};
+
+static const struct tk *findparam(const char *s, const struct pr *pr)
+{
+ for (size_t i = 0; i < pr->nparams; i++)
+ {
+ const struct param *p = &pr->params[i];
+ const struct tk *tk = p->tk;
+
+ if (!strcmp(tk->s, s))
+ return tk;
+ }
+
+ return NULL;
+}
+
+static int param(const struct tk *tk, const struct stentry *e, struct pr *pr)
+{
+ size_t n = pr->nparams + 1;
+ struct param *params = realloc(pr->params, n * sizeof *params);
+
+ if (!params)
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ pr->params = params;
+ pr->params[pr->nparams++] = (struct param){.tk = tk, .entry = e};
+ return 0;
+}
+
+static int setret(const struct tk *tk, const struct stentry *e, struct pr *pr)
+{
+ if (!(pr->ret = malloc(sizeof *pr->ret)))
+ {
+ perror("malloc(3)");
+ return -1;
+ }
+
+ *pr->ret = (struct param){.tk = tk, .entry = e};
+ return 0;
+}
+
+static int finalize(struct prv *p)
+{
+ const struct fn *fn = fn_cur(p);
+ const struct pr *pr = fn->pr;
+ struct pos init =
+ {
+ .seq = stmts,
+ .stseq = stmts,
+ .step = stmts->steps
+ };
+
+ if (push(&init, p))
+ return -1;
+
+ fprintf(stderr, "\tadding pr with %zu parameters and%s return value\n",
+ pr->nparams, pr->ret ? "" : " no");
+ p->stk = p->tk;
+ return 1;
+}
+
+static int prret(const struct lex *l, const struct tk *tk, struct prv *p)
+{
+ const struct fn *fn = fn_cur(p);
+ struct pr *pr = fn->pr;
+ const char *s = tk->s;
+ const struct storage *lk = fn->lk, *gl = fn->gl;
+ const struct stentry *e, *gle;
+ const struct tk *prm;
+
+ if (!lk || !(e = storage_find(s, lk)))
+ {
+ errloc(tk, "return value \"%s\" not in %s", s, lk->name);
+ return -1;
+ }
+ else if (gl && (gle = storage_find(s, gl)))
+ {
+ const struct loc *loc = &gle->tk->loc;
+
+ errloc(tk, "return value \"%s\" also in %s at %d:%d", s, gl->name,
+ loc->line, loc->col);
+ return -1;
+ }
+ else if ((prm = findparam(s, pr)))
+ {
+ const struct loc *loc = &prm->loc;
+
+ errloc(tk, "return value \"%s\" already listed as "
+ "parameter at %s:%d:%d", tk->s, loc->f, loc->line, loc->col);
+ return -1;
+ }
+ else if (setret(tk, e, pr))
+ return -1;
+
+ return finalize(p);
+}
+
+static const struct tk *prparams(const struct lex *l, struct prv *p, int *ret)
+{
+ const struct tk *tk = p->stk + 1;
+ const struct fn *fn = fn_cur(p);
+ struct pr *pr = fn->pr;
+
+ if (ret)
+ *ret = 0;
+
+ for (;;)
+ {
+ const char *s = tk->s;
+ const struct stentry *e, *gle;
+ const struct tk *prm;
+ const struct storage *lk = fn->lk, *gl = fn->gl;
+
+ if (kw(s) && strcmp(s, "returning"))
+ return tk;
+ else if (!strcmp(s, "returning") && ret)
+ {
+ *ret = 1;
+ return ++tk;
+ }
+ else if ((prm = findparam(s, pr)))
+ {
+ const struct loc *loc = &prm->loc;
+
+ errloc(tk, "parameter \"%s\" already listed at %d:%d", s,
+ loc->line, loc->col);
+ return NULL;
+ }
+ else if (!lk || !(e = storage_find(s, lk)))
+ {
+ errloc(tk, "parameter \"%s\" not in %s", s, lk->name);
+ return NULL;
+ }
+ else if (gl && (gle = storage_find(s, gl)))
+ {
+ const struct loc *loc = &gle->tk->loc;
+
+ errloc(tk, "parameter \"%s\" also in %s at %d:%d", s, gl->name,
+ loc->line, loc->col);
+ return NULL;
+ }
+ else if (param(tk, e, pr))
+ return NULL;
+ else
+ tk++;
+ }
+
+ return tk;
+}
+
+static int pryy(const struct lex *l, struct prv *p)
+{
+ int ret;
+ const struct tk *tk = prparams(l, p, &ret);
+
+ if (!tk)
+ return -1;
+ else if (ret)
+ return prret(l, tk, p);
+
+ return finalize(p);
+}
+
+static int pryn(const struct lex *l, struct prv *p)
+{
+ if (!prparams(l, p, NULL))
+ return -1;
+
+ return finalize(p);
+}
+
+static int prny(const struct lex *l, struct prv *p)
+{
+ return prret(l, p->stk + 1, p);
+}
+
+static int prnn(const struct lex *l, struct prv *p)
+{
+ return finalize(p);
+}
+
+void pr_free(struct pr *pr)
+{
+ if (pr)
+ {
+ free(pr->params);
+ free(pr->ret);
+ }
+
+ free(pr);
+}
+
+int pr(const struct lex *l, struct prv *p)
+{
+ const struct tk *tk = p->tk - 1, *next = p->tk;
+ struct fn *fn = fn_cur(p);
+ struct pos init =
+ {
+ .seq = seqs,
+ .stseq = seqs,
+ .step = seqs->steps
+ };
+
+ if (fn->pr)
+ {
+ const struct loc *loc = &fn->pr->tk->loc;
+
+ errloc(tk, "pr already defined at %s:%d:%d", loc->f, loc->line,
+ loc->col);
+ return -1;
+ }
+ else if (!((fn->pr = malloc(sizeof *fn->pr))))
+ {
+ perror("malloc(3)");
+ return -1;
+ }
+
+ *fn->pr = (struct pr){.tk = tk};
+
+ /* on no parameters or return values, go directly to next sequences list. */
+ if (next - l->tokens < l->ntok
+ && strcmp(next->s, "with")
+ && strcmp(next->s, "returning"))
+ return prnn(l, p);
+ else if (push(&init, p))
+ return -1;
+
+ p->stk = p->tk;
+ return 1;
+}