Python-构建篇-解释器-03~04

前言

部分变量的定义请自行处理

03

读取

我们思考下,如何让解释器读取用户编写的源代码呢?

我们可以使用文件来存储用户编写的源代码,然后使用with open打开源代码文件,再用for循环读取每一行内容

注意:为了确保复用性,我们将其封装为函数,我们让这个函数接收3个参数,content(用户编写的源代码文件路径),env(Environment对象),line_num(起始读取行,默认1)

def stcode(content, env, line_num):

然后我们定义一个局部变量,这个局部变量的值为env对象的variables字典

global_vars = env.variables

但是停一下,我们不能确定后面会使用到多少次global来获取访问和修改global_vars,所以我们需要创建一个函数,使得允许在函数内部通过这些函数来间接访问和修改全局变量

这个函数应接收一个参数name,并让其返回global_vars字典中对应键的值(键为name参数)

同时在内部应再定义一个函数,让它接收两个参数,name以及value,让其能重新将字典里键为参数name的值重新赋值为value,但若此键不存在,就让其创建一个新键值对

最后我们让它用globals函数返回一个字典,再让它将globals_getglobals_set两个函数分别作为get_variableset_variable 加到全局符表中

def globals_get(name):
        return global_vars.get(name)
    def globals_set(name, value):
        global_vars[name] = value
    globals().update({
        'get_variable': globals_get,
        'set_variable': globals_set
    })

接着就是读取源代码文件,并for循环读取每一行内容

with open(content, 'r',encoding="utf-8") as file:
        filepathdpc2 = content
        line_num = 1
        for line_num, line in enumerate(file, start=line_num):
            line = line.strip()

04 

 执行

在解释器能正常读取源代码文件后,我们就要让解释器每读取一行内容就解析一行内容;

我们可以设置关键字/词,当解释器在解析时若遇到关键字/词则执行对应的操作

我的思路是一个关键词为一个函数,外加上简单的映射处理,在部分情况下需要考虑用到正则表达式,比如注释符的位置...

由于需要去考虑控制流结构,所以传统的if,elif...依次判断来作为一级执行肯定不行

这些判断最多只能作为二级执行,而一级执行应考虑的是设置一个关键变量判断,在遇到控制流结构时,将这个变量设置为是否触发的关键标准

它将作为权衡一二级执行+平衡各控制流结构之间的中心;

但还要注意的是各个关键词的上下顺序,哪个放在关键变量判断之前,哪些放在关键变量判断内

以及执行完控制流结构后对关键变量的处理

所以根据上面描述,我们可以敲定:

控制流结构触发关键词放在关键变量判断前,非控制流结构函数触发关键词放在关键变量判断内部

所以我们定义一个全局变量:doom,并在stcode函数内部global它

我的思路是doom为0就可以进入二级执行,反之doom-1

global doom
#控制流结构关键词部分
if doom == 0:
    #非控制流结构关键词部分
else:
    doom-=1

在这里作为一个示例,我只会讲两个,实际上许多函数的实现都是直接套模板就行,拿参数,再调用python内置函数就行了;

后面讲的就是控制流结构部分和GUI部分的了

注释符

在这里注释符我以//为标准

首先判断解释器当前读取的这一行内容有没有其触发的关键字/词

if 'xxx' in line:

在这里由于是注释符,所以我就写为

if '//' in line:

当if成立时该做什么呢?既然是注释,所以注释的内容是不参与其执行过程的,所以我们就可以跳过这一行内容

continue

但是这就完了吗?肯定不是,如果你去测试,你就会发现,当一行内容里只要有//出现这一行就会被注释掉,所以我们要限制它,我们可以使用正则表达式,来确保//只在一行内容最前时才生效

我们要让这个正则表达式匹配以 #// 开头的行,如果匹配则返回true,反之false

def zsfxjh_match(linecon):
    comment_pattern = re.compile(r'^[ ]*#|^[ ]*//.*')
    if comment_pattern.match(linecon):
        return True
    else:
        return False
if zsfxjh_match(line):
    continue

赋值

若不是我在上面写了取两个示例,或许我都忘了这一茬

赋值实际上很简单,我们先要判断是否存在关键字等号

if '=' in line:

如果存在我们就可以用split将等号左右分割,这样就可以得到变量和其要赋予的值

但是不要忘了检查哟,避免用户coding错误

然后拿到name和expr值,记得去除空白字符

but,还要再判断一手,在值那(expr)是callback和直接赋值

如果是callback那就是判断其有左括号,反之为直接赋值

但是我们还得思考一下如果是callback该怎么做

这时我们就可以考虑去再执行一次stcode函数

什么意思呢?也就是获取expr内容,并将其写入临时文件,再调用stcode来执行这个临时文件

但是这是两个不同的执行,那怎么获取其返回值呢?

先定义一个全局变量ycc_bl,然后新增一个函数,函数接收三个参数:变量名称,执行代码,env对象

在函数内,global刚定义的全局变量ycc_bl,然后我们调用另外一个函数(不必多说),这个函数的参数将接收参数执行代码的值,最后返回临时文件路径;我们调用stcode函数,最后使用env对象的set_variable方法来赋值即可
 

def temp_while2(temp_content):
    with tempfile.NamedTemporaryFile(mode='w+', delete=False, encoding='utf-8') as temp_file:
        temp_file.write(temp_content)
        temp_file.seek(0)
        temp = temp_file.name
        return temp
def open_fz(blname,code_line,env):
    global ycc_bl
    file_pathbn = temp_while2(code_line)
    stcode(file_pathbn,env,1)
    env.set_variable(blname, ycc_bl)
parts = line.split('=', 1)
    if len(parts) == 2:
        name, expr = parts
        name = name.strip()
        if '(' in expr:
            open_fz(name,expr,env)
        else:
            env.set_variable(name, expr)

最重要的一点:
比如说我设置了一个函数'MD5'

那么在函数md5实现内部,我就应该加入ycc_bl = xxx

来确保这个函数可以返回值

if 'md5' in line:
    xxxx...
    xxxx...
    a = xxx...
    ycc_bl = a #实现callback

End

只要不是控制流结构关键词的判断都放在doom判断内

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值