#include "all.h" static FILE *outfp; static void pri(const char *fmt, ...); static void gentype(const struct type *ty) { assert(ty); switch (ty->t) { case TYvoid: pri("void"); break; case TYbool: pri("_Bool"); break; case TYint: pri("%sint%z_t", ty->int_signed ? "" : "u", 8 * ty->size); break; case TYfloat: pri("%s", ty->size == 4 ? "float" : "double"); break; case TYptr: pri("%t *", ty->child); break; case TYarr: assert(ty->length >= 0); case TYslice: case TYfn: case TYstruct: case TYunion: case TYeunion: assert(ty->_cname); pri("%s", ty->_cname); break; case TYenum: gentype(ty->enu.intty); break; case TYvalist: pri("__builtin_va_list"); break; } if (ty->konst) pri(" const"); } static void pristring(const char *s, u64 n) { extern int isprint(int); pri("\""); for (int i = 0; i < n; ++i) { if (s[i] == '"') pri("\\\""); else if (s[i] == '\\') pri("\\\\"); else if (s[i] == '?') pri("\\?"); else if (isprint(s[i])) pri("%c", s[i]); else fprintf(outfp, "\\%.3o", s[i]); } pri("\""); } static void genexpr(struct expr *expr); static void geniniex(struct expr *ex); static void geneuiniex(struct expr *ex); 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, outfp); continue; } switch ((c = *fmt++)) { case '%': fputc(c, outfp); break; case 'c': ch = bswap32(va_arg(ap, int)); if (ch == 0) fputc(ch, outfp); else while (ch) { if (ch & 0xFF) fputc(ch, outfp); ch >>= 8; } break; case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break; case 'U': fprintf(outfp, "%llu", (unsigned long long)va_arg(ap, u64)); break; case 'I': fprintf(outfp, "%lld", (long long)va_arg(ap, u64)); break; case 'z': fprintf(outfp, "%zu", va_arg(ap, size_t)); break; case 'f': fprintf(outfp, "%.20f", va_arg(ap, double)); break; case 's': S = va_arg(ap, const char *); fprintf(outfp, "%s", S ? S : "(null)"); break; case 'w': ws = va_arg(ap, int); for (int i = 0; i < ws; ++i) fprintf(outfp, " "); break; case 'S': S = va_arg(ap, const char *); pristring(S, va_arg(ap, u64)); break; case 't': gentype(va_arg(ap, const struct type *)); break; case 'e': genexpr(va_arg(ap, struct expr *)); break; case 'n': ; struct expr *ex = va_arg(ap, struct expr *); ex->t == Eini ? geniniex(ex) : ex->t == Eeuini ? geneuiniex(ex) : assert(0); break; default: fprintf(outfp, "pri(): bad fmt '%%%c'\n", c); abort(); break; } } va_end(ap); } static void genblock(struct blockstmt block); static void geniniex(struct expr *ex) { if (ex->t == Ezeroini) pri("{0}"); else { assert(ex->t == Eini); pri("{ "); for (int i = 0; i < ex->ini.args.n; ++i) { struct iniarg *arg = &ex->ini.args.d[i]; if (ex->ty->t == TYarr) if (arg->ex.t == Eini || arg->ex.t == Eeuini) pri("[%I] = %n, ", arg->idx, &arg->ex); else pri("[%I] = %e, ", arg->idx, &arg->ex); else if (arg->ex.t == Eini || arg->ex.t == Eeuini) pri(".%s_ = %n, ", arg->fld, &arg->ex); else pri(".%s_ = %e, ", arg->fld, &arg->ex); } pri("}"); } } static void geneuiniex(struct expr *ex) { if (ex->t == Ezeroini) pri("{0}"); else { assert(ex->t == Eeuini); if (ex->euini.ini) { pri("{ /* %s */ %I, .u.%s_ = ", ex->euini.fnam, ex->euini.tag, ex->euini.fnam); struct expr *it = ex->euini.ini; if (it->t == Eini || it->t == Eeuini) pri("%n }", it); else pri("%e }", it); } else pri("{ /* %s */ %I }", ex->euini.fnam, ex->euini.tag); } } static void genexpr(struct expr *ex) { assert(ex); const struct type *ty = unconstify(ex->ty); struct decl *decl; switch (ex->t) { case Eintlit: intlit: if (ty == ty_int) pri("%I", ex->i); else if (ty == ty_u64) pri("((uint64_t)%U)", ex->i); else pri("((%t)%I)", ty, ex->i); break; case Eflolit: pri("%f%s", ex->f, ty->size == 4 ? "f" : ""); break; case Estrlit: pri("%S", ex->strlit.d, ex->strlit.n); break; case Eboolit: pri("((_Bool)%U)", ex->i); break; case Enullit: pri("NULL"); break; case Ename: if ((ex->ref->t == Dfn || ex->ref->t == Dstatic) && *ex->ref->_cname) pri("%s", *ex->ref->_cname); else if (ex->ref->t == Dlet && ex->ref->var.id >= 0) pri("%s_%d__", ex->ref->name, ex->ref->var.id); else pri("%s", ex->ref->name); break; case Eprefix: pri("(%c(%e))", ex->unop.op, ex->unop.child); break; case Epostfix: pri("(%e)%c", ex->unop.child, ex->unop.op); break; case Ebinop: pri("((%e) %c (%e))", ex->binop.lhs, ex->binop.op == '?\?' ? '?:' : ex->binop.op, ex->binop.rhs); break; case Econd: pri("((%e) ? (%e) : (%e))", ex->cond.test, ex->cond.t, ex->cond.f); break; case Ecall: pri("%e(", ex->call.callee); for (int i = 0; i < ex->call.args.n; ++i) { pri("%e", &ex->call.args.d[i]); if (i < ex->call.args.n - 1) pri(", "); } pri(")"); break; case Eindex: pri("%e%s[%e]", ex->index.lhs, ex->index.lhs->ty->t == TYslice ? ".ptr" : "", ex->index.rhs); break; case Eblock: pri("(\n"); genblock(ex->block); pri(")"); break; case Eas: if (ex->ty->t != TYarr) pri("((%t)%e)", ex->ty, ex->child); else pri("(%e)", ex->child); break; case Eenumval: pri("/*%s:%s*/", ex->ty->enu.name, ex->enu.vname); ty = ex->ty->enu.intty; goto intlit; break; case Ezeroini: if (ty->t == TYarr || ty->t == TYstruct || ty->t == TYunion || ty->t == TYeunion || ty->t == TYslice) pri("((%t){0})", ty); else pri("((%t)0)", ty); break; case Eini: pri("((%t)%n)", ty, ex); break; case Eget: pri("%e%s%s%s_", ex->get.lhs, ex->get.lhs->ty->t == TYptr ? "->" : ".", (ex->get.lhs->ty->t == TYeunion || (ex->get.lhs->ty->t == TYptr && ex->get.lhs->ty->child->t == TYeunion) ? "u." : ""), ex->get.fld); break; case Emcall: decl = container_of(ex->mcall.met, struct decl, fn); assert(*decl->_cname); pri("%s(", *decl->_cname); for (int i = 0; i < ex->mcall.args.n; ++i) { pri("%e", &ex->mcall.args.d[i]); if (i < ex->mcall.args.n - 1) pri(", "); } pri(")"); break; case Eslice: ;static int id; // TODO range assertions pri("({ %t __start%d = %e; ", ex->slice.start->ty, id, ex->slice.start); pri("(%t) { %e%s + __start%d, %e - __start%d }; })", ex->ty, ex->slice.lhs, ex->slice.lhs->ty->t == TYslice ? ".ptr" : "", id, ex->slice.end, id); ++id; break; case Elen: pri("%e%slen", ex->child, ex->child->ty->t == TYptr ? "->" : "."); break; case Eptr: pri("%e%sptr", ex->child, ex->child->ty->t == TYptr ? "->" : "."); break; case Eeutag: pri("%e%st", ex->child, ex->child->ty->t == TYptr ? "->" : "."); break; case Eeuini: pri("((%t)", ty); geneuiniex(ex); pri(")"); break; case Evastart: pri("__builtin_va_start(%e, %e)", ex->binop.lhs, ex->binop.rhs); break; case Evaarg: pri("__builtin_va_arg(%e, %t)", ex->child, ex->ty); break; case Evaend: pri("__builtin_va_end(%e)", ex->child); break; } } static void gendecl(struct decl *decl, bool toplevel); static void genfn(bool externp, const char *cname, struct fn *fn); static void genstatic(bool externp, const char *cname, struct var *var); static void genstmt(struct blockstmt *block, struct stmt *stmt) { const char *p = fileid2path(stmt->span.fileid); if (stmt->t != Sblock) pri("#line %d %S\n", stmt->span.line, p, (u64)strlen(p)); switch (stmt->t) { case Sblock: genblock(stmt->block); break; case Sexpr: genexpr(&stmt->expr); pri(";\n"); break; case Sdecl: ; struct decl decl = stmt->decl; switch (decl.t) { case Dlet: pri("%t %s_%d__", decl.var.ty, decl.name, decl.var.id); if (decl.var.ini) { pri(" = "); if ((decl.var.ty->t == TYstruct || decl.var.ty->t == TYunion || decl.var.ty->t == TYarr) && (decl.var.ini->t == Ezeroini || decl.var.ini->t == Eini)) { geniniex(decl.var.ini); } else if (decl.var.ini->t == Eeuini) { geneuiniex(decl.var.ini); } else { pri("%e", decl.var.ini); } } pri(";\n"); break; case Dfn: if (decl.externp) genfn(1, decl.fn.name, &decl.fn); break; case Dstatic: if (decl.externp) genstatic(1, decl.name, &decl.var); break; case Ddef: case Dtype: case Dmacro: case Dtepl: case Dlabel: gendecl(&stmt->decl, 0); break; } break; case Sifelse: pri("if (%e) ", &stmt->ifelse.test); genblock(stmt->ifelse.t); if (stmt->ifelse.f) { pri("else\n"); genstmt(block, stmt->ifelse.f); } break; case Swhile: pri("while (%e) {", &stmt->loop.test); genblock(stmt->loop.body); pri("_cont%d:;} _brk%d:;\n", stmt->loop.id, stmt->loop.id); break; case Sdowhile: pri("do {"); genblock(stmt->loop.body); pri("_cont%d:;} while (%e); _brk%d:;\n", stmt->loop.id, &stmt->loop.test, stmt->loop.id); break; case Sfor: pri("{\n"); for (int i = 0; i < stmt->loop.ini.n; ++i) genstmt(block, &stmt->loop.ini.d[i]); pri("for (; "); pri("%e;", &stmt->loop.test); if (stmt->loop.next) pri(" %e", stmt->loop.next); pri(") {"); genblock(stmt->loop.body); pri("_cont%d:; }", stmt->loop.id); pri("} _brk%d:;\n", stmt->loop.id); break; case Siswitch: pri("switch (%e) {", &stmt->iswitch.test); for (int i = 0; i < stmt->iswitch.cs.n; ++i) { struct iswitchcase c = stmt->iswitch.cs.d[i]; for (int i = 0; i < c.es.n; ++i) pri("case %e: ", &c.es.d[i]); genblock(c.t); pri("break;\n"); } if (stmt->iswitch.f) { pri("default: "); genblock(*stmt->iswitch.f); } pri("}\n"); break; case Seuswitch: if (!stmt->euswitch.byptr) { pri("{ %t __stmp = %e;\n", stmt->euswitch.test.ty, &stmt->euswitch.test); pri("switch (__stmp.t) {", &stmt->euswitch.test); for (int i = 0; i < stmt->euswitch.cs.n; ++i) { struct euswitchcase c = stmt->euswitch.cs.d[i]; pri("case /* %s */ %d: ", c.fld->name, c.vval); if (c.capt) pri("{ %t %s_%d__ = __stmp.u.%s_;\n", c.fld->ty, c.capt, c.captid, c.fld->name); genblock(c.t); if (c.capt) pri("}\n"); pri("break;\n"); } } else { pri("{ %t *__stmp = &%e;\n", stmt->euswitch.test.ty, &stmt->euswitch.test); pri("switch (__stmp->t) {", &stmt->euswitch.test); for (int i = 0; i < stmt->euswitch.cs.n; ++i) { struct euswitchcase c = stmt->euswitch.cs.d[i]; pri("case /* %s */ %d: ", c.fld->name, c.vval); if (c.capt && c.captptr) pri("{ %t %s_%d__ = &__stmp->u.%s_;\n", c.captty, c.capt, c.captid, c.fld->name); if (c.capt && !c.captptr) pri("{ %t %s_%d__ = __stmp->u.%s_;\n", c.captty, c.capt, c.captid, c.fld->name); genblock(c.t); if (c.capt) pri("}\n"); pri("break;\n"); } } if (stmt->iswitch.f) { pri("default: "); genblock(*stmt->iswitch.f); } pri("}\n"); pri("}\n"); break; case Sreturn: pri("do { "); if (stmt->ret.ex) { if (stmt->ret.ex->ty->t != TYvoid) pri("__auto_type __ret = "); pri("%e;", stmt->ret.ex); } for (struct defer* defer = block->defers; defer; defer = defer->next) { if (defer->age < stmt->ret.deferage) { const char *p = fileid2path(defer->ex.span.fileid); pri("\n#line %d %S\n", defer->ex.span.line, p, (u64)strlen(p)); genexpr(&defer->ex); pri(";\n"); } } pri("return%s;", (stmt->ret.ex && stmt->ret.ex->ty->t != TYvoid) ? " __ret" : ""); pri("} while (0);\n"); break; case Sbreak: pri("goto _brk%d;\n", stmt->brkcon.id); break; case Scontinue: pri("goto _cont%d;\n", stmt->brkcon.id); break; case Scswitch: pri("if (0) ;\n"); for (int i = 0; i < stmt->cswitch.cs.n; ++i) { pri("else if (%e)\n", &stmt->cswitch.cs.d[i].test); genblock(stmt->cswitch.cs.d[i].t); } if (stmt->cswitch.f) { pri("else\n"); genblock(*stmt->cswitch.f); } break; } } static void genblock(struct blockstmt block) { pri("{\n"); for (int i = 0; i < block.stmts.n; ++i) genstmt(&block, &block.stmts.d[i]); for (struct defer* defer = block.defers; defer; defer = defer->next) { if (defer->blockid != block.id) continue; const char *p = fileid2path(defer->ex.span.fileid); pri("\n#line %d %S\n", defer->ex.span.line, p, (u64)strlen(p)); genexpr(&defer->ex); pri(";\n"); } pri("}\n"); } #define blocktostmt(Block) \ &(struct stmt) {Sblock, .block = Block} static void liftnested(struct stmt *stmt); static void liftdecl(struct decl *decl); static void liftnestedex(struct expr *ex) { if (ex) switch (ex->t) { case Eintlit: case Eflolit: case Estrlit: case Eboolit: case Enullit: case Ename: case Ezeroini: case Eenumval: break; case Eprefix: liftnestedex(ex->unop.child); break; case Epostfix: liftnestedex(ex->unop.child); break; case Ebinop: liftnestedex(ex->binop.lhs); liftnestedex(ex->binop.rhs); break; case Econd: liftnestedex(ex->cond.test); liftnestedex(ex->cond.t); liftnestedex(ex->cond.f); break; case Ecall: liftnestedex(ex->call.callee); for (int i = 0; i < ex->call.args.n; ++i) liftnestedex(&ex->call.args.d[i]); break; case Eindex: liftnestedex(ex->index.lhs); liftnestedex(ex->index.rhs); break; case Eblock: liftnested(blocktostmt(ex->block)); break; case Eas: case Elen: case Eeutag: case Eptr: liftnestedex(ex->child); break; case Eini: for (int i = 0; i < ex->ini.args.n; ++i) liftnestedex(&ex->ini.args.d[i].ex); break; case Eget: liftnestedex(ex->get.lhs); break; case Emcall: liftdecl(container_of(ex->mcall.met, struct decl, fn)); for (int i = 0; i < ex->mcall.args.n; ++i) liftnestedex(&ex->mcall.args.d[i]); break; case Eslice: liftnestedex(ex->slice.lhs); liftnestedex(ex->slice.start); liftnestedex(ex->slice.end); break; case Eeuini: liftnestedex(ex->euini.ini); break; case Evastart: liftnestedex(ex->binop.lhs); liftnestedex(ex->binop.rhs); break; case Evaarg: case Evaend: liftnestedex(ex->child); break; } } static void lifttype(const struct type *ty) { if (ty->t == TYstruct || ty->t == TYunion || ty->t == TYeunion) for (int i = 0; i < ty->agg.decls.n; ++i) liftdecl(ty->agg.decls.d[i]); } static void liftdecl(struct decl *decl) { static int id; switch (decl->t) { case Dfn: if ((decl->fn.body || (decl->container && !decl->externp)) && !*decl->_cname) { if (decl->container) *decl->_cname = xasprintf("__m%s_%s%d", decl->container->agg.name ? decl->container->agg.name : "_", decl->fn.name, decl->fn.id); else *decl->_cname = xasprintf("__f%s_%d", decl->fn.name, decl->fn.id); genfn(decl->externp, *decl->_cname, &decl->fn); } break; case Dstatic: if (!decl->externp) { assert(decl->var.ini); *decl->_cname = xasprintf("__s%s_%d", decl->name, id++); genstatic(decl->externp, *decl->_cname, &decl->var); } break; case Dlet: liftnestedex(decl->var.ini); break; case Dtype: lifttype(decl->ty); break; case Dtepl: for (struct teplcache *cache = decl->tepl.cache; cache; cache = cache->next) { for (int i = 0; i < cache->args.n; ++i) { if (cache->args.d[i].typ) lifttype(cache->args.d[i].ty); } lifttype(cache->ty); } default: break; } } static void // lift nested fns and static vars liftnested(struct stmt *stmt) { if (!stmt) return; switch (stmt->t) { case Sblock: for (int i = 0; i < stmt->block.stmts.n; ++i) liftnested(&stmt->block.stmts.d[i]); break; case Sexpr: liftnestedex(&stmt->expr); break; case Sdecl: liftdecl(&stmt->decl); break; case Sifelse: liftnested(stmt->ifelse.f); liftnested(blocktostmt(stmt->ifelse.t)); break; case Swhile: case Sdowhile: liftnestedex(&stmt->loop.test); liftnested(blocktostmt(stmt->loop.body)); break; case Sfor: for (int i = 0; i < stmt->loop.ini.n; ++i) liftnested(&stmt->loop.ini.d[i]); liftnestedex(&stmt->loop.test); liftnestedex(stmt->loop.next); liftnested(blocktostmt(stmt->loop.body)); break; case Siswitch: liftnestedex(&stmt->iswitch.test); for (int i = 0; i < stmt->iswitch.cs.n; ++i) { // not visiting constant exprs liftnested(blocktostmt(stmt->iswitch.cs.d[i].t)); } if (stmt->iswitch.f) liftnested(blocktostmt(*stmt->iswitch.f)); break; case Sreturn: if (stmt->ret.ex) liftnestedex(stmt->ret.ex); break; case Seuswitch: liftnestedex(&stmt->euswitch.test); for (int i = 0; i < stmt->euswitch.cs.n; ++i) { liftnested(blocktostmt(stmt->euswitch.cs.d[i].t)); } if (stmt->euswitch.f) liftnested(blocktostmt(*stmt->euswitch.f)); break; case Sbreak: case Scontinue: break; case Scswitch: for (int i = 0; i < stmt->cswitch.cs.n; ++i) { liftnestedex(&stmt->cswitch.cs.d[i].test); liftnested(blocktostmt(stmt->cswitch.cs.d[i].t)); } if (stmt->cswitch.f) liftnested(blocktostmt(*stmt->cswitch.f)); break; } } static void defctype(const struct type *ty, void *_); static void genfn(bool externp, const char *cname, struct fn *fn) { liftnested(fn->body); if (!externp) pri("static "); pri("%t %s(", fn->retty, cname); for (int i = 0; i < fn->params.n; ++i) { pri("%t %s", fn->params.d[i].ty, fn->params.d[i].name ? fn->params.d[i].name : ""); if (i < fn->params.n - 1 || fn->variadic) pri(", "); } if (fn->variadic) pri("..."); pri(")"); if (!fn->body) { pri(";\n"); } else { genblock(fn->body->block); } } static void genstatic(bool externp, const char *cname, struct var *var) { if (externp && !var->ini) pri("extern "); else if (!externp) pri("static "); pri("%t %s",var->ty, cname); if (var->ini) pri((var->ini->t == Eini || var->ini->t == Eeuini) ? " = %n" : " = %e", var->ini); pri(";\n"); } static void gendecl(struct decl *decl, bool toplevel) { const char *p = fileid2path(decl->span.fileid); if (decl->_gen) return; switch (decl->t) { case Dfn: pri("#line %d %S\n", decl->span.line, p, (u64)strlen(p)); if (decl->fn.body) assert(toplevel); if (!*decl->_cname) *decl->_cname = (char *)decl->fn.name; genfn(decl->externp, *decl->_cname, &decl->fn); break; case Dstatic: pri("#line %d %S\n", decl->span.line, p, (u64)strlen(p)); genstatic(decl->externp, *decl->_cname ? *decl->_cname : decl->name, &decl->var); break; case Dlet: assert(!toplevel); break; case Dtype: case Ddef: case Dtepl: case Dmacro: case Dlabel: break; } decl->_gen = 1; } static void declctype(const struct type *ty, void *_) { static int id; char **cname = (char **)&ty->_cname; const char *kind; if (!ty->_cname) switch (ty->t) { case TYvoid: case TYbool: case TYvalist: case TYenum: case TYint: case TYfloat: case TYptr: case TYarr: case TYslice: case TYfn: *(bool *)&ty->_defined = 1; break; case TYstruct: case TYeunion: kind = "struct"; goto agg; case TYunion: kind = "union"; agg: if (ty->konst) { declctype(unconstify(ty), NULL); *cname = (char *)unconstify(ty)->_cname; break; } *(bool *)&ty->_defined = 0; *cname = xasprintf("__ta%s%d", ty->agg.name ? ty->agg.name : "", id++); pri("typedef %s %s %s;\n", kind, *cname, *cname); } } #define isagg(ty) ((ty)->t == TYstruct || (ty)->t == TYunion || (ty)->t == TYenum) static void defctype(const struct type *ty, void *_) { static int id; char **cname = (char **)&ty->_cname; const char *kind; if (!ty->_cname || (!ty->_defined)) switch (ty->t) { case TYvoid: case TYbool: case TYvalist: case TYenum: case TYint: case TYfloat: break; case TYptr: if (!isagg(ty->child)) defctype(ty->child, NULL); break; case TYarr: if (ty->length >= 0) { defctype(ty->child, NULL); *cname = xasprintf("__ty%d", id++); pri("typedef %t %s[%U];\n", ty->child, *cname, ty->length); } break; case TYslice: if (ty->konst) { ty = unconstify(ty); } if (ty->child->konst) { const struct type *ty2 = unconstifychild(ty); defctype(ty2, NULL); *cname = (char *)ty2->_cname; return; } if (ty->_cname) break; *cname = xasprintf("__ty%d", id++); if (!isagg(ty->child)) defctype(ty->child, NULL); pri("typedef struct { %t *ptr; size_t len; } %s;\n", ty->child, *cname); pri("_Static_assert(sizeof(%s) == %U, \"sizeof(%t) == %U\");\n", *cname, (u64)ty->size, ty, (u64)ty->size); pri("_Static_assert(__alignof__(%s) == %U, \"__alignof__(%t) == %U\");\n", *cname, (u64)ty->align, ty, (u64)ty->align); break; case TYfn: *cname = xasprintf("__ty%d", id++); defctype(ty->fn.retty, NULL); for (int i = 0; i < ty->fn.params.n; ++i) defctype(ty->fn.params.d[i], NULL); pri("typedef %t %s(", ty->fn.retty, *cname); for (int i = 0; i < ty->fn.params.n; ++i) { pri("%t", ty->fn.params.d[i]); if (i < ty->fn.params.n - 1 || ty->fn.variadic) pri(", "); } if (ty->fn.variadic) pri("..."); pri(");\n"); break; case TYstruct: kind = "struct"; goto agg; case TYunion: kind = "union"; agg: *(bool *)&ty->_defined = 1; if (ty->konst) { defctype(unconstify(ty), NULL); *cname = (char *)unconstify(ty)->_cname; break; } if (!ty->agg.fwd) { for (int i = 0; i < ty->agg.flds.n; ++i) { struct aggfield fld = ty->agg.flds.d[i]; defctype(fld.ty, NULL); } pri("%s %s {\n", kind, *cname); if (!ty->agg.flds.n) pri("char _;\n"); for (int i = 0; i < ty->agg.flds.n; ++i) { struct aggfield fld = ty->agg.flds.d[i]; pri("%t %s_;\n", fld.ty, fld.name); } pri("};\n"); pri("_Static_assert(sizeof(%s) == %U, \"sizeof(%t) == %U\");\n", *cname, (u64)ty->size, ty, (u64)ty->size); pri("_Static_assert(__alignof__(%s) == %U, \"__alignof__(%t) == %U\");\n", *cname, (u64)ty->align, ty, (u64)ty->align); } break; case TYeunion: *(bool *)&ty->_defined = 1; if (ty->konst) { defctype(unconstify(ty), NULL); *cname = (char *)unconstify(ty)->_cname; break; } for (int i = 0; i < ty->agg.flds.n; ++i) { struct aggfield *fld = &ty->agg.flds.d[i]; if (fld->ty) defctype(fld->ty, NULL); } if (!ty->agg.fwd) { pri("struct %s {\n", *cname); pri("%t t;\n", ty->agg.enumty); pri("union {\n", ty->agg.enumty); for (int i = 0; i < ty->agg.flds.n; ++i) { struct aggfield *fld = &ty->agg.flds.d[i]; if (fld->ty) pri("%t %s_;\n", fld->ty, fld->name); } pri("} u;\n};\n"); pri("_Static_assert(sizeof(%s) == %U, \"sizeof(%t) == %U\");\n", *cname, (u64)ty->size, ty, (u64)ty->size); pri("_Static_assert(__alignof__(%s) == %U, \"__alignof__(%t) == %U\");\n", *cname, (u64)ty->align, ty, (u64)ty->align); } break; } } static void prelude() { pri("#include \n" "#include \n" "#define and &&\n" "#define or ||\n"); } void cgen(FILE *fp, const struct comfile *cf) { outfp = fp; prelude(); visittypes(declctype, NULL); visittypes(defctype, NULL); for (int i = 0; i < cf->decls.n; ++i) { if (cf->decls.d[i]->t != Dfn && cf->decls.d[i]->t != Dstatic) liftdecl(cf->decls.d[i]); gendecl(cf->decls.d[i], 1); } }