表达式解析趣谈

代码的编译是计算机科学的一大命题,其博大精深,难以尽数。这里 ,我们捡着一个小命题娱乐一下。
程序代码中,总是少不了数学运算,其实对于我们来说很熟悉的数学计 算,在计算机里也是要做一些编译处理的。
例如,4+9*3+7-2这样一个简单的四则运算 ,对于人来说就是:
  4+9*3+7-2
=4+27+7-2
=31+7-2
=38-2
=36

这里面,我们实际上已经在下意识里做了很多思考。首先 ,大脑会按照运算符划分开各个子算式,然后找出运算优先级的子式 ,按顺序计算完后,将结果填充给下一级,依次递归 ,直至整个算式完成。
计算机的编译/解释过程,其实跟这个很像,也是先找出最高优先级的 子式,然后依次递归构造出一个语法解析树,调用数学运算指令计算每 个节点,返回结果。对于每个单步运算,计算机里面调用一次+、- 、*、/的时候,其实是一次函数操作,每个运算符执行对应的函数 ,比如1+1,其实就是+(1, 1)。在编译时,通常会把这样的运算翻译为后缀表达式,+(1, 1)就变成了1 1 -,这样的好处是计算机逐次读入每一个词,遇到操作数就压栈 ,遇到操作符就把所需个数的操作数从栈里弹出来计算 ,然后再把结果压进去,这个过程以轻松匹配复杂表达式。不过— —这么看起来是不很累?特别是复杂算式,就看不清层次了 。我们把它用括号包起来,就成了(1 1 -),这样清晰一些了吧,我们现在按这种方式把开头的那个式子写成
(((4 (9 3 *)+) 7+) 2 -)
现在,我们用一个[]表示堆栈,左边是栈顶,右边是栈底 。现在我们模拟计算机的解释过程。
    (((4 (9 3 *)+) 7+) 2 -)
=>[4]                             4入栈
=>[9 4]                         9入栈
=>[3 9 4]                      3入栈
=>* (9 3) [4]                  读到*,弹出最上面两个数3和9——需要注意,因为堆栈的后入先出 特性,实际上栈顶的元素反而在参数表的右边
=>[27 4]                       把相乘以后的结果27重新压入栈
=>+ (4 27) []                 读到+,弹出最上面两个数27和4
=>[31]                          把相加结果31入栈
=>[7 31]                        7入栈
=>+ (31 7)[]                  读到+,弹出最上面两个数7和31
=>[38]                          把相加以后的结果38入栈
=>[2 38]                       2入栈
=>- (38 2)[]                   读到-,弹出最上面两个数2和38
=>[36]                          把相减结果36入栈
=>36                            检测到运算过程已经完成,把结果从堆栈中弹出返回

以上这个过程对计算机是很方便,但是对于我们读起来还是有点别扭 ,把运算符放前面不是更好懂么?编译原理中,前缀表达式也是一种常 见的写法,于是:
(((4 (9 3 *)+) 7+) 2 -)=>(-(+(+ 4 (* 9 3)) 7) 2)
这个么,应该有朋友已经发现了,这不就是一段LISP代码么?!
我有很长时间不能很好的理解LISP代码,直到有位朋友说 ,LISP就是语法解析树的前缀表达……
以此文向他致敬!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ccat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值