为什么会出现'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;例如:
- 过滤器 = 2
- 过滤器 < 2
- 过滤器 > 2
零作为一个值,有效!!!
哪里出错了?
感谢您的帮助,
耶尼尔
在这里进行测试,我发现将 FLOAT 定义标记放在 DATE 定义之前问题就消失了。
...
FLOAT: DIGIT+ (POINT DIGIT+)?;
DATE: DIGIT DIGIT? SEPARATOR MONTH SEPARATOR DIGIT DIGIT (DIGIT DIGIT)?;
...
不知道为什么。顺序重要吗?
你的词法分析器规则有很多歧义。在你的情况下,具体搞砸的是数字 1-9
可以与 DIGIT
和 MONTH
、JAN
等匹配。数字 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
...
所以它不是 DIGIT
或 FLOAT
- 它是 MONTH
。因此,您的 filter
规则不匹配。是的,规则的顺序很重要,因为在出现歧义的情况下,ANTLR 会选择第一条规则。
消除词法分析器的歧义。将月份和类似的标记放入语法规则中。你还有很多其他地方,比如你的 FLOAT
使得 DIGIT
不可能独立出现,你仍然在规则中引用 DIGIT
和 FLOAT
。如果 DIGIT
在语法级别没有意义,请将其作为片段并在解析器规则中仅使用 FLOAT
。
并养成使用 grun
and/or ANTLR 插件的习惯 IDE 以确保您了解词法分析器和解析器实际看到的内容。
我写了如下组合语法:
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;例如:
- 过滤器 = 2
- 过滤器 < 2
- 过滤器 > 2
零作为一个值,有效!!!
哪里出错了?
感谢您的帮助,
耶尼尔
在这里进行测试,我发现将 FLOAT 定义标记放在 DATE 定义之前问题就消失了。
...
FLOAT: DIGIT+ (POINT DIGIT+)?;
DATE: DIGIT DIGIT? SEPARATOR MONTH SEPARATOR DIGIT DIGIT (DIGIT DIGIT)?;
...
不知道为什么。顺序重要吗?
你的词法分析器规则有很多歧义。在你的情况下,具体搞砸的是数字 1-9
可以与 DIGIT
和 MONTH
、JAN
等匹配。数字 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
...
所以它不是 DIGIT
或 FLOAT
- 它是 MONTH
。因此,您的 filter
规则不匹配。是的,规则的顺序很重要,因为在出现歧义的情况下,ANTLR 会选择第一条规则。
消除词法分析器的歧义。将月份和类似的标记放入语法规则中。你还有很多其他地方,比如你的 FLOAT
使得 DIGIT
不可能独立出现,你仍然在规则中引用 DIGIT
和 FLOAT
。如果 DIGIT
在语法级别没有意义,请将其作为片段并在解析器规则中仅使用 FLOAT
。
并养成使用 grun
and/or ANTLR 插件的习惯 IDE 以确保您了解词法分析器和解析器实际看到的内容。