Antlr4 mismatched input错误:'protected'未被识别为MODIFIER
问题描述
定义了如下ANTLR语法规则:
declareField : MODIFIER* typeVar nameType ASSIGN value ';'; nameType : NAME(('.')NAME)*; typeVar : nameType | nameType'<'typeVar'>' | typeVar'['']'; value : PRIMITIVE_VALUE;
以及对应的词法令牌规则:
ASSIGN : '='; NULL : 'null'; INT : [0-9]+; FLOAT : [0-9]+.[0-9]+; STRING : '"'[a-zA-Z_0-9.]*'"'; CHAR : '\''[a-zA-Z_0-9]'\''; BOOLEAN : TRUE | FALSE; TRUE : 'true'; FALSE : 'false'; PRIMITIVE_VALUE : INT | FLOAT | STRING | CHAR | BOOLEAN | NULL; PUBLIC : 'public'; PRIVATE : 'private'; FINAL : 'final'; STATIC : 'static'; VOLATILE : 'volatile'; TRANSIENT : 'transient'; SYNCHRONIZED : 'synchronized'; NATIVE : 'native'; ABSTRACT : 'abstract'; PROTECTED : 'protected'; MODIFIER : PUBLIC | PRIVATE | FINAL | STATIC | VOLATILE | TRANSIENT | SYNCHRONIZED | NATIVE | ABSTRACT | PROTECTED; NAME : [a-zA-Z_][a-zA-Z_0-9]*; WS: [ \t\r\n]+ -> channel(HIDDEN);
预期该语法能正确解析输入语句:
protected static final int test = 10;
但实际触发错误:
line 1:0 mismatched input 'protected' expecting {MODIFIER, NAME}
尽管protected已被明确定义为MODIFIER规则的分支,需要排查匹配错误的原因并解决。
错误原因
核心问题是词法规则的优先级逻辑与语法规则的令牌期望不匹配:
- ANTLR词法分析器遵循「先定义的规则优先级更高」原则,你先定义了
PROTECTED、STATIC等具体修饰符关键字规则,后定义MODIFIER规则。因此输入的protected、static等字符串会被优先匹配为PROTECTED、STATIC等具体令牌,永远不会被识别为MODIFIER令牌。 - 而语法规则
declareField开头使用MODIFIER*,期望接收MODIFIER类型的令牌,但实际得到的是PROTECTED、STATIC等具体令牌,因此触发输入不匹配错误。
解决方案
提供两种可行修复方案,按需选择:
方案一:修改语法规则适配具体令牌
保留现有词法规则,将语法规则中的MODIFIER替换为所有具体修饰符关键字的组合:
declareField : (PUBLIC | PRIVATE | FINAL | STATIC | VOLATILE | TRANSIENT | SYNCHRONIZED | NATIVE | ABSTRACT | PROTECTED)* typeVar nameType ASSIGN value ';'; nameType : NAME(('.')NAME)*; typeVar : nameType | nameType'<'typeVar'>' | typeVar'['']'; value : PRIMITIVE_VALUE;
修改后语法规则可直接接受所有具体修饰符令牌,输入能正常解析。
方案二:简化词法规则统一令牌类型
删除单独的PUBLIC、PROTECTED等关键字词法规则,直接在MODIFIER中定义所有修饰符字符串:
ASSIGN : '='; NULL : 'null'; INT : [0-9]+; FLOAT : [0-9]+'\.'[0-9]+; // 修复原规则中.未转义的问题 STRING : '"'[a-zA-Z_0-9.]*'"'; CHAR : '\''[a-zA-Z_0-9]'\''; BOOLEAN : 'true' | 'false'; PRIMITIVE_VALUE : INT | FLOAT | STRING | CHAR | BOOLEAN | NULL; MODIFIER : 'public' | 'private' | 'final' | 'static' | 'volatile' | 'transient' | 'synchronized' | 'native' | 'abstract' | 'protected'; NAME : [a-zA-Z_][a-zA-Z_0-9]*; WS: [ \t\r\n]+ -> channel(HIDDEN);
语法规则保持原有的declareField : MODIFIER* typeVar nameType ASSIGN value ';';即可,此时词法器会将所有修饰符字符串匹配为MODIFIER令牌,与语法规则期望一致。
额外优化提示
原FLOAT规则中的.未转义,会匹配任意字符(正则中.是通配符),已在方案二中修复为[0-9]+'\.'[0-9]+,避免错误匹配非数字分隔符的字符串。
内容的提问来源于stack exchange,提问作者Arsenii Abichev
相关产品推荐
相关产品推荐

