diff options
Diffstat (limited to 'display.c')
| -rw-r--r-- | display.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/display.c b/display.c new file mode 100644 index 0000000..308fa24 --- /dev/null +++ b/display.c @@ -0,0 +1,226 @@ +#include "display.h" +#include "cgen.h" +#include "errloc.h" +#include "fn.h" +#include "lit.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "storage.h" +#include "type.h" +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +static int finalize(const struct lex *l, const struct display *d, + const struct prv *p) +{ + const struct ast *ast = p->ast; + struct fn *fn = &ast->fns[ast->nfns - 1]; + size_t n = fn->nstmts + 1; + struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); + + if (!stmts) + { + perror("realloc(3)"); + return -1; + } + + fn->stmts = stmts; + fn->stmts[fn->nstmts++] = (struct stmt) + { + .type = DISPLAY, + .u.display = *d + }; + + fprintf(stderr, "\t\tadding display statement with %zu entries%s\n", + d->nentries, d->println ? "" : ", no lf"); + return 0; +} + +static int entry(const struct lex *l, const struct tk *tk, struct display *d, + struct prv *p) +{ + size_t n = d->nentries + 1; + struct dspentry *entries; + const struct stentry *stentry = NULL; + const struct fn *fn = fn_cur(p); + const struct lit *lit = NULL; + + if (tk->type == ID) + { + const struct type *t = NULL; + + if ((t = type_find(fn, tk->s))) + { + if (t->type != C) + { + errloc(tk, "type \"%s\" not a constant", tk->s); + return -1; + } + else if (!(lit = lit_push(t->tk, p))) + return -1; + } + else if (!(stentry = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + } + + if (tk->type == LIT && !(lit = lit_push(tk, p))) + return -1; + else if (!(entries = realloc(d->entries, n * sizeof *entries))) + { + perror("realloc(3)"); + return -1; + } + + d->entries = entries; + d->entries[d->nentries++] = (struct dspentry) + { + .tk = tk, + .lit = lit, + .entry = stentry + }; + + return 0; +} + +static int cg_val(const struct tk *tk) +{ + const char *num = tk->s; + int neg = *num == '-'; + unsigned long long uv; + char *end; + + fputs("call $printf(l $____fmt", stdout); + errno = 0; + uv = strtoull(num, &end, 16); + + if (!neg && !errno && !*end) + printf("lx, ..., l %llu )\n", uv); + else + { + errno = 0; + uv = strtoull(num, &end, 0); + + if (neg || errno || *end) + { + long long v = strtoll(num, NULL, 0); + printf("l, ..., l %lld )\n", v); + } + else + printf("l, ..., l %llu )\n", uv); + } + + return 0; +} + +static int cg_lit(const struct dspentry *e) +{ + const struct lit *l = e->lit; + + if (!l) + { + fprintf(stderr, "%s: unexpected null literal\n", __func__); + return -1; + } + + puts("%v =l loadl $stdout"); + printf("call $fputs(l $%s, w %%v)\n", l->name); + return 0; +} + +static int cg_id(const struct dspentry *de, const struct fn *fn) +{ + const struct stentry *e = de->entry; + const struct type *t = e->t; + const char *id = e->tk->s; + int global = cgen_global(fn, e); + size_t sz = t->sz; + const char *asz = cgen_sz(sz < 4 ? 4 : sz); + const struct param *ret = fn->pr->ret; + int isret = ret && ret->entry == e; + + if (global) + printf("%%v =%s load%s $%s\n", asz, cgen_load(t), id); + else if (isret) + printf("%%v =%s add 0, %%__ret\n", asz); + else + printf("%%v =%s add 0, %%%s_\n", asz, id); + + if (isret) + printf("call $printf(l $____fmt%s, ..., w %%__ret )\n", cgen_type(t)); + else if (global) + printf("call $printf(l $____fmt%s, ..., w %%v )\n", cgen_type(t)); + else + printf("call $printf(l $____fmt%s, ..., w %%%s_ )\n", cgen_type(t), id); + + return 0; +} + +int display_cgen(const struct display *d, struct cgen *c) +{ + for (size_t i = 0; i < d->nentries; i++) + { + const struct dspentry *e = &d->entries[i]; + const struct tk *tk = e->tk; + + if (tk->type == LIT && cg_lit(e)) + return -1; + else if (tk->type == NUM && cg_val(tk)) + return -1; + else if (tk->type == ID && e->entry && cg_id(e, c->fn)) + return -1; + else if (tk->type == ID && e->lit && cg_lit(e)) + return -1; + } + + if (d->println) + puts("call $putchar(l 10 )"); + + return 0; +} + +void display_free(struct display *d) +{ + free(d->entries); +} + +int display(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk + 1; + struct display d = {0}; + struct pos *pos = &p->pos[p->i]; + int eof; + + if (lex_eof(l, tk)) + { + errloc(tk - 1, "incomplete display statement"); + return -1; + } + + for (;;) + if (entry(l, tk, &d, p)) + goto failure; + else if ((eof = lex_eof(l, ++tk)) || kw(tk->s)) + break; + + if (eof || strcmp(tk->s, "etc")) + d.println = 1; + else if (!eof) + tk++; + + if (finalize(l, &d, p)) + goto failure; + + pos->seq = pos->stseq = stmts; + pos->step = stmts->steps; + p->stk = tk; + return 1; + +failure: + display_free(&d); + return -1; +} |
