text: /*
  * Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved.
  *
  * OpenArkFE is licensed under the Mulan PSL v2.
  * You can use this software according to the terms and conditions of the Mulan PSL v2.
  * You may obtain a copy of Mulan PSL v2 at:
  *
  *  http://license.coscl.org.cn/MulanPSL2
  *
  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
  * FIT FOR A PARTICULAR PURPOSE.
  * See the Mulan PSL v2 for more details.
  */
  #include <vector>
  #include <cstring>
  
  #include "reserved_gen.h"
  #include "spec_parser.h"
  #include "auto_gen.h"
  #include "base_gen.h"
  #include "massert.h"
  #include "token_table.h"
  
  namespace maplefe {
  
  ///////////////////////////////////////////////////////////////////////////////////////
  //                       Summary functions during parsing
  // During matching phase in the language parser, we often need to print the stack of
  // rule table traversing in order to easily find the bug cause. So we need a set of
  // functions to help dump the information. As an example, a major request is to dump the
  // table name when we step into a new rule table. This request a mapping from the ruletable
  // address to the table name.
  //
  // We generate two files gen_summary.h and gen_summary.cpp to include all the functions we
  // may need. These two files are generated by autogen. Don't modify them.
  //
  // 1. For the rule table name mapping
  //
  //    In header file, we need
  //
  //      typedef struct {
  //        const RuleTable *mAddr;
  //        const char      *mName;
  //      }RuleTableSummary;
  //      extern RuleTableSummary gRuleTableSummarys[];
  //      extern unsigned RuleTableNum;
  //      extern std::vector<unsigned> gFailed[621];
  //
  //    In Cpp file, we need
  //
  //    #include "gen_summary.h"
  //    unsigned RuleTableNum;
  //    RuleTableSummary gRuleTableSummarys[] = {
  //      {&TblLiteral, "TblLiteral"},
  //      ...
  //    };
  ///////////////////////////////////////////////////////////////////////////////////////
  
  FileWriter *gSummaryHFile;
  FileWriter *gSummaryCppFile;
  unsigned    gRuleTableNum;
  std::vector<std::string> gTopRules;
  
  // write the beginning part of summary file
  static void PrepareSummaryCppFile() {
    gSummaryCppFile->WriteOneLine("#include \"rule_summary.h\"", 25);
    gSummaryCppFile->WriteOneLine("#include \"common_header_autogen.h\"", 34);
    gSummaryCppFile->WriteOneLine("namespace maplefe {", 19);
    gSummaryCppFile->WriteOneLine("RuleTableSummary gRuleTableSummarys[] = {", 41);
  }
  
  // write the ending part of summary file
  static void FinishSummaryCppFile() {
    gSummaryCppFile->WriteOneLine("};", 2);
    std::string num = std::to_string(gRuleTableNum);
    std::string num_line = "unsigned RuleTableNum = ";
    num_line += num;
    num_line += ";";
    gSummaryCppFile->WriteOneLine(num_line.c_str(), num_line.size());
    gSummaryCppFile->WriteOneLine("const char* GetRuleTableName(const RuleTable* addr) {", 53);
    gSummaryCppFile->WriteOneLine("  for (unsigned i = 0; i < RuleTableNum; i++) {", 47);
    gSummaryCppFile->WriteOneLine("    RuleTableSummary summary = gRuleTableSummarys[i];", 53);
    gSummaryCppFile->WriteOneLine("    if (summary.mAddr == addr)", 30);
    gSummaryCppFile->WriteOneLine("      return summary.mName;", 27);
    gSummaryCppFile->WriteOneLine("  }", 3);
    gSummaryCppFile->WriteOneLine("  return NULL;", 14);
    gSummaryCppFile->WriteOneLine("}", 1);
  
    std::string s = "BitVector gFailed[";
    s += std::to_string(gRuleTableNum);
    s += "];";
    gSummaryCppFile->WriteOneLine(s.c_str(), s.size());
  
    s = "SuccMatch gSucc[";
    s += std::to_string(gRuleTableNum);
    s += "];";
    gSummaryCppFile->WriteOneLine(s.c_str(), s.size());
  
    s = "unsigned gTopRulesNum = ";
    s += std::to_string(gTopRules.size());
    s += ";";
    gSummaryCppFile->WriteOneLine(s.c_str(), s.size());
  
    s = "RuleTable* gTopRules[";
    s += std::to_string(gTopRules.size());
    s += "] = {";
    unsigned i = 0;
    for (; i < gTopRules.size(); i++) {
      s += "&";
      s += gTopRules[i];
      if (i < gTopRules.size() - 1)
        s += ",";
    }
    s += "};";
    gSummaryCppFile->WriteOneLine(s.c_str(), s.size());
    gSummaryCppFile->WriteOneLine("}", 1);
  }
  
  ///////////////////////////////////////////////////////////////////////////////////////
  //
  //                The major implementation  of Autogen
  //
  ///////////////////////////////////////////////////////////////////////////////////////
  
  void AutoGen::Init() {
    std::string lang_path("../gen/");
  
    std::string summary_file_name = lang_path + "gen_summary.cpp";
    gSummaryCppFile = new FileWriter(summary_file_name);
    summary_file_name = lang_path + "gen_summary.h";
    gSummaryHFile = new FileWriter(summary_file_name);
    gRuleTableNum = 0;
  
    PrepareSummaryCppFile();
  
    std::string hFile = lang_path + "gen_reserved.h";
    std::string cppFile = lang_path + "gen_reserved.cpp";
    mReservedGen = new ReservedGen("../../../autogen/reserved.spec", hFile.c_str(), cppFile.c_str());
    mReservedGen->SetReserved(mReservedGen);
    mGenArray.push_back(mReservedGen);
  
    hFile = lang_path + "gen_iden.h";
    cppFile = lang_path + "gen_iden.cpp";
    std::string specFile = "../../../";
    specFile += mLang;
    specFile += "/identifier.spec";
    mIdenGen  = new IdenGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mIdenGen->SetReserved(mReservedGen);
    mGenArray.push_back(mIdenGen);
  
    hFile = lang_path + "gen_literal.h";
    cppFile = lang_path + "gen_literal.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/literal.spec";
    mLitGen  = new LiteralGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mLitGen->SetReserved(mReservedGen);
    mGenArray.push_back(mLitGen);
  
    hFile = lang_path + "gen_type.h";
    cppFile = lang_path + "gen_type.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/type.spec";
    mTypeGen  = new TypeGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mTypeGen->SetReserved(mReservedGen);
    mGenArray.push_back(mTypeGen);
  
    hFile = lang_path + "gen_attr.h";
    cppFile = lang_path + "gen_attr.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/attr.spec";
    mAttrGen  = new AttrGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mAttrGen->SetReserved(mReservedGen);
    mGenArray.push_back(mAttrGen);
  
    hFile = lang_path + "gen_separator.h";
    cppFile = lang_path + "gen_separator.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/separator.spec";
    mSeparatorGen  = new SeparatorGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mSeparatorGen->SetReserved(mReservedGen);
    mGenArray.push_back(mSeparatorGen);
  
    hFile = lang_path + "gen_operator.h";
    cppFile = lang_path + "gen_operator.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/operator.spec";
    mOperatorGen  = new OperatorGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mOperatorGen->SetReserved(mReservedGen);
    mGenArray.push_back(mOperatorGen);
  
    hFile = lang_path + "gen_keyword.h";
    cppFile = lang_path + "gen_keyword.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/keyword.spec";
    mKeywordGen  = new KeywordGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mKeywordGen->SetReserved(mReservedGen);
    mGenArray.push_back(mKeywordGen);
  
    hFile = lang_path + "gen_stmt.h";
    cppFile = lang_path + "gen_stmt.cpp";
    specFile = "../../../";
    specFile += mLang;
    specFile += "/stmt.spec";
    mStmtGen  = new StmtGen(specFile.c_str(), hFile.c_str(), cppFile.c_str());
    mStmtGen->SetReserved(mReservedGen);
    mGenArray.push_back(mStmtGen);
  
    hFile = lang_path + "gen_token.h";
    cppFile = lang_path + "gen_token.cpp";
    mTokenGen  = new TokenGen(hFile.c_str(), cppFile.c_str());
    mTokenGen->SetReserved(mReservedGen);
    mGenArray.push_back(mTokenGen);
  }
  
  AutoGen::~AutoGen() {
    std::vector<BaseGen*>::iterator it = mGenArray.begin();
    for (; it != mGenArray.end(); it++){
      BaseGen *gen = *it;
      delete gen;
    }
  
    if (gSummaryHFile)
      delete gSummaryHFile;
    if (gSummaryCppFile)
      delete gSummaryCppFile;
  }
  
  // When parsing a rule, its elements could be rules in the future rules, or
  // it could be in another XxxGen. We simply put Pending for these elements.
  //
  // BackPatch() is the one coming back to solve these Pending. It has to do
  // a traversal to solve one by one.
  void AutoGen::BackPatch() {
    std::vector<BaseGen*>::iterator it = mGenArray.begin();
    for (; it != mGenArray.end(); it++){
      BaseGen *gen = *it;
      gen->BackPatch(mGenArray);
    }
  }
  
  void AutoGen::Run() {
    std::vector<BaseGen*>::iterator it = mGenArray.begin();
    for (; it != mGenArray.end(); it++){
      BaseGen *gen = *it;
      gen->Run(mParser);
    }
  }
  
  void AutoGen::Gen() {
    Init();
    Run();
    BackPatch();
  
    // Prepare the tokens in all rules, by replacing all keyword, operator,
    // separators with tokens. All rules will contain index to the
    // system token.
    gTokenTable.mOperators = &(mOperatorGen->mOperators);
    gTokenTable.mSeparators = &(mSeparatorGen->mSeparators);
    gTokenTable.mKeywords = mKeywordGen->mKeywords;
    gTokenTable.Prepare();
  
    std::vector<BaseGen*>::iterator it = mGenArray.begin();
    for (; it != mGenArray.end(); it++){
      BaseGen *gen = *it;
      gen->Generate();
    }
  
    FinishSummaryCppFile();
  }
  
  }
  