启
前排警告,Rust注意!!!
上班总是CURD,摸鱼太多,一直没有目标。看到说程序员有三大浪漫:操作系统、编译原理和图形学。作为个不专业的程序员,我只能选择编译原理来摸索一下,来恶补基础知识。于是乎,就有了这坨东西evalit。
当然啦,也没有这么简单,一开始的时候,是看到了这个expr,得到了启发,觉得可以搞个类似东东来做个脚本工具来方便集成到程序里面,方便一些自定义、可编程的操作。至于现在这坨成果,那就有点离题万里。
翻开提交记录,赫然看到第一次提交代码是在2023年9月1日。间间断断,有闲心就摸鱼写写,终于在近段时间,能搞出个能用的版本(代码是被强行rebase过的,记录也不完整了)。
中间写时,没有规划,也没有设计,一直把框架变来变去,也是重构过好几版。就目前的情况,也只能说能跑,至于结果吗,也不知道它会不会跑乱掉。
总体而言,可以看到一个不专业的程序员,能写出一个多垃圾的解释器。各位看到的话,要引以为鉴,切勿模仿。
承
总览上来看,这是一个语法解释器,可以编译一段代码到ByteCode,然后跑在一个基于寄存器的虚拟机上。
如果各位不怕脏了眼睛,打开这项目,会发现这些:
语法设计
说是设计,其实是没有设计,只有抄袭,而且还抄得不对,233。
首先,一切都是对象?该语法只有一些简单类型:
| type | rust type | description |
|---|---|---|
bool | bool | 布尔值 |
int | i64 | 整型数 |
float | f64 | 浮点数 |
string | String | 字符串 |
array | Vec | 数组 |
map | HashMap<String, T> | 映射 |
再就是运算符:只有简单的:
| operator | description |
|---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 取余 |
== | 相等 |
!= | 不等 |
< | 小于 |
<= | 小于或等于 |
> | 大于 |
>= | 大于或等于 |
&& | 逻辑与 |
|| | 逻辑或 |
有限的控制流:
| control flow | description |
|---|---|
if | 条件 |
while | 循环 |
for | 迭代器 |
break | 跳出循环 |
continue | 跳过当前循环 |
return | 返回 |
实现
整体解释器实现,会有几块:
-
语法解析。就是一个parser,解析出AST。使用pest写的。自己手写的词法解析,也不是不行,但是要应对各种语法处理逻辑,估计也写不好,还是直接用pest比较方便,就是要查查文档,对着各种已有的例子抄一抄就行了。
-
语义检查和类型检查。这个没什么好介绍的,其实就是脱裤子放屁啦,这么点的语法解释器,也用不上这个大杀器,其实多余的。问就是AI生成的,代码不是自己写。
-
Lowering。话说这个的中文是叫什么?就是把AST转化为IR。对的,这个项目,是搞了奇葩的IR层,其实没有什么意义的,特别是对于解释器来说。
-
Codegen。应该叫代码生成?就是把上面的IR转为为ByteCode。为啥啊,单纯为了照顾坑爹的VM。同时,里面还有个搓搓的寄存器分配器,这个需要特别注意,千万不要去看,因为里面都是坑,没有正确的算法支撑,写的时候折腾最久,一切都是靠磨出来的,只依赖项目几个有限的测试用例来保证一下它可能是符合运行预期的。
-
Runtime。就是上面提到的虚拟机以及围绕它的一些数据结构等等。这个坑爹虚拟机是基于寄存器,里面会模仿x86的一些行为,比如calling convention,函数调用使用压栈入参,函数局部变量使用寄存器和栈。注意啦,这个虚拟机的操作对象都是一个个Object哈,还记得上面说过的一切都是对象么,所有寄存器和栈里面都是
Arc<RwLock<Box<dyn Object>>>。嘛,反正也没追求什么性能。 -
GC。哈哈哈,想多了。这坨东西没有设计有垃圾回收,你都看到了,它用的是Arc。所以它没有正确垃圾处理,反正一直不回收也是一种垃圾处理嘛。对了,这样的它是应对了不了循环引用的。使用的时候请注意啦,小心它会一口一口吃掉你的内存。
转
假如看到了上面的说明,都还在看的话,可以说一下这个项目可以做到什么了。
-
它有几个有限的单元测试。里面可以看到,这个解释器可以完成一个简单的fib计算。就是斐波纳契数列的前10个总和会是143。
-
正如scripting的例子里面展示的那样,可以嵌入async的rust里面,满足一些简单脚本功能,调用通过调用rust的暴露进去的方法来完成写逻辑处理。
合
总的来说,作为一个不专业的程序员,写出的这坨糟糕的解释器,暴露了很多问题:
-
首先,项目规划,应该是要有设计,有想法,特别是要有技术支撑。不是科班出身,没有系统学过编译原理这一块的东西,靠着自己折腾,是很难搞的。
-
其次,自身不行,AI来凑。目前来说,AI是能用的,特别用于帮忙梳理思路和补全代码;但是它的能力有限,现在仍然有些问题。等它发展起来,估计我这等混子程序员就要被淘汰了。
-
最后,自己写代码,自己写代码,自己写代码。纸上得来终觉浅,绝知此事要躬行!
最后的最后,项目的地址是这个:https://github.com/zzzdong/evalit。
PS:不排除下一步搞一个可以本地运行的native语言。就是用pest解析语法,cranelift生成机器码,mmtk来做垃圾回收,类似Go的模样。