#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 #include #include #include 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; }