即使不匹配,ANTLR词法分析器规则也会消耗字符吗?

问题描述:

我有一个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'); 

'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