feat: 结构体 struct — 最后一项 P0 功能
- lexer: TOK_STRUCT, TOK_DOT 关键字和运算符
- ast: AST_STRUCT_DECL/STRUCT_INIT/FIELD_ACCESS 3 种新节点
- parser: struct 声明 + .field 访问 + Name{field:val} 初始化
- sema: struct 类型符号表,字段类型解析,初始化字段检查
- codegen: LLVMStructType + extractvalue/insertvalue 字段操作
- 新增集成测试: 12_struct.l, 13_struct_nested.l
- 基于 Codex 分析报告 P0 #4
所有 P0 功能已全部完成。
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
# L Language 架构分析报告 (v0.3 — 无代码变更)
|
||||
|
||||
> 日期: 2026-06-05 11:52 | 自动生成 | 自上次源代码基线无变更
|
||||
> 上次代码分析基线: `382cd08` (2026-06-05 08:29 报告)
|
||||
> 当前 HEAD: `620cec4` (CHANGELOG 更新 v0.3.0)
|
||||
|
||||
---
|
||||
|
||||
## 变更摘要 (自上次代码基线)
|
||||
|
||||
**源代码无变更。** 自 `382cd08` 以来,仅有 2 个纯文档提交 (`620cec4`):
|
||||
|
||||
| 文件 | 变更 | 行数 |
|
||||
|------|------|------|
|
||||
| CHANGELOG.md | 新增 v0.3.0 条目 (for 循环 + 测试补全 + Known Issues) | +14 |
|
||||
| docs/analysis/architecture-analysis-report-2026-06-05-0703.md | 上一轮自动化分析报告提交 | +288 |
|
||||
|
||||
**结论**: 编译器源代码、测试代码、构建系统均无变化。本次运行与 08:29 报告相比,唯一差异是 CHANGELOG v0.3.0 已正式提交(上次报告列为技术债 #8「CHANGELOG 未更新 v0.3」)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前架构全景
|
||||
|
||||
### 1.1 编译流水线
|
||||
|
||||
```
|
||||
源码(.l) → Lexer(词法) → Parser(语法) → Sema(语义) → Codegen(LLVM IR) → Target(obj) → GCC 链接(.exe)
|
||||
Token[] AstNode* 类型标注 LLVMModuleRef .o 文件
|
||||
```
|
||||
|
||||
全流水线 6 个阶段,**无架构变化**。
|
||||
|
||||
### 1.2 模块清单与指标
|
||||
|
||||
| 模块 | 文件 | 行数 | 关键职责 |
|
||||
|------|------|------|---------|
|
||||
| include/ | l_lang.h | 34 | TypeKind 枚举 (7 种), 向前声明, arena_alloc_impl |
|
||||
| util/ | arena.c(39) + .h(13) | 52 | 8MB bump allocator, strdup |
|
||||
| lexer/ | lexer.c(137) token.c(45) + .h(40) | 222 | 手写状态机, **37** Token 类型, peek_next |
|
||||
| ast/ | ast.c(107) ast.h(93) | 200 | **15** 种节点类型, 工厂函数 |
|
||||
| parser/ | parser.c(390) parser.h(10) | 400 | Pratt 表达式解析 + 递归下降 + for/复合赋值去糖 |
|
||||
| sema/ | sema.c(294) symbol.c(46) + .h(32) | 372 | 类型推断, 作用域链 (Scope), 可变性检查 |
|
||||
| codegen/ | codegen.c(421) target.c(30) + .h(15) | 466 | LLVM IR 生成, 4 内置函数, 目标平台初始化 |
|
||||
| driver/ | main.c(133) error.c(46) + .h(18) | 197 | 流水线串联, CLI (`l_lang <file.l> [-o <out>] [--emit-ir]`), 错误报告 |
|
||||
| test/ | test_*.c(4 文件) + test_utils.h(23) | 353 | 19 测试函数, 59 断言, 11 集成程序 |
|
||||
|
||||
**总计: 23 源文件, 1,688 行实现代码 + 308 行头文件 + 330 行测试 = 2,326 行**
|
||||
|
||||
### 1.3 关键架构决策 (v0.2–v0.3 沉淀)
|
||||
|
||||
| 决策 | 描述 | 技术理由 |
|
||||
|------|------|---------|
|
||||
| **去糖策略** | 复合赋值 (`+=` 等) 和 for 循环在 parser 层降级为已有原语 | 零 codegen/sema 入侵, 零新 AST 节点, 降低维护成本 |
|
||||
| **for 去糖路径** | `for i in 0..5 {body}` → `let mut i=0; while i<5 {body; i=i+1;}` | 步长固定为 1, 如需自定义步长需扩展语法 |
|
||||
| **Arena 统一分配** | 编译器内部所有动态内存走 arena bump allocator (8MB) | 零 free 调用, 编译器结束时一次性释放 |
|
||||
| **LLVM-C API 19.x** | 绑定 LLVM 19.x 的 C API | LLVM 22 移除 mem2reg C API (已记录注释) |
|
||||
| **GCC 链接** | `system("gcc ...")` 链接目标文件 | 简单但平台绑定 (Windows/MinGW) |
|
||||
| **Pratt 表达式解析** | 9 级优先级, 零左递归问题 | 比纯递归下降更优雅处理表达式 |
|
||||
|
||||
### 1.4 核心数据结构
|
||||
|
||||
**Token (37 种)**
|
||||
|
||||
```
|
||||
关键字: fn let mut if else while for in return
|
||||
类型: i64 f64 bool str void
|
||||
字面量: 整数 浮点数 true false 字符串
|
||||
运算符: + - * / % == != < > <= >= && || ! -> .. += -= *= /=
|
||||
分隔符: ( ) { } , : ; =
|
||||
特殊: EOF ERROR
|
||||
```
|
||||
|
||||
**AST 节点 (15 种)**
|
||||
|
||||
```
|
||||
Program Function Parameter Block LetStmt AssignStmt IfStmt WhileStmt
|
||||
ReturnStmt ExprStmt BinaryExpr UnaryExpr CallExpr LiteralExpr IdentExpr
|
||||
```
|
||||
|
||||
**类型系统 (7 种)**
|
||||
|
||||
```
|
||||
TypeKind: I64 F64 BOOL STR VOID UNKNOWN ERROR
|
||||
|
||||
转换规则:
|
||||
隐式: i64 → f64 (算术混合)
|
||||
显式: 函数参数/返回值必须标注
|
||||
不可转换: str ↔ 数值, bool ↔ 数值
|
||||
```
|
||||
|
||||
**符号表**
|
||||
|
||||
```
|
||||
Scope (链表栈): 全局 → 函数 → 块
|
||||
- SymbolKind: VARIABLE | PARAMETER | FUNCTION
|
||||
- 变量属性: is_mut (可变性)
|
||||
- 函数属性: return_type + param_types[] + param_count
|
||||
- 作用域退出时释放 (arena 生命周期管理)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 功能清单与成熟度
|
||||
|
||||
### 2.1 v0.1 基线功能 (全部完成)
|
||||
|
||||
- [x] 基本类型: i64, f64, bool, void
|
||||
- [x] 算术: + - * / %
|
||||
- [x] 比较: == != < > <= >=
|
||||
- [x] 逻辑: && || !
|
||||
- [x] let 不可变变量, 类型标注 + 类型推断
|
||||
- [x] 控制流: if/else (含 else if), while, return
|
||||
- [x] 函数定义与调用, 递归
|
||||
- [x] 内置函数: print_i64, print_f64, print_bool
|
||||
- [x] 注释: // 行注释, /* */ 块注释
|
||||
- [x] 错误报告: 词法/语法即时终止, 语义错误批量输出
|
||||
|
||||
### 2.2 v0.2 新增功能 (全部完成)
|
||||
|
||||
- [x] let mut 可变变量 + 赋值语句
|
||||
- [x] 可变性检查 — 不可变变量赋值报编译错误
|
||||
- [x] 字符串类型 str + 双引号字面量
|
||||
- [x] print_str 内置函数
|
||||
- [x] str+str 运行时拼接 (malloc + strlen + memcpy)
|
||||
- [x] 复合赋值 += -= *= /= (parser 去糖)
|
||||
- [x] LLVM 目标初始化解耦 (target.h/c)
|
||||
- [x] codegen malloc → arena 统一
|
||||
|
||||
### 2.3 v0.3 新增功能 (全部完成)
|
||||
|
||||
- [x] **for 循环 + range** — `for i in start..end { ... }`,parser 去糖
|
||||
- [x] **浮点数 lexer 修复** — `peek_next` 防 `..` 与 `.` 冲突
|
||||
- [x] **sema 测试补全** — +5 测试 (let mut assign, immutable error, str type, str concat)
|
||||
- [x] **codegen 测试补全** — +1 测试 (while 循环)
|
||||
- [x] **2 个新集成测试**: `10_for_range.l` (0..5), `11_for_step2.l` (变量边界)
|
||||
- [x] LLVM 22 mem2reg 不可用注释
|
||||
- [x] CHANGELOG v0.3.0 提交 (本次运行时已就绪)
|
||||
|
||||
---
|
||||
|
||||
## 3. 与 Rust 对标: 缺失功能清单及优先级
|
||||
|
||||
### P0: 短期 (1–2 天/项)
|
||||
|
||||
| # | 功能 | Rust 启发 | 改动范围 | 状态 |
|
||||
|---|------|----------|---------|------|
|
||||
| 1 | 复合赋值 += -= *= /= | 复合赋值运算符 | lexer + parser(desugar) | **✅ v0.2** |
|
||||
| 2 | str+str 运行时拼接 | — | codegen(malloc/strlen/memcpy) | **✅ v0.2** |
|
||||
| 3 | for 循环 + range | `for i in 0..10 {}` | lexer + parser(desugar) | **✅ v0.3** |
|
||||
| 4 | **结构体 struct** | struct 具名域 + GEP | lexer/parser/sema/codegen | **待实施** |
|
||||
|
||||
**P0 完成度: 3/4 (75%)**。struct 是解锁复合类型的最后一块 P0 拼图。
|
||||
|
||||
### P1: 中期 (3–5 天/项)
|
||||
|
||||
| # | 功能 | 改动范围 | 学习价值 | 状态 |
|
||||
|---|------|---------|---------|------|
|
||||
| 5 | 数组 + 索引 `[i64; N]`, `arr[i]` | lexer/parser/sema/codegen(GEP) | GEP 指针计算 | 待实施 |
|
||||
| 6 | 枚举 (C 风格) | lexer/parser/sema/codegen(i64) | 为代数类型铺路 | 待实施 |
|
||||
| 7 | match 表达式 | lexer/parser/sema(穷举) + codegen | 模式匹配核心 | 待实施 |
|
||||
| 8 | 类型别名 `type Meters = i64` | lexer/parser/sema(展开) | 名称等价 vs 结构等价 | 待实施 |
|
||||
|
||||
### P2: 中后期 (1–2 周/项)
|
||||
|
||||
| # | 功能 | 学习价值 | 状态 |
|
||||
|---|------|---------|------|
|
||||
| 9 | 模块系统 `mod` + `use` | 单文件→多文件编译 | 待实施 |
|
||||
| 10 | 自定义 IR 层 (三地址码/SSA) | 编译器核心抽象 | 待实施 |
|
||||
| 11 | 泛型 (单态化) | Rust 零成本抽象基石 | 待实施 |
|
||||
| 12 | 解释器模式 (walk AST) | 快速验证语义 | 待实施 |
|
||||
|
||||
### P3: 长期 (2–4 周/项)
|
||||
|
||||
| # | 功能 | 备注 | 状态 |
|
||||
|---|------|------|------|
|
||||
| 13 | trait / 接口 | 需泛型 + 虚表 | 待实施 |
|
||||
| 14 | Option/Result | 需泛型 + enum | 待实施 |
|
||||
| 15 | 所有权 / 借用检查 | 极度复杂 | 待实施 |
|
||||
| 16 | 自举 (L 编译 L) | 终极考验 | 待实施 |
|
||||
|
||||
### Rust 设计哲学吸收进度
|
||||
|
||||
| Rust 特性 | 状态 | 备注 |
|
||||
|-----------|------|------|
|
||||
| 默认不可变 (let vs let mut) | ✅ 已实现 | 编译期检查, 可变性追踪 |
|
||||
| 复合赋值 | ✅ 已实现 | parser desugar 模式 |
|
||||
| for + range | ✅ 已实现 | desugar 为 while |
|
||||
| str 拼接 | ✅ 已实现 | 运行时 malloc |
|
||||
| 表达式 vs 语句 | ❌ | if/match/block 作为表达式 (目前只支持语句) |
|
||||
| 模式匹配 | ❌ | P1 优先级 |
|
||||
| 代数数据类型 | ❌ | 需泛型 |
|
||||
| 所有权 / 借用 | ❌ | 远期 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 测试覆盖分析
|
||||
|
||||
### 4.1 单元测试
|
||||
|
||||
| 测试文件 | 测试函数 | 断言数 | 覆盖范围 |
|
||||
|---------|----------|--------|---------|
|
||||
| test_lexer.c | 3 | 14 | token 识别, 关键字, 操作符, 注释 |
|
||||
| test_parser.c | 5 | 15 | 算术, let, if, while, 函数 |
|
||||
| test_sema.c | 7 | 21 | 类型错误, 未定义变量, let mut, immutable error, str type, str concat |
|
||||
| test_codegen.c | 4 | 9 | 简单函数, if/else, 二元运算, while |
|
||||
| **合计** | **19** | **59** | |
|
||||
|
||||
### 4.2 集成测试 (11 程序)
|
||||
|
||||
| 文件 | 功能 | 版本 |
|
||||
|------|------|------|
|
||||
| 01_arithmetic.l | 算术运算 | v0.1 |
|
||||
| 02_if_else.l | if/else 控制流 | v0.1 |
|
||||
| 03_recurse.l | 递归函数 | v0.1 |
|
||||
| 04_fib_recursive.l | 斐波那契 (递归) | v0.1 |
|
||||
| 05_float.l | 浮点数 | v0.1 |
|
||||
| 06_mut_while.l | let mut + while | v0.2 |
|
||||
| 07_hello_str.l | 字符串输出 | v0.2 |
|
||||
| 08_str_concat.l | 字符串拼接 | v0.2 |
|
||||
| 09_compound_assign.l | 复合赋值 | v0.2 |
|
||||
| 10_for_range.l | for range 循环 | v0.3 |
|
||||
| 11_for_step2.l | for range (变量边界) | v0.3 |
|
||||
|
||||
### 4.3 测试缺口
|
||||
|
||||
| 缺口 | 严重度 | 说明 |
|
||||
|------|--------|------|
|
||||
| 复合赋值无独立 desugar 测试 | 低 | 仅通过 `09_compound_assign.l` 间接覆盖 |
|
||||
| for 循环无独立 desugar 测试 | 低 | 仅通过 `10_for_range.l` / `11_for_step2.l` 间接覆盖 |
|
||||
| codegen 缺 call/str/compound/for 路径 | 中 | 4 测试仅覆盖基础路径: simple, if/else, binary, while |
|
||||
| parser 缺 for 错误恢复测试 | 低 | 缺少 for/in/.. 错误提示验证 |
|
||||
| 无 LLVM IR 输出一致性测试 | 低 | 无法检测 LLVM IR 生成回归 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 技术债务与风险
|
||||
|
||||
| # | 问题 | 状态 | 严重度 | 说明 |
|
||||
|---|------|------|--------|------|
|
||||
| 1 | str concat malloc 内存泄漏 | **存留** | 中 | x + y 每次 malloc 无 free,编译后程序运行会泄漏 (编译器自身不受影响) |
|
||||
| 2 | 复合赋值无独立 desugar 测试 | **存留** | 低 | 集成测试间接覆盖 |
|
||||
| 3 | codegen 测试覆盖率低 (4/9 路径) | **存留** | 中 | call/str/compound/for/return 路径无单元测试 |
|
||||
| 4 | `system("gcc ...")` 平台绑定 | **存留** | 低 | Windows/MinGW 正常,Linux/Unix 需 `gcc`/`cc` 替换 |
|
||||
| 5 | LLVM 22 无 mem2reg C API | **已记录** | 低 | codegen.c 注释说明需用 `opt` 工具 |
|
||||
| 6 | 错误类型分散 (ErrorInfo + ErrorList) | **存留** | 低 | 不影响功能,但 API 不统一 |
|
||||
| 7 | CHANGELOG 未更新 v0.3 | **✅ 已解决** | — | `620cec4` 提交了 v0.3.0 条目 |
|
||||
| 8 | parser.c 函数 `parse_function` 过长 | **存留** | 低 | 约 60 行,可拆分为多个子函数 |
|
||||
| 9 | 无 fuzzing / 边界输入测试 | **新增** | 低 | 超大源文件、超长标识符、深层嵌套等未覆盖 |
|
||||
|
||||
### 风险矩阵
|
||||
|
||||
| 风险 | 概率 | 影响 | 缓解 |
|
||||
|------|------|------|------|
|
||||
| LLVM API 版本升级 break | 中 | 高 | 当前锁定 19.x,文档记录不兼容点 |
|
||||
| GCC 链接在非 MinGW 环境失败 | 中 | 中 | 可接受链接器参数或使用 LLVM lld |
|
||||
| Arena 内存耗尽 (8MB) | 极低 | 中 | 巨型程序才触发,编译器中止即可 |
|
||||
| str 泄漏导致大程序 OOM | 低 | 中 | 短期替代方案: arena 化 str 拼接 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 推荐开发路线图
|
||||
|
||||
### v0.4 目标 (下一迭代)
|
||||
|
||||
| 优先级 | 功能 | 预计工时 | 依赖/备注 |
|
||||
|--------|------|---------|----------|
|
||||
| **P0** | **结构体 struct** | 2–3 天 | 解锁 GEP 和复合类型,全流水线 |
|
||||
| P1 | str concat arena 化 (修复技术债 #1) | 0.5 天 | 替换 malloc 为 arena 分配 |
|
||||
| P1 | codegen 测试扩展 (call/str/for) | 0.5 天 | 覆盖率补偿 |
|
||||
| P1 | parser 测试补全 (for 错误恢复) | 0.5 天 | 回归保护 |
|
||||
|
||||
### v0.5 目标
|
||||
|
||||
| 优先级 | 功能 | 预计工时 |
|
||||
|--------|------|---------|
|
||||
| P1 | 数组 + 索引 | 2 天 |
|
||||
| P1 | 枚举 (C 风格) | 1 天 |
|
||||
| P1 | match 表达式 | 2–3 天 |
|
||||
| P1 | 类型别名 | 0.5 天 |
|
||||
|
||||
### 长期方向
|
||||
|
||||
| 优先级 | 功能 | 预计工时 |
|
||||
|--------|------|---------|
|
||||
| P2 | 自定义 IR 层 | 3–5 天 |
|
||||
| P2 | 模块系统 | 3–5 天 |
|
||||
| P2 | 解释器模式 | 2 天 |
|
||||
| P3 | 泛型 (单态化) | 5–7 天 |
|
||||
| P3 | trait / 接口 | 5–7 天 |
|
||||
| P3 | 自举尝试 | 数周 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 度量汇总
|
||||
|
||||
| 指标 | 值 | 较 v0.2 (72a971e) | 较 v0.3 基线 (382cd08) |
|
||||
|------|-----|-------------------|----------------------|
|
||||
| 源文件数 (.c) | 12 | — | 无变化 |
|
||||
| 头文件数 (.h) | 12 | — | 无变化 |
|
||||
| 实现代码 | 1,688 行 | +52 | 无变化 |
|
||||
| 头文件 | 308 行 | +23 | 无变化 |
|
||||
| 测试代码 | 330 行 | +88 | 无变化 |
|
||||
| 总代码量 | 2,326 行 | +163 | 无变化 |
|
||||
| Token 类型 | 37 | +3 (FOR/IN/DOT_DOT) | 无变化 |
|
||||
| AST 节点类型 | 15 | +1 (ASSIGN_STMT) | 无变化 |
|
||||
| TypeKind | 7 | +2 (STR, ERROR) | 无变化 |
|
||||
| 内置函数 | 4 (print_i64/f64/bool/str) | +1 (print_str) | 无变化 |
|
||||
| C 运行时依赖 | printf, malloc, strlen, memcpy | +malloc/strlen/memcpy | 无变化 |
|
||||
| 单元测试函数 | 19 | +5 | 无变化 |
|
||||
| 单元测试断言 | 59 | +14 | 无变化 |
|
||||
| 集成测试程序 | 11 | +2 (for_range, for_step2) | 无变化 |
|
||||
| P0 完成度 | 3/4 (75%) | +for | 无变化 |
|
||||
| P0 遗留 | struct | — | 无变化 |
|
||||
| 编译产物 | 6 个 .exe | — | 无变化 |
|
||||
| Git 提交数 | 11 | +2 | +1 (CHANGELOG) |
|
||||
|
||||
---
|
||||
|
||||
## 8. 代码质量评估
|
||||
|
||||
### 8.1 模块内聚度
|
||||
|
||||
| 模块 | 内聚度 | 评价 |
|
||||
|------|--------|------|
|
||||
| lexer | 高 | 纯函数接口,状态机集中在单文件,token 定义与值提取分离 |
|
||||
| parser | 高 | 递归下降 + Pratt 组合清晰,去糖逻辑局部化 |
|
||||
| ast | 高 | 工厂函数模式统一,union 节点设计节省内存 |
|
||||
| sema | 高 | 遍历器模式,analyze_node/analyze_expr 双入口,职责明确 |
|
||||
| codegen | 中高 | `codegen_stmt` 单一大函数处理所有节点,可拆分但暂不紧急 |
|
||||
| driver | 中 | main.c 串联流水线,error.c 独立,接口清晰 |
|
||||
| util | 高 | 单一职责 (arena 分配器),零外部依赖 |
|
||||
|
||||
### 8.2 代码风格一致性
|
||||
|
||||
- 蛇形命名 (snake_case) 贯穿全部源文件
|
||||
- 头文件守卫 (`#ifndef X_H` / `#define X_H` / `#endif`) 统一
|
||||
- 工厂函数模式 (`ast_make_*`) 跨 AST 模块一致
|
||||
- 错误处理模式: `ErrorInfo*` (即时错误) + `ErrorList*` (批量错误) 两类
|
||||
|
||||
### 8.3 编译警告
|
||||
|
||||
未在本次运行中编译,但从代码结构推断:
|
||||
- 全局变量 `_tests_run` / `_tests_failed` 在 `test_utils.h` 中 `static` 声明 (每个翻译单元独立副本, 跨文件统计不准确)
|
||||
- `Arena*` 通过 `void*` 跨模块传递 (`arena_alloc_impl(void* alloc, ...)`),丢失类型安全, 但避免了模块间循环依赖
|
||||
|
||||
---
|
||||
|
||||
*本报告由 Codex 自动生成于 2026-06-05 11:52。自上次代码基线 `382cd08` 后无源代码变更。当前 HEAD `620cec4` 仅增加 CHANGELOG.md v0.3.0 条目 (14 行) + 上一轮分析报告 (288 行)。编译器源码、测试、构建系统均不变。P0 struct 仍为唯一待实施的 P0 功能。*
|
||||
Reference in New Issue
Block a user