【问题标题】:ANTLR3 Hetero nodes are not createdANTLR3 Hetero 节点未创建
【发布时间】:2011-10-05 07:57:46
【问题描述】:

我正在尝试根据此处提供的示例创建异构树:http://www.antlr.org/wiki/display/ANTLR3/Tree+construction#Treeconstruction-Heterogeneoustreenodes

我已经创建了一个语法文件如下:

grammar T; 

options { 
  language=CSharp3; 
  ASTLabelType=CommonTree;
  output=AST; 
  TokenLabelType=CommonToken;
  k=3;
} 

tokens { 
  ROOT; 
  UNARY_MIN; 
} 

@lexer::header 
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;
  using ANTLRSandbox.Criteria;
}

@parser::header 
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;
  using ANTLRSandbox.Criteria;
}


@parser::namespace { ANTLRSandbox } 
@lexer::namespace { ANTLRSandbox } 


public
parse 
  :  exp EOF -> ^(ROOT<RootNode> exp) 
  ; 

exp 
  :  addExp 
  ; 

addExp 
  :  mulExp (('+'<PlusNode> | '-'<MinusNode>)^ mulExp)* 
  ; 

mulExp 
  :  unaryExp (('*' | '/')^ unaryExp)* 
  ; 

unaryExp 
  :  '-' atom -> ^(UNARY_MIN atom) 
  |  atom 
  ; 

atom 
  :  Number 
  |  '(' exp ')' -> exp 
  ; 

Number 
  :  ('0'..'9')+ ('.' ('0'..'9')+)? 
  ; 

Space  
  :  (' ' | '\t' | '\r' | '\n'){Skip();} 
  ; 

节点类如下所示:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Antlr.Runtime;
using Antlr.Runtime.Tree;

namespace ANTLRSandbox.Criteria
{
  public class RootNode : CommonTree
  {
    public RootNode(int ttype) { }
    public RootNode(int ttype, IToken t) { }
    public RootNode(IToken t) { }
  }
}

PlusNodeMinusNode 的类与 RootNode 相同,所以我不会在这里发布它们。

这是我创建实际树的方法:

    string s = "(12.5 + 56 / -7) * 0.5";

    ANTLRStringStream Input = new ANTLRStringStream(s);
    TLexer Lexer = new TLexer(Input);
    CommonTokenStream Tokens = new CommonTokenStream(Lexer);
    TParser Parser = new TParser(Tokens);

    TParser.parse_return ParseReturn = Parser.parse();
    CommonTree Tree = (CommonTree)ParseReturn.Tree;

代码运行没有任何错误,但是当我“监视”Tree 对象时,它的所有节点都是CommonTree 类型,并且我在PlusNodeMinusNodeRootNode 构造函数中放置的所有断点都是错过了。

我已关注 ANTLR3 wiki 页面中提供的示例,但在网络上找不到任何示例。我知道他们打算在某个时候放弃这种方法(在 ANTLR3 preview notes 上找到了这个)但是这个实现更适合我(我需要根据语法上下文创建不同的对象类型)。

那么……有什么提示吗?我错过了什么吗?一些选项/标志将其放入语法定义文件中?

谢谢! D.

【问题讨论】:

  • 我不认为你最终想出了如何让 C# 3 目标生成异构节点,是吗?接受的答案并没有真正回答问题。我遇到了同样的困难。
  • 不,运气不好。我最终在Create 方法中使用了带有工厂的树适配器(CommonTreeAdaptor)。

标签: tree antlr nodes antlr3 heterogeneous


【解决方案1】:

I just received an answer that works from the main contributor of the CSharp3 target。基本上,在指定节点类型时,必须显式使用node=;您不能依赖记录的隐式行为。例如,您需要更改:

parse 
  :  exp EOF -> ^(ROOT<RootNode> exp)
  ; 

...到这个:

parse 
  :  exp EOF -> ^(ROOT<node=RootNode> exp)
  ; 

在我自己的语法中,一旦我对我的重写规则进行了这个更改,解析器最终会输出异构节点。

