字节码解释器,虚拟机简单原型

制件自己的编程语言之基础,字节码解释器,也是一个mini虚拟机。

《游戏编程模式》一书中有一章讲字节码(模式),自定义一些指令集,对应于游戏中的某些操作,由用户(不是指游戏玩家)来自由组合使用它们灵活实现一些功能。这种功能等同于提供接口给脚本使用,方式上类似于实现一个小型的虚拟机。

在这里重制一个超简单的虚拟机。

操作码(opcode)

首先确定虚拟机有哪些操作,需要的指令集(有点类似于汇编指令)。 通常都会有: * 运算操作(加减乘除等) * 比较运算 * 逻辑运算 * 条件语句 * 循环语句 * switch语句 * 函数调用

在这里只定义加减乘除操作

enum Instruction
{
    OPCODE_NUM,     // 数值(操作数)
    OPCODE_ADD,     // add op
    OPCODE_SUB,     // sub op
    OPCODE_DIV,     // div op
    OPCODE_MUL,     // mul op
};

操作数

有了上面的操作,总得有操作对象吧,这就是操作数了,也算是函数的参数吧。这些操作数是如何保存的呢?栈。

字节码解释器

字节码解释器,即不断读取字节码,并解释执行之。

class VM
{
public:
    VM() : StackIndex_(0) {}
public:
    char interpret(char bytecode[], size_t size);

private:
    int add(int left, int right);
    int sub(int left, int right);
    int div(int left, int right);
    int mul(int left, int right);

private:
    char    pop();          // 出栈
    void    push(char c);   // 入栈
private:
    static const char MAX_STACK = 100;
    char StackIndex_;
    char Stack_[MAX_STACK];             // 存入操作数的栈
};


char VM::interpret(char bytecode[], size_t size)
{
    for (size_t i = 0; i < size; i++)
    {
        // 提取操作码
        Instruction opcode = static_cast<Instruction>(bytecode[i]);
        switch (opcode)
        {
        case OPCODE_NUM:
            push(bytecode[++i]);    // 将操作数压入栈
            break;
        case OPCODE_ADD:
        {
            char a = pop();     // 从栈中取值(操作数)
            char b = pop();
            char value = a + b;
            push(value);        // 将运算结果压入栈
        }
            break;
        case OPCODE_SUB:
        {
            char a = pop();
            char b = pop();
            char value = a - b;
            push(value);
        }
            break;
        case OPCODE_DIV:
        {
            char a = pop();
            char b = pop();
            char value = a / b;
            push(value);
        }
            break;
        case OPCODE_MUL:
        {
            char a = pop();
            char b = pop();
            char value = a * b;
            push(value);
        }
            break;
        default:
            assert(false);
            break;
        }
    }

    return pop();
}

上面使用字节码的方式实现了一个解释器,具有加减乘除计算器的功能。

小结

上面的实现类似实现一套自定义的汇编指令,只要输入合法的opcode,解释器就会给出结果,是一个虚拟机的简单原型。模拟汇编语言实现一套操作,包含操作码部分的所有操作。

源码:https://github.com/huiliu/Learn/tree/master/VM

参考资料 1. 《游戏编程模式》