刚开始玩 ANTLR 并试图理解我在尝试解析错误输入时收到的错误消息。 这是我的(简单的)语法:
grammar Playground;
stmtList: (expr EOS)+;
expr:
IDENTIFIER ('!' | '^') IDENTIFIER
| expr ('*' | '/') expr
| expr ('+' | '-') expr
| INT
| IDENTIFIER;
MAKE: 'make';
INT: '0' | [1-9] [0-9]*;
IDENTIFIER: [a-zA-Z0-9]+;
EQUAL: '='; // Dummy token that can be recognised
EOS: '\r'? '\n';
WS: [ \t\n\r]+ -> skip;
这是我要解析的文本:
blah=blah
再一次,我知道这段文字与定义的语法不匹配。我得到的错误如下:
第 1:4 行不匹配的输入 '=' 期望 {'*', '/', '+', '-', EOS}
我的问题是——为什么 ANTLR 推荐的预期标记集不包括像 '!' 和 '^' 这样的标记,它们也在 expr 规则的第一个替代项中定义?我觉得我在这里缺少一些基本知识。任何帮助表示赞赏!
我的期望是看到如下所示的错误消息:
第 1:4 行不匹配的输入 '=' 期望 {'!', '^', '*', '/', '+', '-', EOS}
'!' 和 '^' 标记包含在预期的标记集中。
我正在阅读 The Definitive ANTLR 4 Reference,我也尝试使用 ANTLR 的 TestRig 生成令牌。
在
grun Playground stmtList -tokens
上运行blah=blah
给我以下输出:
[@0,0:3='blah',<IDENTIFIER>,1:0]
[@1,4:4='=',<'='>,1:4]
[@2,5:8='blah',<IDENTIFIER>,1:5]
[@3,9:9='\n',<EOS>,1:9]
[@4,10:9='<EOF>',<EOF>,2:0]
ANTLR 版本:4.11.1
这是因为您的
IDENTIFIER
规则中有两个以 expr
开头的选项。因此它们都可以与您的第一个标识符匹配。这就是实际发生的事情。第一个 blah
匹配为 IDENTIFIER
并且解析器尝试 expr
中的第一个 alt。这失败了,因为下一个标记是 EQUAL
,所以它尝试下一个以左递归 expr
规则开始的 alt 并再次进行相同的尝试。 expr
匹配 IDENTIFIER
因为你的最后一个 alt,所以下一步是匹配运算符,但都失败了。最后你得到了 2 个左递归 alts 的预期标记,因为它们的第一部分匹配:
如果您删除
expr
规则中的最后一个替代项,结果如您所料:
因为现在没有
expr
与单个IDENTIFIER
的匹配,所以第一个alt就是用来报错的。