4

我正在为 PL/SQL 编写一个简单的解析器和重写器工具,我已经完成了解析器并获得了 AST,但现在我遇到了两个问题:

  1. 如何获取 AST 的某些节点,从而改变它们的值?
  2. 更改节点后,如何从更新的 AST 重新生成 SQL ANTLR AST 是否提供类似的接口来执行此操作?

示例 SQL:select a,b from t where a=2

解析sql并获取ast后,我想将sql更改为

select fun(a),b from t where a = fun1(2);

顺便说一句,我用 ANTLR 为 C 生成 AST,

感谢您的任何建议!

4

2 回答 2

3

请参阅我关于如何从 AST 重新生成源代码的SO 答案。

它的工作比你想象的要多得多。

ANTLR 以字符串模板的形式提供了一些帮助,但您可能会发现这些好坏参半:虽然它们可以生成代码文本,但它们会准确生成模板中的内容,您可能希望根据其原始布局重新生成代码,字符串模板的布局要覆盖的内容。

于 2012-08-01T04:01:46.043 回答
0

以下代码将遍历 AST 并将所有 AST 节点打印到 stderr。同样的树遍历器是可以替换树节点的树转换器的基础。

分配新的树节点: (pANTLR3_BASE_TREE)(psr->adaptor->nilNode(psr->adaptor));

删除 AST 节点: parentASTnode->deleteChild(parentASTnode, nodeIndex); [deleteChild 不会释放已删除的节点]

将节点替换为: parentASTnode->replaceChildren(parentASTnode, nStartChildIndex, nStopChildIndex, newASTnode); [您不能在 AST 树层的中间插入节点,您只能替换节点或添加到父节点子列表的末尾]

void  printTree(pANTLR3_BASE_TREE t, int indent) 
{
    pANTLR3_BASE_TREE child = NULL;
    int     children = 0;
    char *  tokenText = NULL;
    string  ind = "";
    int     i = 0;

    if ( t != NULL ) 
      {
        children = t->getChildCount(t);
        for ( i = 0; i < indent; i++ )
          ind += "   ";

        for ( i = 0; i < children; i++ )
          {
            child = (pANTLR3_BASE_TREE)(t->getChild(t, i));
            tokenText = (char *)child->toString(child)->chars;
            fprintf(stderr, "%s%s\n", ind.c_str(), tokenText);
            if (tokenText == "<EOF>")
              break;
            printTree(child, indent+1);
          }
      }
}


// Run the parser
pANTLR3_BASE_TREE langAST = (psr->start_rule(psr)).tree; 

// Print the AST
printTree(langAST, 0);

// Get the Parser Errors
int nErrors = psr->pParser->rec->state->errorCount;
于 2013-03-22T20:17:06.533 回答