1

次のことも可能ですか?antlrに与えられた入力を「逆」にして、各トークンを前のトークンの子にします。

したがって、入力の場合(各トークンは「。」文字で区切られていると想定します):

Stack.Overflow.Horse

文法で次のASTを生成したいと思います。

Horse
  |---Overflow
         |---Stack

これまでのところ、ノードを逆にすることができましたが、ノードを互いに子にすることはできません。

function
 : ID PERIOD function
   -> function ID
 | ID
 ;

ID  : 'a'..'z'*
    ;
4

1 に答える 1

3

それを行う簡単な方法はないと思います。次のようにルールを作成できます。

function
 : ID PERIOD function
   -> ^(function ID)
 | ID
 ;

ただし、それは最後のノードをルートにし、他のすべてのノードをその子にするだけです。たとえば、次のソース:

a.b.c.d.e

次のツリーになります。

    e
 / / \ \
d c   b a

最初に を解析するときはとの再帰呼び出しにa.b.c.d.eなるaため、簡単な修正方法はわかりません。IDb.c.d.efunction

a.b.c.d.e
| +-----+
|    |
|    `-----> function
|
`----------> ID

その結果、それはその子としてb.c.d.e持つことになります。athen にbなるとID、こちらも子として の隣に追加されaます。あなたの場合、aを子として削除してから、 の子のリストに追加する必要がありますb。しかし、私の知る限り、それはANLTRでは不可能です(少なくとも、文法内できれいな方法ではありません)。


編集

さて、回避策としてエレガントなものを考えていましたが、期待どおりには機能しませんでした。lastしたがって、洗練されていない解決策として、ノードを書き換えルールのルートとして一致させることができます。

function
  :  (id '.')* last=id -> ^($last)
  ;

次に、演算子を使用して、すべての可能な先行ノード ( children) を収集します。List+=

function
  :  (children+=id '.')* last=id -> ^($last)
  ;

パーサーでカスタム メンバー メソッドを使用して、これらchildrenをツリーのルートに「注入」します (! で右から左に移動しますList)。

function
  :  (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -> ^($last)
  ;

ちょっとしたデモ:

grammar ReverseTree;

options {
  output=AST;
}

tokens {
  ROOT;
}

@members {
  private void reverse(List nodes, CommonTree root) {
    if(nodes == null) return;
    for(int i = nodes.size()-1; i >= 0; i--) {
      CommonTree temp = (CommonTree)nodes.get(i);
      root.addChild(temp);
      root = temp;
    }
  }
}

parse
  :  function+ EOF -> ^(ROOT function+)
  ;

function
  :  (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -> ^($last)
  ;

id 
  :  ID
  ;

ID
  :  ('a'..'z' | 'A'..'Z')+
  ;

Space
  :  ' ' {skip();}
  ;

そして、ちょっとしたテストクラス:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("a.b.c.d.e    Stack.Overflow.Horse    singleNode");
        ReverseTreeLexer lexer = new ReverseTreeLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ReverseTreeParser parser = new ReverseTreeParser(tokens);
        ReverseTreeParser.parse_return returnValue = parser.parse();
        CommonTree tree = (CommonTree)returnValue.getTree();
        DOTTreeGenerator gen = new DOTTreeGenerator();
        StringTemplate st = gen.toDOT(tree);
        System.out.println(st);
    }
}

次のような AST が生成されます。

代替テキスト

入力文字列の場合:

"a.b.c.d.e    Stack.Overflow.Horse    singleNode"
于 2010-09-27T15:40:00.213 に答える