ANTLR3报错咨询:NAME令牌为何无法被匹配?
ANTLR语法中TASK与NAME冲突问题解析
问题描述
定义了如下ANTLR语法文件Test.g:
options { language = Java; output=AST; } reference : TASK | NAME ; TASK : (~'^')+ EOF ; NAME : ('A'..'Z')+ ;
运行时收到报错:error(208): Test.g:19:1: The following token definitions can never be matched because prior tokens match the same input: NAME
疑问:两者字符集不同,且TASK必须以EOF结尾,NAME不含EOF,理论上不会匹配相同字符串,为何会出现冲突?
问题原因
ANTLR的词法分析遵循两个核心规则:
- 最长匹配优先:优先选择能匹配最长输入的词法规则。
- 定义顺序优先:若多个规则能匹配相同长度的输入,优先选用定义在前的规则。
你的TASK规则(~'^')+ EOF中,EOF是词法规则的结束标记,代表该token必须覆盖到输入的末尾。而NAME规则匹配的全大写字母序列,同时也完全符合TASK规则中的(~'^')+(大写字母不属于^),且当输入是全大写字母并到文件末尾时,TASK会先匹配整个输入(因为TASK定义在NAME前面),导致NAME规则永远没有触发的机会。
简单说:任何符合NAME的输入,同时也符合TASK的匹配条件,且TASK的定义顺序更早,所以NAME永远不会被匹配。
解决方法
方法1:调整词法规则顺序
将NAME规则放在TASK前面,这样当输入是全大写字母时,会优先匹配NAME;只有当输入包含非大写字母且到文件末尾时,才会匹配TASK:
options { language = Java; output=AST; } reference : TASK | NAME ; NAME : ('A'..'Z')+ ; TASK : (~'^')+ EOF ;
方法2:缩小TASK的匹配范围
修改TASK规则,排除NAME的匹配场景,比如让TASK匹配包含非大写字母的内容到EOF:
options { language = Java; output=AST; } reference : TASK | NAME ; TASK : (~'^')*[^A-Z](~'^')* EOF ; NAME : ('A'..'Z')+ ;
内容的提问来源于stack exchange,提问作者Adithya Chakilam
相关产品推荐
相关产品推荐

