ANTLR duplicate a tree

后端 未结 2 875
小蘑菇
小蘑菇 2020-12-18 13:05

I use ANTLR to build a tree (CommonTree) like follwing (language: JAVA):

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


        
相关标签:
2条回答
  • 2020-12-18 13:48

    Try something like this:

    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());
    

    which would produce:

    (&& a (|| b X))
    (&& a (|| b c))
    

    for the input "a && (b || c)". I.e., the tree has X, but the copy would will have the original contents: c.

    Note that I choose CommonTree and CommonToken objects because those are the default Token and Tree implementations. If you choose to create your own Token and/or Tree, chances are that you'll subclass the CommonTree and CommonToken classes, in which case my suggestion would not break.

    A CommonTree is nothing more than a wrapper around a CommonToken, holding a bit of extra information: a parent node, and child nodes. That is why I also copy all the information from the CommonToken objects.

    0 讨论(0)
  • 2020-12-18 13:58

    I had the same issue stumbling over dupTree(), which seemed to be deprecated and then Bart's posting, which steered me into the right direction. I finally ended up with the following, which is using the constructor of CommonTree accepting a CommonTree - abstracting it from the need to copy the individual fields.

      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;
      }
    

    NB: I stuck with Bart's naming convention.

    0 讨论(0)
提交回复
热议问题