我之前对编译器、解释器都挺感兴趣的,研究过Lua解释器的源码,也看过golang运行时的源码。
随着近年来,科技战愈演愈烈,虽然我们在高科技的某些方面不再受制于人,但是像编译器、调试器,例如 gcc、gdb、clang,虽然是开源的,但是开源团体成员会受到 zz 的压力,哪天不对我们开源了呢?
另外,国内的编译原理的教学大多数都停留在理论层面,实战并不多,而编译器、调试器等工具的实现,深深地依赖 CPU 芯片的架构和操作系统的实现机理。这些现在都是我们的弱项。
我在工作中实现消息中间件产品解析类似 SQL 语法的过程中,也参考了一些其他书籍,有一本叫《用C/C++从零写一个C语言编译器》,阅读这本图书的过程中,那些曾经停留在编译原理书上的理论变成一行行可真实运行的代码和程序,并且我可以自由在我的新“SQL”中增加我喜欢的语法。那种畅快淋漓,犹如庖丁解牛,洋洋洒洒。
我将近花了两个多月的时间,把这本书翻译了中文版,当然,期间因为无暇刷碗,被媳妇喷了很多次。女人嘛,只会影响我拔刀的速度。不信,你看山西大同。
此书读来酣畅淋漓,读完后你的操作系统和汇编功能增加了一甲子。当你看到你自己写的各种基础数据类型、指针、结构体等如何变成一行行二进制机器指令,你为你的函数调用如何分配栈空间,那种成就感无以复加。
-
引言
-
在Linux上安装GCC和GDB
-
在MacOS上安装命令行工具
-
在Apple Silicon上运行
-
验证你的设置
-
测试套件 -
额外加分功能 -
为何编写C语言编译器
-
编译过程概述
-
你将构建的内容
-
如何使用本书
-
关于选择实现语言的建议
-
系统要求
-
其他资源
-
开始吧!
第一部分:基础内容
-
第1章:一个极简编译器
-
抽象语法树示例 -
抽象语法树定义 -
形式语法 -
递归下降解析 -
编译器的四个阶段 -
你好,汇编语言! -
编译器驱动程序 -
词法分析器 -
语法分析器 -
汇编生成 -
代码生成 -
总结 -
其他资源 -
第2章:一元运算符
-
将TACKY转换为汇编 -
替换伪寄存器 -
修正指令 -
定义TACKY -
TACKY生成 -
为临时变量生成名称 -
更新编译器驱动程序 -
汇编中的取反和按位求补 -
栈 -
词法分析器 -
语法分析器 -
TACKY:一种全新的中间表示形式 -
汇编生成 -
代码生成 -
总结 -
其他资源 -
第3章:二元运算符
-
在汇编中进行算术运算 -
将二元运算转换为汇编 -
替换伪寄存器 -
修正idiv, add, sub, and imul指令 -
递归下降解析的问题 -
足够好的解决方案:重构语法 -
优先级攀升的应用 -
更好的解决方案:优先级攀升 -
词法分析器 -
语法分析器 -
TACKY生成 -
汇编生成 -
代码生成 -
额外加分:按位运算符 -
总结 -
其他资源 -
第4章:逻辑运算符和关系运算符
-
替换伪寄存器 -
修正cmp指令 -
比较和状态标志 -
条件设置指令 -
跳转指令 -
向TACK添加跳转、复制和比较操作 -
将短路运算符转换为TACKY -
生成标签 -
短路运算符 -
词法分析器 -
语法分析器 -
TACKY生成 -
汇编中的比较和跳转 -
汇编生成 -
代码生成 -
总结 -
其他资源 -
第5章:局部变量
-
变量和赋值表达式 -
声明、语句和函数体 -
无返回语句的函数 -
变量解析 -
--validate选项 -
更新后的抽象语法树(AST)和语法 -
改进的优先级攀升算法 -
变量、声明与赋值
-
词法分析器
-
语法分析器
-
语义分析
-
TACKY生成
-
额外加分内容:复合赋值、自增和自减
-
总结
-
第6章:if语句和条件表达式
-
将if语句转换;为TACKY -
将条件表达式转换为TACKY -
解析if语句 -
变量解析 -
词法分析器 -
语法分析器 -
变量解析 -
TACKY生成 -
解析条件表达式 -
额外加分内容:label标签与goto语句 -
总结 -
第7章:复合语句
-
在多个作用域中解析变量 -
更新变量解析伪代码 -
作用域详解 -
语法分析器 -
变量解析 -
TACKY生成 -
总结
-
第8章 循环
-
break和continue语句 -
do循环 -
while循环 -
for循环 -
扩展变量解析
-
循环标记
-
实现循环标记
-
循环以及如何跳出循环
-
词法分析器
-
语法分析器
-
语义分析
-
TACKY生成
-
额外加分:switch语句 -
总结
-
第9章 函数
-
理解调用约定 -
使用System V应用二进制接口(ABI)调用函数 -
将函数调用和定义转换为汇编 -
替换伪寄存器 -
在指令修正过程中分配栈空间 -
扩展标识符解析
-
编写类型检查器
-
声明和定义
-
函数调用
-
标识符链接
-
声明、定义和调用函数
-
编译库
-
词法分析器
-
语法分析器
-
语义分析
-
TACKY生成
-
汇编生成
-
代码生成
-
调用库函数
-
总结
-
第10章 文件作用域变量声明和存储类说明符
-
为变量定义生成汇编代码
-
根据存储期替换伪寄存器
-
修正指令
-
标识符解析:解析外部变量
-
类型检查:跟踪静态函数和变量
-
解析类型和存储类说明符 -
区分函数声明和变量声明 -
作用域
-
链接
-
存储期
-
定义与声明
-
错误情况
-
关于声明的一切
-
汇编中的链接和存储期
-
词法分析器
-
语法分析器
-
语义分析
-
TACKY生成
-
汇编生成
-
代码生成
-
总结
第二部分:整型之外的类型
-
第11章 长整型
-
在后端符号表中跟踪汇编类型 -
替换长字和四字伪寄存器 -
修正指令 -
跟踪临时变量的类型 -
生成额外的返回指令 -
向抽象语法树添加类型信息 -
表达式类型检查 -
返回语句类型检查 -
声明类型检查并更新符号表 -
类型转换
-
静态长整型变量
-
汇编中的长整型
-
词法分析器
-
语法分析器
-
语义分析
-
TACKY生成
-
汇编生成
-
代码生成
-
总结
-
第12章 无符号整型
-
替换伪寄存器 -
修正div和MovZeroExtend指令 -
无符号比较 -
无符号除法 -
零扩展 -
相同大小的有符号和无符号类型之间的转换 -
将无符号整型(unsigned int)转换为更大的类型 -
将有符号整型(signed int)转换为更大的类型 -
从更大类型转换为更小类型 -
再次探讨类型转换
-
词法分析器
-
语法分析器
-
类型检查器
-
TACKY生成
-
汇编中的无符号整数运算
-
汇编生成
-
代码生成
-
总结
-
第13章 浮点数
-
用内存操作数替换伪寄存器 -
修正 lea 和 push 指令 -
TACKY 中的指针操作 -
TACKY 转换策略 -
检查指针表达式的类型 -
在符号表中跟踪静态指针初始化器 -
解析声明 -
解析类型名称 -
整合所有内容 -
词法分析器 -
语法分析器 -
语义分析 -
TACKY生成 -
汇编生成 -
代码生成 -
总结 -
对象和值
-
指针操作
-
取地址和解引用操作 -
空指针和类型转换 -
指针比较 -
对解引用指针的操作 -
第14章 指针
-
格式化浮点数 -
标记浮点常量 -
将常量存储在只读数据段 -
将静态变量初始化为0.0或 -0.0 -
整合所有内容 -
浮点常量 -
一元指令、二元指令和条件跳转 -
类型转换 -
函数调用 -
返回指令 -
从TACKY到汇编的完整转换 -
伪寄存器替换 -
指令修正 -
使用SSE指令 -
在System V调用约定中使用浮点值 -
用SSE指令进行算术运算 -
比较浮点数 -
在浮点型和整型之间转换 -
识别浮点型常量词法单元 -
匹配常量的结尾 -
舍入模式
-
舍入常量
-
舍入类型转换
-
舍入算术运算
-
IEEE 754,它有什么用?
-
IEEE 754双精度格式
-
舍入行为
-
链接共享库
-
词法分析器
-
语法分析器
-
类型检查器
-
TACKY生成
-
汇编中的浮点运算
-
汇编生成
-
代码生成
-
额外加分:NaN
-
总结
-
其他资源
-
第15章 数组和指针算术运算
-
将TACKY转换为汇编 -
替换伪内存操作数 -
修正指令 -
指针算术运算 -
下标操作 -
复合初始化器 -
暂定数组定义 -
将数组转换为指针 -
验证左值 -
检查指针算术运算的类型 -
检查下标表达式的类型 -
检查强制类型转换表达式的类型 -
检查函数声明的类型 -
检查复合初始化器的类型 -
初始化静态数组 -
用零初始化初始化标量变量 -
解析数组声明符 -
解析抽象数组声明符 -
解析复合初始化器 -
解析下标表达式 -
数组声明和初始化器 -
数组的内存布局 -
数组到指针的退化 -
通过指针算术运算访问数组元素 -
更多指针算术运算 -
函数声明中的数组类型 -
我们未实现的内容 -
数组和指针算术运算
-
词法分析器
-
语法分析器
-
类型检查器
-
TACKY生成
-
汇编生成
-
代码生成
-
总结
-
第16章 字符和字符串
-
你好,世界(再次相见)! -
字符操作 -
顶级常量 -
从TACKY到汇编的完整转换 -
伪操作数替换 -
指令修正 -
作为数组初始化器的字符串字面值 -
表达式中的字符串字面值 -
TACKY中的顶级常量 -
字符 -
表达式中的字符串字面值 -
用于初始化非静态变量的字符串字面值 -
用于初始化静态变量的字符串字面值 -
解析类型说明符 -
解析字符常量 -
解析字符串字面值 -
整合所有内容 -
字符特性
-
字符串字面值
-
在汇编中处理字符串
-
词法分析器
-
语法分析器
-
类型检查器
-
TACKY生成
-
汇编生成
-
代码生成
-
总结
-
第17章 支持动态内存分配
-
具有void返回类型的函数 -
转换为void -
包含void操作数的条件表达式 -
sizeof表达式 -
最新最棒的TACKY中间表示(IR) -
与void *之间的转换 -
具有void返回类型的函数 -
标量和非标量类型 -
对不完整类型的限制 -
对void的额外限制 -
包含void操作数的条件表达式 -
对算术表达式和比较的现有验证 -
sizeof表达式 -
void类型
-
使用void *进行内存管理
-
完整类型和不完整类型
-
sizeof运算符
-
词法分析器
-
语法分析器
-
类型检查器
-
TACKY生成
-
汇编生成
-
总结
-
第18章 结构体
-
扩展汇编抽象语法树(AST) -
复制结构体 -
在函数调用中使用结构体 -
整合所有内容 -
替换伪操作数 -
对结构体进行分类 -
传递结构体类型的参数 -
返回结构体 -
实现成员访问操作符 -
将复合初始化器转换为TACKY -
解析结构体标签 -
检查结构体类型 -
结构体成员声明
-
标签和成员命名空间
-
我们未实现的结构体类型声明
-
声明结构体类型
-
对结构体进行操作
-
结构体在内存中的布局
-
词法分析器
-
语法分析器
-
语义分析
-
TACKY生成
-
System V调用约定中的结构体
-
汇编生成
-
代码生成
-
额外加分:联合体
-
总结
-
其他资源
第三部分:优化
-
第19章 优化TACKY程序
-
活跃性分析 -
删除无用存储 -
支持第二部分TACKY程序 -
可达复制分析 -
重写TACKY指令 -
支持第二部分TACKY程序 -
消除不可达代码块 -
删除无用跳转 -
删除无用标签 -
删除空代码块 -
定义控制流图 -
创建基本代码块 -
向控制流图添加边 -
将控制流图转换为指令列表 -
使控制流图代码可复用 -
第一部分TACKY程序的常量折叠 -
支持第二部分TACKY程序 -
常量折叠
-
不可达代码消除
-
复制传播
-
无用存储消除
-
综合运用我们的能力
-
安全性和可观察行为
-
四种TACKY优化方法
-
测试优化过程
-
连接优化阶段
-
常量折叠
-
控制流图
-
不可达代码消除
-
关于数据流分析的一些知识
-
复制传播
-
无用存储消除
-
总结
-
其他资源
-
第20章 寄存器分配
-
更新冲突图 -
保守合并 -
实现寄存器合并 -
在寄存器分配过程中处理多种类型 -
定义冲突图 -
构建冲突图 -
计算溢出成本 -
对冲突图进行着色 -
构建寄存器映射并重写函数体 -
检测冲突
-
溢出寄存器
-
方法一:将所有内容存放在栈上
-
方法二:寄存器分配
-
方法三:采用合并策略的寄存器分配
-
实际中的寄存器分配
-
更新编译器流水线
-
扩展汇编抽象语法树(AST)
-
将TACKY转换为汇编
-
通过图着色进行寄存器分配
-
基本的寄存器分配器
-
使用被调用者保存寄存器修正指令
-
代码生成
-
寄存器合并
-
总结
-
其他资源
后续步骤
-
添加一些缺失的功能
-
安全处理未定义行为
-
编写更多TACKY优化方案
-
支持另一种目标架构
-
为开源编程语言项目做贡献
-
语言项目 -
到此结束!
-
附录A. 使用GDB或LLDB调试汇编代码
-
启动和停止程序 -
显示汇编代码 -
打印表达式 -
检查内存 -
设置条件断点 -
获取帮助 -
配置GDB用户界面 -
启动和停止程序 -
打印表达式 -
检查内存 -
设置条件断点 -
获取帮助 -
程序
-
使用GDB调试
-
使用LLDB调试
-
附录B. 汇编生成和代码生成表
-
将TACKY转换为汇编 -
代码生成 -
将TACKY转换为汇编 -
代码生成 -
第一部分
-
第二部分
-
第三部分
如果你想阅读我的翻译版本,请移步我的知识星球,加入星球后,看置顶帖子即可阅读。
人到中年,养家糊口不易,赚点米。
小方的星球提供五大服务:
-
优问优答 2. 不定期的技术直播和录像 -
优质源码分享和指导 -
模拟面试、职业解惑和简历review -
星球专属技术专栏。
注意:小方的星球不卖课,星球专栏只是星球服务很小的一部分。如果你单纯为了看热闹,请勿加入,倒不如省下这几百块带孩子吃点好的。
小方说服务器开发知识星球详细介绍点击这里。
如果你还不是球友,可以通过下面的优惠券扫码加入(立即优惠40):
老球友续费扫码如下(半价基础上再优惠20):
年纪大了,对越来越多的东西失去了兴趣。虽然现在也带一些团队,看到团队中的新人渴求知识的双眸,我也很乐意分享和指导一二,他们有我当年的影子!我庆幸,我还对实际写代码很感兴趣,一个项目技术方案确定好后,我一定要给自己分几个模块,实际去写一写。
王羲之说:向之所欣,俯仰之间,已为陈迹,犹不能不以之兴怀;况修短随化,终期于尽。
诚然,祝每一位公众号的老读者、新读者,都能在键盘之下、行号之间实现自己的愿望。
推荐阅读

