二元运算符的解释变体

时间:2017-01-07 17:46:26

标签: parsing antlr antlr4 operator-precedence

我正在为包含一些二进制运算符的语言编写语法,这些运算符也可以用作一元运算符(运算符右侧的参数),并且为了更好的错误恢复,我希望它们可以用作也是指运营商。) 我的简化语法如下:
开始:     代码EOF ;

code:
    (binaryExpression SEMICOLON?)*
;

binaryExpression:
    binaryExpression BINARY_OPERATOR binaryExpression //TODO: check before primaryExpression
    | primaryExpression
;

    primaryExpression:
            unaryExpression
            | nularExpression
    ;

    unaryExpression:
        operator primaryExpression
        | BINARY_OPERATOR primaryExpression
    ;

    nularExpression:
        operator
        | BINARY_OPERATOR
        | NUMBER    
        | STRING
    ;

        operator:
            ID
        ;

BINARY_OPERATOR只是一组定义的关键字,它们被输入到解析器中 我的问题是Antlr更喜欢使用BINARY_OPERATOR作为一元表达式(如果没有其他选择则使用nualr表达式)而不是尝试在二进制表达式中使用它们,因为我需要它完成。
例如,考虑以下输入:for varDec from one to twelve do something其中fromtodo是二元运算符,解析器的输出如下:
ParseTree
正如您所看到的,它将所有二元运算符解释为一元运算符。

我想要实现的目标如下:尝试匹配二进制表达式中的每个BINARY_OPERATOR,并且只有在不可能的情况下才 尝试将它们作为一元表达式匹配如果那不可能那么它可能被认为是一个nular表达式(只有当BINARY_OPERATOR是表达式的唯一内容时才会出现这种情况)。

有没有人知道如何实现理想的行为?

3 个答案:

答案 0 :(得分:0)

您允许运算符像操作数(" nularExpression")和操作数一样充当运算符("运算符:ID")。在这两个好奇的决定之间,你的语法是100%模糊的,并且永远不需要解析二元运算符。我不太了解Antlr,但令我惊讶的是,它并没有警告你,你的语法完全不明确。

Antlr具有handle and recover from errors的机制。使用它们比使用故意模糊的语法要好得多,这使得错误的构造成为公认语法的一部分。 (正如我所说,我不是Antlr的专家,但是有很多Antlr专家经常在这里经过;如果你问一个关于错误恢复的特定的问题,我确定您将获得一个好的答案。您可能还想搜索此站点以获取有关Antlr错误恢复的问题和答案。)

答案 1 :(得分:0)

相当标准的方法是使用单个递归规则来建立可接受的表达式语法。 ANTLR是默认的左关联,因此op expr满足“运算符右侧的参数”所述的一元操作要求。有关关联性的进一步讨论,请参见TDAR第70页。

Ex1:-y+x - > binaryOp{unaryOp{-, literal}, +, literal}

Ex2:-y+-x - > binaryOp{unaryOp{-, literal}, +, unaryOp{-, literal}}

expr
    : LPAREN expr RPAREN
    | expr op expr         #binaryOp
  //| op expr              #unaryOp   // standard formulation
    | op literal           #unaryOp   // limited formulation
    | op                   #errorOp
    | literal
    ;

op  : .... ;

literal
    : KEYWORD
    | ID
    | NUMBER    
    | STRING
    ;

答案 2 :(得分:0)

我想我现在要写的是@GRosenberg的回答。然而,由于我花了一段时间才完全理解它,我将为我的问题提供一个具体的解决方案,以防其他人绊倒这个问题并正在搜索或回答:

诀窍是删除在BINARY_OPERATOR规则中使用unaryExpression的选项,因为这总是首选。相反,我真正想要的是指定如果没有左侧参数,那么以一元的方式使用BINARY_OPERATOR是可以的。这就是我必须指定它的方式:

binaryExpression:
    binaryExpression BINARY_OPERATOR binaryExpression
    | BINARY_OPERATOR primaryExpression
    | primaryExpression
;

这样,只有在BINARY_OPERATOR的左侧没有任何内容时才能使用此语法,并且在其他所有情况下都必须使用二进制语法。