【讨论】:

    【解决方案2】:

    在使用内联树运算符(^ 用于根,! 用于省略规则)时,我从来没有让这些运算符 &lt; ... &gt; 正常工作。我只能建议您在解析器规则的右侧使用重写规则(... -&gt; ^(...)),然后在重写规则中仅定义自定义节点 &lt;NodeName&gt;not 在两侧(!)正如维基提到的:我怀疑维基信息有点过时了。我知道这样的表达式规则使用内联运算符比使用重写规则更具可读性......

    我对 C# 不太流利,所以这里有一个 Java 演示:

    T.g

    grammar T; 
    
    options { 
      ASTLabelType=CommonTree;
      output=AST; 
    } 
    
    tokens {
      ROOT;
      UNARY_MIN;
    }
    
    @members {
    
      public static class RootNode extends CommonTree {
        public RootNode(Token t) { token=t; }
        public RootNode(int ttype) { super(new CommonToken(ttype, "ROOT")); }
        public RootNode(RootNode node) { super(node); }
        public Tree dupNode() { return new RootNode(this); } 
        public String toString() { return "RootNode=" + token.getText(); }
      }
    
      public static class MinusNode extends CommonTree {
        public MinusNode(Token t) { token=t; }
        public MinusNode(MinusNode node) { super(node); }
        public Tree dupNode() { return new MinusNode(this); } 
        public String toString() { return "MinusNode=" + token.getText(); }
      }
    
      public class PlusNode extends CommonTree {
        public PlusNode(Token t) { token=t; }
        public PlusNode(PlusNode node) { super(node); }
        public Tree dupNode() { return new PlusNode(this); } 
        public String toString() { return "PlusNode=" + token.getText(); }
      }
    }
    
    parse 
      :  exp EOF -> ^(ROOT<RootNode> exp)
      ; 
    
    exp 
      :  addExp 
      ; 
    
    addExp 
      :  (mulExp -> mulExp) ( '+' m=mulExp -> ^('+'<PlusNode>  $m $addExp)
                            | '-' m=mulExp -> ^('-'<MinusNode> $m $addExp)
                            )* 
      ; 
    
    mulExp 
      :  unaryExp (('*' | '/')^ unaryExp)* 
      ; 
    
    unaryExp 
      :  '-' atom -> ^(UNARY_MIN atom) 
      |  atom 
      ; 
    
    atom 
      :  Number 
      |  '(' exp ')' -> exp 
      ; 
    
    Number 
      :  ('0'..'9')+ ('.' ('0'..'9')+)? 
      ; 
    
    Space  
      :  (' ' | '\t' | '\r' | '\n') {skip();} 
      ; 
    

    Main.java

    import org.antlr.runtime.*;
    import org.antlr.runtime.tree.*;
    import org.antlr.stringtemplate.*;
    
    public class Main {
    
      private static void traverse(CommonTree tree, int indent) {
        if(tree == null) return;
        for(int i = 0; i < indent; i++) System.out.print("  ");
        System.out.println(tree.getClass().getName() + " -> " + tree.getText());
        for(int i = 0; i < tree.getChildCount(); i++) {
          traverse((CommonTree)tree.getChild(i), indent + 1);
        }
      }
    
      public static void main(String[] args) throws Exception {
        TLexer lexer = new TLexer(new ANTLRStringStream("1 + 2 - 3"));
        TParser parser = new TParser(new CommonTokenStream(lexer));
        CommonTree tree = (CommonTree)parser.parse().getTree();
        traverse(tree, 0);
      }
    }
    

    运行演示:

    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
    

    将打印:

    TParser$RootNode -> ROOT
      TParser$MinusNode -> -
        org.antlr.runtime.tree.CommonTree -> 3
        TParser$PlusNode -> +
          org.antlr.runtime.tree.CommonTree -> 2
          org.antlr.runtime.tree.CommonTree -> 1
    

    【讨论】:

    • 测试过了。我实际上只复制和修改了 c# 所需的东西(字母大小写和代码中的一些小东西)。它从一开始就编译,但是当我转储树时,所有节点都是 CommonTree 类型。不知道还能做什么......我想我会使用 TreeAdaptor 方法,即使我不是它的忠实粉丝!无论如何感谢您的努力!
    • @dcg,这很不幸:(。也许CSharp2 有效?(请注意,它与CSharp3 有不同的运行时类!)。我可能会亲自尝试CSharp3,虽然我在 Mono 和 Ubuntu 上运气不佳(CSharp2 确实在我的系统上工作......)。
    • 我知道。我必须使用 c# - 我正在处理的项目的先前版本是使用 antlr2/chsarp 制作的,并且可以正常工作。我们需要进行升级,并认为我可以遵循相同的模式。反正,走老路!
    猜你喜欢
    • 1970-01-01
    • 2014-05-28
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多