antlr4解决语法歧义

时间:2014-06-12 11:25:45

标签: antlr4

作为帮助我解释数字解释模糊性的Overlapping rules - mismatched input的后续工作,我现在遇到了下一个问题 - 数字也被允许作为标识符的一部分,不幸的是,即使在开始时标识符,所以......

这个语法说明了问题

grammar NOVIANum;

statement :  (priorityT | integerT | levelT )* ;

priorityT : T_PRIO twoDigits ;

integerT : T_INTEGER integer ;

levelT : T_LEVEL levelNumber  ;

levelNumber : ( ZERO (OneToFour | FiveToNine) | ( OneToFour (ZERO | (OneToFour | FiveToNine)) ) ) ;

integer: ZERO*  ( (OneToFour | FiveToNine) ( (OneToFour | FiveToNine) | ZERO )* ) ;

twoDigits : (ZERO | (OneToFour | FiveToNine)) ( ZERO | (OneToFour | FiveToNine) ) ;

WS : [ \t\r\n]+ -> skip ;

T_INTEGER : 'INTEGER' ;
T_LEVEL   : 'LEVEL' ;
T_PRIO    : 'PRIO' ;

ZERO : '0' ;

OneToFour  : [1-4] ;
FiveToNine : [5-9] ;

ID : Letter SeparatorAndLetter* ;

Letter : [a-zA-Z0-9];
SeparatorAndLetter : ([\-]* [_]* Letter+);

以下输入

INTEGER 350
PRIO 10
LEVEL 01

确实有足够的结果

line 1:8 mismatched input '350' expecting {'0', OneToFour, FiveToNine}
line 2:5 no viable alternative at input '10'
line 3:6 no viable alternative at input '01'
(statement (integerT INTEGER (integer 350)) (priorityT PRIO (twoDigits 10)) (levelT LEVEL (levelNumber 01)))

因为在解析" 350"。

时,I​​D将在整数之前启动

有什么方法吗?

谢谢 - 亚历克斯

1 个答案:

答案 0 :(得分:2)

使ID成为解析器规则而不是词法分析器规则。如果一个ID可以只是数字,那么词法分析器就不可能将它分开,并且因为你的整数词法分析规则只匹配1位数,所以词法分析器总是支持ID规则用于超过1位数的数字(词法分析器总是尝试匹配最长的输入序列。)

以下语法适用于您的示例输入:

grammar NOVIANum;

statement :  (priorityT | integerT | levelT | idT)* ;

priorityT : T_PRIO twoDigits ;
integerT  : T_INTEGER integer ;
levelT    : T_LEVEL levelNumber  ;
idT       : T_ID id ;

levelNumber : LVLNUMBER ;
integer     : LVLNUMBER | TWODIGITS | NONZERONR ;
twoDigits   : LVLNUMBER | TWODIGITS ;

number : LVLNUMBER | TWODIGITS | NONZERONR | ANYNUMBER ;
id     : number | STRING ;

WS : [ \t\r\n]+ -> skip ;

T_INTEGER : 'INTEGER' ;
T_LEVEL   : 'LEVEL' ;
T_PRIO    : 'PRIO' ;
T_ID      : 'ID' ;

LVLNUMBER : ZERO (OneToFour | FiveToNine) | OneToFour (ZERO | OneToFour | FiveToNine) ;
TWODIGITS : ZERO ZERO | FiveToNine (ZERO | OneToFour | FiveToNine) ;
NONZERONR : ZERO* (OneToFour | FiveToNine) (ZERO | OneToFour | FiveToNine)* ;
ANYNUMBER : (ZERO | OneToFour | FiveToNine)+ ;

STRING    : (LVLNUMBER | TWODIGITS | NONZERONR | ANYNUMBER | LETTER) (Minus* Underscore* (LVLNUMBER | TWODIGITS | NONZERONR | ANYNUMBER | LETTER)+)* ;

fragment LETTER     : [a-zA-Z];
fragment Minus      : '-' ;
fragment Underscore : '_' ;
fragment ZERO       : '0' ;
fragment OneToFour  : [1-4] ;
fragment FiveToNine : [5-9] ;

虽然这个语法正确地解析了您的示例输入,但如果您有许多不同的特殊数字,例如LVLNUMBERTWODIGITS,则会非常笨拙。我希望在解析后用监听器验证这些值(例如,levelNumber <50)。