【问题】
别人写的一个antlr v4的语法:
grammar Test; A: 'a' | 'b'; r1: A; r2: 'a' 'c';
然后在Mac下去测试,结果出错:
dongli:learn dongli$ antlr4 Test.g4 && javac *.java a line 1:0 mismatched input ‘a’ expecting A (r1 a) |
【解决过程】
1.别人的环境中,是mac的os,然后参考:
https://github.com/antlr/antlr4
已经确保:
的确是正常的,Ctrl+D,即,输入的测试内容的确是a,没有任何输入测试内容方面的错误。
2.然后又确保了,其编译的方式,是没问题的。
即,一起执行:
antlr4 Test.g4 && javac *.java |
和分2次执行:
antlr4 Test.g4 |
是一样的。
3.又去确认了:
javac *.java |
和官网中对应的:
javac Test*.java |
是一样的:
4.然后其又去问问别人:
Dear all, I encounter a token confliction problem. Here is a simplified case: grammar Test; r1: A; A: ‘a’ | ‘b’; When I run ‘grun Test r1 -tree’ with input ‘a’, an error came out: line 1:0 mismatched input ‘a’ expecting A So I checked ‘Test.tokens’: A=3 T__0=2 ‘c’=2 ‘a’=1 There is ‘a’=1 token, which conflicts with ‘a’ in A. So I changed the grammar to: grammar Test; r1: A; AA: ‘a’; the error is the same, and ‘Test.token’ is: AA=2 T__0=1 ‘c’=1 ‘a’=2 Why there is ‘a’=2, since AA contains it. |
5.不过,无论如何,此处的最终输出结果:
(r1 a) |
其实已经是我们所期望的结果了。
只是,想要搞懂,为何出错:
line 1:0 mismatched input ‘a’ expecting A |
6.猜测是否有可能是回车换行引起的,所以最后加上一行支持WS的:
grammar Test; r1: A; r2: 'a' 'c'; A: 'a' | 'b'; WS : [ \t\n]+ -> skip ; // skip spaces, tabs, newlines
结果是可以接受a之后再输入回车,但是错误依旧。
7.其完整的,相关的代码,在:
https://github.com/dongli/FortranParser
8.然后,又去测试一下,针对于r2看看结果如何:
dongli:learn dongli$ grun Test r2 -tree (r2 a c) dongli:learn dongli$ grun Test r2 -tree bc line 1:0 mismatched input ‘b’ expecting ‘a’ (r2 b c) |
很明显,是和希望的结果,一致的。
但是还是不知道为何r1出错。
9.故意把A和AA上下换位置:
grammar Test; r1: A; A: AA | ‘b’; |
试试是否会编译报错,结果竟然,意外的是,编译不报错的。
而之前如果是antlr v3,这样的语法:
A: AA | ‘b’; |
肯定会报错,说AA无法被匹配的。
然后,现在,又注意到,其实上面的写法是正确的。
而如果写成:
AA: ‘a’; |
才可能会报错才对。
10.让其试试,在mac下,用基于neatbeans的那个antlrworks 2.0试试,结果其那边安装插件出错:
11.我这里,win7 x64下,继续去
http://tunnelvisionlabs.com/products/demo/antlrworks
下载那个:
http://tunnelvisionlabs.com/downloads/antlr/2013-01-22-antlrworks-2.0.zip
然后运行其中的
2013-01-22-antlrworks-2.0\antlrworks2\bin\antlrworks264.exe
然后是可以的。
12.mac下,也是可以的。然后用antlrworks 2.0的结果,也是同样的错误:
13.然后注意到字母c有警告,所以看了看是:
Implicit token definition in parser rule
即所谓的:
parser的rule中,不能有普通的literal(字符)。
如果有,应该定义在lexer的token中才对。
14.我这里,后来测试结果也是同样的错误:
15.后来,把此讨论让别人回答:
https://groups.google.com/forum/#!topic/antlr-discussion/3PU6coecDyA
提到了:
ANTLR lexers assign token types based on two things.
1. A lexer rule matching more characters takes precedence over a lexer rule matching fewer characters. 2. A lexer rule appearing first in the grammar takes precedence over a lexer rule appearing later in the grammar.
In your case, the lexer rules A and AB both match the input ‘a’. Since the rule A appears first in the grammar, that is the token type assigned. Your parser rule r1 cannot match the input ‘a’, because the input ‘a’ will never be assigned the type AB. |
但是能想到的也是:
我之前 都可以改为 你现在的最终结果: r1: AB; A: ‘a’; C: ‘c’; AB: A B; WS: [ \t\n]+ -> skip; 故意写成最开始的那个测试例子: grammar Test; A: ‘a’ | ‘b’; r1: A; 不考虑lexer的token中包括literal的前提下 line 1:0 mismatched input ‘a’ expecting A 的 |
16.后来,讨论出来的一些之前就知道的规则是:
lexer的token,就像 c语言中的全局变量 但是特殊的是 有顺序关系 按照前后顺序 先后匹配 |
所以,此处:
你此处只是如测试r1 所以 只是会去判断 是否匹配r1 |
17.但是后来的分析,貌似是对的:
所以它就是根据Test.tokens中的token进行匹配 但是我们已经把A提前了,就不应该被r2中的’a’所影响 |
以及:
或许你的分析有道理: 但是antlr v4的话 就会有问题 就会影响到 然后导致此处报错的 |
18.所以,还是先去抽空测试一把antlr v3中的结果,看看如何。
去
http://www.antlr3.org/download/
下载:
然后双击无法运行,最终是参考:
而解决此问题的。
但是后来,对于antlrworks本身的使用,又出现错误了:
19.然后去用antlrworks v3.5去测试上述语法:
grammar Test; r1: A; r2: 'a' 'c'; A: 'a' | 'b';
测试输入内容是a:
结果,竟然是同样的错误:
20.另外测试了别的改动后的语法,比如:
grammar Test; r1: AA; r2: AA C; AA: 'a'; AAA: AA | 'b'; C: 'c';
结果是正常的:
【总结】
antlr正常的规律是:
lexer的token,就像 c语言中的全局变量 但是特殊的是 有顺序关系 按照前后顺序 先后匹配 |
并且还有:
parser的rule中,最好不要有literal,即普通的字符。 如果有,最好还是单独用lexer的token去匹配 |
然后此处对于:
grammar Test; r1: A; r2: 'a' 'c'; A: 'a' | 'b';
之所以,虽然结果是对的:
(r1 a) |
但是却会报错:
line 1:0 mismatched input ‘a’ expecting A |
的根本原因是:
由于r2这个lexer的rule中,包含了literal,即字母a和字母c
导致,所生成的token是:
T__5=5 A=4 ‘a’=5 ‘c’=6 |
其中,T__5=5,即:
A: ‘a’ | ‘b’; |
中的’a’ ,和
‘a’=5 |
所对应的
r2: ‘a’ ‘c’; |
中的’a’冲突掉了,都是5.
而对于语法:
grammar Test; r1: AA; r2: AA C; AA: 'a'; AAA: AA | 'b'; C: 'c';
生成的tokens是:
AA=4 C=6 |
其中,所有的token,都是数值独立的,没有相同的值,没有互相冲突的。
所以解析起来,也是正确的。
经验总结:
不论是antlr v3还是antlr v4,不论什么情况下,都要确保:
parser的rule中,没有literal(字符)
如果出现了,则要改写为另外的lexer的token。
否则,很可能就会出现此处的,各种意想不到的错误,警告,冲突的。
举例:
错误写法:
grammar Test; r1: A; r2: 'a' 'c'; A: 'a' | 'b';
正确写法:
grammar Test; r1: A | B; r2: A C; A: 'a'; B: 'b'; C: 'c';
另外:
1. 也不能写为:
grammar Test; r1: A_OR_B; r2: A C; A_OR_B: A | B; A: 'a'; B: 'b'; C: 'c';
否则编译就会出错的:
[18:13:16] error(208): Test.g:9:1: The following token definitions can never be matched because prior tokens match the same input: A,B |
意思是:
此处的,A_OR_B,已经匹配到了A或者B,
所以后面的A,B都永远不会被执行到,不会被匹配。
2.也不能写为:
grammar Test; r1: A_OR_B; r2: A C; A: 'a'; B: 'b'; C: 'c'; A_OR_B: A | B;
同理,A和B都被匹配过了,后面的A_OR_B,永远都不会被匹配到。
3.也是可以改为:
grammar Test; r1: a_or_b; r2: A C; a_or_b: A | B; A: 'a'; B: 'b'; C: 'c';
的,但是很明显,a_or_b就是一个多余的,没太大意义的rule了。
转载请注明:在路上 » 【已解决】antlr v4的语法出错:line 1:0 mismatched input ‘a’ expecting A