diff options
Diffstat (limited to 'from.c')
| -rw-r--r-- | from.c | 364 |
1 files changed, 364 insertions, 0 deletions
@@ -0,0 +1,364 @@ +#include "from.h" +#include "cgen.h" +#include "fn.h" +#include "errloc.h" +#include "stmt.h" +#include "storage.h" +#include "tmp.h" +#include "type.h" +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void from_free(struct from *fr) +{ +} + +static int loadvar(const struct from_it *st, struct cgen *c) +{ + const struct stentry *e = st->u.e; + size_t sz = e->t->sz; + const char *tmp = cgen_tmp(sz); + + printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(e->t)); + cgen_printvar(c->fn, e); + putchar('\n'); + return 0; +} + +/* TODO: de-duplicate function */ +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 loadval(const struct from *fr, struct cgen *c) +{ + const struct stentry *dst = fr->var; + const struct from_it *st = &fr->start; + unsigned long long v = tonum(st->u.tk->s); + + printf("store%s %llu, ", cgen_sz(dst->t->sz), v); + cgen_printvar(c->fn, dst); + putchar('\n'); + return 0; +} + +static int endvar(const struct from *fr, struct cgen *c) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +static int endval(const struct from *fr, struct cgen *c) +{ + const struct stentry *src = fr->var; + size_t sz = src->t->sz; + const char *tmp = cgen_tmp(sz); + const struct from_it *end = &fr->end; + const struct tk *tk = end->u.tk; + int neg = *tk->s == '-'; + size_t bl = fr->block_i; + + printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(src->t)); + cgen_printvar(c->fn, src); + putchar('\n'); + printf("%%%s =%s c", tmp, cgen_sz(sz)); + fputs(neg ? "sge" : "uge", stdout); + printf("%s ", cgen_sz(sz)); + printf("%%%s, %s\n", tmp, tk->s); + printf("jnz %%%s, @__end%zu, @__blockbody%zu\n", tmp, bl, bl); + printf("@__blockbody%zu\n", bl); + return 0; +} + +static int from_var(const struct from *fr, struct cgen *c) +{ + const struct from_it *st = &fr->start; + + switch (st->type) + { + case FR_VAR: + if (loadvar(st, c)) + return -1; + break; + + case FR_VAL: + if (loadval(fr, c)) + return -1; + break; + } + + printf("@__block%zu\n", fr->block_i); + + switch (fr->end.type) + { + case FR_VAR: + if (endvar(fr, c)) + return -1; + break; + + case FR_VAL: + if (endval(fr, c)) + return -1; + break; + } + + return 0; +} + +int from_cgen(const struct from *fr, struct cgen *c) +{ + return from_var(fr, c); +} + +static int from_end(const struct stmt *s, struct cgen *c) +{ + const struct from *fr = &s->u.from; + const struct stentry *src = fr->var; + const struct type *t = src->t; + size_t sz = t->sz; + const char *tmp = cgen_tmp(sz); + const struct fn *fn = c->fn; + + printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(t)); + cgen_printvar(fn, src); + putchar('\n'); + printf("%%%s =%s add %%%s, 1\n", tmp, cgen_sz(sz), tmp); + printf("store%s %%%s, ", cgen_sz(sz), tmp); + cgen_printvar(fn, src); + putchar('\n'); + printf("jmp @__block%zu\n", fr->block_i); + return 0; +} + +static int checksym(const struct fn *fn, const struct tk *tk, + struct from_it *fr) +{ + const struct stentry *e = fn_var(fn, tk); + + if (!e) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + + switch (e->t->type) + { + case C: + case BUILTIN: + break; + case U: + case S: + case P: + case T: + case PTR: + case ARY: + { + char *s = type_name(e->t); + + if (s) + errloc(tk, "\"%s\" (\"%s\") cannot be used in \"from\" loop", + tk->s, s); + + free(s); + return -1; + } + } + + fr->type = FR_VAR; + fr->u.e = e; + return 0; +} + +static int check(const struct fn *fn, const struct tk *tk, struct from_it *fr) +{ + switch (tk->type) + { + case NUM: + fr->type = FR_VAL; + fr->u.tk = tk; + break; + case ID: + return checksym(fn, tk, fr); + case LIT: + errloc(tk, "unexpected literal"); + return -1; + case UNDEF: + case ANY: + fprintf(stderr, "%s: unreachable\n", __func__); + return -1; + } + + return 0; +} + +static int finalize(struct prv *p, struct fn *fn, struct from *fr) +{ + struct stmt *s; + struct pos *pos = &p->pos[p->i]; + size_t nst = fn->nstmts + 1, nbl = fn->nblocks + 1, + *bl = realloc(fn->blocks, nbl * sizeof *bl); + + if (!bl) + { + perror("realloc(3)"); + return -1; + } + + fr->block_i = bl[fn->nblocks++] = fn->nstmts; + fn->blocks = bl; + + if (!(s = realloc(fn->stmts, nst * sizeof *s))) + { + perror("realloc(3)"); + return -1; + } + + s[fn->nstmts++] = (struct stmt) + { + .type = FROM, + .u.from = *fr, + .end = from_end + }; + + fn->stmts = s; + pos->seq = pos->stseq = stmts; + pos->step = stmts->steps; + fprintf(stderr, ", iterator %s, block index %zu\n", fr->var->tk->s, + bl[fn->nblocks - 1]); + return 0; +} + +static const struct type *valtype(const struct fn *fn, const struct tk *tk) +{ + char *end; + + errno = 0; + strtol(tk->s, &end, 0); + + if (errno || *end) + { + errno = 0; + strtoll(tk->s, &end, 0); + + if (errno || *end) + return type_find(fn, "ulong"); + + return type_find(fn, "long"); + } + + return type_find(fn, "word"); +} + +static const struct type *ittype(const struct fn *fn, const struct from_it *it) +{ + switch (it->type) + { + case FR_VAL: + return valtype(fn, it->u.tk); + case FR_VAR: + return it->u.e->t; + } + + fprintf(stderr, "%s: unreachable\n", __func__); + return NULL; +} + +static const struct type *gettype(const struct fn *fn, + const struct from_it *a, const struct from_it *b) +{ + const struct type *ta = ittype(fn, a), *tb = ittype(fn, b); + + return ta->sz > tb->sz ? ta : tb; +} + +int from(const struct lex *l, struct prv *p) +{ + const struct tk *start = p->stk + 1, *end = p->stk + 3; + struct fn *fn = fn_cur(p); + struct from fr = {0}; + const struct type *t; + + if (check(fn, start, &fr.start) + || check(fn, end, &fr.end) + || !(t = gettype(fn, &fr.start, &fr.end)) + || !(fr.var = tmp_create(fn, t))) + return -1; + + fprintf(stderr, "\t\tadding from statement [%s, %s]", start->s, end->s); + + if (finalize(p, fn, &fr)) + return -1; + + p->stk = ++end; + return 1; +} + +static int checkvar(const struct fn *fn, const struct tk *tk, struct from *fr) +{ + const struct stentry *e; + + if (tk->type != ID) + { + errloc(tk, "\"%s\" not a variable", tk->s); + return -1; + } + else if (!(e = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + else if (e->t->type != BUILTIN) + { + errloc(tk, "variable \"%s\" not an integer", tk->s); + return -1; + } + + fr->var = e; + return 0; +} + +int from_id(const struct lex *l, struct prv *p) +{ + const struct tk *start = p->stk + 1, *end = p->stk + 3, *var = p->stk + 5; + struct fn *fn = fn_cur(p); + struct from fr = {0}; + + if (check(fn, start, &fr.start) + || check(fn, end, &fr.end) + || checkvar(fn, var, &fr)) + return -1; + + fprintf(stderr, "\t\tadding from statement [%s, %s] using %s", + start->s, end->s, var->s); + + if (finalize(p, fn, &fr)) + return -1; + + p->stk = ++var; + return 1; +} + +int from_by(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +int from_idby(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} |
