summaryrefslogtreecommitdiff
path: root/display.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 /display.c
downloadslcob-master.tar.gz
Add project skeletonHEADmaster
Diffstat (limited to 'display.c')
-rw-r--r--display.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..308fa24
--- /dev/null
+++ b/display.c
@@ -0,0 +1,226 @@
+#include "display.h"
+#include "cgen.h"
+#include "errloc.h"
+#include "fn.h"
+#include "lit.h"
+#include "parse.h"
+#include "prv.h"
+#include "stmt.h"
+#include "storage.h"
+#include "type.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int finalize(const struct lex *l, const struct display *d,
+ const struct prv *p)
+{
+ const struct ast *ast = p->ast;
+ struct fn *fn = &ast->fns[ast->nfns - 1];
+ size_t n = fn->nstmts + 1;
+ struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts);
+
+ if (!stmts)
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ fn->stmts = stmts;
+ fn->stmts[fn->nstmts++] = (struct stmt)
+ {
+ .type = DISPLAY,
+ .u.display = *d
+ };
+
+ fprintf(stderr, "\t\tadding display statement with %zu entries%s\n",
+ d->nentries, d->println ? "" : ", no lf");
+ return 0;
+}
+
+static int entry(const struct lex *l, const struct tk *tk, struct display *d,
+ struct prv *p)
+{
+ size_t n = d->nentries + 1;
+ struct dspentry *entries;
+ const struct stentry *stentry = NULL;
+ const struct fn *fn = fn_cur(p);
+ const struct lit *lit = NULL;
+
+ if (tk->type == ID)
+ {
+ const struct type *t = NULL;
+
+ if ((t = type_find(fn, tk->s)))
+ {
+ if (t->type != C)
+ {
+ errloc(tk, "type \"%s\" not a constant", tk->s);
+ return -1;
+ }
+ else if (!(lit = lit_push(t->tk, p)))
+ return -1;
+ }
+ else if (!(stentry = fn_var(fn, tk)))
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ }
+
+ if (tk->type == LIT && !(lit = lit_push(tk, p)))
+ return -1;
+ else if (!(entries = realloc(d->entries, n * sizeof *entries)))
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ d->entries = entries;
+ d->entries[d->nentries++] = (struct dspentry)
+ {
+ .tk = tk,
+ .lit = lit,
+ .entry = stentry
+ };
+
+ return 0;
+}
+
+static int cg_val(const struct tk *tk)
+{
+ const char *num = tk->s;
+ int neg = *num == '-';
+ unsigned long long uv;
+ char *end;
+
+ fputs("call $printf(l $____fmt", stdout);
+ errno = 0;
+ uv = strtoull(num, &end, 16);
+
+ if (!neg && !errno && !*end)
+ printf("lx, ..., l %llu )\n", uv);
+ else
+ {
+ errno = 0;
+ uv = strtoull(num, &end, 0);
+
+ if (neg || errno || *end)
+ {
+ long long v = strtoll(num, NULL, 0);
+ printf("l, ..., l %lld )\n", v);
+ }
+ else
+ printf("l, ..., l %llu )\n", uv);
+ }
+
+ return 0;
+}
+
+static int cg_lit(const struct dspentry *e)
+{
+ const struct lit *l = e->lit;
+
+ if (!l)
+ {
+ fprintf(stderr, "%s: unexpected null literal\n", __func__);
+ return -1;
+ }
+
+ puts("%v =l loadl $stdout");
+ printf("call $fputs(l $%s, w %%v)\n", l->name);
+ return 0;
+}
+
+static int cg_id(const struct dspentry *de, const struct fn *fn)
+{
+ const struct stentry *e = de->entry;
+ const struct type *t = e->t;
+ const char *id = e->tk->s;
+ int global = cgen_global(fn, e);
+ size_t sz = t->sz;
+ const char *asz = cgen_sz(sz < 4 ? 4 : sz);
+ const struct param *ret = fn->pr->ret;
+ int isret = ret && ret->entry == e;
+
+ if (global)
+ printf("%%v =%s load%s $%s\n", asz, cgen_load(t), id);
+ else if (isret)
+ printf("%%v =%s add 0, %%__ret\n", asz);
+ else
+ printf("%%v =%s add 0, %%%s_\n", asz, id);
+
+ if (isret)
+ printf("call $printf(l $____fmt%s, ..., w %%__ret )\n", cgen_type(t));
+ else if (global)
+ printf("call $printf(l $____fmt%s, ..., w %%v )\n", cgen_type(t));
+ else
+ printf("call $printf(l $____fmt%s, ..., w %%%s_ )\n", cgen_type(t), id);
+
+ return 0;
+}
+
+int display_cgen(const struct display *d, struct cgen *c)
+{
+ for (size_t i = 0; i < d->nentries; i++)
+ {
+ const struct dspentry *e = &d->entries[i];
+ const struct tk *tk = e->tk;
+
+ if (tk->type == LIT && cg_lit(e))
+ return -1;
+ else if (tk->type == NUM && cg_val(tk))
+ return -1;
+ else if (tk->type == ID && e->entry && cg_id(e, c->fn))
+ return -1;
+ else if (tk->type == ID && e->lit && cg_lit(e))
+ return -1;
+ }
+
+ if (d->println)
+ puts("call $putchar(l 10 )");
+
+ return 0;
+}
+
+void display_free(struct display *d)
+{
+ free(d->entries);
+}
+
+int display(const struct lex *l, struct prv *p)
+{
+ const struct tk *tk = p->stk + 1;
+ struct display d = {0};
+ struct pos *pos = &p->pos[p->i];
+ int eof;
+
+ if (lex_eof(l, tk))
+ {
+ errloc(tk - 1, "incomplete display statement");
+ return -1;
+ }
+
+ for (;;)
+ if (entry(l, tk, &d, p))
+ goto failure;
+ else if ((eof = lex_eof(l, ++tk)) || kw(tk->s))
+ break;
+
+ if (eof || strcmp(tk->s, "etc"))
+ d.println = 1;
+ else if (!eof)
+ tk++;
+
+ if (finalize(l, &d, p))
+ goto failure;
+
+ pos->seq = pos->stseq = stmts;
+ pos->step = stmts->steps;
+ p->stk = tk;
+ return 1;
+
+failure:
+ display_free(&d);
+ return -1;
+}