正如『正义的花生』在数学与编程中提到的一样:
普通程序员使用的编程语言,就算是C++这样毛病众多的语言,其实也已经比数学家使用的语言好很多。用数学的语言可以写出含糊复杂的证明,在期刊或者学术会议上蒙混过关,用程序语言写出来的代码却无法混过计算机这道严格的关卡。因为计算机不是人,它不会迷迷糊糊的点点头让你混过去,或者因为你是大师就不懂装懂。代码是需要经过现实的检验的。如果你的代码有问题,它迟早会导致出问题。
诚然,大牛作者在思想上有很多偏执的地方,但是往往他的观点我都有着不小的认同感。前边那篇『怎样写一个解释器』也是他的文章。
所以,学习写一个解释器,可以带给我更多的思考,从效率,空间,机器等等方面进一步认识程序运行的本质,将这种认识正反馈到实际编程中,将潜移默化的带来影响。当然,这篇文章试着依葫芦画瓢的写完一个解释器,显然仅仅算是摸了摸门道,想要继续探索,还有更多的事情可以做。做更多的事情,可以参考上边提到的开源项目Crianza。
堆栈机的执行原理很简单,将需要处理的值放进堆栈中,然后执行。Python, Java这些高级语言将它作为自己的虚拟机。
所以我们利用了堆栈的方式存放指令。首先,我们需要一个指令指针栈,它能够储存返回地址。这个返回地址就是当我们执行一个子程序(如函数)的时候,需要用它跳回到开始调用该函数的地方。
我们将这个复杂的问题简洁化。比如有一个数学表达式:(2+3)*4 ,这个表达式的意思就是依次推入2 3 + 4 *, 将2 和3 依次推入栈中,接下来要推入的指令是 +, 将两个数字弹出,令他们执行加法运算,然后将结果入栈。然后继续进行下去,直到计算出结果。
依靠这个原理,我们开始建立一个栈,我们使用python 中的一个类 collections.deque。
from collections import deque
class Stack(deque): # 定义一个栈
push = deque.append # 添加元素
# 返回最后一个元素
def top(self):
return self[-1]
deque 中自带pop 方法,所以我们就不用再定义 pop .
接下来我们继续构建一个虚拟机的类 Machine。 我们需要两个栈和一段储存代码的内存空间。一个栈储存数据,一个栈储存地址。得益于Python 动态类型,因此我们可以往列表里面存储任何东西,但是我们不能区分列表里面的内置函数和字符串,正确的做法是将Python 内置函数单独存放在一个列表。这里我们使用字典方法,键值分别对应字符串和函数。另外,我们需要一个指令指针,用来指向代码中下一个需要被执行的模块。
class Machine:
def __init__(self, code): # 预先定义一个初始化函数
self.data_stack = Stack()
self.return_addr_stack = Stack()
self.code = code
self.instruction_pointer = 0
# 再创建一些栈结构中必备的函数
def pop(self):
return self.data_stack.pop()
def push(self, value):
self.data_stack.push(value)
def top(self):
return self.data_stack.top()
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-34020-2.html
应该清醒清醒