表达评估

时间:2011-01-16 19:32:18

标签: algorithm math evaluation vb5

我正在做一个表达式评估程序,就像this一样。我的问题是我无法弄清楚如何处理操作优先级。我使用递归来找到最内部的括号,当找到它们时,解决它们内部的表达式,如下所示:

Evaluate("2 + (3 * 5)")

将以这种方式重新调用自己:

Evaluate("3 * 5")

现在,由于没有括号,它会计算结果并再次调用自己:

Evaluate("2 + 15")

好的,正如预期的那样,返回值为17。但如果我拨打Evaluate("2 + 3 * 5"),结果是:

Evaluate("2 + 3 * 5")
Evaluate("5 * 5")

这显然是错误的。
基本上我是从左到右解决操作。如何选择必须先执行的操作?我想在每个操作中添加几个括号,但它看起来不太好 那么,我是否需要首先解析整个表达式?还有另一种方法吗?

4 个答案:

答案 0 :(得分:2)

这是一篇很好的文章,展示了如何使用带有.net的Antlr来做这种事情。

http://www.codeproject.com/KB/recipes/sota_expression_evaluator.aspx

听起来你想要手工编写你的解析器,但这将为你提供所需的一切,以便了解如何正确地执行此操作。

基本上,您通过将表达式定义为一系列可能的操作来实现优先级,其中每个操作在下一级操作。然后按照该序列的顺序对操作的优先级进行编码。

E.g。一个非常简单的例子,带有'+'和'*'

additiveExpression: multiplicativeExpression '+' multiplicativeExpression
multiplicativeExpression: number '*' number

你的手写递归下降解析器从顶层规则开始并向下运行。

你可以使用Antlr做一个非常简单的语法,然后看看它生成了什么代码 - 在这种情况下代码非常短,所以很容易理解。

如果你的语法会以任何方式变得复杂,我会鼓励你使用像Antlr这样的工具,因为它消除了解析代码中很多繁重的工作 - 它就是那种已经完成的东西以前数百次,非常机械。它让你专注于你想用表达式做的有趣的东西。

答案 1 :(得分:2)

可能有用的东西是使用波兰表示法:http://en.wikipedia.org/wiki/Polish_notation#Computer_programming。此表示法允许您不需要括号并帮助您处理操作顺序。

使用这个的好处是有算法来评估这些表达式。也可以将中缀表达式转换为前缀或后缀表达式。

以下是一个如何完成的示例 - 让我们举例“2 + 3 * 5”:

2 + 3 * 5
b = 3 * 5
    -convert b-
b = * 3 5
2 + b
    -convert expression-
+ 2 b
    -expand b-
+ 2 * 3 5

前几次我做了这些转换,我对他们非常困惑。如果它也适合你,不要被吓倒,只是继续练习。有什么好处是你可以找到帮助你进行转换的算法,所以这应该有所帮助。

进行此转换的一大优势是可以从左到右评估修改后的表达式。该算法运行如下:

维护两个堆栈 - 一个用于运算符,一个用于操作数。 从左到右评估:

  1. 如果遇到操作员,请将其推入操作员堆栈
  2. 如果遇到并且操作数(数字)将其推入操作数堆栈
  3. 一旦为最顶层的运算符找到了足够的操作数(大多数情况下为两个),请查看运算符并对两个操作数执行该操作。
  4. 将步骤#3的结果推送到操作数堆栈。
  5. 我过度简化了一些事情,可能错过了一些步骤,因此仅将此作为起点。有些细节我已经跳过/不记得了。其中一些包括二元或一元运算符,如何处理括号,如何处理权力评估等等。

    希望这会有所帮助并祝你好运:)

答案 2 :(得分:1)

无论如何你必须递归。因此,即使你看到一个+,你必须递归。实质上,您必须将没有括号的所有二元运算符视为具有它们。

2 + 3 * 5确实是2 +(3 * 5)。

答案 3 :(得分:0)

搜索您的最高优先级运算符并首先执行此操作,然后继续。因此,如果只有+和*,则搜索*的实例,并将子字符串aaaa * bbbb替换为aaaa * bbbb的值。一旦没有这样的实例,请继续+。

如果给定操作员内的订单很重要(例如,如果包含^),则必须决定从哪些操作员开始。