ANTLR4语法中比较运算符匹配异常问题求助
问题分析与解决方案
问题原因
- 非法运算符组合被接受:ANTLR词法分析器采用最长匹配原则,但当输入包含多余字符(如
===中的第三个=)时,剩余字符无法匹配任何词法规则,ANTLR默认会尝试错误恢复,跳过非法字符继续解析,导致非法组合看似被“接受”。 - 解析时丢失最后一个等号:以
number !== value为例,词法分析会将!==拆分为!=(NEQ)和单独的=,而单独的=无对应词法规则,被解析器错误恢复机制忽略,最终丢失该字符。
修复步骤
1. 调整词法规则顺序(增强可读性)
将多字符运算符放在单字符运算符之前,虽然ANTLR优先按最长匹配处理,但此顺序更符合直觉,避免混淆:
GE: '>=' ; GT: '>' ; LE: '<=' ; LT: '<' ; EQ: '=='; NEQ: '!=' ;
2. 添加非法字符拦截规则
在词法规则末尾添加规则,匹配任何未被前面规则覆盖的字符并直接报错,阻止错误恢复:
INVALID_CHAR: . -> fail;
此规则会让词法分析器遇到非法字符(如单独的=、!)时立即终止并报错,避免解析器跳过错误继续执行。
3. 完整修复后的语法
grammar Filter; filter: expr EOF ; expr: expr 'and' expr | expr 'or' expr | 'not' expr | '(' expr ')' | compExpr ; compExpr: ( operand (EQ | NEQ) operand ) | ( numOperand (GT | GE | LT | LE) numOperand ) ; operand: qualifiedName | nodeId | STR | bool | numOperand ; numOperand: INT | HEX | TIMESTAMP | qualifiedName ; bool: TRUE | FALSE ; qualifiedName: NAME ( '.' NAME )* ; nodeId: SERIAL ; // 多字符运算符优先定义 GE: '>=' ; GT: '>' ; LE: '<=' ; LT: '<' ; EQ: '=='; NEQ: '!=' ; TRUE: 'true' ; FALSE: 'false' ; NAME: [a-zA-Z_$][a-zA-Z0-9_$]* ; INT: '-'? DIGIT+ ; STR: '"' (~["])* '"' ; HEX: '0x' [0-9a-fA-F]+ ; SERIAL: [0-9a-zA-Z]+ ; TIMESTAMP: DIGIT DIGIT':'DIGIT DIGIT':'DIGIT DIGIT('.'DIGIT DIGIT DIGIT)? ; DIGIT: [0-9] ; WS : [ \t\r\n]+ -> skip ; // 拦截所有非法字符 INVALID_CHAR: . -> fail;
验证效果
- 输入
===:词法分析匹配==后,剩余的=触发INVALID_CHAR规则,直接报错,拒绝非法组合。 - 输入
number !== value:!==拆分为!=和=,=触发报错,不会丢失字符,而是提示非法输入。 - 合法运算符(如
==、>=)仍可正常解析。
内容的提问来源于stack exchange,提问作者UglyBob
相关产品推荐
相关产品推荐

