我写了“半个”解释器
导读
本文建议有一定计算机基础的同学阅读。一共1131个字
一
在刚开始写Python
的时候,我就有一个很好奇的点,Python
有好几种解释器,其中甚至还有一种用Python
写的解释器(自己解释自己)。
前段时间刚好得空,做了一些调研,也看了一些书,动手用Go
写了“半个”解释器,也完完整整的学习了一下解释器相关的知识。
至于为什么是“半个”,是因为我只写了语法解析部分,没有写求值部分。
PS: 现在要写一个解释器并不是啥难事,只要有心,网络上相关的资料和书籍有非常多。
二
用大白话来说,解释器其实就是一个翻译官,把编写的代码翻译成机器码,让计算机运行的这么个东西。
运行原理也很简单,先把代码结构化为解释器内部的结构,然后进行计算,最终得到一个结果。
明白了上文的内容后要动手写一个解释器其实也没有非常复杂,代码本身来说就是一串文本,解释器首先会一个字符一个字符的读取代码,其次把读取到的代码按照一定的规则转化成解释器内部的语法树(AST
),最后进行计算求值。
一定的规则,实际上就是每种编码语言的规范,例如怎么定义变量,怎么声明函数等等。
三
写解释器的过程,跟我们平时写业务代码差不多。
平时我们进行开发的时候,都是一个个的功能模块,然后通过RPC
(或者内存)调用,把这些功能模块串联起来。解释器也类似,只不过解释器的功能模块是ast
、lexer
、parser
等等。
四
解释器的优化(一般来说是求值部分),跟我们平时做业务代码的调优也是一样的。我们日常在进行代码优化的时候,是根据实际运行的情况,有的放矢的进行调整,并没有一个”绝对正确“的方案。解释器也是一样的,通常来说都会综合考虑运行速度,消耗内存以及安全等方面。当然,大部分的优化方向是让它们运行的更快。
Lua编程语言的主要实现最初是解释器,该解释器能生成字节码并在基于寄存器的虚拟机中执行字节码。在该语言首次发布的12年后,诞生了另一种实现:LuaJIT。LuaJIT的创建者Mike Pall的目标很明确,那就是创建最快的Lua实现。方法是使用JIT将紧凑的字节码格式编译为针对不同体系结构且高度优化的机器代码。这样LuaJIT在所有基准测试中均击败了原来的Lua实现,而且提升不是一点点,有时会快50倍。
五
这个过程,确实学习到了挺多东西的,同时也对一些领域的认知有了一些改观。
例如常见的代码规范检查工具的运行机制,基本上可以推断出来是一个不求值的解释器。
又或是一些自动生成代码的过程,以前我的做法都是直接用模板替换,现在来看,逆向AST
来实现会更优雅并且多样化程度更高。
同时对于编译器的一些实现也能有一个很好的理解和推断。
六
本人对解释器这块了解程度也确实比较粗浅,如有错误欢迎指正。