2012-01-01 18 views
3

私は、テンプレート言語を解析するantlr文法を構築しようとしています。その言語は任意のテキストに埋め込むことができ、境界は開閉タグ({{/}})でマークされます。antlr3文法でのレクサー状態の切り替え

foo {{ someVariable }} bar 

foobarが無視されるべきである、と{{}}タグ内部の一部を解析する必要がある場合は:だから有効なテンプレートは次のようになります。私は、{}というタグを除いて、基本的に問題の答えがあるthis questionを見つけました。私は2つの開閉文字にマッチするように文法を修正しようとしましたが、すぐにこれを行うと、BUFFERルールはすべての文字、開閉括弧も消費します。 LDルールが呼び出されることはありません。

区切り文字に2文字が含まれていて、文字が1文字しかないときに区切り文字を消費しない場合、antlrレクサーがBufferルールですべてのトークンを消費している理由は誰にもありますか?

grammar Test; 

    options { 
     output=AST; 
     ASTLabelType=CommonTree; 
    } 

    @lexer::members { 
     private boolean insideTag = false; 
    } 

    start 
     : (tag | BUFFER)* 
     ; 

    tag 
     : LD IDENT^ RD 
     ; 

    LD @after { 
     // flip lexer the state 
     insideTag=true; 
     System.err.println("FLIPPING TAG"); 
    } : '{{'; 

    RD @after { 
     // flip the state back 
     insideTag=false; 
    } : '}}'; 

    SPACE : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;}; 
    IDENT : (LETTER)*; 
    BUFFER : { !insideTag }?=> ~(LD | RD)+; 

    fragment LETTER : ('a'..'z' | 'A'..'Z'); 
+0

「IDENT :(LETTER)*;」(おそらく)レクサーが無限ループになることに注意してください。レクサールール_must_は常に少なくとも1文字と一致します。 –

答えて

2

あなたは(デモでBUFFERルールを参照)カッコ(...)+内部述語を含むことにより、先に{{を見るまでは、1回以上の任意の文字を一致させることができます。

デモ:それはあなたの文法の最初の字句解析ルールとしてBUFFERルールおくのがベストだと

grammar Test; 

options { 
    output=AST; 
    ASTLabelType=CommonTree; 
} 

@lexer::members { 
    private boolean insideTag = false; 
} 

start 
    : tag EOF 
    ; 

tag 
    : LD IDENT^ RD 
    ; 

LD 
@after {insideTag=true;} 
: '{{' 
; 

RD 
@after {insideTag=false;} 
: '}}' 
; 

BUFFER 
: ({!insideTag && !(input.LA(1)=='{' && input.LA(2)=='{')}?=> .)+ {$channel=HIDDEN;} 
; 

SPACE 
: (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;} 
; 

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

注:その方法は、それが試される最初のトークンとなります。

あなたが今"foo {{ someVariable }} bar"を解析する場合は、以下のASTが作成されます。

enter image description here

+0

あなたのexplantationのために多くのありがとう。それは今完璧に動作します。 – pulse00

+0

@RobertGruendlerようこそ。 –

0

は、このような文法がニーズに合わないでしょうか?なぜ私はBUFFERを複雑にする必要があるのか​​わかりません。

grammar test; 

options { 
    output=AST; 
    ASTLabelType=CommonTree; 
} 

@lexer::members { 
    private boolean inTag=false; 
} 

start 
    : tag* EOF 
    ; 

tag 
    : LD IDENT RD -> IDENT 
    ; 

LD 
@after { inTag=true; } 
: '{{' 
; 

RD 
@after { inTag=false; } 
: '}}' 
; 

IDENT : {inTag}?=> ('a'..'z'|'A'..'Z'|'_') 'a'..'z'|'A'..'Z'|'0'..'9'|'_')* 
    ; 

BUFFER 
: . {$channel=HIDDEN;} 
; 
関連する問題