自制动态语言Medusa的解释器

今天整理了一下学习编译原理时,实现语言Medusa时写的笔记,搞出了一篇类似说明文档的东西,介绍下Medusa


语法部分

Medusa是一门动态脚本语言,语法和代码格式借鉴Python,运行代码在顶层书写。

Medusa不识别':' ';'等符号,但识别white spcae和换行符:
1 + -9:执行结果是-8
1 + - 9:语法分析错误

语句Statement暂分func defination、if、while、return、expression几类。
若干statements组成block,由'{'、'}'分隔,block是def、if、while句式 的主体结构
if expression { statements } else { statements }
while expression { statements }
def name( paras ) { statements }

顶层代码定义的变量将放入global  environment 中,block的执行将有自己的local environment,并且local env带有指向父环境的指针

函数定义以'def'关键词起始,不支持在block中定义函数,所有的函数由func_list列表保存

Medusa带有简单的报错处理,错误信息有行号、字符位置、出错记号流以及提示,水平有限,不支持错误校正、预测处理,报错后即终止程序。


内部设计和结构

interpreter
解释器类,包含解释过程中需要的绝大数的数据结构,如记号流、函数表、全局环境、stack等等。init过程完成初始化工作,并向函数表中添加内置函数,目前内置函数仅有print函数

词法分析:
使用自己写的正则表达式引擎(支持基本的正则符号:'?' '*' '+' '|' '('和')'),构建状态机输出,状态转移矩阵。词法scaner对源程序文本做检查,输出记号流,遇到不符合正则规则的字符串,报错并exit。
构造状态机的算法:首先将正则的中缀形式转换成后缀形式,例如a|b|c|d变为a b c d | | |,使用栈完成不确定有限状态自动机的构造,再利用闭包算法将NFA转换为DFA。

语法分析:
过程没有使用yacc、bison等自动生成器,使用递归下降算法手写而成,程序的上下文无关语法表示如下:
proc -> def id(id...){ statements }
         |statement
statement -> return exp 
               | exp
              | if exp {statements} else {statements}
              | while exp {statements}

表达式exp使用算术运算符、比较运算符、赋值运算符连接callfunc(函数调用)、variable(变量)、literal(字面常量)等节点, 在语法分析模块中的表示形式是AST。 Medusa 没有bool型变量,不同于C、c++中可将数值型转换为bool型, if、while句子只判别exp结果非0和0
语法分析过程还将向函数表添加自定义函数

语义分析:
由于Medusa是一门动态类型的语言,变量不需要声明,直接定义并使用,所以传统语义分析中的类型检查部分实现较难,解释器将此功能化为执行期执行,而变量符号表也随之移到执行期间建立

执行:
execute.cc为执行过程代码,执行statements,最重要的exp执行过程是后序遍历AST树,递归调用求解表达式的值;
执行过程解释器还将完成垃圾回收工作,gc算法是mark&sweep
符号表 以 pair<string,MdsObject*>形式表示了程序上下文, 多个env对象可区分程序的作用域,每个env对象都有parent域指向父环境,最顶层的env就是global env,当前作用域没有变量声明时,搜索上层环境;
stack用于保存exp计算时的临时值,这些值没有变量名。

内存分配:
采用两级分配器模型,最底层是封装了malloc、free函数的内存池,用于向内核申请大块内存;次级分配器是对象分配器,维护了多条空闲区域链表,链表放置了大小8、16、24...126字节的空闲区域,解释器空间申请将从这里得到满足,空闲区域不足时将向内存池申请新的空间。分配的内存块前置一个BlockMeta类,放置mark标志位和大小信息。
(内存模块是为了个人理解内存模型和分配策略而造的轮子,实际上malloc、free即可,这里说明一下)

变量模型:
Medusa的类型舍弃了C、JAVA中的原始类型设计, 变量的值不在放在变量内,而是 参考了python,采用引用模型。 Medusa包含三个内置类型,int、string、list,为了减少工作量,省去了float、bool、long等类型。三种内置类型分别对应MdsIntObject、MdsStringObject、MdsListObject三个类,继承自MdsObject,利用多态实现不同的调用以及提供统一的上层接口;
所有的值对象在内存中都只有唯一的拷贝,并且放入int_map、string_map、list_map三张表中,表的索引分别是对象值的hash值( int、char*、void*[] );
env维护的是一个 “pair<string(变量名),  MdsObject* >” 的数组;
表达式“c = a+b”的执行如下:在local env中寻找关键字“a”、“b”,提取变量值,即 MdsObject的指针,计算两个对象的相加值,并利用结果的hash值在 int_map、string_map、list_map寻找对象,没有则新建并插入,最后将env中关键字“c”项的内容写为结果对象的地址。

gc:
Medusa支持对象的垃圾回收,mark&sweep的起始点为全局环境、函数局部环境链表、用于运算过程的stack容器中的对象(保存临时变量)。gc触发时机是每16次内存申请操作时。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Medusa是一个基于深度学习的图像生成模型,它可以生成逼真的人脸图像。下面是一个简单的Medusa使用教程: 1. 安装依赖:首先,你需要安装Python和一些依赖库,比如TensorFlow和NumPy。你可以使用pip命令来安装它们: ``` pip install tensorflow numpy ``` 2. 下载预训练模型:Medusa的开发者已经在GitHub上提供了预训练模型,你可以从以下链接下载: ``` https://github.com/Psyche-mia/Medusa ``` 3. 导入模型和相关库:将下载的预训练模型文件导入到你的项目中,并导入相关的库: ```python import tensorflow as tf import numpy as np # 导入预训练模型 model_path = 'path_to_model/medusa.pb' with tf.gfile.GFile(model_path, 'rb') as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) tf.import_graph_def(graph_def, name='') ``` 4. 生成图像:使用Medusa生成图像的过程涉及到向模型输入噪声并获取输出图像。以下是一个简单的函数来执行这个过程: ```python def generate_image(): with tf.Session() as sess: input_tensor = sess.graph.get_tensor_by_name('input:0') output_tensor = sess.graph.get_tensor_by_name('output:0') # 生成噪声 noise = np.random.randn(1, 512) # 输入噪声并获取输出图像 generated_image = sess.run(output_tensor, feed_dict={input_tensor: noise}) # 将图像从[-1, 1]范围转换为[0, 255]范围 generated_image = (generated_image + 1) * 127.5 # 显示生成的图像 plt.imshow(generated_image[0].astype(np.uint8)) plt.show() ``` 5. 调用生成函数:调用上述生成函数来生成图像: ```python generate_image() ``` 这只是一个简单的Medusa使用教程。你可以根据自己的需要对其进行更多的定制和扩展。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值