这个东西一直是大家关注的热点,也是这个题目的真正目标所在,希望大家能够好好学习了解这个部分的思路想法。虽然这个思路不是以后编译原理上面的标准思路,也不是什么正统方法,但是它确实符合大家的想法和一贯的思路。因为不够正统和强悍,如有高人敬请指点。
那么我们来考虑一下这个表达式,如果只有加减运算符大家是否感觉能很好的解决呢?
首先是单位的数字和运算符(只有加减),那么我们就只用顺序处理即可。形如:a+b-c+d,我们是如何计算的呢?首先计算a+b,然后将结果e替代a+b-->e-c+d-->h+d-->i一次一次计算替换的反复。如此以来我们就有了一个思路,拿出三个,计算结果丢进去,再拿出三个计算。我们假设,这个表达式已经切割好了,放在一个栈(第二步有讲)里面,我们通过对栈操作实现全部运算。
while stack is not empty
do operator : = pop()
second : = pop()
res : = first < operator > second
push(res)
first : = pop()
return first
以上的计算是基于:运算符优先级一样,格式正确。剩下的就是来切割解析这个表达式使之成为这种结构。我们只需要一直解析这个字符串,如果出现,标点则前面的就是一个数,我们将它压入栈中。就是类似的方法喽。
n: = 1
while n <= length[expression]
do if expression[n] is the operator
then if not p = ""
then push(p)
p=""
push(expression[n])
else p: = p + expression[n]
n: = n + 1
return stack
好了,我们现在是同优先级的没有问题了,如果有高优先级的怎么办呢?
如果只考虑+-*/那么只要是*/号出现就可以对其操作符左右的数据进行运算了。也就是说在上面的伪代码里面我们需要加一步判断operator是否为*/的情况,然后进行运算。但是如果我们只扫描到operator就要运算,对于一个双目运算符来说还差一边啊,那么我们能否将这个判断推迟到压入数字的时候进行呢?这样我们需要在压入数据的时候提出前面的若干项进行处理了。
n: = 1
while n <= length[expression]
do if expression[n] is the operator
then if not p = ""
then
// Be careful
operator : = pop()
if operator is the * or /
then
first : = pop()
second : = p
p: = first < operator > second
push(p)
p = ""
push(expression[n])
else p: = p + expression[n]
n: = n + 1
return stack
如此以来我们实现了+-*/了,HOHO 不错吧,思路就是这样一步一步来的。
下面我们想加入括号了,现在我们继续想,其实括号就是更高的一层优先级了,由于基于以上的运算处理,在括号“缝合”(即碰到了')')的时候括号里面只有加减法,也就是说刚刚的栈处理结束标志是表达式末尾开始的标志就是表达式开头,而这里的开头是‘(’结尾是‘)’,还有什么区别吗?其实没什么了,那么我们按照这个思路,如果expression[n]是括号,‘(’压入栈中,')'开始运算将结果压入栈中。这样看似乎不难哦。
n: = 1
while n <= length[expression]
do if expression[n] is the operator
then if not p = ""
then
// Be careful
operator : = pop()
if operator is the * or /
then
first : = pop()
second : = p
p: = first < operator > second
push(p)
p = ""
push(expression[n])
elseif expression[n] is the bracket ( or )
then
if expression[n] = " ( "
then push(expression[n])
else res:=compute the expression between the " ( " and " ) "
//Push the result
push(res)
else p: = p + expression[n]
n: = n + 1
return stack
这样看似乎很爽啊,但是大家看看这个表达式 1+(2+3*4)*(5+6)
计算结果是 165 而不是正确结果 155.为什么呢?
因为我们在计算之后直接压入栈中而忽略了前面的那个*号。至此我们应该知道,一旦压入数据就得检查前面的operator.
这样以来我们需要对push(object)单独再包装一下,使它明白只要压入就得检查.
至此我们已经知道了基本的运算体系。
在实际编码过程中,大家可能要碰到大量的边界讨论问题,这一定要小心。
关于乘方和小数问题我将尽快写出来。