#include "all.h" #include static void pri(const char *fmt, ...); static void pritype(const struct type *ty) { assert(ty); if (ty->konst) pri("const "); switch (ty->t) { case TYvoid: pri("void"); break; case TYbool: pri("bool"); break; case TYint: pri("%c%z", ty->int_signed ? 'i' : 'u', 8 * ty->size); break; case TYfloat: pri("f%z", 8 * ty->size); break; case TYptr: pri("*%t", ty->child); break; case TYarr: assert(ty->length >= 0); pri("[%U]%t", ty->length, ty->child); break; case TYslice: pri("[#]%t", ty->child); break; case TYfn: pri("fn("); for (int i = 0; i < ty->fn.params.n; ++i) { pri("_ %t", ty->fn.params.d[i]); pri(", "); } if (ty->fn.variadic) pri("..."); pri(") %t", ty->fn.retty); default:assert(0); } } static void dumpexpr(const struct expr *expr); static void pristring(const char *s, u64 n) { extern int isprint(int); pri("\""); for (int i = 0; i < n; ++i) { if (isprint(s[i])) pri("%c", s[i]); else fprintf(stderr, "\\%.3o", s[i]); } pri("\""); } const char * tokt2str(int t) { static char buf[128]; if (t == TKintlit) { return "integer literal"; } else if (t == TKident) { return "identifier"; } else if (t == TKstrlit) { return "string literal"; } else if (t == TKchrlit) { return "character literal"; } else if (t == TKeof) { return "end of file"; } else if (t < NUM_KEYWORDS) { snprintf(buf, sizeof buf - 1, "`%s'", keyword2str[t]); } else if (t > 0xFF) { unsigned m = bswap32(t); int i = 0; strcpy(buf, "`"); while (m) { if (m & 0xFF) buf[i++] = m; m >>= 8; } strcpy(buf, "'"); } else { snprintf(buf, sizeof buf - 1, "`%c'", t); } return buf; } const char * tok2str(struct tok tok) { static char buf[512]; if (tok.t == TKintlit) { snprintf(buf, sizeof buf - 1, "`%llu'", (unsigned long long)tok.ilit.i); } else if (tok.t == TKident || tok.t == TKmacident) { snprintf(buf, sizeof buf - 1, "`%s'", tok.str); } else if (tok.t == TKgensym) { snprintf(buf, sizeof buf - 1, "`$%s'", tok.str); } else if (tok.t == TKstrlit) { snprintf(buf, sizeof buf - 1, "\"%s\"", tok.str); } else if (tok.t == TKchrlit) { u64 t = bswap64(tok.ilit.i); int i = 1; strcpy(buf, "'"); while (t) { if (t & 0xFF) buf[i++] = t; t >>= 8; } buf[i] = '\0'; strcat(buf, "'"); } else if (tok.t == TKeof) { return ""; } else if (tok.t < NUM_KEYWORDS) { snprintf(buf, sizeof buf - 1, "`%s'", keyword2str[tok.t]); } else if (tok.t > 0xFF) { unsigned t = bswap32(tok.t); int i = 1; strcpy(buf, "`"); while (t) { if (t & 0xFF) buf[i++] = t; t >>= 8; } buf[i] = '\0'; strcat(buf, "'"); } else { snprintf(buf, sizeof buf - 1, "`%c'", tok.t); } return buf; } void pritoktree(struct toktree toks) { fprintf(stderr, "[ "); for (int i = 0; i < toks.n; ++i) { fprintf(stderr, "%s ", tok2str(toks.d[i])); } fprintf(stderr, "]"); } void pri(const char *fmt, ...) { va_list ap; unsigned ch; const char *S; int ws; va_start(ap, fmt); for (char c; (c = *fmt++);) { if (c != '%') { fputc(c, stderr); continue; } switch ((c = *fmt++)) { case '%': fputc(c, stderr); break; case 'c': ch = bswap32(va_arg(ap, int)); while (ch) { fputc(ch, stderr); ch >>= 8; } break; case 'd': fprintf(stderr, "%d", va_arg(ap, int)); break; case 'U': fprintf(stderr, "%llu", (unsigned long long)va_arg(ap, u64)); break; case 'z': fprintf(stderr, "%zu", va_arg(ap, size_t)); break; case 'f': fprintf(stderr, "%f", va_arg(ap, double)); break; case 's': fprintf(stderr, "%s", va_arg(ap, const char *)); break; case 'w': ws = va_arg(ap, int); for (int i = 0; i < ws; ++i) fprintf(stderr, " "); break; case 'S': S = va_arg(ap, const char *); pristring(S, va_arg(ap, u64)); break; case 't': pritype(va_arg(ap, const struct type *)); break; case 'e': dumpexpr(va_arg(ap, const struct expr *)); break; default: fprintf(stderr, "pri(): bad fmt '%%%c'\n", c); abort(); break; } } va_end(ap); } static void dumpexpr(const struct expr *expr) { switch (expr->t) { case Eintlit: pri("%U_%t", expr->i, expr->ty); break; case Eflolit: pri("%f%s", expr->f, expr->ty->size == 4 ? "f" : ""); break; case Estrlit: pri("%S", expr->strlit.d, expr->strlit.n); break; case Eboolit: pri("#%c", expr->i ? 't' : 'f'); break; case Enullit: pri("#null"); break; case Ename: pri("%s", expr->ref->name); break; case Ebinop: pri("(%e %c %e)", expr->binop.lhs, expr->binop.op, expr->binop.rhs); break; case Eprefix: pri("%c(%e)", expr->unop.op, expr->unop.child); break; case Epostfix: pri("(%e)%c", expr->unop.child, expr->unop.op); break; case Econd: pri("(%e) ? (%e) : (%e)", expr->cond.test, expr->cond.t, expr->cond.f); break; case Ecall: pri("%e(", expr->call.callee); for (int i = 0; i < expr->call.args.n; ++i) { pri("%e", &expr->call.args.d[i]); if (i < expr->call.args.n - 1) pri(", "); } pri(")"); break; case Eindex: pri("%e[%e]", expr->index.lhs, expr->index.rhs); break; default: assert(0 && "exprbad"); } } static void dumpdecl(const struct decl *decl, int ws); static void dumpstmt(const struct stmt *stmt, int ws); static void dumpblock(const struct blockstmt *block, int ws) { pri("%w{\n", ws -1); for (int i = 0; i < block->stmts.n; ++i) dumpstmt(&block->stmts.d[i], ws + 1); pri("%w}\n", ws - 1); } static void dumpstmt(const struct stmt *stmt, int ws) { switch (stmt->t) { case Sblock: dumpblock(&stmt->block, ws); break; case Sdecl: dumpdecl(&stmt->decl, ws); break; case Sexpr: pri("%w%e\n", ws, &stmt->expr); break; case Sifelse: pri("%wif (%e)\n", ws, &stmt->ifelse.test); dumpblock(&stmt->ifelse.t, ws + 1); if (stmt->ifelse.f) { pri("%welse\n", ws); dumpstmt(stmt->ifelse.f, ws + 1); } break; case Swhile: pri("%wwhile %e\n", ws, &stmt->loop.test); dumpblock(&stmt->loop.body, ws + 1); break; case Sfor: pri("%wfor \n", ws); if (stmt->loop.ini) dumpstmt(stmt->loop.ini, ws + 1); pri("%w; %e; ", ws + 1, &stmt->loop.test); if (stmt->loop.next) pri("%e", stmt->loop.next); pri("\n"); dumpblock(&stmt->loop.body, ws + 1); break; case Siswitch: pri("%wswitch %e {\n", ws, &stmt->iswitch.test); for (int i = 0; i < stmt->iswitch.cs.n; ++i) { struct iswitchcase *c = &stmt->iswitch.cs.d[i]; pri("%wcase ", ws); for (int j = 0; j < c->es.n; ++j) pri("%e, ", &c->es.d[j]); pri("do\n"); dumpblock(&c->t, ws + 1); } if (stmt->iswitch.f) { pri("%wcase else\n", ws); dumpblock(stmt->iswitch.f, ws + 1); } pri("%w}\n", ws); break; case Sreturn: if (stmt->retex) pri("%wreturn %e;\n", ws, stmt->retex); else pri("%wreturn;\n", ws); break; } } static void dumpdecl(const struct decl *decl, int ws) { pri("%w", ws); pri("decl %s ", decl->name); switch (decl->t) { case Dtype: pri(" %t\n", decl->ty); break; case Dlet: case Dstatic: pri(" %t", decl->var.ty); if (decl->var.ini) pri(" = %e", decl->var.ini); pri("\n"); break; case Dfn: pri("<%sfn> (", decl->externp ? "extern " : ""); for (int i = 0; i < decl->fn.params.n; ++i) pri("%s %t, ", decl->fn.params.d[i].name, decl->fn.params.d[i].ty); if (decl->fn.variadic) pri("..."); pri(") %t", decl->fn.retty); if (decl->fn.body) { pri("\n"); dumpstmt(decl->fn.body, ws + 1); } else { pri(" <...>\n"); } break; case Dmacro: pri(" {\n"); for (int i = 0; i < decl->macro.cs.n; ++i) { struct macrocase c = decl->macro.cs.d[i]; pri("("); for (int j = 0; j < c.params.n; ++j) { if (j == c.params.n - 1 && c.variadic) pri("..."); pri("%s", c.params.d[j]); if (j < c.params.n - 1) pri(", "); } pri(") "); pritoktree(c.body); pri("\n"); } pri("}\n"); break; } } void dumptransunit(const struct transunit *tu) { for (int i = 0; i < tu->decls.n; ++i) dumpdecl(&tu->decls.d[i], 0); }