编译原理入门课:(前言)实现一个表达式解析计算器

3,411 阅读5分钟

原文地址:苹果梨的博客

首先要聊聊我为什么想要写一篇编译原理的入门课。熟悉我的人可能会知道,我喜欢把复杂难懂的东西拆解成简单易理解的东西,无论是在代码的设计上,还是在知识的分享上。另外我也是个实用主义者,写出来的代码光好看没有什么卵用,必须要有实际的用途,它才是有价值的代码。所以写这样一个系列的博客,主要有两个目的:

  1. 拆解编译原理里一部分入门级别的基础知识,用最少的篇幅讲解编译器前端的大致工作原理
  2. 实现一个可以解析并计算简单数学表达式的库,让需要的人可以使用它完成一些计算功能

所谓编译器前端,主要是指词法分析、语法分析这一类解析的过程,负责把我们写的代码翻译成计算机可以理解的格式。编译器后端,主要负责把前端解析得到的中间代码进行优化,生成CPU可以运行的二进制代码。编译器后端的知识,需要对汇编、计算机组成原理之类的知识有一定了解,才能更好的理解。所以我在这里不太打算深入讲解编译器后端的知识,想要全面了解编译原理的同学可以参考别的教程进行学习。

推荐书籍

曾经尝试学习过编译原理的同学,可能会深有感触,抱着书啃起来很枯燥,很容易从入门到放弃。编译原理的三大著名书籍人称龙书、虎书、鲸书,具体书名大家自己搜一下就很容易找到。我们比较熟悉的一本应该就是下图这个龙书——《编译原理》,普及最广应该是因为翻译得比较好吧。书里说的大部分是理论知识,很可能看完三四章后,了解了很多编译器中的概念和方法,但是想要自制个编译器就会觉得无从下手。不过这不会影响它的地位,想深入学习编译原理肯定还是离不开它的,建议对编译器感兴趣的同学先从博客入门,入门后如果觉得想要更深入,再买一本《编译原理》回去啃也不迟。

01-A

推荐博客及开源库

首推一个lotabout大佬的《手把手教你构建 C 语言编译器》系列博客。博客从构建虚拟机开始,然后逐步的介绍词法分析再到语法分析,围绕着已经构建好的虚拟机一步步构造编译器。从构造编译器的过程上来说,大概是下图这样:

01-B

lotabout大佬的教程总结起来有以下特点:

  1. 编译器完整:包含编译器前端和编译器后端,对了解编译器完整工作流程有很大帮助

  2. 功能丰富:支持变量,条件和循环语句等复杂功能

  3. 较为深入:对虚拟机设计的讲解,以及对应虚拟机的代码生成逻辑都讲得较为深入。这个有好有坏,好处当然是大家能学到的东西更多,坏处就是对于不了解CPU和汇编的同学来说太难理解

  4. 中期无法运行:教程中期几篇的结尾都会有“本章的代码还无法正常运行”。这是必然的,编译器必须完成完整的流程才能运行,在虚拟机的基础上没有完成生成代码的逻辑,肯定会无法运行。这就可能让中间的学习过程有一定的断层

推荐的开源库首先也是推荐lotabout大佬博客对应的GitHub开源库:write-a-C-interpreter。光对着代码干啃很累,有对应的博客当然还是学起来更快的。

然后推荐的是Fabrice Bellard大神的otcc,这应该是最迷你的C语言编译器了,迷你但五脏俱全,甚至于可以做到自举(自举就是自己可以编译自己)。它是当年Fabrice Bellard参加国际混淆(混乱)C语言代码大赛的获奖作品,可以编译C语言的子集。当然我们阅读代码的时候请阅读非混淆版本的,不然你的大脑可能得跟计算机一样才能看懂写得是什么……

想再深入学习代码就试着看TinyCC吧,是Fabrice Bellard基于otcc扩展写出来的完整的C语言编译器,号称最快最小。这个级别的代码,反正我已经看不懂了……

本入门课

我这里要写的入门课,一开始就说了不包含编译器后端,所以这里不能叫它编译器,只能叫做解释器或者说计算器。和大部分的编译原理课不同,我会先写出来可以运行的最小单元,然后一边展开知识范围一边迭代,让解释器可以支持更多的功能。大概的过程会是这样:

01-C

是不是更像是一个软件的常规迭代过程些?入门课会有以下特征:

  1. 只含编译器前端,功能只有简单计算,简化了要学习的内容
  2. 始终可以运行,持续迭代新功能

目录会如下:

(一)用最简单的语法分析器解析加减法

(二)递归解析中怎么处理运算符优先级

(三)简单错误处理逻辑以及负数的解析

(四)用词法解析处理多位数字和空白符

(五)解析ID型词法和函数调用语法

后面还可能会补充其他内容,要看看大家对什么内容/功能感兴趣,还要等我的懒癌被治好。

入门课对应的代码都会开源放在GitHub:SlimeExpressionC

想要更多的功能/教学可以在我的博客里留言,或者到对应的开源库下面去提issue,也热烈欢迎你们提MR或者fork出去自己玩。今天就先水到这里。