void BreakStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { const std::vector<int> &labelIds = cg.getBreakScopes(); if (labelIds.empty()) { cg_printf("throw_fatal(\"bad %s\");\n", m_name); return; } int64 depth = getDepth(); if (!depth) { unsigned size = labelIds.size(); int labelId = 0; int varId = cg.createNewLocalId(shared_from_this()); cg_printf("int64 %s%d;\n", Option::TempPrefix, varId); m_exp->outputCPPBegin(cg, ar); cg_printf("%s%d = (", Option::TempPrefix, varId); m_exp->outputCPP(cg, ar); cg_printf(");\n"); m_exp->outputCPPEnd(cg, ar); if (size > 1) { cg_printf("switch ("); cg_printf("%s%d", Option::TempPrefix, varId); cg_printf(") {\n"); for (unsigned int i = 0; i < size; i++) { labelId = labelIds[i]; labelId &= ~CodeGenerator::BreakScopeBitMask; cg_printf("case %d: goto %s%d;\n", int(labelIds.size() - i), m_name, labelId); cg.addLabelId(m_name, labelId); } cg_printf("default:\n"); } else { labelId = labelIds.back(); labelId &= ~CodeGenerator::BreakScopeBitMask; cg.addLabelId(m_name, labelId); } cg_printf("if ("); cg_printf("%s%d", Option::TempPrefix, varId); cg_printf("<2) {\n"); cg_printf("goto %s%d;\n", m_name, labelId); cg_printf("} else {\n"); cg_printf("throw_fatal(\"bad %s\");\n", m_name); cg_printf("}\n"); if (size > 1) { cg_printf("}\n"); } return; } assert(depth >= 1); if (depth > (int64)labelIds.size()) { cg_printf("throw_fatal(\"bad %s\");\n", m_name); return; } int labelId = labelIds[labelIds.size() - depth]; if (depth > 1 || labelId & CodeGenerator::InsideSwitch) { if (depth == 1 && labelId & CodeGenerator::StaticCases) { cg_printf("break;\n"); // continue will turn into break as well } else { labelId &= ~CodeGenerator::BreakScopeBitMask; cg_printf("goto %s%d;\n", m_name, labelId); cg.addLabelId(m_name, labelId); } } else { cg_printf("%s;\n", m_name); } }