2012-04-13 50 views
5

我有一個antlr詞法分析規則的一個奇怪的副作用,我創建了一個(幾乎)最小的工作示例來演示它。 在這個例子中,我想匹配字符串[0..1]例如。但是當我調試語法時,到達解析器的令牌流只包含[..1]。第一個整數,無論​​它包含多少個數字總是被消耗,我不知道如何發生。如果我刪除FLOAT規則,一切都很好,所以我猜這個錯誤在某個地方。但由於它不應該匹配[0..1]中的任何內容,所以我很困惑。即使不匹配,ANTLR詞法分析器規則也會消耗字符嗎?

我很樂意爲任何可能出錯的指針。這是我的例子:

grammar min; 
options{ 
language = Java; 
output = AST; 
ASTLabelType=CommonTree; 
backtrack = true; 
} 
tokens { 
    DECLARATION; 
} 

declaration : LBRACEVAR a=INTEGER DDOTS b=INTEGER RBRACEVAR -> ^(DECLARATION $a $b); 

EXP : 'e' | 'E'; 
LBRACEVAR: '['; 
RBRACEVAR: ']'; 
DOT: '.'; 
DDOTS: '..'; 

FLOAT 
    : INTEGER DOT POS_INTEGER 
    | INTEGER DOT POS_INTEGER EXP INTEGER 
    | INTEGER EXP INTEGER 
    ; 

INTEGER : POS_INTEGER | NEG_INTEGER; 
fragment NEG_INTEGER : ('-') POS_INTEGER; 
fragment POS_INTEGER : NUMBER+; 
fragment NUMBER: ('0'..'9'); 

回答

6

'0'詞法分析器丟棄,下面的錯誤產生:

line 1:3 no viable alternative at character '.' 
line 1:2 extraneous input '..' expecting INTEGER 

這是因爲當詞法分析器遇到'0.',它試圖創建一個FLOAT令牌,但不能。並且由於沒有其他規則可以回溯到匹配'0.',它會產生錯誤,丟棄'0'並創建一個令牌DOT

這就是ANTLR的詞法分析器的工作原理:它不會回溯匹配INTEGER後跟DDOTS(注意backtrack=true僅適用於解析器規則!)。

FLOAT規則的內部,您必須確保當前面的雙精度值爲'.'時,您會生成一個INTEGER令牌。只有當單個'.'後跟一個數字(('.' DIGIT)=>部分)時,纔可以通過添加句法謂詞(('..')=>部分)並生成FLOAT令牌。看到下面的演示:

declaration 
: LBRACEVAR INTEGER DDOTS INTEGER RBRACEVAR 
; 

LBRACEVAR : '['; 
RBRACEVAR : ']'; 
DOT  : '.'; 
DDOTS  : '..'; 

INTEGER 
: DIGIT+ 
; 

FLOAT 
: DIGIT+ (('.' DIGIT)=> '.' DIGIT+ EXP? 
      | ('..')=>  {$type=INTEGER;} // change the token here 
      |    EXP 
     ) 
; 

fragment EXP : ('e' | 'E') DIGIT+; 
fragment DIGIT : ('0'..'9'); 
+0

現在,這是一個(至少對我而言)意想不到的行爲。感謝這個全面的例子,我已經完成了並且正在運行:-) – Lichtblitz 2012-04-13 07:45:35

+0

@Lichtblitz,不客氣,是的,標記'..'(與INT-和FLOAT-令牌結合使用)很棘手! :) – 2012-04-13 08:54:33

相關問題