用300多行C++代码写一个超简单的编译器
目标
将一个可以支持输入任意多个字符串的语言的源代码编译成exe格式的可执行文件。
该语言只支持一种语句,格式是【 print(字符串); 】,也就是以【print】开头,后跟【(】, 再跟着一个【字符串】,最后跟着【)】和【;】 ,一条语句只包含5个单词,一个程序支持任意多条该语句。
麻雀虽小,五脏俱全。
流程

词法分析
词法分析就是将源代码分割成一个一个的单词,舍弃不需要的字符,比如注释等。
那么需要先定义单词的结构,先定义单词的类型:

然后是单词:

只要知道什么单词以什么开头,后面跟着什么,以什么结尾,词法分析就很简单了:




错误处理
没有哪个程序员不会写错代码的,因此,错误处理也是必不可少的一部分,这部分的主要目的是识别出语法错误,并告诉程序员在哪里出了什么错误。
这里当出现错误的时候,就简单地告诉出错信息和位置,然后结束编译。

语法分析
整个结构和词法分析差不多。

这是识别具体语句的部分:

其中还嵌入了语义分析的代码和中间代码生成的代码。
语义分析
语法分析识别出的是源代码的结构,而语义分析要判断这个语句是要做什么,能不能这么做。

因此,这里只需要判断调用的那个函数是不是“print”函数就行了。
中间代码生成
此处,我使用的是三地址码表示的中间代码,三地址码只是一个结构,该结构有一个操作码和3个操作数,并没有指定实际的操作码和操作数是什么。这些需要我们自己定义,也就是构造我们自己专属的指令集。而指令集用什么结构表示都可以,比如三地址码,抽象语法树,有向无环图等,这是多对多的关系。

汇编生成
到这一步,就是编译器的后端了,需要选择具体的机器的指令集和汇编器。不同的汇编器的汇编代码的语法可能不同。
当然也可以不生成汇编代码,直接生成可执行文件。但是这就需要了解可执行文件的结构,以及具体的指令的编码是什么了,比如nop指令的编码是0x90。
这里,我选择了686指令集已经masm32汇编器。
至于中间代码怎么转成汇编代码,基本是一条中间代码对应多条汇编代码,怎么对应?加法对加法,入栈对入栈,赋值对赋值,就是这么回事。





测试




如果汇编出错,那么很可能是没有安装masm32!!!