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();
}
示例#2
0
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);
  }
}