超级简单的虚拟机(Python 实现)(文末有赠书)

点击上方“Python爬虫与数据挖掘”,进行关注

回复“书籍”即可获赠Python从入门到进阶共10本电子书

雄关漫道真如铁,而今迈步从头越 。

我们这次实现的简单虚拟机,和计算机的 cpu 有点类似。无非就是取指令,执行指令之类的操作。

常见的虚拟机通常分为两类,一种是栈式虚拟机,另一种是寄存器虚拟机。比如说 CPython, Jvm 就是基于栈的虚拟机,而 lua 则是基于寄存器的虚拟机。

我们这次实现的“玩具”虚拟机,就是一种基于栈的虚拟机。

虚拟机有三个重要属性,code 代表要执行的指令列表,stack 用于保存临时变量,而 addr 代表当前指令的地址。

# Python高效编程
class Machine:
    def __init__(self, code):
        self.code = code
        self.stack = list()
        self.addr = 0

原理其实很简单,我们通过不断获取当前指令地址,从指令列表中获取指令和数据,如果是数字或者字符串,就压入栈中;如果是指令,就执行相应函数。

为了少些几个字符,我们向 Machine 类中添加几个方法:

def push(self, value):
    self.stack.append(value)

def pop(self):
    return self.stack.pop()

@property
def top(self):
    return self.stack[-1]

我们通过 dispatch 方法,来判断当前从指令列表中取得的片段是指令还是数据:

def dispatch(self, opcode):
    dispatch_map = {
        "%":        self.mod,
        "*":        self.mul,
        "+":        self.plus,
        "-":        self.minus,
        "/":        self.div,
        "==":       self.eq,
        "cast_int": self.cast_int,
        "cast_str": self.cast_str,
        "drop":     self.drop,
        "dup":      self.dup,
        "exit":     self.exit,
        "if":       self.if_stmt,
        "jmp":      self.jmp,
        "over":     self.over,
        "print":    self.print,
        "println":  self.println,
        "read":     self.read,
        "stack":    self.dump_stack,
        "swap":     self.swap,
        }
    if opcode in dispatch_map:
        dispatch_map[opcode]()
    elif isinstance(opcode, int):
        self.push(opcode)
    elif isinstance(opcode, str)\
        and opcode[0] == opcode[-1] == '"':
        self.push(opcode[1:-1])

dispatch_map 就对应我们在 Machine 类中实现的方法。

比如说 plus 方法和 jmp 方法:

def plus(self):
    v2 = self.pop()
    v1 = self.pop()
    self.push(v1 + v2)


def jmp(self):
    addr = self.pop()
    if 0 <= addr < len(self.code):
        self.addr = addr
    else:
        raise RuntimeError("addr must be integer")

其余方法也很简单,大家可以直接查看源代码。

好了,在加入一个 run 函数,我们就可以解释代码了。只要当前地址小于指令长度,就不断取指令,执行指令。

def run(self):
    while self.addr < len(self.code):
        opcode = self.code[self.addr]
        self.addr += 1
        self.dispatch(opcode)

我们创建 Machine 类,并执行 run 函数,注意字符串要用引号括起来

>>> from vm import Machine
>>> Machine([521, 1314,"+", 6, "*","println"]).run()
11010

我们还可以给虚拟机加一个交互式界面:

def repl(prompt="VM>> "):
    welcome()
    while True:
        try:
            text = read(prompt)
            code = list(tokenize(text))
            code = constants_fold(code)
            Machine(code).run()
        except (RuntimeError, IndexError):
            stdout.write("1表达式不合法\n")
        except KeyboardInterrupt:
            stdout.write("请使用exit退出程序\n")

在读取用户输入字符串之后,对字符串处理:

def parse_word(word):
    try:
        return int(word)
    except ValueError:
        try:
            return float(word)
        except ValueError:
            return word

def tokenize(text):
    for word in text.split():
        yield parse_word(word)

最后放张效果图:

文章源代码详情:https://github.com/xflywind/vm

文末送书:在公众号后台回复“送书”两个字,将有机会参与到《深入PHP》的送书活动中来,看大家的手气啦~~

------------------- End -------------------

往期精彩文章推荐:

欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持

想加入Python学习群请在后台回复【入群

万水千山总是情,点个【在看】行不行

/今日留言主题/

你认为这个世界上最好的编程语言是什么?

尖科超级脚本虚拟机是一个功能强大、基于微软Windows系统操作系统的脚本虚拟机<br/>主要功能有:支持多种脚本语言,并且可以同一脚本文件中使用不同的语言,并且通过共享内存方式共享不同语言的脚本的数据。支持图形界面的开发,通过CForm对象的CreateForm方法创建具有可处理事件的Windows标准图形窗体,并且基于VB的控件管理技术让你使用Windows标准控件及处理他们的事件。<br/>支持控制台程序的开发,开发出基于命令行交互的程序。<br/>你可以用VBScript来创建图形界面,用JavaScript来处理他们的事件,内置的App类可以管理你的程序,内置文件系统CFileSystem类,输入输出CFileIO类,及注册表访问CRegistry类等,功能不断加入中...<br/>下载包内有详尽的使用例子!<br/><br/>模块表:<br/><br/>APP 程序类<br/>CommonDlg 通用对话框类<br/>CConsole 控制台类<br/>CFileIO 文件输入输出类<br/>CFileSystem 文件系统类<br/>CForm 窗体管理类<br/>PrintPreView 打印预览类<br/>Collection 数据集类<br/>CRegistry 注册表操作类<br/>CScriptEngine 脚本引擎类<br/>CSharedMem 共享内存类<br/>CWin32 Win32类<br/>SuperScript.ApiControl 提供纯 API的控件近28个控件:<br/> ApiGroupBox = 0 ;分组框<br/> ApiCmdButton = 1 ;命令按钮<br/> ApiCheckBox = 2 ;检查框<br/> ApiRadioButton = 3 ;单选按钮<br/> ApiLabel = 4 ;标签<br/> ApiTextBox = 5 ;文本框<br/> ApiMutilLineTextBox = 6 ;多行文本框<br/> ApiIPField = 7 ;IP地址框<br/> ApiRichEdit = 8 ;丰富文本框控件<br/> <br/> ApiTreeView = 9 ;树形框 ;windows 标准通用控件<br/> ApiListView = 10 ;超级列表框<br/> ApiProgressBar = 11 ;进度条控件<br/> ApiStatusBar = 12 ;状态栏<br/> ApiPageScroller = 13 ;页面滚动控件<br/> ApiToolBar = 14 ;工具栏<br/> ApiTabCtl = 15 ;类似SSTab控件<br/> ApiTrackBar = 16 ;调节杠控件<br/> ApiUpDown = 17 ;调整框<br/> ApiDateTimePicker = 18 ;日期型控件<br/> ApiCalendar = 19 ;日历<br/> ApiCombo = 20 ;组合框<br/> ApiComboEx = 21 ;增强型列表框<br/> ApiImageBox = 22 ;图形列表框<br/> ApiListBox = 23 ;列表框<br/> ApiReBar = 24 ;Coolbar似的工具栏容器控件<br/> ApiHotKey = 25 ;用于设置热键的控件<br/> ApiAnimation = 26 ;AVI动画播放控件<br/> ApiToolTip = 27 ; 气球提示控件<br/> ApiImageList = 28 ;图片列表<br/>SuperScript.vbaDataField 提供对数据库字段绑定的控件<br/>Frm 窗体模板<br/>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值