首页 > 解决方案 > 自动修改 C++ 代码:将代码从解析树转换回源代码

问题描述

我正在尝试修改 C++ 代码。我得到一段代码和行号,我需要在给定的行号处应用代码。像这样:

1 void foo(){
2 int a = 5;
3 int b = 10;
4 }

和行号:2,3。现在我想在行号之后自动插入代码:

1 void foo(){
2 int a = 5;
3 newcode();
4 int b = 10;
5 newcode();
6 }

在另一个线程中,人们说 antlr 是一个很好的方法。所以我尝试使用 antlr 运行时 api。生成解析树很容易。我还找到了修改它的方法。但是现在我不知道如何从解析树中取回源代码?我真的不需要源代码,只需将解析树编译为可执行程序就足够了。我怎样才能做到这一点?

有没有更简单的方法来解决我的问题?也许只是阅读代码,计算 \n 并在 2 和 3 \ni 之后放入我的代码?

编辑:对于我的学士论文,我得到了一段并行代码,我需要强制它执行给定的交错。因此,我需要编写一个工具来在代码中的给定行自动插入“EnterCriticalSection(...)”和“LeaveCriticalSection(...)”等指令。现在,我得到了另一份工作,重命名主函数并插入我自己的主函数。我认为这不适用于计数线。

标签: c++antlrtransformation

解决方案


一个可能的解决方案是使用生成的解析树来获取令牌位置(每个TerminalNode都有一个Token实例,附加了它在原始源代码中的位置信息)。有了它,您可以开始从原始源流中复制未修改的文本,然后插入属于该位置的您自己的文本。之后复制下一个未修改的代码部分,然后插入您的下一个修改。循环执行此操作,直到到达 EOF。

这种情况并不关心最终格式,但我认为这可能不相关 - 您的任务听起来像是您正在为某些测量进行代码检测。

这是我用来检索给定两个解析树节点的原始源代码的代码:

std::string MySQLRecognizerCommon::sourceTextForRange(tree::ParseTree *start, tree::ParseTree *stop, bool keepQuotes) {
  Token *startToken = antlrcpp::is<tree::TerminalNode *>(start) ? dynamic_cast<tree::TerminalNode *>(start)->getSymbol()
                                                                : dynamic_cast<ParserRuleContext *>(start)->start;
  Token *stopToken = antlrcpp::is<tree::TerminalNode *>(stop) ? dynamic_cast<tree::TerminalNode *>(start)->getSymbol()
                                                              : dynamic_cast<ParserRuleContext *>(stop)->stop;
  return sourceTextForRange(startToken, stopToken, keepQuotes);
}

//----------------------------------------------------------------------------------------------------------------------

std::string MySQLRecognizerCommon::sourceTextForRange(Token *start, Token *stop, bool keepQuotes) {
  CharStream *cs = start->getTokenSource()->getInputStream();
  size_t stopIndex = stop != nullptr ? stop->getStopIndex() : std::numeric_limits<size_t>::max();
  std::string result = cs->getText(misc::Interval(start->getStartIndex(), stopIndex));
  if (keepQuotes || result.size() < 2)
    return result;

  char quoteChar = result[0];
  if ((quoteChar == '"' || quoteChar == '`' || quoteChar == '\'') && quoteChar == result.back()) {
    if (quoteChar == '"' || quoteChar == '\'') {
      // Replace any double occurence of the quote char by a single one.
      replaceStringInplace(result, std::string(2, quoteChar), std::string(1, quoteChar));
    }

    return result.substr(1, result.size() - 2);
  }

  return result;
}

此代码取自MySQL Workbench 解析器模块


推荐阅读