我认为,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的基础。
通过在左递归规则中在顶级替代项周围加上括号,您可以将替代项视为“其他”。对于通常为后缀或二进制的替代方案,由于未消除左递归而导致编译错误。对于前缀替代项(具有),语法仍会编译但会更改行为,因为替代项被视为主要表达式,而不是覆盖其在运算符优先级序列中原始位置的运算符。
请注意,在“其他”类别中已经包含顶级替代项的圆括号根本不会改变行为。同样,在非左递归规则中的替代项周围包含括号也不会改变行为。
关于antlr4 - ANTLR4中交替与序列的优先顺序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34250900/