ANTLR4中point规则为何匹配多个数字?
问题分析与解决方案
你遇到的核心问题是ANTLR4词法规则的匹配优先级导致的token拆分错误,让我们一步步拆解:
问题根源
ANTLR的词法分析遵循两个关键规则:
- 最长匹配优先:会尽可能匹配最长的符合规则的字符串。
- 规则定义顺序优先:如果多个规则都能匹配当前输入片段,会选择先定义的规则。
看你的原语法:
INT: [0-9]+; FLOAT: [0-9]*'.'?[0-9]+ ; NUMBER: (INT | FLOAT) ;
当输入2.0时,词法分析器首先会匹配2到INT规则(因为INT定义在FLOAT前面),剩下的.0才会被匹配为FLOAT。这样7 2.0会被拆成三个token:7(INT)、2(INT)、.0(FLOAT)。
而你的point: num num;规则需要两个num(即两个NUMBER),解析器会把前两个token(7和2)作为point的两个num,剩下的.0就没有对应的规则可以匹配,于是出现了mismatched input '0' expecting NUMBER的错误。
修复方案
我们可以通过合并整数与浮点数的词法规则来彻底避免顺序问题,同时优化语法的严谨性:
修改后的完整语法:
grammar example; // 隐藏空白字符 WS: [ \t\r\n]+ -> channel(HIDDEN); // 合并整数和浮点数为一个NUMBER规则,覆盖所有数字情况 NUMBER: [0-9]+ ('.' [0-9]+)? // 匹配整数(如7)和带整数部分的浮点数(如2.0) | '.' [0-9]+; // 匹配不带整数部分的浮点数(如.5) // 标识符规则保持不变 IDSTRING: [a-zA-Z_] [a-zA-Z0-9_]*; // 解析规则 id: IDSTRING; num: NUMBER; sem: ';' ; point: num num; // 修正END的写法:原语法的'END '带空格,WS已被隐藏,直接写'END'即可 macro: 'MACRO' id macroprops* 'END' id; macroprops: macroorigin ; macroorigin: 'ORIGIN' point sem;
关键修改点说明
- 合并NUMBER规则:把
INT和FLOAT合并成一个规则,确保任何数字形式都会被识别为单个NUMBERtoken,彻底解决顺序优先级问题。 - 修正
macro规则中的END:原语法里的'END '包含空格,但WS已经被放到隐藏通道,解析器不会处理显式空格,改为'END'后,会自动跳过END和id之间的空白字符,更符合预期。
测试验证
重新运行你的命令:
antlr4 example.g4 -o example/ cd example javac *.java echo -e "MACRO m_1\n ORIGIN 7 2.0 ;\nEND m_1" | grun example macro -tree
此时应该会输出正确的解析树:
(macro MACRO (id m_1) (macroprops (macroorigin ORIGIN (point (num 7) (num 2.0)) (sem ;))) END (id m_1))
内容的提问来源于stack exchange,提问作者Paul Würtz
相关产品推荐
相关产品推荐

