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

Lic*_*itz 5 antlr antlrworks antlr3

我有一个antlr lexer规则的奇怪副作用,我创建了一个(几乎)最小的工作示例来演示它.在这个例子中,我想匹配String [0..1]例如.但是当我调试语法时,到达解析器的令牌流只包含[..1].第一个整数,无论​​它包含多少位数总是被消耗掉,我不知道它是如何发生的.如果我删除FLOAT规则一切都很好,所以我猜错误在于该规则的某个地方.但由于它根本不应该与任何东西相匹配[0..1],所以我很困惑.

我会为我可能出错的任何指针感到高兴.这是我的例子:

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');
Run Code Online (Sandbox Code Playgroud)

Bar*_*ers 6

'0'是由词法分析器丢弃和下面的错误产生:

line 1:3 no viable alternative at character '.'
line 1:2 extraneous input '..' expecting INTEGER
Run Code Online (Sandbox Code Playgroud)

这是因为当词法分析器遇到时'0.',它会尝试创建一个FLOAT令牌,但不能.由于没有其他规则可以依赖匹配'0.',因此会产生错误,丢弃'0'并创建DOT令牌.

这就是ANTLR的词法分析器的工作原理:它不会回溯以匹配INTEGER后跟a DDOTS(注意backtrack=true只适用于解析器规则!).

FLOAT规则内部,您必须确保当前面有一个double时'.',您会生成一个INTEGER令牌.您可以通过添加语法谓词(('..')=>部分)来完成此操作,并FLOAT仅在单个'.'数字后跟一个数字(('.' DIGIT)=>部分)时生成标记.请参阅以下演示:

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');
Run Code Online (Sandbox Code Playgroud)