2

次のようなサブツリーを持つantlrグラマーがあります。

 ^(type ID)

に変換したい:

 ^(type DUMMY ID)

type は 'a'|'b' です。

注: 私が本当にやりたいことは、ダミーの名前を生成して、匿名のインスタンス化を明示的に変換することです。

以下の文法に絞り込みましたが、次のようになります。

(a bar) (b bar)
got td
got bu
Exception in thread "main" org.antlr.runtime.tree.RewriteEmptyStreamException: rule type
        at org.antlr.runtime.tree.RewriteRuleElementStream._next(RewriteRuleElementStream.java:157)
        at org.antlr.runtime.tree.RewriteRuleSubtreeStream.nextNode(RewriteRuleSubtreeStream.java:77)
        at Pattern.bu(Pattern.java:382)

エラーメッセージは続きます。これまでの私のデバッグ:

  1. 入力は、2 つのツリーを生成する最初の文法を通過しました。a バーと b バー。
  2. 2 番目の文法はツリーに一致します。tdとbuを印刷しています。
  3. 書き換えがクラッシュしますが、理由がわかりませんか? RewriteEmptyStreamException とはどういう意味ですか?

この種の書き換えを行う適切な方法は何ですか?

私の主な文法 Rewrite.g:

grammar Rewrite;

options {
  output=AST;
}

@members{
  public static void main(String[] args) throws Exception {
      RewriteLexer lexer = new RewriteLexer(new ANTLRStringStream("a foo\nb bar"));
      RewriteParser parser = new RewriteParser(new CommonTokenStream(lexer));
      CommonTree tree = (CommonTree)parser.test().getTree();
      System.out.println(tree.toStringTree());

      CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);        
      Pattern p = new Pattern(nodes);

      CommonTree newtree = (CommonTree) p.downup(tree);
  }
}

type 
    : 'a'
    | 'b'
    ;

test : id+;
id   : type ID  -> ^(type ID["bar"]);

DUMMY : 'dummy';
ID   : ('a'..'z')+;
WS : (' '|'\n'|'r')+ {$channel=HIDDEN;};

そしてPattern.g

tree grammar Pattern;

options {
    tokenVocab = Rewrite;
    ASTLabelType=CommonTree;
    output=AST;
    filter=true;             // tree pattern matching mode
}

topdown
    : td
    ;

bottomup
    : bu
    ;

type 
    : 'a'
    | 'b'
    ;

td
    : ^(type ID) { System.out.println("got td"); }
    ;

bu
    : ^(type ID) { System.out.println("got bu"); }
        -> ^(type DUMMY ID)
    ;

コンパイルするには:

java -cp ../jar/antlr-3.4-complete-no-antlrv2.jar org.antlr.Tool Rewrite.g 
java -cp ../jar/antlr-3.4-complete-no-antlrv2.jar org.antlr.Tool Pattern.g 
javac -cp ../jar/antlr-3.4-complete-no-antlrv2.jar *.java 
java -classpath .:../jar/antlr-3.4-complete-no-antlrv2.jar RewriteParser

編集 1: antlr4 も使用してみましたが、同じクラッシュが発生します。

4

2 に答える 2

2

書き換えを機能させるには、2 つの小さな問題に対処する必要があります。1 つは の問題で、もう 1 つRewritePatternです。

Rewrite出力 に示すように、文法は^(type ID)出力 AST のルート要素として生成されます(a bar) (b bar)。変換は実際には子交換の形式であるため、ルート要素を変換することはできません。要素の親は要素を削除し、新しい「変換された」バージョンに置き換えます。親がないと、エラーが発生しますCan't set single child to a list。ルートを追加するには、架空のトークンROOTまたは好きな名前を作成し、エントリレベルのルールの AST 生成で次のように参照するだけですtest : id+ -> ^(ROOT id+);

Patternあなたが得ているエラーを生成する文法は、ルールによって混乱しています:type書き直しtype : 'a' | 'b' ;の一部として。ここでの低レベルの詳細はわかりませんが、どうやらツリー パーサーは、変換を記述するときのようtypeに、アクセスされたルート ルールの状態を維持しないようです^(type ID)(または、できないか、すべきではないか、またはいくつかのその他の制限)。これに対処する最も簡単な方法は、次の 2 つの変更を行うことです。

  • ルールをからjustに変更して、テキスト "a" と "b"IDをレクサーのルールに一致させます。typeRewritetype: 'a' | 'b';type: ID;
  • ルールbuを にPatternマッチさせ^(ID ID)、 に変換し^(ID DUMMY ID)ます。

Rewriteの へのいくつかのマイナーなデバッグ変更によりmain、 input"a foo\nb bar"は次の出力を生成します。

(ROOT (a foo) (b bar))
got td
got bu
(a foo) -> (a DUMMY foo)
got td
got bu
(b bar) -> (b DUMMY bar)
(ROOT (a DUMMY foo) (b DUMMY bar))

変更したファイルは次のとおりです。

Rewrite.g

grammar Rewrite;

options {
  output=AST;
}

tokens { 
 ROOT;
}

@members{
  public static void main(String[] args) throws Exception {
      RewriteLexer lexer = new RewriteLexer(new ANTLRStringStream("a foo\nb bar"));
      RewriteParser parser = new RewriteParser(new CommonTokenStream(lexer));
      CommonTree tree = (CommonTree)parser.test().getTree();
      System.out.println(tree.toStringTree());

      CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);        
      Pattern p = new Pattern(nodes);

      CommonTree newtree = (CommonTree) p.downup(tree, true); //print the transitions to help debugging
      System.out.println(newtree.toStringTree()); //print the final result
  }
}

type : ID;
test : id+ -> ^(ROOT id+);
id   : type ID  -> ^(type ID);

DUMMY : 'dummy';
ID   : ('a'..'z')+;
WS : (' '|'\n'|'r')+ {$channel=HIDDEN;};

パターン.g

tree grammar Pattern;

options {
    tokenVocab = Rewrite;
    ASTLabelType=CommonTree;
    output=AST;
    filter=true;             // tree pattern matching mode
}

topdown
    : td
    ;

bottomup
    : bu
    ;

td
    : ^(ID ID) { System.out.println("got td"); }
    ;

bu
    : ^(ID ID) { System.out.println("got bu"); }
        -> ^(ID DUMMY ID)
    ;
于 2012-12-03T21:48:38.863 に答える
1

書き換えの有無にかかわらず、ツリーパターンの経験はあまりありません。しかし、それらで書き換えルールを使用する場合、オプションには も含める必要があると思いますrewrite=true;。The Definitive ANTLR Reference はそれらを処理していないため、完全にはわかりません (詳細については、ANTLR wikiを参照してください)。

ただし、このような (比較的) 単純な書き直しの場合、別個の文法は実際には必要ありません。DUMMY次のように、架空のトークンを作成して、他のパーサー ルールに挿入することができます。

grammar T;

options {
  output=AST;
}

tokens {
  DUMMY;
}

test : id+;
id   : type ID  -> ^(type DUMMY["dummy"] ID);

type 
 : 'a'
 | 'b'
 ;

ID : ('a'..'z')+;
WS : (' '|'\n'|'r')+ {$channel=HIDDEN;};

入力を解析します:

a bar 
b foo

次の AST に変換します。

ここに画像の説明を入力

レクサーが入力をトークン"dummy"としてトークン化することも意図している場合は、ブロックを次のようDUMMYに変更することに注意してください。tokens { ... }

tokens {
  DUMMY='dummy';
}

他のルールにaを挿入することもできます。DUMMY

于 2012-12-03T20:27:22.150 に答える