如何在解析单个表达式后触发解析错误?ANTLR语法问题
我有如下ANTLR语法:
start : expression ; expression : | dateOperatorExpression | numberOperatorExpression | stringOperatorExpression | methodBooleanExpression | doubleMethodOperatorExpression | numberInExpression | stringInExpression | bracketExpression | andExpression | orExpression | notExpression ; numberInExpression: | WS? METHOD WS? IN WS? '{' WS? NUMBER (WS? ',' WS? NUMBER)* '}' WS? ; stringInExpression: | WS? METHOD WS? IN WS? '{' WS? STRING (WS? ',' WS? STRING)* '}' WS? ; dateOperatorExpression: | WS? DATE WS? OPERATOR WS? DATE WS? | WS? DATE WS? OPERATOR WS? METHOD WS? | WS? METHOD WS? OPERATOR WS? DATE WS? | WS? DATE WS? OPERATOR WS? NULLVALUE WS? | WS? NULLVALUE WS? OPERATOR WS? DATE WS? ; numberOperatorExpression: | WS? NUMBER WS? OPERATOR WS? NUMBER WS? | WS? NUMBER WS? OPERATOR WS? METHOD WS? | WS? METHOD WS? OPERATOR WS? NUMBER WS? | WS? NUMBER WS? OPERATOR WS? NULLVALUE WS? | WS? NULLVALUE WS? OPERATOR WS? NUMBER WS? ; stringOperatorExpression: | WS? STRING WS? OPERATOR WS? STRING WS? | WS? STRING WS? OPERATOR WS? METHOD WS? | WS? METHOD WS? OPERATOR WS? STRING WS? | WS? STRING WS? OPERATOR WS? NULLVALUE WS? | WS? NULLVALUE WS? OPERATOR WS? STRING WS? ; doubleMethodOperatorExpression: | WS? METHOD WS? OPERATOR WS? METHOD WS? | WS? METHOD WS? OPERATOR WS? NULLVALUE WS? | WS? NULLVALUE WS? OPERATOR WS? METHOD WS? ; methodBooleanExpression: | WS? METHOD WS? OPERATOR WS? BOOLEAN WS? | WS? BOOLEAN WS? OPERATOR WS? METHOD WS? ; bracketExpression: | '(' WS? expression WS? ')' ; andExpression : | AND WS? '(' expression (',' expression)* WS? ')' ; orExpression : | OR WS? '(' expression (',' expression)* WS? ')' ; notExpression : | NOT WS? expression ; WS: (' ' | '\t' | '\r' | '\n')+ -> skip; AND: 'AND' | 'and'; OR: 'OR' | 'or'; NOT: 'NOT' | 'not' | '!'; IN: 'IN' | 'in'; OPERATOR: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'ILIKE' | 'ilike' | 'LIKE' | 'like'; NULLVALUE: 'null' | 'NULL'; BOOLEAN: 'true' | 'false' | 'TRUE' | 'FALSE'; METHOD: [a-zA-Z_][a-zA-Z0-9_.]*; NUMBER: [0-9.]+; STRING: '"' [a-zA-Z0-9%]+ '"'; DATE: [0-9][0-9][0-9][0-9][-][0-9][0-9][-][0-9][0-9]('T'[0-9][0-9]':'[0-9][0-9]':'[0-9][0-9])?;
该语法支持类似如下的查询语句:
and((retired == true), or ((age >= 25), not(father.address.street != null)), firstName in {"John", "Pete"})
为避免用户输入错误(比如误加多余括号时,解析器仅处理and((retired == true))并忽略剩余内容),我尝试将start规则修改为:
start : (expression)+ ;
但出现错误提示:rule start contains a closure with at least one alternative that can match an empty string。请问为何会出现此错误?如何实现解析恰好一个表达式后触发错误的需求?
出现这个错误的核心原因是你的expression规则(以及所有子规则)定义了空匹配分支。
看expression的定义:
expression : | dateOperatorExpression | ... // 其他分支 ;
第一个:后面直接跟|,这意味着expression存在一个可以匹配空字符串的备选分支。当你把start改成(expression)+时,ANTLR会检测到这个闭包(+表示至少一次重复)可能陷入无限循环——因为空字符串可以被无限次匹配,而不需要消耗任何输入。这种歧义会触发ANTLR的语法检查错误。
所有子规则(比如numberInExpression、dateOperatorExpression等)也都存在同样的空分支问题,它们都能匹配空字符串,进一步加剧了这个问题。
要实现“解析恰好一个表达式,多余内容直接报错”的需求,需要分两步操作:
1. 修复所有规则的空分支
把每个规则中开头的空分支去掉——也就是删除:后面的第一个|。例如:
- 原
expression规则:
修改后:expression : | dateOperatorExpression | ... ;expression : dateOperatorExpression | numberOperatorExpression | stringOperatorExpression | methodBooleanExpression | doubleMethodOperatorExpression | numberInExpression | stringInExpression | bracketExpression | andExpression | orExpression | notExpression ; - 原
numberInExpression规则:
修改后:numberInExpression: | WS? METHOD WS? IN WS? '{' WS? NUMBER (WS? ',' WS? NUMBER)* '}' WS? ;numberInExpression: WS? METHOD WS? IN WS? '{' WS? NUMBER (WS? ',' WS? NUMBER)* '}' WS? ;
所有其他子规则都需要做同样的修改,确保每个规则只能匹配非空的有效内容。
2. 让start规则匹配到输入结束
将start规则改为匹配一个表达式 + 输入结束标记(EOF),这样如果输入中存在表达式之外的多余内容,解析器会直接报错:
start : expression EOF;
这样修改后,当用户输入多余的括号或其他内容时,解析器会因为无法匹配到EOF而抛出错误,完美解决你之前遇到的“忽略剩余内容”的问题。
内容的提问来源于stack exchange,提问作者Yves V.

