antlr4解决语法歧义

antlr4解决语法歧义,antlr4,Antlr4,作为帮助我解决解释数字时的歧义的后续行动,我现在进入下一期——数字也被允许作为标识符的一部分,不幸的是,甚至在标识符的开头,所以 这个语法说明了这个问题 grammar NOVIANum; statement : (priorityT | integerT | levelT )* ; priorityT : T_PRIO twoDigits ; integerT : T_INTEGER integer ; levelT : T_LEVEL levelNumber ; levelNu

作为帮助我解决解释数字时的歧义的后续行动,我现在进入下一期——数字也被允许作为标识符的一部分,不幸的是,甚至在标识符的开头,所以

这个语法说明了这个问题

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”时,as ID将在整数之前输入

有办法吗


谢谢-Alex将
ID
作为解析器规则而不是词法规则。如果一个ID只能是数字,那么lexer就不可能将其分开,因为您的整数lexer规则只匹配1位数字,所以对于超过1位的数字,lexer总是倾向于使用
ID
规则(lexer总是尝试匹配可能最长的输入序列)

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

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] ;

尽管该语法正确地解析了示例输入,但如果您有许多不同的特殊数字,如
LVLNUMBER
twodights
,则该语法相当笨拙。我更愿意在解析后使用侦听器验证这些值(例如levelNumber<50)。

在本例中,
Number
lexer规则永远不会匹配。它需要是一个解析器规则
number
。多亏了你们两位,现在所有位都在解析器级别,这就导致了另一个问题,即使用“id”作为
T_id:'id'
idT:T\u ID输入
ID1Z
IDMyLevel
会导致
行9:0在输入“”处没有可行的替代方案
(语句(integerT INTEGER(INTEGER 35 0))(priorityT PRIO(两位数10))(levelT LEVEL(levelnumber 01))(idT ID(ID(number 1)(separatorAndLetter Z))(idT ID(ID M(separatorAndLetter y))(levelT levelnumber))
即,作为Lexer令牌的所有内容现在都将被标识为Lexer令牌,即使它是id的一部分(现在是解析器规则)因此->没有可行的替代方案再次感谢,@ibizarudi,但恐怕还没有雪茄。LEVELX的id可以正常工作,但是
LEVEL-X
会导致
第10:3行在输入“级别”上没有可行的替代方案
第10:8行不匹配的输入“-”期望LvlNumber
(idT id id)(levelT-LEVEL(levelNumber-X)))
再次更新
STRING
现在应该匹配任何有效的标识符,而不仅仅是数字,因为它们由上面的四条lexer规则匹配。如果某个标识符恰好与
字符串
不匹配,则应编辑此elxer规则以匹配它以使其正常工作。