四时宝库

程序员的知识宝库

chibicc:一个小型 C 编译器(c0编译器)

更多互联网精彩资讯、工作效率提升关注【飞鱼在浪屿】(日更新)

github仓库:https://github.com/rui314/chibicc

chibicc 是实现大多数 C11 特性的小型 C 编译器。尽管它可能属于“玩具编译器”类别,但 chibicc 可以编译几个真实世界的程序,包括Git、 SQLite、 libpng和 chibicc 本身,而无需对已编译的程序进行修改。这些程序生成的可执行文件通过了相应的测试套件。因此,chibicc 实际上支持各种 C11 功能,并且能够正确编译数十万行真实世界的 C 代码。

chibicc 是作为我目前正在写的一本关于 C 编译器和低级编程的书的参考实现而开发的。这本书以渐进的方式涵盖了广泛的主题;在第一章中,读者将实现一个只接受一个数字作为“语言”的“编译器”,然后它将在本书的每一节中一次获得一个特性,直到编译器接受的语言与 C11 匹配规范指定。我从Abdulaziz Ghuloum的论文中采用了这种渐进方法。


chibicc 支持 C11 的几乎所有强制特性和大多数可选特性以及一些 GCC 语言扩展。

小型编译器中经常缺少但 chibicc 支持的功能包括(但不限于):

  • 预处理器
  • float、double 和 long double
  • alloca()
  • 变长数组
  • 复合文字
  • 线程局部变量
  • 原子变量
  • 常用符号
  • 指定初始化器
  • L、u、U 和 u8 字符串文字
  • 按照 x86-64 SystemV ABI 的规定,采用或返回结构作为值的函数

当 chibicc 在源代码中发现错误时,它会输出一条简单但很好的错误消息。


chibicc 包含以下阶段:

标记化:标记器将字符串作为输入,将其分解为标记列表。

预处理:预处理器将令牌列表作为输入,并输出新的宏扩展令牌列表。它在扩展宏的同时解释预处理器指令。

解析:递归后代解析器从预处理器的输出构造抽象语法树。它还为每个 AST 节点添加了一个类型。

Codegen:代码生成器为给定的 AST 节点发出汇编文本。

chibicc 不会太努力地节省内存。例如,在标记器启动之前,首先将整个输入源文件读入内存。

如果知道 n 不太大,那么慢速算法就可以了。例如,预处理器中使用链表作为集合,因此遍历复杂度是 O(n)。但这很好,因为 n 通常很小。即使 n 可能非常大,也会坚持使用简单的慢速算法,直到基准测试证明这是一个瓶颈。

Node每个 AST 节点类型只使用结构成员中的几个成员。其他未使用Node的成员只是在运行时浪费内存。可以使用联合来节省内存,但将所有内容简单地放在同一个结构中。低效率可以忽略不计。即使这很重要,也可以随时更改代码使用联合。主要是想避免过早优化。

chibicc 始终使用 分配堆内存calloc,这是malloc使用零清除内存的变体。calloc比malloc稍慢,但应该是合格的。

最后但同样重要的是,chibicc 使用calloc但从不调用分配内存free。在进程退出之前,分配的堆内存不会被释放。这种内存管理策略看起来很奇怪,但对于编译器等短期程序来说却很有意义。DMD 是 D 编程语言的编译器,出于同样的原因使用相同的内存管理方案。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接