#include "all.h" #include static void pritype(const struct type *ty) { const char *kind; assert(ty); if (ty->konst) epri("const "); switch (ty->t) { case TYvoid: epri("void"); break; case TYbool: epri("bool"); break; case TYint: epri("%c%z", ty->int_signed ? 'i' : 'u', 8 * ty->size); break; case TYfloat: epri("f%z", 8 * ty->size); break; case TYptr: epri("*%t", ty->child); break; case TYarr: assert(ty->length >= 0); epri("[%U]%t", ty->length, ty->child); break; case TYslice: epri("[#]%t", ty->child); break; case TYfn: epri("fn("); for (int i = 0; i < ty->fn.params.n; ++i) { epri("_ %t", ty->fn.params.d[i]); epri(", "); } if (ty->fn.variadic) epri("..."); epri(") %t", ty->fn.retty); break; case TYenum: epri("%s", ty->enu.name ? ty->enu.name : "(anonymous enum)"); break; case TYstruct: kind = "struct"; goto agg; case TYunion: kind = "union"; goto agg; case TYeunion: kind = "tagged union"; agg: epri(ty->agg.name ? ty->agg.name : "(anonymous %s)", kind); if (ty->agg.tpargs.n) { epri("<"); int n = ty->agg.tpargs.n; for (int i = 0; i < n; ++i) { epri("%t", ty->agg.tpargs.d[i].ty); if (i < n - 1) epri(", "); } epri("%bc", '>'); } break; case TYvalist: epri("va_list"); } } static void dumpexpr(const struct expr *expr); static void pristring(const char *s, u64 n) { extern int isprint(int); epri("\""); for (int i = 0; i < n; ++i) { if (isprint(s[i])) epri("%c", s[i]); else fprintf(stderr, "\\%.3o", s[i]); } epri("\""); } 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 || tok.t == TKlabel) { 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 == TKtype) { return ""; } else if (tok.t == TKexpr) { return ""; } else if (tok.t == TKhwhen) { return "`#when'"; } else if (tok.t == TKstrify) { return "`#strify'"; } 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 vepri(const char *fmt, va_list ap) { unsigned ch; const char *S; int ws; for (char c; (c = *fmt++);) { bool bold = 0; if (c != '%') { fputc(c, stderr); continue; } again: if (bold) fprintf(stderr, "\x1b[1m"); switch ((c = *fmt++)) { case '%': fputc(c, stderr); break; case 'b': bold = 1; goto again; 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 'p': fprintf(stderr, "%p", va_arg(ap, void *)); break; case 'q': S = va_arg(ap, const char *); pristring(S, strlen(S)); 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': epri("\x1b[1m"); pritype(va_arg(ap, const struct type *)); epri("\x1b[0m"); break; case 'T': fprintf(stderr, "%s", tok2str(va_arg(ap, struct tok))); break; case 'k': fprintf(stderr, "%s", tokt2str(va_arg(ap, int))); break; case 'e': dumpexpr(va_arg(ap, const struct expr *)); break; default: fprintf(stderr, "pri(): bad fmt '%%%c'\n", c); abort(); break; } if (bold) fprintf(stderr, "\x1b[0m"); } } void epri(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vepri(fmt, ap); va_end(ap); } static void dumpexpr(const struct expr *expr) { switch (expr->t) { case Eintlit: epri("%U_%t", expr->i, expr->ty); break; case Eflolit: epri("%f%s", expr->f, expr->ty->size == 4 ? "f" : ""); break; case Estrlit: epri("%S", expr->strlit.d, expr->strlit.n); break; case Eboolit: epri("#%c", expr->i ? 't' : 'f'); break; case Enullit: epri("#null"); break; case Ename: epri("%s", expr->ref->name); break; case Ebinop: epri("(%e %c %e)", expr->binop.lhs, expr->binop.op, expr->binop.rhs); break; case Eprefix: epri("%c(%e)", expr->unop.op, expr->unop.child); break; case Epostfix: epri("(%e)%c", expr->unop.child, expr->unop.op); break; case Econd: epri("(%e) ? (%e) : (%e)", expr->cond.test, expr->cond.t, expr->cond.f); break; case Ecall: epri("%e(", expr->call.callee); for (int i = 0; i < expr->call.args.n; ++i) { epri("%e", &expr->call.args.d[i]); if (i < expr->call.args.n - 1) epri(", "); } epri(")"); break; case Eindex: epri("%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) { epri("%w{\n", ws -1); for (int i = 0; i < block->stmts.n; ++i) dumpstmt(&block->stmts.d[i], ws + 1); epri("%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: epri("%w%e\n", ws, &stmt->expr); break; case Sifelse: epri("%wif (%e)\n", ws, &stmt->ifelse.test); dumpblock(&stmt->ifelse.t, ws + 1); if (stmt->ifelse.f) { epri("%welse\n", ws); dumpstmt(stmt->ifelse.f, ws + 1); } break; case Swhile: epri("%wwhile %e\n", ws, &stmt->loop.test); dumpblock(&stmt->loop.body, ws + 1); break; case Sfor: epri("%wfor \n", ws); /* if (stmt->loop.ini) dumpstmt(stmt->loop.ini, ws + 1); epri("%w; %e; ", ws + 1, &stmt->loop.test); if (stmt->loop.next) epri("%e", stmt->loop.next); epri("\n"); dumpblock(&stmt->loop.body, ws + 1); */ break; case Siswitch: epri("%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]; epri("%wcase ", ws); for (int j = 0; j < c->es.n; ++j) epri("%e, ", &c->es.d[j]); epri("do\n"); dumpblock(&c->t, ws + 1); } if (stmt->iswitch.f) { epri("%wcase else\n", ws); dumpblock(stmt->iswitch.f, ws + 1); } epri("%w}\n", ws); break; case Sreturn: if (stmt->ret.ex) epri("%wreturn %e;\n", ws, stmt->ret.ex); else epri("%wreturn;\n", ws); break; default:assert(0); } } static void dumpdecl(const struct decl *decl, int ws) { epri("%w", ws); epri("decl %s ", decl->name); switch (decl->t) { case Dtype: epri(" %t\n", decl->ty); break; case Dlet: case Dstatic: epri(" %t", decl->var.ty); if (decl->var.ini) epri(" = %e", decl->var.ini); epri("\n"); break; case Ddef: epri(" %t = %e", decl->var.ty, decl->var.ini); case Dfn: epri("<%sfn> (", decl->externp ? "extern " : ""); for (int i = 0; i < decl->fn.params.n; ++i) epri("%s %t, ", decl->fn.params.d[i].name, decl->fn.params.d[i].ty); if (decl->fn.variadic) epri("..."); epri(") %t", decl->fn.retty); if (decl->fn.body) { epri("\n"); dumpstmt(decl->fn.body, ws + 1); } else { epri(" <...>\n"); } break; case Dmacro: epri(" {\n"); for (int i = 0; i < decl->macro.cs.n; ++i) { struct macrocase c = decl->macro.cs.d[i]; epri("("); for (int j = 0; j < c.params.n; ++j) { if (j == c.params.n - 1 && c.variadic) epri("..."); epri("%s", c.params.d[j]); if (j < c.params.n - 1) epri(", "); } epri(") "); pritoktree(c.body); epri("\n"); } epri("}\n"); break; case Dtepl: case Dlabel: assert(0); } } void dumpcomfile(const struct comfile *cf) { for (int i = 0; i < cf->decls.n; ++i) dumpdecl(cf->decls.d[i], 0); }