【问题标题】:Antlr4 Arithmetic Grammar Is Ignoring Order of Precedence (PEMDAS)Antlr4 算术语法忽略优先顺序 (PEMDAS)
【发布时间】:2022-11-09 22:41:01
【问题描述】:

语法定义

据我了解,ANTLR4 支持左递归以尊重算术的优先顺序。话虽如此,语法如下:

grammar Arithmetic;

arithmetic: arithmeticExpression;

arithmeticExpression:
    LPARAN inner = arithmeticExpression RPARAN                      # Parentheses
    | left = arithmeticExpression POW right = arithmeticExpression  # Power
    | left = arithmeticExpression MUL right = arithmeticExpression  # Multiplication
    | left = arithmeticExpression DIV right = arithmeticExpression  # Division
    | left = arithmeticExpression ADD right = arithmeticExpression  # Addition
    | left = arithmeticExpression SUB right = arithmeticExpression  # Subtraction
    | arithmeticExpressionInput                                     # ArithmeticInput;

arithmeticExpressionInput: NUMBER;

number: NUMBER;

/* Operators */
LPARAN: '(';
RPARAN: ')';
POW: '^';
MUL: '*';
DIV: '/';
ADD: '+';
SUB: '-';

/* Data Types */
NUMBER: '-'? [0-9]+;

/* Whitespace & End of Lines */
EOL: '\r'? '\n';
WS: [ \t]+ -> channel(HIDDEN);

注意:我已经简化了测试的语法。

输入

5 + 21 / 7 * 3

输出解析树

问题

在从arithmetic 开始的输出解析树中。您可以看到优先顺序没有遵循 PEMDAS,即使它是通过语法中的左递归定义的。在使用函数调用为VisitAddition 调试 Antlr 生成的访问者代码时也会观察到这一点。

我用谷歌搜索了这个,与示例相比,我看不出我做错了什么,因为它们看起来都一样。

环境

ANTLR 版本:4.11.1

构建目标:CSharp

.NET 项目包:

  1. Antlr4BuildTasks@11.1.0
  2. Antlr4.Runtime.Standard@4.11.1

【问题讨论】:

  • 你能解释一下结果与你想要的有什么不同吗?乘法的优先级高于除法的事实?这就是您在语法中定义它的方式。如果您希望乘法和除法具有相同的优先级,则需要在相同的选项中将它们一起定义(加号和减号相同)。
  • @sepp2k,当然,我想遵循 PEMDAS 的数学优先顺序。但是,它目前没有遵循该命令。就像解析语法时,它在乘法之前调用加法是错误的。这导致计算时结果在数学上不正确。
  • 您展示的解析树等同于5 + (21 / (7 * 3))。数学上正确的是5 + ((21 / 7) * 3)。所以+(相对于*/)的优先级很好。
  • 数学中通常的约定是+- 具有相同的优先级,*/ 具有相同的优先级。 “PEMDAS”应该读作“PE(MD)(AS)”(或者根本不使用首字母缩写词)。如果您将其解释为严格的顺序,则您编写的语法是“PEMDAS”的正确实现。那只是不正确的解释。
  • 明白了,我的错。我想在我的脑海中,我期待看到VisitX 按优先顺序(PEMDAS)导致我认为它以错误的顺序解析!我将测试更多的方程并确保我得到正确的输出。

标签: antlr antlr4


【解决方案1】:

正如@sepp2k 在 cmets 中提到的(谢谢)。

问题出在语法上,因为 multiplicationdivisionadditionsubtraction 都被分成了单独的 OR 规则行。本质上是在应该是PE(MD)(AS) 时创建 PEMDAS。

这是固定语法的示例:

arithmeticExpression:
    arithmeticExpressionInput                                                           # ArithmeticInput
    | LPARAN inner = arithmeticExpression RPARAN                                        # Parentheses
    | left = arithmeticExpression operator = POW right = arithmeticExpression           # Power
    | left = arithmeticExpression operator = (MUL|DIV) right = arithmeticExpression #
        MultiplicationOrDivision
    | left = arithmeticExpression operator = (ADD|SUB) right = arithmeticExpression #
        AdditionOrSubtraction;

现在输出的解析树更干净了:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多