diff options
Diffstat (limited to 'warn.c')
| -rw-r--r-- | warn.c | 146 |
1 files changed, 146 insertions, 0 deletions
@@ -0,0 +1,146 @@ +#include "warn.h" +#include "cgen.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "storage.h" +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +static int finalize(const struct lex *l, const struct prv *p, + const struct print *pr) +{ + 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 = WARN, + .u.warn.p = *pr + }; + + fprintf(stderr, "\t\tadding warn statement with %zu entries%s\n", + pr->nentries, pr->println ? "" : ", no lf"); + 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 prientry *e) +{ + const struct lit *l = e->lit; + const char *tmp; + + if (!l) + { + fprintf(stderr, "%s: unexpected null literal\n", __func__); + return -1; + } + + printf("%%%s =l loadl $stderr\n", (tmp = cgen_tmp(sizeof (void *)))); + printf("call $fputs(l $%s, w %%%s)\n", l->name, tmp); + return 0; +} + +static int cg_id(const struct prientry *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), *tmp = cgen_tmp(sz); + + if (global) + printf("%%%s =%s load%s $%s\n", tmp, asz, cgen_load(t), id); + else + printf("%%%s =%s load%s %%%s_\n", tmp, asz, cgen_load(t), id); + + puts("%z =l loadl $stderr"); + fputs("call $fprintf(w %z, l $____fmt", stdout); + + if (t->type == PTR) + fputs("lx, ..., l ", stdout); + else + printf("%s, ..., %s ", cgen_type(t), asz); + + printf("%%%s)\n", tmp); + + return 0; +} + +int warn_cgen(const struct warn *w, struct cgen *c) +{ + const struct print *p = &w->p; + + for (size_t i = 0; i < p->nentries; i++) + { + const struct prientry *e = &p->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 (p->println) + { + puts("%v =l loadl $stderr"); + puts("call $fputc(l 10 , w %v)"); + } + + return 0; +} + +void warn_free(struct warn *w) +{ + print_free(&w->p); +} + +int warn(const struct lex *l, struct prv *p) +{ + return print(l, p, finalize); +} |
