2011-02-04 16 views
5

は、まず私はこの文法は意味がありません知っているが、私は、\ nSecondトークンここで、この文法に最初のトークンここに入力」を与えると、それはANTLRルール優先行動ANTLRルールの優先順位

grammar test; 

options 
{ 

output=AST; 
backtrack=true; 
memoize=true; 

} 

rule_list_in_order : 
    (
    first_rule 
    | second_rule 
    | any_left_over_tokens)+ 
    ; 


first_rule 
    : 
    FIRST_TOKEN 
    ; 


second_rule:  
    FIRST_TOKEN NEW_LINE SECOND_TOKEN NEW_LINE; 


any_left_over_tokens 
    : 
    NEW_LINE 
    | FIRST_TOKEN 
    | SECOND_TOKEN; 



FIRST_TOKEN 
    : 'First token here' 
    ; 

SECOND_TOKEN 
    : 'Second token here'; 

NEW_LINE 
    : ('\r'?'\n') ; 

WS : (' '|'\t'|'\u000C') 
    {$channel=HIDDEN;} 
    ; 

をテストするために作成されました'、それはsecond_ruleにマッチします。

最初のルールがany_left_over_tokensの最初のルールと一致することが期待されます。これは、開始ポイントであるrule_order_listのsecond_ruleの前にfirst_ruleが表示されるためです。なぜこれが起こるのか誰も説明できますか?

乾杯

答えて

12

まず、ANTLRのレクサーは、上から下への入力をトークン化します。したがって、最初に定義されたトークンは、それよりも優先順位が高くなります。ルールに重複トークンがある場合は、ほとんどの文字に一致するルールが優先されます(貪欲な一致)。

パーサーの規則にも同じ原則があります。最初に定義されたルールも最初に一致します。たとえば、ルールfooで、サブルールaは最初bの前に試されます:

foo 
    : a 
    | b 
    ; 

注あなたのケースでは、2 NDルールがマッチした、しかし、そうしようとし、失敗していないこと末尾に改行がないため、エラーが発生します。

line 0:-1 mismatched input '<EOF>' expecting NEW_LINE 

これはまったく一致しません。しかし、は、が奇数です。

  1. first_rule( "ここで最初のトークン")
  2. any_left_over_tokens( "改行")
  3. any_left_over_tokens:あなたはbacktrack=trueを設定しているので、それは、少なくともバックトラックと一致している必要があります最初の場所でfirst_ruleと一致しない場合(「ここでは第二のトークン」)

また、最初にsecond_ruleに一致するようにしてください。

述語を手動で行うときの簡単なデモ(のオプション{backtrackを無効にする...

クラスでテストすることができ
grammar T; 

options { 
    output=AST; 
    //backtrack=true; 
    memoize=true; 
} 

rule_list_in_order 
    : ((first_rule)=> first_rule {System.out.println("first_rule=[" + $first_rule.text + "]");} 
    | (second_rule)=> second_rule {System.out.println("second_rule=[" + $second_rule.text + "]");} 
    | any_left_over_tokens  {System.out.println("any_left_over_tokens=[" + $any_left_over_tokens.text + "]");} 
    )+ 
    ; 

first_rule 
    : FIRST_TOKEN 
    ; 

second_rule 
    : FIRST_TOKEN NEW_LINE SECOND_TOKEN NEW_LINE 
    ; 

any_left_over_tokens 
    : NEW_LINE 
    | FIRST_TOKEN 
    | SECOND_TOKEN 
    ; 

FIRST_TOKEN : 'First token here'; 
SECOND_TOKEN : 'Second token here'; 
NEW_LINE  : ('\r'?'\n'); 
WS   : (' '|'\t'|'\u000C') {$channel=HIDDEN;}; 

期待出力生成
import org.antlr.runtime.*; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     String source = "First token here\nSecond token here"; 
     ANTLRStringStream in = new ANTLRStringStream(source); 
     TLexer lexer = new TLexer(in); 
     CommonTokenStream tokens = new CommonTokenStream(lexer); 
     TParser parser = new TParser(tokens); 
     parser.rule_list_in_order(); 
    } 
} 

:それは問題ではないことを

first_rule=[First token here] 
any_left_over_tokens=[ 
] 
any_left_over_tokens=[Second token here] 

注}部)は次のようになりますあなたが使用する場合:

rule_list_in_order 
    : ((first_rule)=> first_rule 
    | (second_rule)=> second_rule 
    | any_left_over_tokens 
    )+ 
    ; 

または

rule_list_in_order 
    : ((second_rule)=> second_rule // <--+--- swapped 
    | (first_rule)=> first_rule // <-/ 
    | any_left_over_tokens 
    )+ 
    ; 

のいずれも、期待される出力を生成します。

私の推測では、あなたがバグを見つけた可能性があります。

あなたは決定的な回答が必要な場合に備えて、YoutはANTLRメーリングリストを試すことができます(ここでは頻繁にTerence Parrが頻繁に訪れます)。

幸運を祈る!

PS。私はANTLR v3.2でこれをテストしました

+0

ありがとうBart - いつものように洞察力があります。参考のために、入力は「ここでは最初のトークン\ n 2番目のトークン\ n」となっていました。第2の\ nの不在はタイプオです。メーリングリストも試してみます。 –

+1

@リチャード、ああ、私は(改行について)見る。はい、2番目のルール*が一致します。メモリがうまく機能している場合は、backtrack-optionを有効にして、パーサーができるだけ一致するようにしたので、1番目のサブルールに一致してから2番目のサブルールにバックトラッキングし、それにぴったり合っているので、それに固執しています(しかし、私はそれについて100%確信していません。あなたがメーリングリストに投稿しているなら、それも尋ねてください!:))。あなたはもちろん歓迎です! –