summaryrefslogtreecommitdiff
path: root/set.c
diff options
context:
space:
mode:
Diffstat (limited to 'set.c')
-rw-r--r--set.c589
1 files changed, 589 insertions, 0 deletions
diff --git a/set.c b/set.c
new file mode 100644
index 0000000..bad43a9
--- /dev/null
+++ b/set.c
@@ -0,0 +1,589 @@
+#include "set.h"
+#include "cgen.h"
+#include "errloc.h"
+#include "fn.h"
+#include "lex.h"
+#include "parse.h"
+#include "prv.h"
+#include "stmt.h"
+#include "storage.h"
+#include "type.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static int mv(const struct lex *l, struct prv *p);
+static int maddr(const struct lex *l, struct prv *p);
+static int msz(const struct lex *l, struct prv *p);
+static int mimb(const struct lex *l, struct prv *p);
+
+static const struct seq seqs[] =
+{
+ /* size of elementary data types */
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "void"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "byte"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "halfword"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "word"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "long"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "ubyte"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "uhalfword"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "uword"},
+ {0}}, .fn = msz},
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ID, "ulong"},
+ {0}}, .fn = msz},
+
+ /* address of variable */
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "address"},
+ {ID, "of"},
+ {ID},
+ {0}}, .fn = maddr},
+
+ /* size of variable or type alias */
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ID, "size"},
+ {ID, "of"},
+ {ANY},
+ {0}}, .fn = msz},
+
+ /* array index or aggregate member */
+ {(struct step[]){
+ {ID, NULL, 1},
+ {ID, "to"},
+ {ANY},
+ {ID, "of"},
+ {ID},
+ {0}}, .fn = mimb},
+
+ /* simple set */
+ {(struct step[]){{ID, NULL, 1}, {ID, "to"}, {ANY}, {0}}, .fn = mv},
+ {0}
+};
+
+static unsigned long long tonum(const char *s)
+{
+ unsigned long long v;
+ char *end;
+
+ errno = 0;
+ v = strtoull(s, &end, 0);
+
+ if (*s == '-' || errno || *end)
+ return strtoll(s, NULL, 0);
+
+ return v;
+}
+
+static int dst(const struct lex *l, const struct tk *tk, struct set *mv,
+ struct prv *p)
+{
+ const struct stentry *e = fn_var(fn_cur(p), tk);
+ size_t n = mv->ndsts + 1;
+ struct setdst *dsts;
+
+ if (!e)
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ else if (!(dsts = realloc(mv->dsts, n * sizeof *dsts)))
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ mv->dsts = dsts;
+ mv->dsts[mv->ndsts++] = (struct setdst){.entry = e};
+ return 0;
+}
+
+static int checkzero(const struct tk *tk, const struct set *mv,
+ unsigned long long v)
+{
+ if (!mv->srcv)
+ return 0;
+
+ for (size_t i = 0; i < mv->ndsts; i++)
+ {
+ const struct stentry *dst = mv->dsts[i].entry;
+
+ if (dst->t->type != BUILTIN)
+ {
+ errloc(tk, "destination \"%s\" cannot be set to \"%s\"",
+ dst->tk->s, tk->s);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int checkcompat(const struct tk *tk, const struct set *mv)
+{
+ for (size_t i = 0; i < mv->ndsts; i++)
+ {
+ const struct stentry *dst = mv->dsts[i].entry;
+ const struct type *st = mv->src->t, *dt = dst->t;
+
+ /* TODO: integer promotions */
+ if (st->type != dt->type
+ || st->sz != dt->sz
+ || st->sign != dt->sign)
+ {
+ errloc(tk, "destination \"%s\" cannot be set to \"%s\"",
+ dst->tk->s, tk->s);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int mv(const struct lex *l, struct prv *p)
+{
+ const struct tk *tk = p->stk;
+ const struct stentry *e;
+ struct stmt *stmt = stmt_cur(p);
+ struct set *mv = &stmt->u.set;
+
+ while (!lex_eof(l, tk) && !kw((tk)->s))
+ if (dst(l, tk++, mv, p))
+ return -1;
+
+ /* skip "to" */
+ tk++;
+
+ if (tk->type == LIT)
+ {
+ /* this can only be applied to arrays of/pointers to chars */
+ fprintf(stderr, "%s: TODO\n", __func__);
+ return -1;
+ }
+ else if (tk->type == NUM)
+ {
+ mv->type = MV_VAL;
+ mv->srcv = tonum(tk->s);
+
+ if (checkzero(tk, mv, mv->srcv))
+ return -1;
+ }
+ else if (tk->type == ID)
+ {
+ const struct fn *fn = fn_cur(p);
+ const struct type *t = type_find(fn, tk->s);
+
+ if (t)
+ {
+ if (t->type != C)
+ {
+ errloc(tk, "type \"%s\" not a constant", tk->s);
+ return -1;
+ }
+
+ mv->type = MV_VAL;
+ mv->srcv = t->u.c.v;
+
+ if (checkzero(tk, mv, mv->srcv))
+ return -1;
+ }
+ else if ((e = fn_var(fn_cur(p), tk)))
+ {
+ mv->type = MV_VAR;
+ mv->src = e;
+
+ if (checkcompat(tk, mv))
+ return -1;
+ }
+ else
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ }
+
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < mv->ndsts; i++)
+ fprintf(stderr, "%s ", mv->dsts[i].entry->tk->s);
+
+ fprintf(stderr, "to %s\n", tk->s);
+
+ if (pop(l, p))
+ return -1;
+
+ p->stk = ++tk;
+ return 1;
+}
+
+static int maddr(const struct lex *l, struct prv *p)
+{
+ const struct tk *tk = p->stk;
+ struct stmt *stmt = stmt_cur(p);
+ struct set *mv = &stmt->u.set;
+ const struct stentry *e;
+
+ while (!lex_eof(l, tk) && !kw((tk)->s))
+ {
+ const struct stentry *e = fn_var(fn_cur(p), tk);
+
+ if (e && e->t->type != PTR)
+ {
+ errloc(tk, "destination \"%s\" not a pointer", tk->s);
+ return -1;
+ }
+ else if (dst(l, tk++, mv, p))
+ return -1;
+ }
+
+ /* skip "to address of" */
+ tk += 3;
+
+ if (!(e = fn_var(fn_cur(p), tk)))
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ else if (pop(l, p))
+ return -1;
+
+ mv->type = MV_ADDR;
+ mv->src = e;
+ p->stk = ++tk;
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < mv->ndsts; i++)
+ fprintf(stderr, "%s ", mv->dsts[i].entry->tk->s);
+
+ fprintf(stderr, "to address of %s\n", mv->src->tk->s);
+ return 1;
+}
+
+static int msz(const struct lex *l, struct prv *p)
+{
+ const struct tk *tk = p->stk;
+ const struct stentry *e;
+ struct stmt *stmt = stmt_cur(p);
+ struct set *mv = &stmt->u.set;
+ const struct fn *fn = fn_cur(p);
+ const struct type *t;
+
+ while (!lex_eof(l, tk) && !kw((tk)->s))
+ {
+ const struct stentry *e = fn_var(fn_cur(p), tk);
+
+ if (e && e->t->type != BUILTIN)
+ {
+ errloc(tk, "destination \"%s\" not an integer", tk->s);
+ return -1;
+ }
+ else if (dst(l, tk++, mv, p))
+ return -1;
+ }
+
+ /* skip "to size of" */
+ tk += 3;
+
+ if (tk->type == NUM)
+ {
+ errloc(tk, "cannot compute size of a number");
+ return -1;
+ }
+ else if (tk->type == LIT)
+ mv->srcv = strlen(tk->s) + 1;
+ else if ((t = type_find(fn, tk->s)))
+ {
+ if (!t->sz)
+ {
+ errloc(tk, "type \"%s\" has no size", tk->s);
+ return-1;
+ }
+
+ mv->srcv = t->sz;
+ }
+ else if ((e = fn_var(fn, tk)))
+ mv->srcv = e->t->sz;
+ else
+ return-1;
+
+ if (pop(l, p))
+ return -1;
+
+ mv->type = MV_VAL;
+ p->stk = ++tk;
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < mv->ndsts; i++)
+ fprintf(stderr, "%s ", mv->dsts[i].entry->tk->s);
+
+ fprintf(stderr, "size=%llu\n", mv->srcv);
+ return 1;
+}
+
+static int mimb(const struct lex *l, struct prv *p)
+{
+ const struct tk *tk = p->stk;
+ const struct fn *fn = fn_cur(p);
+ struct stmt *stmt = stmt_cur(p);
+ struct set *mv = &stmt->u.set;
+
+ while (!lex_eof(l, tk) && !kw((tk)->s))
+ if (dst(l, tk++, mv, p))
+ return -1;
+
+ /* skip "to" */
+ tk++;
+
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < mv->ndsts; i++)
+ fprintf(stderr, "%s ", mv->dsts[i].entry->tk->s);
+
+ if (tk->type == LIT)
+ {
+ errloc(tk, "unexpected literal \"%s\"", tk->s);
+ return -1;
+ }
+ else if (tk->type == ID && !(mv->off = fn_var(fn, tk)))
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ else if (tk->type == NUM)
+ mv->srcv = tonum(tk->s);
+
+ fprintf(stderr, "to [%s] ", tk->s);
+
+ /* skip index and "of" */
+ tk += 2;
+
+ if (!(mv->src = fn_var(fn, tk)))
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ else if (pop(l, p))
+ return -1;
+
+ fprintf(stderr, " of %s\n", tk->s);
+ mv->type = MV_IMB;
+ p->stk = ++tk;
+ return 1;
+}
+
+void set_free(struct set *m)
+{
+ if (m)
+ free(m->dsts);
+}
+
+static int cg_val(const struct set *m, const struct stentry *dst,
+ struct cgen *c)
+{
+ const char *name = dst->tk->s, *szstr = cgen_sz(dst->t->sz),
+ *ab = cgen_abity(dst->t);
+ int global = cgen_global(c->fn, dst);
+
+ if (ab)
+ {
+ if (global)
+ printf("store%s %llu, $%s", szstr, m->srcv, name);
+ else
+ {
+ printf("store%s %llu, ", szstr, m->srcv);
+ printf("%%%s_", name);
+ }
+ }
+ else
+ {
+ fputs("%r =l call $memset(l ", stdout);
+
+ if (global)
+ printf("$%s", name);
+ else
+ printf("%%%s_", name);
+
+ printf(", w 0, l %zu)", dst->t->sz);
+ }
+
+ putchar('\n');
+ return 0;
+}
+
+static int cg_addr(const struct set *m, const struct stentry *dst,
+ struct cgen *c)
+{
+ const char *name = dst->tk->s;
+ const struct stentry *src = m->src;
+
+ printf("store%s ", cgen_sz(dst->t->sz));
+
+ if (cgen_global(c->fn, src))
+ printf("$%s", src->tk->s);
+ else
+ printf("%%%s_", src->tk->s);
+
+ fputs(", ", stdout);
+
+ if (cgen_global(c->fn, dst))
+ printf("$%s", name);
+ else
+ printf("%%%s_", name);
+
+ putchar('\n');
+ return 0;
+}
+
+static int cg_var(const struct set *m, const struct stentry *dst,
+ struct cgen *c)
+{
+ const struct stentry *src = m->src;
+ const char *name = dst->tk->s, *tmp = cgen_tmp(src->t->sz);
+
+ printf("%%%s =%s load%s ", tmp, cgen_sz(src->t->sz), cgen_load(src->t));
+
+ if (cgen_global(c->fn, src))
+ printf("$%s\n", src->tk->s);
+ else
+ printf("%%%s_\n", src->tk->s);
+
+ printf("store%s %%%s, ", cgen_sz(dst->t->sz), tmp);
+
+ if (cgen_global(c->fn, dst))
+ printf("$%s", name);
+ else
+ printf("%%%s_", name);
+
+ putchar('\n');
+ return 0;
+}
+
+int set_cgen(const struct set *m, struct cgen *c)
+{
+ for (size_t i = 0; i < m->ndsts; i++)
+ {
+ const struct stentry *dst = m->dsts[i].entry;
+
+ switch (m->type)
+ {
+ case MV_VAL:
+ if (cg_val(m, dst, c))
+ return -1;
+ break;
+
+ case MV_ADDR:
+ if (cg_addr(m, dst, c))
+ return -1;
+ break;
+
+ case MV_VAR:
+ if (cg_var(m, dst, c))
+ return -1;
+ break;
+
+ case MV_IMB:
+ fprintf(stderr, "%s: TODO\n", __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int set(const struct lex *l, struct prv *p)
+{
+ const struct tk *next = p->tk;
+ const char *ns;
+ struct fn *fn = fn_cur(p);
+ size_t n = fn->nstmts + 1;
+ struct stmt *stmts;
+
+ if (lex_eof(l, next))
+ {
+ errloc(next - 1, "incomplete set statement");
+ return -1;
+ }
+ else if (kw((ns = next->s)))
+ {
+ errloc(next, "incomplete set statement");
+ 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 = SET};
+
+ struct pos init =
+ {
+ .seq = seqs,
+ .stseq = seqs,
+ .step = seqs->steps
+ };
+
+ if (push(&init, p))
+ return -1;
+
+ p->stk = p->tk;
+ return 1;
+}