为什么会出现'no viable alternative at input'?

Why occurs 'no viable alternative at input'?

我写了如下组合语法:

grammar KeywordGrammar;

options{
TokenLabelType = MyToken;
}

//start rule
start: sequence+ EOF;

sequence: keyword filter?;

filter: simpleFilter | logicalFilter | rangeFilter;

logicalFilter: andFilter | orFilter | notFilter;

simpleFilter: lessFilter | greatFilter | equalFilter | containsFilter;

andFilter: simpleFilter AND? simpleFilter;

orFilter: simpleFilter OR simpleFilter;

lessFilter: LESS (DIGIT | FLOAT|DATE);

notFilter: NOT IN? (STRING|ID);

greatFilter: GREATER (DIGIT|FLOAT|DATE);

equalFilter: EQUAL (DIGIT|FLOAT|DATE);

containsFilter: EQUAL (STRING|ID);

rangeFilter:  RANGE? DATE DATE? | RANGE? FLOAT FLOAT?; 

keyword: ID | STRING;

DATE: DIGIT DIGIT? SEPARATOR MONTH SEPARATOR DIGIT DIGIT (DIGIT DIGIT)?;

MONTH: JAN
     | FEV 
     | MAR
     | APR
     | MAY
     | JUN
     | JUL
     | AUG
     | SEP
     | OCT
     | NOV
     | DEC
     ;

JAN : 'janeiro'|'jan'|'01'|'1';
FEV : 'fevereiro'|'fev'|'02'|'2';
MAR : 'março'|'mar'|'03'|'3';
APR : 'abril' |'abril'|'04'|'4';
MAY : 'maio'| 'mai'| '05'|'5';
JUN : 'junho'|'jun'|'06'|'6';
JUL : 'julho'|'jul'|'07'|'7';
AUG : 'agosto'|'ago'|'08'|'8';
SEP : 'setembro'|'set'|'09'|'9';
OCT : 'outubro'|'out'|'10';
NOV : 'novembro'|'nov'|'11';
DEC : 'dezembro'|'dez'|'12';

SEPARATOR: '/'|'-';

AND: ('e'|'E');

OR: ('O'|'o')('U'|'u');

NOT: ('N'|'n')('Ã'|'ã')('O'|'o');

IN: ('E'|'e')('M'|'m');

GREATER: '>' | ('m'|'M')('a'|'A')('i'|'I')('o'|'O')('r'|'R') ;

LESS: '<' | ('m'|'M')('e'|'E')('n'|'N')('o'|'O')('r'|'R');

EQUAL: '=' | ('i'|'I')('g'|'G')('u'|'U')('a'|'A')('l'|'L');

RANGE: ('e'|'E')('n'|'N')('t'|'T')('r'|'R')('e'|'E');

FLOAT: DIGIT+ | DIGIT+ POINT DIGIT+;

ID: (LETTER|DIGIT+ SYMBOL) (LETTER|SYMBOL|DIGIT)*;

STRING: '"' ( ESC_SEQ | ~('\'|'"') )* '"';

DIGIT: [0-9];

WS: (' '
  |  '\t'
  |  '\r'
  |  '\n') -> skip
  ;

POINT: '.' | ',';

fragment 
LETTER: 'A'..'Z'
      | 'a'..'z'
      | '\u00C0'..'\u00D6'
      | '\u00D8'..'\u00F6'
      | '\u00F8'..'\u02FF'
      | '\u0370'..'\u037D'
      | '\u037F'..'\u1FFF'
      | '\u200C'..'\u200D'
      | '\u2070'..'\u218F'
      | '\u2C00'..'\u2FEF'
      | '\u3001'..'\uD7FF'
      | '\uF900'..'\uFDCF'
      | '\uFDF0'..'\uFFFD'
      ;

fragment 
SYMBOL: '-' | '_';

fragment
HEX_DIGIT: ('0'..'9'|'a'..'f'|'A'..'F');

fragment
ESC_SEQ: '\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\')
       | UNICODE_ESC
       | OCTAL_ESC
       ;

fragment
OCTAL_ESC: '\' ('0'..'3') ('0'..'7') ('0'..'7')
         | '\' ('0'..'7') ('0'..'7')
         | '\' ('0'..'7')
         ;

fragment
UNICODE_ESC: '\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;

但是 输入时没有可行的选择 错误仅在尝试解析以下类型的句子时发生:关键字 OPERATOR DIGIT;例如:

零作为一个值,有效!!!

哪里出错了?

感谢您的帮助,

耶尼尔

在这里进行测试,我发现将 FLOAT 定义标记放在 DATE 定义之前问题就消失了。

...
FLOAT: DIGIT+ (POINT DIGIT+)?;

DATE: DIGIT DIGIT? SEPARATOR MONTH SEPARATOR DIGIT DIGIT (DIGIT DIGIT)?;
...

不知道为什么。顺序重要吗?

你的词法分析器规则有很多歧义。在你的情况下,具体搞砸的是数字 1-9 可以与 DIGITMONTHJAN 等匹配。数字 0 不受此影响问题。使用 grun-tokens 来诊断您遇到的这类问题:

$ grun KeywordGrammar start -tokens
filter = 0
[@0,0:5='filter',<24>,1:0]
[@1,7:7='=',<21>,1:7]
[@2,9:9='0',<23>,1:9]
[@3,11:10='<EOF>',<-1>,2:0]

$ grun KeywordGrammar start -tokens
filter = 2
[@0,0:5='filter',<24>,1:0]
[@1,7:7='=',<21>,1:7]
[@2,9:9='2',<1>,1:9]
[@3,11:10='<EOF>',<-1>,2:0]
line 1:9 no viable alternative at input '=2'

如您所见,0 在第一种情况下是令牌类型 <23>,在第二种情况下 2 是令牌类型 <1>。看看你生成的KeywordGrammar.tokens:

MONTH=1
JAN=2
...
FLOAT=23
...

所以它不是 DIGITFLOAT - 它是 MONTH。因此,您的 filter 规则不匹配。是的,规则的顺序很重要,因为在出​​现歧义的情况下,ANTLR 会选择第一条规则。

消除词法分析器的歧义。将月份和类似的标记放入语法规则中。你还有很多其他地方,比如你的 FLOAT 使得 DIGIT 不可能独立出现,你仍然在规则中引用 DIGITFLOAT。如果 DIGIT 在语法级别没有意义,请将其作为片段并在解析器规则中仅使用 FLOAT

并养成使用 grun and/or ANTLR 插件的习惯 IDE 以确保您了解词法分析器和解析器实际看到的内容。