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