这个仓库里的编译器叫 TigerLite,是我用 C++20 和 LLVM 写的一个小编译器。语法上借了一点 Tiger 的形式,但没有照着完整 Tiger 做,目前只保留了 int、局部定长数组、函数、分支和循环这些东西。项目的重点不是把语言做大,而是自己把 lexer、parser、AST、语义检查、LLVM IR 生成和运行这条线走通。
现在代码里有手写 lexer、递归下降 parser、AST、简单的作用域检查和类型检查,也有一点 AST 层面的优化,比如常量折叠、if (0) / while (0) 这种分支处理,以及几个很小的代数化简。后端直接用 LLVM C++ API 生成 IR,运行时目前还是调用外部的 lli。
一个最小程序大概长这样:
fn main() -> int {
var x: int = 1 + 2 * 3;
return x;
}可以打印 AST:
./build/tigerlite --ast examples/const_fold.tl也可以直接看生成的 LLVM IR:
./build/tigerlite --emit-ir examples/const_fold.tl如果本机能找到 lli,可以直接运行:
./build/tigerlite --run examples/while_sum.tl目录没有拆得很细:
.
CMakeLists.txt
include/tl/ 头文件
src/ lexer/parser/sema/optimizer/irgen/main
examples/ 几个手写的小程序
tests/ CTest 用例
docs/ 一些实现和语法笔记
构建需要 CMake、Ninja、支持 C++20 的编译器和 LLVM 开发包。进入 TigerLite-Compiler 目录后执行下面的命令。我的本地环境里 LLVM 是自己编出来的,所以一般会显式传 LLVM_DIR、clang 路径和 lli 路径:
cmake -S . -B build -G Ninja \
-DLLVM_DIR=/path/to/llvm/lib/cmake/llvm \
-DCMAKE_C_COMPILER=/path/to/clang \
-DCMAKE_CXX_COMPILER=/path/to/clang++ \
-DTIGERLITE_LLI_PATH=/path/to/lli
cmake --build build常用的几个命令是:
./build/tigerlite --tokens file.tl
./build/tigerlite --ast file.tl
./build/tigerlite --emit-ir file.tl
./build/tigerlite --run file.tl
./build/tigerlite --no-opt --emit-ir file.tl测试用 CTest 跑:
ctest --test-dir build --output-on-failuretests/syntax/ok 里是应该正常通过的程序,tests/syntax/bad 和 tests/semantic/bad 里是故意写错的程序,tests/run 里主要检查 IR 片段和 lli 的运行结果。
语言细节放在 docs/language.md,实现上的一些取舍放在 docs/design.md。
后面如果继续改,我会先补 parser 的错误恢复、更多 scope 测试,再考虑加 for / break。执行方式也可以换成 ORC JIT,这样就不用每次 shell out 到 lli。