因为我们的 Lua
版把测试程序存为一个字符串表 program
的形式, 因此可以很简单地取得任意一条指令.
虚拟机有一个用来定位当前指令的地址计数器, 一般被称为 指令指针
或 程序计数器
, 它指向即将执行的指令, 通常被命名为 IP
或 PC
. 在我们的 Lua
版中, 因为表的索引以 1
开始, 所以这样定义:
-- 指令指针初值设为第一条
IP = 1
那么结合我们的 program
表, 很容易理解 program[IP]
的含义: 它以 IP
作为表的索引值, 去取 program
表中的第 1
条记录, 完整代码如下:
IP = 1
instr = program[IP];
如果我们打印 instr
的值, 会返回字符串 PSH
, 这里我们可以写一个取指函数 fetch
, 如下:
function fetch()
return program[IP]
end
该函数会返回当前被调用的指令, 那么我们想要取得下一条指令该如何呢? 很简单, 只要把指令指针 IP
加 1
即可:
x = fetch() -- 取得指令 PSH
IP = IP + 1 -- 指令指针加 1
y = fetch() -- 取得操作数 5
我们知道, 虚拟机是会自动执行的, 比如指令指针会在每执行一条指令时自动加 1
指向下一条指令, 那么我们如何让这个虚拟机自动运行起来呢? 因为一个程序直到它执行到 HLT
指令时才会停止, 所以我们可以用一个无限循环来模拟虚拟机, 这个无限循环以遇到 HLT
指令作为终止条件, 代码如下:
running = true
-- 设置指令指针指向第一条指令
IP = 1
while running do
local x = fetch()
if x == "HLT" then running = false end
IP = IP + 1
end
说明: 代码中的
local
表示x
是一个局部变量, 其他不带local
的都是全局变量
一个虚拟机最基本的核心就是上面这段代码了, 它揭示了最本质的东西, 我们可以把上面这段代码看做一个虚拟机的原型代码, 更复杂的虚拟机都可以在这个原型上扩展.
不过上面这段代码什么具体工作也没做, 它只是顺序取得程序中的每条指令, 检查它们是不是停机指令 HLT
, 如果是就跳出循环, 如果不是就继续检查下一条, 相当于只执行了 HLT
.