diff options
Diffstat (limited to 'set.c')
| -rw-r--r-- | set.c | 589 |
1 files changed, 589 insertions, 0 deletions
@@ -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; +} |
