二元运算符的解释变体

Interpretation variants of binary operators

我正在为一种包含一些二元运算符的语言编写语法,这些运算符也可以用作一元运算符(运算符右侧的参数)并且为了更好的错误恢复我希望它们是也可用作 nular 运算符)。
我的简化语法如下所示:
开始: 代码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_OPERATORs 用作一元表达式(如果没有其他选择,则使用 nualr 表达式)而不是尝试在二进制表达式中使用它们,因为我需要这样做。
例如,考虑以下输入:for varDec from one to twelve do something 其中 fromtodo 是二元运算符,解析器的输出如下:

如您所见,它将所有二元运算符解释为一元运算符。

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

有没有人知道如何实现所需的行为?

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

Antlr 有 handle and recover from errors 的机制。使用它们比编写故意模棱两可的语法要好得多,这种语法会使错误的结构成为可接受的语法的一部分。 (正如我所说,我不是 Antlr 专家,但有一些 Antlr 专家经常路过这里;如果你问 specific 关于错误恢复的问题,我相信你会得到一个很好的答案。您可能还想搜索此站点以获取有关 Antlr 错误恢复的问题和答案。)

相当标准的方法是使用单个递归规则来建立可接受的表达式语法。 ANTLR 默认是左结合的,所以 op expr 满足 "argument to the right side of the operator" 规定的一元运算要求。有关关联性的进一步讨论,请参阅 TDAR 第 70 页。

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

例 2:-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
    ;

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

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

binaryExpression:
    binaryExpression BINARY_OPERATOR binaryExpression
    | BINARY_OPERATOR primaryExpression
    | primaryExpression
;

只有在 BINARY_OPERATOR 左侧没有任何内容的情况下,这种语法才有可能出现,而在其他情况下,必须使用二进制语法。