实现一个脚本引擎

Part VII:虚拟机(The Virtual Machine)

序言
bl_line.jpg (1610 bytes)

我们已经在Part V产生了中间代码,并且我们想要把它转换成可执行代码,好让我们能够执行一个程序.但是我已经决定要先建立一个虚拟机,这样我们可以知道该如何处理产生可执行代码.

虚拟机当然是一个脚本引擎中非常重要的组件.我们的代码将在它那里执行,所以它最好快一些.但是这里我将不把焦点集中到速度上.

Oh yeah:这部分结束后,你将完全免费的得到我那令人惊奇的堆栈模板(Amazing Stack Template),也不需要额外的小费.并且你将得到一个为这部分特别编写的很酷的字符串类,它完成至少5个精密的工作.那是你的物有所值的东西.

但是,首先是一个不同机器类型的说明.在Part V我只是说了我们的VM将是什么种类,没有说明其它的可能.Andy Campbell询问我关于这方面的其它可能性,并且我想其他人也许会感兴趣.

机器类型
gl_line.jpg (1418 bytes)

以前说过,我们的机器将是一个堆栈机器(stack machine).在真实的机器中,堆栈CPU被用于早期的计算机(并且今天依然在一些简单的设备中使用).缺点是需要很多的堆栈操作:每个操作数需要一个PUSH,每个结果需要一个POP.尽管你直接使用这个结果来进行下面的计算,所以那不总是必须的.

现在的大多数CPU有寄存器(数量非常有限的存储位置)来进行操作而不是堆栈;堆栈依然在函数传递参数时使用.可以只在寄存器上操作的机器被称为load/store机器,因为你必须load每个你用到的值,然后在你计算完后store每个结果.

某些处理器只操作内存数据;没有堆栈,也没有寄存器.使用这种处理器的机器被称为三地址机器(three-address machines),因为绝大多数指令有三个地址操作数(例如 ADD dest,src1,src2).由于内存带宽的限制,我认为他们不会在很多硬件中使用,但是他是虚拟机的一个选择.

对于虚拟机,堆栈机器非常容易实现,因为当你计算一个表达式时不需要临时变量来存储中间结果;你把所有东西放入堆栈(它与你处理一个后缀表达式的方法十分相似).虽然我将在这里使用临时变量.后面还有更多内容.

我不清楚三地址机器是否可能有一个优点;速度是最重要的一个,尽管我尝试了两者,我能肯定的说出哪个在优化中做了更少的计算...我想优化三地址代码更容易,所以也许这是这种机器的一个优点.

JAVA表面上使用一个堆栈机器(我听说是这样,我对JAVA VM不熟).

一件虚拟的非常容易的事(A Virtual Piece of Cake)
bl_line.jpg (1610 bytes)

我们的虚拟机对象根本就不复杂.它的最重要的成员有:一个指令数组,一个字符串表和一个堆栈.它有三个主要的接口函数:Reset,Read和Execute.

指令数组存储我们的程序包含的指令.指令类简单极了,看上去就像我们在Part 5中的中间代码使用的一样.

字符串表只是一个指针数组,它可以是NULL或者一个当前使用的字符串.这可能是一个程序的变量,或者一个堆栈中的临时变量.

我们的堆栈是由整数组成的.它们指向字符串表,使我们知道什么字符串现在在堆栈中.为什么我使用整数,而不是字符串类的指针呢?因为我想保持事物的简单(为了读者,也为了我自己):记住我们有时也想让堆栈存储布尔值,所以我们不得不建立一个存储字符串指针或布尔值的'stack item'类...现在我们只是使用一个整数:如果它是非负数,我们知道它指向一个字符串,如果它是负数它就是一个布尔值.它是脏的代码,但是他有利于工作并且每个人都可以理解它.不要在家试它,不要在一个真正的项目中使用它.

现在是接口函数.'Reset'重新初始化VM.它是一个很简单的函数.

'Read'将要在程序中读取.下次我们将改变这个函数让他从stdin中读取,但是现在它里面有一个测试程序.如果你喜欢就改写它--只是小心的让程序保持正确,不要让我们的VM崩溃.

'Execute'执行当前在内存中的程序.这也是一个简单的函数:它有一个指令指针,它察看一个指令,然后使用一个switch语句执行正确的代码.关于临时变量的一个说明:每当我们把一个变量放到堆栈,我们需要它的一个拷贝:我们不能只是把在字符串表中的变量的索引值进栈,因为他们的值可能改变并且接着堆栈中的值也会改变.这就是为什么几乎每个堆栈操作都使用NewTempCopy和DelTempCopy.

一点关于优化VM的说明:我们应该确保我们的堆栈操作尽可能的快;我们的堆栈模板不是特别的快.在字符串操作上也一样.一般而言,我们应该使通用的case快.最好把所有普通的优化技术应用到VM上.

关于VM还有很多要说:存储分配(allocation schemes),垃圾收集(garbage collection),保持他们稳定和高速,但是我想我将推延到下一部分.

下一次
bl_line.jpg (1610 bytes)

下一次我们将最终执行代码.然后我们就完成了我们的简单的脚本引擎.之后我可能给出一个复杂的真实的脚本引擎的概貌,并且讨论所需的主题.

Quote!
gl_line.jpg (1418 bytes)

"Come," called the old man, "come now or you will be late."

"Late?" said Arthur. "What for?"

"What is your name, human?"

"Dent. Arthur Dent," said Arthur.

"Late, as in the late Dentarthurdent," said the old man, sternly. "It's a sort of threat you see." Another wistful look came into his tired old eyes. "I've never been very good at them myself, but I'm told they can be very effective."

HHG 1:22

Downloads
bl_line.jpg (1610 bytes)

Download the tutorial code (tut7.zip) (5k)



返回目录
diamond Garden制作 2000年1月