aboutsummaryrefslogtreecommitdiff
path: root/set.c
diff options
context:
space:
mode:
Diffstat (limited to 'set.c')
-rw-r--r--set.c552
1 files changed, 552 insertions, 0 deletions
diff --git a/set.c b/set.c
new file mode 100644
index 0000000..3058040
--- /dev/null
+++ b/set.c
@@ -0,0 +1,552 @@
+#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 *s,
+ struct prv *p)
+{
+ const struct stentry *e = fn_var(fn_cur(p), tk);
+ size_t n = s->ndsts + 1;
+ struct setdst *dsts;
+
+ if (!e)
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ else if (!(dsts = realloc(s->dsts, n * sizeof *dsts)))
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ s->dsts = dsts;
+ s->dsts[s->ndsts++] = (struct setdst){.entry = e};
+ return 0;
+}
+
+static int checkzero(const struct tk *tk, const struct set *s,
+ unsigned long long v)
+{
+ if (!s->srcv)
+ return 0;
+
+ for (size_t i = 0; i < s->ndsts; i++)
+ {
+ const struct stentry *dst = s->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 *s)
+{
+ for (size_t i = 0; i < s->ndsts; i++)
+ {
+ const struct stentry *dst = s->dsts[i].entry;
+ const struct type *st = s->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 *s = &stmt->u.set;
+
+ while (!lex_eof(l, tk) && !kw((tk)->s))
+ if (dst(l, tk++, s, 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)
+ {
+ s->type = SET_VAL;
+ s->srcv = tonum(tk->s);
+
+ if (checkzero(tk, s, s->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;
+ }
+
+ s->type = SET_VAL;
+ s->srcv = t->u.c.v;
+
+ if (checkzero(tk, s, s->srcv))
+ return -1;
+ }
+ else if ((e = fn_var(fn_cur(p), tk)))
+ {
+ s->type = SET_VAR;
+ s->src = e;
+
+ if (checkcompat(tk, s))
+ return -1;
+ }
+ else
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ }
+
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < s->ndsts; i++)
+ fprintf(stderr, "%s ", s->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 *s = &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++, s, 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;
+
+ s->type = SET_ADDR;
+ s->src = e;
+ p->stk = ++tk;
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < s->ndsts; i++)
+ fprintf(stderr, "%s ", s->dsts[i].entry->tk->s);
+
+ fprintf(stderr, "to address of %s\n", s->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 *s = &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++, s, 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)
+ s->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;
+ }
+
+ s->srcv = t->sz;
+ }
+ else if ((e = fn_var(fn, tk)))
+ s->srcv = e->t->sz;
+ else
+ return-1;
+
+ if (pop(l, p))
+ return -1;
+
+ s->type = SET_VAL;
+ p->stk = ++tk;
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < s->ndsts; i++)
+ fprintf(stderr, "%s ", s->dsts[i].entry->tk->s);
+
+ fprintf(stderr, "size=%llu\n", s->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 *s = &stmt->u.set;
+
+ while (!lex_eof(l, tk) && !kw((tk)->s))
+ if (dst(l, tk++, s, p))
+ return -1;
+
+ /* skip "to" */
+ tk++;
+
+ fputs("\t\tadding set ", stderr);
+
+ for (size_t i = 0; i < s->ndsts; i++)
+ fprintf(stderr, "%s ", s->dsts[i].entry->tk->s);
+
+ if (tk->type == LIT)
+ {
+ errloc(tk, "unexpected literal \"%s\"", tk->s);
+ return -1;
+ }
+ else if (tk->type == ID && !(s->off = fn_var(fn, tk)))
+ {
+ errloc(tk, "undefined reference to \"%s\"", tk->s);
+ return -1;
+ }
+ else if (tk->type == NUM)
+ s->srcv = tonum(tk->s);
+
+ fprintf(stderr, "to [%s] ", tk->s);
+
+ /* skip index and "of" */
+ tk += 2;
+
+ if (!(s->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);
+ s->type = SET_IMB;
+ p->stk = ++tk;
+ return 1;
+}
+
+void set_free(struct set *m)
+{
+ if (m)
+ free(m->dsts);
+}
+
+static int cg_val(const struct set *s, const struct stentry *dst,
+ struct cgen *c)
+{
+ const char *szstr = cgen_sz(dst->t->sz), *ab = cgen_abity(dst->t);
+ const struct fn *fn = c->fn;
+
+ if (ab)
+ {
+ printf("store%s %llu, ", szstr, s->srcv);
+ cgen_printvar(fn, dst);
+ }
+ else
+ {
+ fputs("%r =l call $memset(l ", stdout);
+ cgen_printvar(fn, dst);
+ printf(", w 0, l %zu)", dst->t->sz);
+ }
+
+ putchar('\n');
+ return 0;
+}
+
+static int cg_addr(const struct set *s, const struct stentry *dst,
+ struct cgen *c)
+{
+ printf("store%s ", cgen_sz(dst->t->sz));
+ cgen_printvar(c->fn, s->src);
+ fputs(", ", stdout);
+ cgen_printvar(c->fn, dst);
+ putchar('\n');
+ return 0;
+}
+
+static int cg_var(const struct set *s, const struct stentry *dst,
+ struct cgen *c)
+{
+ const struct stentry *src = s->src;
+ const char *tmp = cgen_tmp(src->t->sz);
+
+ printf("%%%s =%s load%s ", tmp, cgen_sz(src->t->sz), cgen_load(src->t));
+ cgen_printvar(c->fn, src);
+ putchar('\n');
+ printf("store%s %%%s, ", cgen_sz(dst->t->sz), tmp);
+ cgen_printvar(c->fn, dst);
+ putchar('\n');
+ return 0;
+}
+
+static int cg_imb(const struct set *s, const struct stentry *e, struct cgen *c)
+{
+ fprintf(stderr, "%s: TODO\n", __func__);
+ return -1;
+}
+
+int set_cgen(const struct set *s, struct cgen *c)
+{
+ for (size_t i = 0; i < s->ndsts; i++)
+ {
+ const struct stentry *dst = s->dsts[i].entry;
+
+ static int (*const f[])(const struct set *, const struct stentry *,
+ struct cgen *) =
+ {
+ [SET_VAL] = cg_val,
+ [SET_ADDR] = cg_addr,
+ [SET_VAR] = cg_var,
+ [SET_IMB] = cg_imb
+ };
+
+ if (f[s->type](s, dst, c))
+ 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;
+}