1个不稳定版本

0.0.1 2022年3月9日

#163 in #own

MIT 许可证

120KB
2.5K SLoC

编译器

用Rust编写的编译器。先做一个简单的东西,然后随着时间的推移使其变得更好。

我发现有用的东西

  • LLVM
    • Godbolt的x86-64 clang,-g0 -O1,以及IR查看器(以文本形式显示LLVM IR)
    • 在线的LLVM资源到目前为止对更抽象的概念没有帮助。一旦你有了一个具体的问题或想知道可以调用哪些函数,文档可能有所帮助,但总的来说,在线资源到目前为止还没有帮助。Godbolt通常更快、更可靠。

想法

简单的语言,具有简单的用户语义。

编译器作为库暴露,可以在构建脚本中导入以完成更复杂的事情。默认模式是解释给定的文件,这使得这个事情更容易做。

使编译器作为一个库更容易使用,这样我们就可以运行关于哪些模式是有帮助的以及哪些不是的实验。

最终目标

  1. 对熟悉C语义的人来说易于开发
  2. 易于编写脚本来自动化简单的事情
  3. 可以轻松优化内存访问模式
  4. 可以输出另一种更易于生产的语言的易读代码

包含在基本语言中

  • 原始类型、指针、切片
  • 函数
  • 控制流
  • 类型ID,运行时类型信息
  • 动态内存
  • 迭代器(作为宏?或者作为类似宏的行为的生成器?)
  • 作用域开始/结束指令,作用域功能启用/禁用
  • 简单的编译时常量(即字面量)
  • 结构体
  • C ABI
  • 简单的枚举
  • 基本类型推断
  • 函数指针
  • 分配器
  • 隐式上下文
  • defer,命名continue/break
  • 某种“抛出错误”的东西,但不使用栈回溯
  • 空值检查:a ?? ba?.ba?(a?[等。
  • 某种“传递这个如果它抛出错误”的东西,即could_error()!

未知

  • 泛型
  • 闭包
  • 复杂的枚举
  • 非空类型
  • 重载
  • 运算符重载
  • 接口/特性等
  • 匿名结构体
  • 契约/类型要求
  • 编译时常量评估
  • 元组
  • async-await
  • 修改抽象语法树
  • 自定义类型检查
  • 使用显式类型字段进行继承?可以将其称为封闭,并成为枚举?

太复杂,请使用编译器API

  • Python ABI
  • 正确性检查
  • 生成模糊器,测试框架
  • 以字符串或节点形式插入源代码

太复杂,请自行处理

  • 继承
  • 垃圾回收
  • RAII

预期架构

抽象语法树内存布局

  • 由于在编译的大部分过程中不会访问位置信息,因此抽象语法树以结构体在一片区域中,位置在另一片区域中布局。
  • 解析器线程请求大范围;这些范围内的数据被锁定在正在解析的文件上
  • 不是每个位置都需要文件标记,因此将它们附加到范围上
  • 使用32位ID而不是引用。如果真的需要,我们可以在并发类型检查的同时进行解析,以释放更多的ID空间,但这似乎是不必要的。

字节码内存布局

  • 全局垃圾回收器管理基本块的生存期/分配
  • 一旦数据被写入,就是只读的,重写器将写入新的基本块并将其写入全局ID表
  • ID表可能预先分配?我不知道

注意:这一切都没有实现

词法分析/解析 -> 一个全局词法分析器线程,X个解析器线程

  1. 全局线程对输入进行词法分析

  2. 将相关数据发送到解析器线程

    1. 解析器在完成后将完整的抽象语法树数据发送到全局类型检查器线程
    2. 解析器将附加的文件路径发送到词法分析器
  3. 回到1

检查 -> 一个全局类型数据库/线程,由多个线程执行抽象语法树检查

  1. 等待抽象语法树

  2. 从抽象语法树中获取类型并存储在全局数据库中

    注意:这可以并发完成吗?有必要或没有必要这样做?

  3. 一旦所有类型都可用,启动类型检查线程

编写作业系统+分配器 使用取消令牌的概念允许任务取消

依赖项

~0.5–7.5MB
~43K SLoC