void SwitchStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { int labelId = cg.createNewLocalId(shared_from_this()); bool staticCases = true; if (!m_exp->getType()->isInteger()) { staticCases = false; } else if (m_cases) { bool seenDefault = false; set<int64> seenNums; for (int i = 0; i < m_cases->getCount(); i++) { CaseStatementPtr stmt = dynamic_pointer_cast<CaseStatement>((*m_cases)[i]); if (stmt->getCondition()) { if (!stmt->isLiteralInteger() || seenDefault) { staticCases = false; break; } // detecting duplicate case value int64 num = stmt->getLiteralInteger(); if (seenNums.find(num) != seenNums.end()) { staticCases = false; break; } seenNums.insert(num); } else { seenDefault = true; } } } labelId |= CodeGenerator::InsideSwitch; if (staticCases) labelId |= CodeGenerator::StaticCases; cg.pushBreakScope(labelId, false); labelId &= ~CodeGenerator::BreakScopeBitMask; cg_indentBegin("{\n"); string var; int varId = -1; if (m_exp->preOutputCPP(cg, ar, 0)) { varId = cg.createNewLocalId(shared_from_this()); var = string(Option::SwitchPrefix) + lexical_cast<string>(varId); m_exp->getType()->outputCPPDecl(cg, ar, getScope()); cg_printf(" %s;\n", var.c_str()); m_exp->outputCPPBegin(cg, ar); cg_printf("%s = (", var.c_str()); m_exp->outputCPP(cg, ar); cg_printf(");\n"); m_exp->outputCPPEnd(cg, ar); } if (staticCases) { cg_printf("switch ("); if (!var.empty()) { cg_printf("%s", var.c_str()); } else { m_exp->outputCPP(cg, ar); } cg_printf(") {\n"); if (m_cases) m_cases->outputCPP(cg, ar); cg_printf("}\n"); } else { if (var.empty()) { varId = cg.createNewLocalId(shared_from_this()); if (m_exp->hasContext(Expression::LValue) && m_exp->is(Expression::KindOfSimpleVariable)) { var = getScope()->getVariables()->getVariableName( cg, ar, static_pointer_cast<SimpleVariable>(m_exp)->getName()); } else { var = string(Option::SwitchPrefix) + lexical_cast<string>(varId); m_exp->getType()->outputCPPDecl(cg, ar, getScope()); cg_printf(" %s = (", var.c_str()); m_exp->outputCPP(cg, ar); cg_printf(");\n"); } } if (m_cases && m_cases->getCount()) { CaseStatementPtr defaultCase; int defaultCaseNum = -1; for (int i = 0; i < m_cases->getCount(); i++) { CaseStatementPtr stmt = dynamic_pointer_cast<CaseStatement>((*m_cases)[i]); if (stmt->getCondition()) { stmt->outputCPPAsIf(cg, ar, varId, var.c_str(), i); } else { defaultCase = stmt; defaultCaseNum = i; } } if (defaultCaseNum != -1) { defaultCase->outputCPPAsIf(cg, ar, varId, var.c_str(), defaultCaseNum); } else { cg_printf("goto break%d;\n", labelId); cg.addLabelId("break", labelId); } cg_printf("\n"); for (int i = 0; i < m_cases->getCount(); i++) { CaseStatementPtr stmt = dynamic_pointer_cast<CaseStatement>((*m_cases)[i]); stmt->outputCPPByNumber(cg, ar, varId, !stmt->getCondition() && defaultCaseNum != i ? -1 : i); } } } // Even though switch's break/continue will never goto these labels, we need // them for "break/continue n" inside switches. if (cg.findLabelId("continue", labelId)) { cg_printf("continue%d:;\n", labelId); } if (cg.findLabelId("break", labelId)) { cg_printf("break%d:;\n", labelId); } cg_indentEnd("}\n"); cg.popBreakScope(); }
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); } }