我认为测序(由子规则隐式给出)在ANTLR4解析器中具有比交替更高的优先级(由|字符明确给出),这意味着
a : x | y z ;
在语义上是相同的
a : x | ( y z) ;
看一下ANTLR4的书并进行搜索,我无法找到明确的陈述,但这似乎是合理的,但是给出了规则
expression : pmqident | constant | [snip] | '(' scalar_subquery ')' | unary_operator expression // this is unbracketed | expression binary_operator expression [snip] ;
我喂它这个select - 2 / 3
我得到这个解析树
而如果我只是添加括号unary_operator expression
并且完全没有改变,那就得到这个
expression : [snip] '(' scalar_subquery ')' | ( unary_operator expression ) // brackets added here | expression binary_operator expression [snip] ;
并给它相同的SQL,我明白了
我有什么误会?
(顺便说一句,另外," - 2/3"到"( - (2/3))"的怪异解析实际上就是我想要的那个.这就是MSSQL的做法.疯狂的世界)
好的,重现(适合我),不是完全最小但严重剥离的代码.文件名为MSSQL.g4:
grammar MSSQL; expression : constant | unary_operator expression // bracket/unbracket this | expression binary_operator expression ; constant : INTEGER_CONST ; INTEGER_CONST : [0-9]+ ; binary_operator : arithmetic_operator ; arithmetic_operator : subtract | divide ; add_symbol : PLUS_SIGN ; subtract : MINUS_SIGN ; divide : DIVIDE_SIGN ; unary_operator : SIGN ; SIGN : PLUS_SIGN | MINUS_SIGN ; DIVIDE_SIGN : '/' ; PLUS_SIGN : '+' ; MINUS_SIGN : '-' ; SKIPWS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
用DOS编写它(给出相关部分):
set CurrDir=%~dp0 set CurrDir=%CurrDir:~0,-1% cd %CurrDir% java org.antlr.v4.Tool -Werror -o %CurrDir%\MSSQL MSSQL.g4 IF %ERRORLEVEL% NEQ 0 goto problem javac %CurrDir%\MSSQL\MSSQL*.java IF %ERRORLEVEL% NEQ 0 goto problem cd ./MSSQL echo enter sql... java org.antlr.v4.gui.TestRig MSSQL expression -gui -trace -tokens
输入是 - 2 / 3
在win2k8R2上运行,位的版本如下
C:\Users\jan>java -version java version "1.8.0_65" Java(TM) SE Runtime Environment (build 1.8.0_65-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode) C:\Users\jan>java org.antlr.v4.Tool ANTLR Parser Generator Version 4.5.1
还有什么需要吗?有人可以复制吗?
坦率地说,我很难相信这是一个错误.这太过于元素了.
仅供参考我发现这不是通过包围/不支持,而是通过将规则的主体提升为规则,并注意到行为发生了变化.
这个答案是在antlr/antlr4#564没有修复的情况下编写的.
在代码生成过程中,ANTLR在重写左递归规则以在递归下降解析器中工作时查找一些特定模式.
请考虑以下规则:
expression : INT | '++' expression | expression '++' | expression '+' expression ;
后缀:以递归调用开始的顶级替代方案.在该示例中,替代方案expression '++'
属于此类别.
前缀:以递归调用结束的顶级替代.在该示例中,替代方案'++' expression
属于此类别.
二进制:以递归调用开始和结束的顶级替代方法.在该示例中,替代方案expression '+' expression
属于此类别.
其他:其他一切.在该示例中,替代方案INT
属于此类别.
匹配这些模式时,不执行任何简化.这包括删除其他不必要的括号,这是问题antlr/antlr4#564的基础.
通过在左递归规则中的顶级替代项中包括括号,可以强制将替代项视为" 其他".对于通常为后缀或二进制的替代方法,由于未消除的左递归而导致编译错误.对于前缀替代(您有),语法仍然可以编译但更改行为,因为替代被视为主表达式而不是操作符,它会覆盖其在运算符优先级序列中的原始位置.
请注意,包含已在" 其他"类别中的顶级替代项的括号不会改变行为.同样,在非递归规则中包含替代项的括号不会改变行为.