ANTLR4中交替与测序的优先顺序

时间:2015-12-13 12:07:14

标签: antlr4

我认为测序(由子规则隐式给出)在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我得到了这个解析树

parse tree of unbracketed expression

然而,如果我只是在unary_operator expression附近添加括号,并且完全没有改变,那么

expression :
[snip]
        '(' scalar_subquery ')' 
    |
        ( unary_operator expression )   // brackets added here
    |
        expression binary_operator expression
[snip]
    ;

并给它相同的SQL,我得到了这个

parse tree of bracketed expression

我误解了什么?

(顺便说一句,另外,将“ - 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 crud(给出相关部分):

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

还需要其他什么吗?有人可以复制吗?

坦率地说,我很难相信这是一个错误。这太元素了。

仅供参考我发现这最初不是通过包围/取消包围,而是通过将规则的主体提升为规则,并注意到行为发生了变化。

1 个答案:

答案 0 :(得分:5)

这个答案是在antlr/antlr4#564没有修复的情况下写的。

在代码生成过程中,当重写左递归规则以在递归下降解析器中工作时,ANTLR会查找一些特定模式。

考虑以下规则:

expression
  : INT
  | '++' expression
  | expression '++'
  | expression '+' expression
  ;
  1. 后缀:使用递归调用启动的顶级替代方案。在示例中,替代expression '++'属于此类别。
  2. 前缀:使用递归调用结束的顶级替代方案。在示例中,替代'++' expression属于此类别。
  3. 二进制: 以递归调用开始和结束的顶级替代方案。在示例中,替代expression '+' expression属于此类别。
  4. 其他:其他所有内容。在示例中,替代INT属于此类别。
  5. 匹配这些模式时,不执行任何简化。这包括删除其他不必要的括号,这是问题antlr/antlr4#564的基础。

    通过在左递归规则中的顶级替代项中包括括号,可以强制将替代项视为其他。对于通常为后缀二进制的替代方法,由于未消除的左递归而导致编译错误。对于前缀备选方案(您有),语法仍然可以编译但更改行为,因为替代方案被视为主表达式而不是操作符,它会覆盖其在运算符优先级序列中的原始位置。

    请注意,包含已包含在其他类别中的顶级替代附近的括号不会改变行为。同样,在非递归规则中包含替代项的括号不会改变行为。