Files
l-language/docs/architecture-analysis-report-2026-06-05.md
T
Serendipity f8c5e18188 fix: 技术债修复 — codegen malloc→arena + .codegraphignore
- codegen.c: VarEntry/FnEntry/ptypes 全部改用 arena_alloc,消除 malloc/free
- codegen_module 新增 Arena* 参数,main.c 传入主 arena
- 新增 .codegraphignore 排除 build/ 和 .codegraph/
- 基于 Codex 分析报告第7节技术债务
2026-06-05 00:37:54 +08:00

337 lines
11 KiB
Markdown

# L Language 架构分析与功能建议报告
> 日期: 2026-06-05 | 自动生成
> 项目: L Language v0.1 — 用 C17 实现的静态类型编译型语言
---
## 1. 当前架构全景
### 1.1 编译流水线
```
源码(.l) → Lexer(词法分析) → Parser(语法分析) → Sema(语义分析) → Codegen(LLVM IR) → 链接(.exe)
Token[] AstNode* 类型标注 LLVMModuleRef GCC/ld
```
一条经典的单趟编译器流水线,手写实现,无依赖生成器。
### 1.2 模块深度分析
| 模块 | 行数(估) | 关键数据结构 | 现状评估 |
|------|----------|-------------|---------|
| lexer/ | ~200 | Token {kind, start, length, line, col} | 稳定,支持 25+ Token 类型、行/块注释 |
| ast/ | ~150 | AstNode {kind, type, as{union}} | 14 种节点,工厂函数风格 |
| parser/ | ~400 | Parser {tokens, pos, filename, arena} | 递归下降 + Pratt 优先级解析,成熟 |
| sema/ | ~200 | Scope {head, parent}, Symbol {name, kind, type} | 作用域链、类型推断、类型检查 |
| codegen/ | ~300 | CgCtx {builder, var_table, fn_table} | LLVM-C API 完整映射,含内置 printf |
| util/ | ~80 | Arena bump allocator | 8MB 固定大小,贯穿全流水线 |
| driver/ | ~150 | 流水线串联 | 带 --emit-ir、-o 参数 |
### 1.3 技术选择评估
| 选择 | 评价 |
|------|------|
| C17 + CMake | 轻量,适合学习编译器全流程 |
| Arena allocator | 极简内存管理,无 GC 开销,无内存泄漏 |
| LLVM-C API | 成熟稳定,但版本差异需在 CMake 中处理 |
| 手写词法/语法分析 | 0 外部依赖,完整控制权 |
| Pratt 解析 | 优雅处理表达式优先级,扩展方便 |
| GCC 链接 | 简单粗暴,跨平台需额外处理 |
---
## 2. 当前功能清单与成熟度
### 已实现 (v0.1)
- [x] 基本类型: i64, f64, bool, void
- [x] 算术运算: + - * / %
- [x] 比较运算: == != < > <= >=
- [x] 逻辑运算: && || !
- [x] 变量声明: let 不可变,支持类型标注和类型推断
- [x] 控制流: if/else, while
- [x] 函数定义与调用: 参数、返回类型、递归
- [x] 内置函数: print_i64, print_f64, print_bool
- [x] 注释: // 行注释, /* */ 块注释
- [x] 错误报告: 词法/语法即时终止, 语义错误收集后批量输出
- [x] 测试: 41(词法) + 15(语法) + 9(语义) 单元测试, 5 个集成测试程序
### 未实现 (与 Rust 对标)
- [ ] 字符串类型 (只有 printf 的内建打印)
- [ ] 数组/切片
- [ ] 自定义结构体/枚举
- [ ] let mut 可变变量 + 赋值语句
- [ ] 复合赋值: += -= *= /=
- [ ] for 循环 / loop 循环
- [ ] match 模式匹配
- [ ] 泛型
- [ ] 模块系统 / 多文件编译
- [ ] trait / 接口
- [ ] 所有权 / 借用 / 生命周期
- [ ] 类型别名
- [ ] 标准库
---
## 3. 向 Rust 学习: 功能优先级建议
按"学习价值 + 实现难度 + 对编译器的收获"排序。
### P0: 短期可加(1-2 天)
#### 3.1 let mut + 赋值语句
Rust 启发: Rust 中 let 默认不可变,let mut 声明可变变量。
改动范围:
- lexer: 新增 mut 关键字 Token
- parser: let_stmt 添加 is_mut 标志; 新增 assignment_stmt
- sema: 可变性检查(不可变变量不能赋值)
- codegen: 赋值语句生成 store IR
学习价值: 理解"默认不可变"的设计哲学如何贯穿全编译流程。
#### 3.2 字符串类型 + 字符串字面量
Rust 启发: Rust 的 &str 和 String 区分, 但初期只需一个简单字符串。
改动范围:
- lexer: 双引号字符串字面量 Token ("...")
- parser: 字符串字面量 AST 节点
- sema: 新增 TYPE_STR 类型
- codegen: 字符串常量在 LLVM IR 中生成全局数组; print_str 内置函数
- driver: 字符串在 IR 中需 i8* 指针表示
学习价值: 掌握 LLVM 中常量和全局变量的处理。
### P1: 中期(3-5 天)
#### 3.3 数组类型
Rust 启发: [T; N] 固定大小数组。
改动范围:
- lexer: [ ] Token 已有
- ast: AST_ARRAY_TYPE, AST_INDEX_EXPR 节点
- parser: 类型语法 [i64; 10], 索引表达式 arr[0]
- sema: 数组类型检查, 索引必须为 i64, 边界检查
- codegen: LLVM alloca + GEP 指针计算
学习价值: 学习 GEP (GetElementPtr) 指针计算, 这是 LLVM 中最重要的概念之一。
#### 3.4 结构体 (struct)
Rust 启发: Rust 的 struct 定义具名域。
改动范围:
- lexer: struct 关键字, . 点号
- ast: AST_STRUCT_DECL, AST_FIELD_ACCESS 节点
- parser: struct 声明 + 初始化 + 字段访问
- sema: 结构体类型符号表, 字段类型解析
- codegen: LLVM 结构体类型 (LLVMStructType), GEP 访问字段
学习价值: 深入 LLVM 结构体类型与 GEP 偏移量的精确定位。
#### 3.5 枚举 + 简单模式匹配
Rust 启发: Rust 的 enum 是代数数据类型, 但初期可以先做 C 风格 enum。
改动范围:
- lexer: enum, :: 作用域解析
- ast: AST_ENUM_DECL 节点
- parser: enum 声明
- sema: enum 类型符号表
- codegen: enum 在 LLVM 中用 i64 表示 (C 风格)
学习价值: 为后续 Rust 风格的代数类型和 match 做铺垫。
### P2: 中后期(1-2 周)
#### 3.6 match 表达式
Rust 启发: Rust 的 match 是穷举模式匹配, 表达式级别。
改动范围:
- lexer: match, =>, _ 通配符
- ast: AST_MATCH_EXPR, AST_MATCH_ARM 节点
- parser: match 表达式解析
- sema: 穷举性检查, 模式变量绑定
- codegen: switch 或 if-else 链生成
学习价值: 模式匹配是 PL 设计中最重要的概念之一。
#### 3.7 for 循环 + Range
Rust 启发: for i in 0..10 {}
改动范围:
- lexer: for, in, .. Token
- ast: AST_FOR_STMT, AST_RANGE_EXPR 节点
- parser: for 循环解析
- sema: 范围类型检查
- codegen: 翻译为 while 循环 IR
学习价值: 语法糖如何被编译为底层控制流, 理解"去糖" (desugaring)。
#### 3.8 类型别名 (type)
Rust 启发: type Meters = i64;
- lexer: type 关键字
- ast: AST_TYPE_ALIAS 节点
- parser: 类型别名声明
- sema: 类型别名展开
- codegen: 透明 (别名展开后与原类型相同)
学习价值: 类型系统的"名称等价"vs"结构等价"概念。
### P3: 长期(2-4 周)
#### 3.9 泛型
Rust 启发: Rust 的泛型是编译期单态化。
改动范围:
- lexer: < > (已有) + 类型参数语法
- ast: AST_GENERIC_FN, AST_TYPE_PARAM 节点
- parser: 带类型参数的函数签名
- sema: 泛型符号表, 单态化展开
- codegen: 按具体类型展开生成代码
学习价值: 单态化 (monomorphization) 是 Rust 零成本抽象的基石。
#### 3.10 trait / 接口
Rust 启发: Rust 的 trait 定义行为契约。
改动范围:
- ast: AST_TRAIT_DECL, AST_IMPL_BLOCK 节点
- parser: trait + impl 语法
- sema: trait 一致性检查, 虚表/静态分发
- codegen: 动态分发 (虚表指针) / 静态分发 (单态化)
学习价值: 理解"接口"在编译期/运行时的不同实现策略。
#### 3.11 模块系统 / 多文件编译
Rust 启发: Rust 的 mod + use 模块系统。
改动范围:
- driver: 多文件读取 + 编译单元管理
- ast: AST_MODULE, AST_USE 节点
- parser: mod, use 关键字
- sema: 模块作用域, 可见性检查
- codegen: 链接多个编译单元
学习价值: 从单文件到多文件的跳跃, 理解链接过程和符号解析。
---
## 4. 架构改进建议
### 4.1 短期改进
1. **代码生成与链接解耦**
- 当前: codegen.c 中混合了 LLVM IR 生成和初始化 LLVM 目标
- 建议: 抽取 target_init() 到独立的 target.c, codegen.c 只负责 AST->IR
2. **错误类型统一**
- 当前: ErrorInfo (单个错误) 和 ErrorList (错误列表) 存在于多个模块
- 建议: 统一为 CompilerError { phase, message, line, col, filename } 结构体
3. **测试框架扩展**
- 当前: 手写断言宏, 缺少 codegen 层测试
- 建议: 新增 test_codegen.c, 测试 AST->LLVM IR 是否正确
### 4.2 中期改进
4. **IR 中间表示层**
- 当前: AST 直接生成 LLVM IR, 跳过了"自己设计 IR"这一步
- 建议: 在 AST 和 LLVM IR 之间加一层自定义 IR (三地址码或 SSA 形式)
- 学习价值: 理解"IR 是编译器的核心抽象"这句话的真正含义
5. **解释器模式**
- 建议: 在 codegen/ 旁加一个 interp/ 模块, 直接 walk AST 解释执行
- 好处: 快速验证语义正确性, 无需 LLVM 编译; 区分编译和解释模式
6. **调用约定抽象**
- 当前: codegen 直接调 LLVMBuildCall2
- 建议: 抽一层 abi.h, 封装参数传递和返回值处理
### 4.3 长期改进
7. **自举准备**
- 用 L Language 写一个 L Language 编译器的最小实现
- 分阶段: 先让 L 输出 AST -> 再输出 LLVM IR -> 最终用 L 编译自己
8. **增量编译**
- 缓存已编译模块的时间戳和符号表
- 只重新编译有改动的文件
---
## 5. Rust 设计哲学清单: 哪些值得吸收
| Rust 特性 | L 是否该加 | 理由 |
|-----------|-----------|------|
| 默认不可变 (let vs let mut) | 是 | 编译期检查, 几乎零实现成本 |
| 表达式 vs 语句 | 是 | if/match/block 可作为表达式 |
| 模式匹配 | 是 | 最优雅的控制流之一 |
| 代数数据类型 (enum + 带字段) | 是 | 类型安全的设计模式 |
| Option/Result 错误处理 | 有条件 | 需要泛型 + enum, 实现门槛高 |
| 所有权 / 借用 | 暂不加 | 需要借用检查器, 复杂度远超当前阶段 |
| 生命周期标注 | 暂不加 | 所有权系统的伴生概念 |
| trait 系统 | 暂不加 | 需要泛型 + 虚方法表, 实现成本高 |
| 宏系统 | 暂不加 | 极其复杂, 自举后才考虑 |
| 模块系统 | 可以加简单版 | 简单 mod + 文件包含即可 |
---
## 6. 推荐开发路线图
### 短期 (下一个迭代)
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P0 | let mut + 赋值语句 | 1 天 |
| P0 | 字符串类型 + 字面量 + print_str | 1 天 |
| P1 | 数组 + arr[i] 索引 | 2 天 |
| P0 | for 循环 + range | 1 天 |
### 中期 (下下个迭代)
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P1 | 结构体 | 2-3 天 |
| P1 | 枚举 (C 风格) | 1 天 |
| P2 | match 表达式 | 2-3 天 |
| P1 | 类型别名 | 0.5 天 |
### 长期
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P2 | 自定义 IR 层 | 3-5 天 |
| P3 | 泛型 | 5-7 天 |
| P2 | 模块系统 | 3-5 天 |
| P3 | trait / 接口 | 5-7 天 |
| P3 | 自举尝试 | 数周 |
---
## 7. 技术债务与风险
| 问题 | 影响 | 建议 |
|------|------|------|
| codegen.c 中 malloc 混用 arena | 内存管理不一致 | 优先使用 arena, 或实现统一的代码生成器分配器 |
| system("gcc ...") 链接 | 平台不兼容 | 封装 Linker 接口, 支持直接调用 ld/lld |
| 无 codegen 层单元测试 | IR 正确性无保障 | 添加 test_codegen.c, 用 LLVMVerifyModule 验证 |
| 所有变量用 alloca | 效率低 | LLVM opt -mem2reg 可以优化, 但当前没跑优化 pass |
| 无 .codegraphignore | 索引可能包含无关文件 | 添加 .codegraphignore 排除 build/ |
---
*本报告由 Codex 自动生成。下次运行: 2 小时后。*