5

我有一个 antlr 词法分析器规则的奇怪副作用,我创建了一个(几乎)最小的工作示例来演示它。例如,在这个例子中,我想匹配字符串[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');
4

1 回答 1

6

'0'词法分析器丢弃,并产生以下错误:

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

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

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

FLOAT规则中,您必须确保当双倍'.'领先时,您会产生一个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');
于 2012-04-13T07:18:08.600 回答