ANTLR3 Гетеро узлы не создаются - PullRequest
4 голосов
/ 05 октября 2011

Я пытаюсь создать гетерогенное дерево на основе приведенного ниже примера: 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) { }
  }
}

Классы PlusNode и MinusNode идентичны RootNode, поэтому я не буду публиковать их здесь.

А вот как я создаю фактическиеtree:

    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 и все точки останова, которые я поместил в PlusNode, MinusNode, RootNode конструкторы отсутствуют.

У меня есть пример, представленный на вики-странице ANTLR3, и я не смог найти образец в Интернете.Я знаю, что они собираются отказаться от этого подхода в какой-то момент (об этом я узнал в предварительных заметках ANTLR3), но эта реализация мне подходит больше (мне нужно создавать разные типы объектов на основе грамматического контекста).

Итак ... любойнамеки?Я что-то пропустил?Какой-нибудь параметр / флаг для помещения его в файл определения грамматики?

Спасибо!D.

Ответы [ 2 ]

2 голосов
/ 23 июля 2012

Я только что получил ответ, который работает от основного участника цели CSharp3 . По сути, при указании типа узла вы должны явно использовать node=; Вы не можете полагаться на неявное поведение, описанное в документации. Например, вам нужно изменить это:

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

... к этому:

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

В моей собственной грамматике, как только я внес это изменение в мои правила перезаписи, синтаксический анализатор, наконец, вывел гетерогенные узлы.

1 голос
/ 05 октября 2011

Мне никогда не удавалось заставить эти операторы < ... > работать при использовании операторов встроенного дерева (^ для корней и ! для пропущенных правил). Все, что я могу порекомендовать, это использовать правила перезаписи (... -> ^(...)) справа от ваших правил синтаксического анализатора, а затем определять только пользовательский узел, <NodeName>, в правиле перезаписи , а не с обеих сторон ( !) как упоминалось в вики: я подозреваю, что информация в вики немного устарела. Я знаю, что такие правила выражений гораздо более читабельны с помощью встроенных операторов, чем с правилами перезаписи ...

Я не слишком бегло говорю на 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
...