- 需要有基本的编译原理常识。构造基本的编译原理常识,一方面来自于对已有语言的使用经验,了解基本术语。比如用C,那么起码知道语言要素包括宏、表达式、语句、语句块、函数、指针等;还知道C语言有编译、链接和执行三个阶段。这些基本概念对宏观掌握学习进程是很有必要的。另外一方面编译原理的常识,要来自图书。比如龙书、SICP。在这一步,得知道大部分语言的处理都要分为词法、语法、语义和代码生成四个阶段。每个阶段,分别是做什么的。
- 了解具体的编译算法。了解到什么程度,取决于使用第三方工具,还是需要自己从字符开始处理。个人建议,乔姆斯基文法体系、(扩展)巴克斯范式(EBNF),正则表达式,和LL(1)的递归下降分析法是必须要掌握的。对LL(k),LR(k)要有概念。其中,四则运算表达式的分析是很好的练习。
- 对语法的感觉。初学者设计语言的难度有两点。第一,不知道什么样的语法/语义是需要的;第二,不知道设计的文法能否实现。如果练习过递归下降法,应该已经有了基本的感觉。这个时候可以试图实现熟悉的语言。一些常用语言的Grammar Rule都是可以查到的。虽然这些语法,特别是C++,可能是上下文相关的所以用书上的办法难以实现,但是可以实现它的一个子集。通过这样的练习,能对掌握的分析算法能完成什么样的工作就有了个大致的体验。
- 深入了解自己的领域,明确需求。是需要一个类似于自然语言的脚本,还是只是一个表达式。经过3阶段的训练已经有了独立撰写语法的能力。可以写一个基础版本的出来。
- 实现自己的语言,特别是词法和语法部分。这一步最好能Log出尽可能多的信息,例如词列表并打印出分析树。
- 当有了分析树后,就可以去做语义分析了。对于初学者而言,语言的规模要尽可能小,这样语言的解释和语义分析可以合为一体,不用担心哪个部分算是代码生成,哪个部分算是语义分析。所以这一步最好能把解释器也写出来。这一步的要求很简单,知道符号表是做什么的,学会归纳和推导类型,能正确的处理分支和循环语句(如果有的话)。
- 设计一门类似于ASM的VM语言,可以是堆栈机模型,也可以是寄存器机模型。撰写代码生成从语法树上生成这个VM语言出来。并写一个VM的执行器。这一步看起来无从下手,实际上只要肯写,不出一个礼拜就知道怎么做了。一开始这个VM语言可以只用做整数的加减乘除就行了,以后可以慢慢加其他比较重要的特性,比如运行栈啦、代码地址啦,跳转啦等等。另外,把LLVM作为目标也是不错的选择,起码指令的解释不用自己费工夫了,LLVM的手册读起来也很容易。那个Tutorial写的特别好。
至此,语言就初步建立完成了。但是因为一开始能力有限,所以设计出来的语言是磕磕巴巴的。这个时候可以选择:
- 向某个现有的语言靠拢;
- 自己去了解现有语言的机制并进行权衡。这个时候什么动态/静态类型,函数是first class,类和对象才是该考虑的问题。这个时候一定要多读、多用现有的语言。拜编译器经验所赐,会站在一个不同角度上来对待现有的语言;
- 学习Functional Programming,这对设计更好用的文法、更快的编写和修改编译器都有莫大的帮助。例如可以使用Combinator在C++中以类似于DSL的方式配置语法;
- 剩下的就是在Language领域无止尽的挖掘了。上下文相关的语法、语法糖的设计、运行时的辅助机制(例如async,await这些广义上的控制流语句),GC,类型推导和静态分析等等。;
- 最后也是最重要的,充分理解需求,才能在诸多语言要素间做出取舍。
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-08 04:34:36