Python写的Python解释器(三)

编译自:http://www.aosabook.org/en/500L/a-python-interpreter-written-in-python.html 作者:Taavi Burns 翻译:鸿 如有翻译问题或建议,请公众号留言

变量 接下来,给解释器添加变量。 变量需要一条指令来存储变量的值,STORE_NAME; 一条检索它的指令,LOAD_NAME; 以及变量名称到值的映射。 目前,先忽略命名空间和范围,将变量映射存储在解释器对象本身上。 最后,除了常量列表之外,我们必须确保what_to_execute具有变量名称列表。

>>> def s():
...     a = 1
...     b = 2
...     print(a + b)
# a friendly compiler transforms `s` into:
    what_to_execute = {
        "instructions": [("LOAD_VALUE", 0),
                         ("STORE_NAME", 0),
                         ("LOAD_VALUE", 1),
                         ("STORE_NAME", 1),
                         ("LOAD_NAME", 0),
                         ("LOAD_NAME", 1),
                         ("ADD_TWO_VALUES", None),
                         ("PRINT_ANSWER", None)],
        "numbers": [1, 2],
        "names":   ["a", "b"] }

现在新实现如下: 为了跟踪哪些名称绑定了什么值,我们将添加一个环境(environment)字典到init方法。 我们还会添加STORE_NAME和LOAD_NAME。 这些方法首先查找变量名称,然后使用字典来存储或检索其值。现在指令中的参数意味着两个不同的东西了:既是“数字”列表的索引,也可以是“名称”列表的索引。 解释器通过检查正在执行的指令知道它应该是哪个索引。 实现这种逻辑(指令和参数的映射关系)。

class Interpreter:
    def __init__(self):
        self.stack = []
        self.environment = {}
    def STORE_NAME(self, name):
        val = self.stack.pop()
        self.environment[name] = val
    def LOAD_NAME(self, name):
        val = self.environment[name]
        self.stack.append(val)
    def parse_argument(self, instruction, argument, what_to_execute):
        """ Understand what the argument to each instruction means."""
        numbers = ["LOAD_VALUE"]
        names = ["LOAD_NAME", "STORE_NAME"]
        if instruction in numbers:
            argument = what_to_execute["numbers"][argument]
        elif instruction in names:
            argument = what_to_execute["names"][argument]
        return argument
    def run_code(self, what_to_execute):
        instructions = what_to_execute["instructions"]
        for each_step in instructions:
            instruction, argument = each_step
            argument = self.parse_argument(instruction, argument, what_to_execute)
            if instruction == "LOAD_VALUE":
                self.LOAD_VALUE(argument)
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES()
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER()
            elif instruction == "STORE_NAME":
                self.STORE_NAME(argument)
            elif instruction == "LOAD_NAME":
                self.LOAD_NAME(argument)

虽然只有五条指令,但是run_code方法开始变得单调乏味了。 如果继续保持这种结构,就需要给每条指令一个if语句分支。这时可以利用Python的动态方法查找进行简化。 定义一个名为FOO的方法来执行名为FOO的指令,所以我们可以使用Python的getattr函数来实现方法查找,而不是使用大量的if语句。 run_code方法看起来像这样:

 def execute(self, what_to_execute):
        instructions = what_to_execute["instructions"]
        for each_step in instructions:
            instruction, argument = each_step
            argument = self.parse_argument(instruction, argument, what_to_execute)
            bytecode_method = getattr(self, instruction)
            if argument is None:
                bytecode_method()
            else:
                bytecode_method(argument)

原文发布于微信公众号 - 鸿的学习笔记(shujuxuexizhilu)

原文发表时间:2018-05-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏lgp20151222

ResultSet相关ResultSetMetaData详细

DatabaseMetaData 有关整个数据库的信息:表名、表的索引、数据库产品的名称和版本、数据库支持的操作。 ResultSet 关于某个表的信息或一...

18420
来自专栏晨星先生的自留地

mysql注入高级篇3--报错注入

21940
来自专栏coder修行路

Go基础之--操作Mysql(二)

在上一篇文章中主要整理了Golang连接mysql以及一些基本的操作,并进行了大概介绍,这篇文章对增删查改进行详细的整理 读取数据 在上一篇文章中整理查询数据...

62560
来自专栏码匠的流水账

聊聊spring for kafka的AckMode

本文主要讲述一下spring for kafka的consumer在spring.kafka.consumer.enable-auto-commit是false...

54420
来自专栏北京马哥教育

10分钟学会理解和解决MySQL乱码问题

本文将详细介绍MySQL乱码的成因和具体的解决方案。在阅读本文之前,强烈建议对字符集编码概念还比较模糊的同学 阅读下博主之前对相关概念的一篇科普:十分钟搞清字符...

31380
来自专栏求教

哪位大神指点下

File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\logging\...

11000
来自专栏V站

Python的flask:models.py来创建mysql数据库

46160
来自专栏张善友的专栏

LINQ to SQL集成到应用程序中需考虑的一些问题

1、LINQ to SQL集成到应用程序中需考虑的一个问题, 到底应该返回IQueryable<T>还是IQueryable? 或许这个列表还应该继续扩展为T,...

22160
来自专栏wym

手把手教你写linux系统下贪吃蛇(二)

创建线程后把第一篇用到的refresh()函数都删除,不然因为缓存区的原因产生乱码

24420
来自专栏Python

Django---ORM操作大全

前言 Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:...

1.1K100

扫码关注云+社区

领取腾讯云代金券