我有以下表达式符号:
expr
: OpenParen expr (Comma expr)* Comma? CloseParen # parenExpr
| OpenParen simpleSelect CloseParen # subSelectExpr
不幸的是,一个simpleSelect
也可以有括号,因此以下语句变得不明确:
select ((select 1))
这是我当前的语法,简化为仅显示问题:
grammar Subselect;
options { caseInsensitive=true; }
statement: query_statement EOF;
query_statement
: query_expr # simple
| query_statement set_op query_statement # set
;
query_expr
: with_clause?
( select | '(' query_statement ')' )
limit_clause?
;
select
: select_clause
(from_clause
where_clause?)?
;
with_clause: 'WITH' expr 'AS (' select ')';
select_clause: 'SELECT' expr (',' expr)*;
from_clause: 'FROM' expr;
where_clause: 'WHERE' expr;
limit_clause: 'LIMIT' expr;
set_op: 'UNION'|'INTERSECT'|'EXCEPT';
expr
: '(' expr ')' # parenExpr
| '(' query_expr ')' # subSelect
| Atom # identifier
;
Atom: [a-z_0-9]+;
WHITESPACE: [ \t\r\n] -> skip;
并在解析上select ((select 1))
,这是输出:
有什么可能的方法来消除这种歧义?
我想主要的事情就在这里:
'(' query_statement ')'
由于它递归地调用自身 - 有没有办法进行间接或其他操作,例如query_statement
从括号内调用本身永远不能有括号?
另外,也许这是一个普遍现象?在官方 MySQL 语法上运行时,我得到同样不明确的输出here:
我很好奇是否有任何语法可以解决这里的问题:https://github.com/antlr/grammars-v4/tree/master/sql。也许最好的方法是在解析文本之前删除重复的括号? (如果是这样,是否有好的工具可以做到这一点,或者我是否需要编写一个额外的 antlr 解析器来做到这一点?)
您的输入生成此解析树:
这是对您的输入的合理解释,并且它被识别为subSelect
expr
。它是subSelect
嵌套在一个parenExpr
(两者都是expr
s).
如果我稍微改变一下你的规则:
expr: '(' query_expr ')' # subSelect
| '(' expr ')' # parenExpr
| Atom # identifier
;
现在它是一个subSelect
解释嵌套的(select 1)
作为查询表达式。
它是不明确的,因为外面的括号表达式could匹配前两个选项中的任何一个都会导致不同的解析树。
在 ANTLR 中,替代方案中的歧义通过“使用”第一个匹配的替代方案来解决。通过这种方式,ANTLR 具有确定性行为,您可以控制使用哪种解释(使用替代顺序)。 ANTLR 语法出现这样的歧义并不罕见。
恕我直言,IntelliJ 插件让很多人绊倒了这个,因为这表明语法有“错误”。在这种情况下 ANTLR 本身不报告错误是有原因的。它具有定义的、确定性的行为。
就“解决”这种歧义而言:语法使用括号来指示两个不同的“事物”这一简单事实表明它本质上是歧义的,所以我不相信您可以在不修改语法的情况下“修复”语法歧义。 (我对此可能是错的,如果有人提供能够消除歧义的重构,我会发现很有趣。)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)