std::unique_ptr Parser::parse()

in Jit/lir/parser.cpp [95:321]


std::unique_ptr<Function> Parser::parse(const std::string& code) {
  enum {
    FUNCTION,
    BASIC_BLOCK,
    INSTR_OUTPUT,
    INSTR_OUTPUT_TYPE,
    INSTR_EQUAL,
    INSTR_NAME,
    INSTR_INPUT,
    INSTR_INPUT_TYPE,
    INSTR_INPUT_COMMA,
    PHI_INPUT_FIRST,
    PHI_INPUT_COMMA,
    PHI_INPUT_SECOND,
    PHI_INPUT_SECOND_TYPE,
    PHI_INPUT_PAR,
  } state = FUNCTION;

  std::unique_ptr<Function> func;
  const char* codestr = code.c_str();
  const char* cur = codestr;
  const char* end = codestr + code.size();

  while (cur != end) {
    auto token = getNextToken(cur);
    auto type = token.type;
    while (true) {
      if (token.type == kComment) {
        // skip comments for now
        break;
      }
      switch (state) {
        case FUNCTION: {
          // expect a function start
          if (type == kNewLine) {
            break;
          }

          expect(type == kFunctionStart, cur, "Expect a function start.");
          func = std::make_unique<Function>();
          func_ = func.get();
          state = BASIC_BLOCK;
          break;
        }
        case BASIC_BLOCK: {
          // expect a basic block start
          if (type == kNewLine) {
            break;
          }
          expect(type == kBasicBlockStart, cur, "Expect a basic block start.");
          int id = token.data;

          block_ = func_->allocateBasicBlock();
          block_->setId(id);
          auto pair = block_index_map_.emplace(id, block_);
          expect(pair.second, cur, "Duplicated basic block id.");

          setSection(std::string(cur, token.length), block_);
          setSuccessorBlocks(std::string(cur, token.length), block_);

          state = INSTR_OUTPUT;
          break;
        }
        case INSTR_OUTPUT: {
          if (type == kNewLine) {
            break;
          } else if (type == kBasicBlockStart) {
            state = BASIC_BLOCK;
            continue;
          }

          instr_ = block_->allocateInstr(Instruction::kNone, nullptr);
          instr_->setId(-1);
          auto output = instr_->output();
          if (type == kId) {
            state = INSTR_NAME;
            continue;
          } else if (type == kVReg) {
            output->setVirtualRegister();
            auto pair = output_index_map_.emplace(token.data, instr_);
            instr_->setId(token.data);
            expect(pair.second, cur, "Duplicated output virtual register.");
          } else if (type == kPhyReg) {
            output->setPhyRegister(jit::codegen::PhyLocation::parse(
                std::string(cur, token.length)));
          } else if (type == kStack) {
            output->setStackSlot(token.data);
          } else if (type == kAddress) {
            output->setMemoryAddress(reinterpret_cast<void*>(token.data));
          } else if (type == kImmediate) {
            output->setConstant(token.data);
          } else if (type == kIndirect) {
            parseIndirect(output, std::string_view(cur, token.length), cur);
          } else {
            expect(false, cur);
          }
          state = INSTR_OUTPUT_TYPE;
          break;
        }
        case INSTR_OUTPUT_TYPE: {
          if (type == kEqual) {
            state = INSTR_EQUAL;
            continue;
          }
          expect(type == kDataType, cur, "Expect output data type.");
          instr_->output()->setDataType(
              getOperandDataType(std::string(cur, token.length)));
          state = INSTR_EQUAL;
          break;
        }
        case INSTR_EQUAL: {
          expect(type == kEqual, cur, "Expect \"=\".");
          state = INSTR_NAME;
          break;
        }
        case INSTR_NAME: {
          expect(type == kId, cur, "Expect an instruction name.");
          instr_->setOpcode(getInstrOpcode(std::string(cur, token.length)));
          state = INSTR_INPUT;
          break;
        }
        case INSTR_INPUT: {
          if (type == kNewLine) {
            state = INSTR_OUTPUT;
            break;
          }
          if (type == kParLeft) {
            state = PHI_INPUT_FIRST;
          } else {
            parseInput(token, cur);
            state = INSTR_INPUT_TYPE;
          }
          break;
        }
        case INSTR_INPUT_TYPE: {
          if (type == kComma || type == kNewLine) {
            state = INSTR_INPUT_COMMA;
            continue;
          }
          expect(type == kDataType, cur, "Expect input data type.");
          expect(
              instr_->getNumInputs() > 0,
              cur,
              "Expect data type to follow an input.");
          OperandBase* input_base =
              instr_->getInput(instr_->getNumInputs() - 1);
          if (!input_base->isLinked()) {
            Operand* input = static_cast<Operand*>(input_base);
            auto data_type = getOperandDataType(std::string(cur, token.length));
            input->setDataType(data_type);
          }
          state = INSTR_INPUT_COMMA;
          break;
        }
        case INSTR_INPUT_COMMA: {
          // expect commas between inputs
          if (type == kNewLine) {
            state = INSTR_OUTPUT;
            break;
          }

          expect(type == kComma, cur, "Expect a comma.");
          state = INSTR_INPUT;
          break;
        }
        case PHI_INPUT_FIRST: {
          // first argument of phi input pairs - basic block id
          expect(type == kBasicBlockRef, cur, "Expect a basic block id.");
          parseInput(token, cur);
          state = PHI_INPUT_COMMA;
          break;
        }
        case PHI_INPUT_COMMA: {
          expect(type == kComma, cur, "Expect a comma.");
          state = PHI_INPUT_SECOND;
          break;
        }
        case PHI_INPUT_SECOND: {
          // second argument of phi input pairs - a variable
          parseInput(token, cur);
          state = PHI_INPUT_SECOND_TYPE;
          break;
        }
        case PHI_INPUT_SECOND_TYPE: {
          if (type == kParRight) {
            state = PHI_INPUT_PAR;
            continue;
          }
          expect(type == kDataType, cur, "Expect phi input second data type.");
          expect(
              instr_->getNumInputs() > 0,
              cur,
              "Expect data type to follow an input.");
          OperandBase* input_base =
              instr_->getInput(instr_->getNumInputs() - 1);
          if (!input_base->isLinked()) {
            Operand* input = static_cast<Operand*>(input_base);
            auto data_type = getOperandDataType(std::string(cur, token.length));
            input->setDataType(data_type);
          }
          state = PHI_INPUT_PAR;
          break;
        }
        case PHI_INPUT_PAR: {
          // expect a right parenthesis
          expect(type == kParRight, cur, "Expect a right parenthesis");
          state = INSTR_INPUT_COMMA;
          break;
        }
      }

      break;
    }

    cur += token.length;
    // skip whitespaces
    while (cur != end && (*cur == ' ' || *cur == '\t')) {
      cur++;
    }
  }

  fixOperands();
  connectBasicBlocks();
  fixUnknownIds();

  return func;
}