【问题标题】:Tree construction: propagate a subtree to child树构造:将子树传播给子树
【发布时间】:2013-01-09 19:24:15
【问题描述】:

假设我有这个简单而无意义的语法:

propagate     :   what^ where*;
what          :   CHAR^;
where         :   NUMBER -> ^(PLUS NUMBER);

NUMBER        :   '0'..'9';
CHAR          :   'a'..'z';
PLUS          :   '+';

如果它解析像a123456789 这样的字符串,它会生成一个像这样的 AST:

我要做的是将what 解析的令牌传递给where 并创建一个AST(对于相同的输入),例如:

我尝试了以下方式:

propagate       :   w=what^ where[$w.text]*;
what            :   CHAR^;
where[String s] :   NUMBER -> ^(PLUS CHAR[s] NUMBER);

NUMBER          :   '0'..'9';
CHAR            :   'a'..'z';
PLUS            :   '+';

如果what 是单个令牌,它可以工作,但如果它是一棵树呢? 这是正确的方法吗?

【问题讨论】:

    标签: parsing antlr antlr3 abstract-syntax-tree


    【解决方案1】:

    方法如下:

    grammar T;
    
    options {
      output=AST;
      ASTLabelType=CommonTree;
    }
    
    parse
     : propagate EOF!
     ;
    
    propagate
     : what^ where[$what.tree]*
     ;
    
    what
     : CHAR
     ;
    
    where[CommonTree lhs]
     : NUMBER -> ^(PLUS {new CommonTree($lhs)} NUMBER)
     ;
    
    NUMBER : '0'..'9';
    CHAR   : 'a'..'z';
    PLUS   : '+';
    

    ANTLRWorks 的调试器可能无法显示正确的 AST:自己创建一个小型驱动程序类:

    import org.antlr.runtime.*;
    import org.antlr.runtime.tree.*;
    import org.antlr.stringtemplate.*;
    
    public class Main {
      public static void main(String[] args) throws Exception {
        TLexer lexer = new TLexer(new ANTLRStringStream("a123"));
        TParser parser = new TParser(new CommonTokenStream(lexer));
        CommonTree tree = (CommonTree)parser.parse().getTree();  
        DOTTreeGenerator gen = new DOTTreeGenerator();
        StringTemplate st = gen.toDOT(tree);
        System.out.println(st);
      }
    }
    

    要运行它,请执行以下操作:

    java -cp antlr-3.3.jar org.antlr.Tool T.g
    javac -cp antlr-3.3.jar *.java
    java -cp .:antlr-3.3.jar Main > ast.dot

    这将产生一个表示以下 AST 的 DOT 文件:

    【讨论】:

    • 如果a是一棵树(有孩子),它似乎只传播树的根(只有a没有孩子),你能检查一下吗?也许这取决于CommonTree的构造函数?
    • @SalvatoreD.,好吧,这不是你问的吗?您的示例和我的演示也是如此。也许编辑您的问题并重新表述,或添加更多示例。
    • 我的问题是,如果我想用它的子节点而不是单个节点传播整个树怎么办。您的演示和我的代码仅传播一个令牌或树的根。如果在您的演示中 a 有两个孩子分别名为 b 和 c,我会喜欢:... ^(PLUS ^(a b c) 1) ^(PLUS ^(a b c) 2) ...
    • @SalvatoreD.,啊,好吧。然后你需要自己做一些额外的工作,因为,AFAIK,ANTLRv3 中没有深拷贝功能。另请参阅此问答:stackoverflow.com/questions/6781019/antlr-duplicate-a-tree 而不是{new CommonTree($lhs)} 执行类似{deepCopy($lhs)} 的操作,其中deepCopy(CommonTree) 是@parser::members{ ... } 部分中的一个方法(当然,它返回CommonTree)。
    • 我刚刚实现了一个像你这样的解决方案,我希望有一种简单的方法来做到这一点,但也许深度克隆是唯一可能的方法。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-26
    • 2022-01-25
    相关资源
    最近更新 更多