ANTLR复制一棵树



我使用ANTLR构建如下的树(CommonTree)(语言:JAVA):

  Parser.prog_return r = parser.prog();
  CommonTree t = (CommonTree) r.getTree();

现在,我需要传递"t"作为参数,并在不影响原始树的情况下进行一些更改。然而,使用Java的指针,这是不可能的,所以我需要复制树。

我一直在网上搜索,我能找到的封闭的东西是ASTFactory类的dupTree()方法。

任何关于如何实现这一目标的建议或建议将不胜感激!

编辑

@Bart Kiers,谢谢你的回答,它绝对有效!

我看到您正在对树进行深度优先遍历,并为访问的每个节点创建CommonTree对象。

我现在的问题是,CommonToken和CommonTree之间的关系是什么,这些属性是做什么的:

cTok.setCharPositionInLine(oTok.getCharPositionInLine());
cTok.setChannel(oTok.getChannel());
cTok.setStartIndex(oTok.getStartIndex());
cTok.setStopIndex(oTok.getStopIndex());
cTok.setTokenIndex(oTok.getTokenIndex());

试试这样:

public static CommonTree copyTree(CommonTree original) {
  CommonTree copy = new CommonTree(original.getToken());
  copyTreeRecursive(copy, original);
  return copy;
}
private static void copyTreeRecursive(CommonTree copy, CommonTree original) {
  if(original.getChildren() != null) {
    for(Object o : original.getChildren()) {
      CommonTree originalChild = (CommonTree)o;
      // get the token from the original child node
      CommonToken oTok = (CommonToken)originalChild.getToken();
      // create a new token with the same type & text as 'oTok' 
      CommonToken cTok = new CommonToken(oTok.getType(), oTok.getText());
      // copy all attributes from 'oTok' to 'cTok'  
      cTok.setLine(oTok.getLine());
      cTok.setCharPositionInLine(oTok.getCharPositionInLine());
      cTok.setChannel(oTok.getChannel());
      cTok.setStartIndex(oTok.getStartIndex());
      cTok.setStopIndex(oTok.getStopIndex());
      cTok.setTokenIndex(oTok.getTokenIndex());
      // create a new tree node with the 'cTok' as token
      CommonTree copyChild = new CommonTree(cTok);
      // set the parent node of the child node
      copyChild.setParent(copy);
      // add the child to the parent node
      copy.addChild(copyChild);
      // make a recursive call to copy deeper
      copyTreeRecursive(copyChild, originalChild);
    }
  }
}
...
// get the original tree
CommonTree tree = (CommonTree)parser.parse().getTree();
// create a copy of the tree
CommonTree copy = copyTree(tree);
// change the contents of the right node of the right node of the root 
((CommonTree)tree.getChild(1).getChild(1)).getToken().setText("X");
System.out.println(tree.toStringTree());
System.out.println(copy.toStringTree());

将产生:

<>之前(&& a (|| b X))(&& a (|| b c))之前

为输入"a && (b || c)"。即,tree中含有X,但copy中仍含有原始的c

注意,我选择CommonTreeCommonToken对象,因为它们是默认的TokenTree实现。如果您选择创建自己的Token和/或Tree,那么您可能会子类化CommonTreeCommonToken类,在这种情况下,我的建议不会中断。

CommonTree只不过是CommonToken的包装器,包含一些额外的信息:父节点和子节点。这就是为什么我也复制了CommonToken对象的所有信息。

我在dupTree()上遇到了同样的问题,它似乎被弃用了,然后Bart的帖子把我引向了正确的方向。我最终得到了下面的代码,这是使用CommonTree的构造函数接受CommonTree——将其从复制单个字段的需要中抽象出来。

  private static CommonTree copyTreeRecursive(CommonTree original) {
    CommonTree copy = new CommonTree(original); // Leverage constructor
    if(original.getChildren() != null) {
      for(Object o : original.getChildren()) {
        CommonTree childCopy  = copyTreeRecursive((CommonTree)o);
        childCopy.setParent(copy);
        copy.addChild(childCopy);
      }
    };
    return copy;
  }

注意:我坚持Bart的命名惯例。

最新更新