Files
l-language/docs/analysis/architecture-analysis-report-2026-06-05-0100.md
T
Serendipity 9e41b09318 fix: str+str 运行时拼接 — malloc + strlen + memcpy
- codegen: 声明 CRT 的 malloc/strlen/memcpy
- str+str 拼接: strlen(l)+strlen(r)+1 → malloc → memcpy×2 → 返回指针
- 新增集成测试 08_str_concat.l ("Hello, " + "World!" → "Hello, World!")
- 修复自报告 §5-6 字符串拼接不工作的 bug
2026-06-05 02:36:23 +08:00

269 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# L Language 架构分析报告 (v0.1+)
> 日期: 2026-06-05 01:00 | 自动生成 | 自上次报告后有 4 个提交
> 上次报告: [docs/architecture-analysis-report-2026-06-05.md](/D:\Code\doing_exercises\programs\L Language\docs\architecture-analysis-report-2026-06-05.md) (v0.1 基线 3b7bab1)
---
## 变更摘要 (自上次报告)
- [x] P0: `let mut` + 赋值语句
- [x] P0: 字符串类型 + 字面量 + `print_str`
- [x] 架构: LLVM 目标初始化解耦 -> `target.h/c`
- [x] 技术债: codegen `malloc` -> arena
- [x] 技术债: 添加 `.codegraphignore`
上次报告提出的 4 项 P0 建议已全部落地。本次报告反映 v0.1 + 4 commits 后的当前快照,新增 588 行代码(net),2 个集成测试程序(06_mut_while.l, 07_hello_str.l)。
| Commit | 功能 |
|--------|------|
| `f8c5e18` | 技术债修复:codegen malloc->arena + .codegraphignore |
| `bd02a49` | `let mut` + 赋值语句 -- while 循环可修改变量 |
| `9a53d97` | 字符串类型 + 字面量 + `print_str` |
| `9ff2990` | LLVM 目标初始化解耦 -- 抽取 target.h/c |
---
## 1. 当前架构全景
### 1.1 编译流水线
```
源码(.l) -> Lexer(词法) -> Parser(语法) -> Sema(语义) -> Codegen(LLVM IR) -> Target(obj) -> 链接(.exe)
Token[] AstNode* 类型标注 LLVMModuleRef .o 文件 GCC/ld
```
一条完整的手写单趟编译器流水线,无依赖生成器。Codegen 层与 Target 层已通过 `target.h/c` 解耦。
### 1.2 模块清单与指标
| 模块 | 文件 | 行数 | 关键数据结构 | 新增功能 |
|------|------|------|-------------|---------|
| lexer/ | lexer.c(131) token.c(44) + .h(49) | 224 | Token {kind, start, length, line, col} | TOK_MUT, TOK_STR, TOK_STR_LIT, TOK_ASSIGN |
| ast/ | ast.c(107) ast.h(93) | 200 | AstNode {kind, type, as{union}} | AST_ASSIGN_STMT, is_mut, str_val |
| parser/ | parser.c(314) parser.h(10) | 324 | Parser {tokens, pos, filename, arena} | let mut 解析, 赋值语句, 字符串字面量 |
| sema/ | sema.c(294) symbol.c(46) + .h(41) | 381 | Scope {head, parent}, Symbol {is_mut} | 可变性检查, TYPE_STR, print_str, 赋值检查 |
| codegen/ | codegen.c(365) target.c(30) + .h(26) | 421 | CgCtx {builder, var_table, fn_table} | Store(赋值), GlobalStringPtr(str) |
| driver/ | main.c(133) error.c(46) + .h(18) | 197 | 流水线串联 | 调用 target_* 接口 |
| util/ | arena.c(39) arena.h(13) | 52 | Arena {memory, offset, capacity} | 8MB bump allocator |
| include/ | l_lang.h | 34 | TypeKind, 公共声明 | TYPE_STR 新增 |
**总计: 22 源文件, ~1,833 行实现代码**
### 1.3 技术选型评估
| 选择 | 评价 | 最新状态 |
|------|------|---------|
| C17 + CMake + MinGW | 轻量,学习友好 | 稳定 |
| Arena bump allocator | 极简内存管理,无 GC 开销 | 已统一(codegen 原先混用 malloc |
| LLVM-C API (19.x) | 成熟但版本差异需处理 | 已适配 LLVMContext API |
| 手写 Lexer/Parser | 0 外部依赖,完整控制 | 稳定,30 种 Token 类型 |
| Pratt 表达式解析 | 优雅处理优先级,易扩展 | 无变化 |
| GCC 链接 (`system()`) | 简单但平台绑定 | 待改进 |
| 分离 target.h/c | 关注点分离,可测试 | **新建模块** |
---
## 2. 功能清单与成熟度
### 2.1 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] 测试: 65 单元测试 + 5 集成测试
### 2.2 v0.1+ 新增功能
- [x] **let mut 可变变量** -- `let mut x: i64 = 0;` 声明可变变量
- [x] **赋值语句** -- `x = x + 1;` 对可变变量赋值(LLVMBuildStore
- [x] **可变性检查** -- 对不可变变量赋值报 "不能对不可变变量赋值(需用 let mut 声明)"
- [x] **字符串类型 str** -- 类型系统新增 TYPE_STR
- [x] **字符串字面量** -- `"Hello, L Language!"` 双引号字面量,LLVMBuildGlobalStringPtr
- [x] **字符串拼接 (语义)** -- `"a" + "b"` 类型检查为 str + str -> str
- [x] **print_str 内置函数** -- 委托 printf("%%s\n", str)
- [x] **target.h/c 独立模块** -- LLVM 目标初始化与 Codegen 解耦
- [x] **集成测试**: 06_mut_while.l (可变 while 循环), 07_hello_str.l (字符串输出)
### 2.3 实现细节
**let mut + 赋值** 贯穿全流水线:
- Lexer: `TOK_MUT` (关键字), `TOK_ASSIGN` (分隔符)
- AST: `AST_ASSIGN_STMT` 节点, `let_stmt.is_mut` 标志
- Parser: `let mut IDENT = expr;` 完整解析; `IDENT = expr;` 赋值语句(标识符后紧跟 `=` 时触发)
- Sema: `Symbol.is_mut` 标记; 赋值时检查可变性 + 类型一致性
- Codegen: `LLVMBuildStore` 向现有 alloca 写入新值
**字符串类型** 实现:
- Lexer: `TOK_STR` (类型关键字), `TOK_STR_LIT` (双引号字面量)
- AST: `literal.str_val` (arena 拷贝), `AST_LITERAL_EXPR` 支持 TYPE_STR
- Parser: `TOK_STR_LIT` 创建 `ast_make_literal_str()`
- Sema: TYPE_STR 加入类型系统; `+` 对 str+str 做类型检查
- Codegen: `LLVMBuildGlobalStringPtr` 生成全局常量; `print_str` 委派 printf
- **限制**: 运行时字符串拼接(str + str)在 codegen 中直接返回左操作数,语义层验证通过但**运行时行为不正确**
---
## 3. 与 Rust 对标:缺失功能清单
按 "学习价值 + 实现难度" 排序。已完成项标注 ✓。
### P0: 短期(1-2 天/项)
| # | 功能 | Rust 启发 | 改动范围 | 学习价值 |
|---|------|----------|---------|---------|
| ✓ | let mut + 赋值 | 默认不可变 | lexer/parser/sema/codegen | 不可变性贯穿全流水线 |
| ✓ | 字符串类型 + 字面量 | &str/String | lexer/parser/sema/codegen | LLVM 全局常量和指针 |
| 1 | **复合赋值** += -= *= /= | 复合赋值运算符 | lexer(4 Token) + parser(desugar) + sema(mut check) | 语法糖去糖 |
| 2 | **修复 str+str 运行时拼接** | -- | codegen(strcat/memcpy) | 运行时内存操作 |
| 3 | **for 循环 + Range** | for i in 0..10 {} | lexer(for/in/..) + parser + sema + codegen->while | 去糖为 while 循环 |
| 4 | **结构体 struct** | struct 具名域 | lexer(struct/.) + parser + sema + codegen(GEP) | GEP 指针计算 |
### P1: 中期(3-5 天/项)
| # | 功能 | 改动范围 | 学习价值 |
|---|------|---------|---------|
| 5 | **数组 + 索引** [i64; N], arr[i] | lexer/parser/sema/codegen(GEP) | GEP 多维指针计算 |
| 6 | **枚举 (C 风格)** | lexer(enum) + parser + sema + codegen(i64) | 为代数类型铺路 |
| 7 | **match 表达式** | lexer/parser/sema(穷举检查) + codegen | 模式匹配是 PL 核心 |
| 8 | **类型别名** type Meters = i64 | lexer/parser/sema(展开) | 名称等价 vs 结构等价 |
### P2: 中后期(1-2 周/项)
| # | 功能 | 学习价值 |
|---|------|---------|
| 9 | 模块系统 mod + use | 从单文件到多文件跳跃 |
| 10 | 自定义 IR 层 (三地址码/SSA) | "IR 是编译器的核心抽象" |
| 11 | 泛型 (单态化) | Rust 零成本抽象的基石 |
| 12 | 解释器模式 (walk AST) | 快速验证语义,无需 LLVM |
### P3: 长期(2-4 周/项)
| # | 功能 | 备注 |
|---|------|------|
| 13 | trait / 接口 | 需泛型 + 虚表 |
| 14 | Option/Result 错误处理 | 需泛型 + enum |
| 15 | 所有权 / 借用检查 | 借用检查器,极度复杂 |
| 16 | 自举 (L 编译 L) | 终极考验 |
### Rust 设计哲学吸收建议
| Rust 特性 | 决策 | 理由 |
|-----------|------|------|
| 默认不可变 (let vs let mut) | **已加** | 编译期检查,零实现成本 |
| 表达式 vs 语句 | 建议加 | if/match/block 作为表达式 |
| 模式匹配 | 建议加 | 最优雅的控制流之一 |
| 代数数据类型 | 有条件 | 需要泛型支持 |
| Option/Result | 有条件 | 依赖泛型 + enum |
| 所有权 / 借用 | 暂不加 | 借用检查器,远超当前阶段 |
| 生命周期标注 | 暂不加 | 所有权系统的伴生 |
| trait 系统 | 暂不加 | 需泛型 + 虚表 |
| 宏系统 | 暂不加 | 自举后才考虑 |
---
## 4. 架构改进:已完成 vs 待实施
### 4.1 已完成 ✓
1. **代码生成与链接解耦** (来自上次报告 4.1-1)
- `src/codegen/target.h/c` 新增 (30+15 行)
- 接口: target_init(), target_get_default_triple(), target_create_machine(), target_emit_obj()
- main.c 减少 25 行 inline LLVM Target API 调用
2. **内存管理统一** (来自上次报告 7-1)
- codegen.c 所有 malloc 替换为 arena_alloc()
- 消除内存泄漏风险
3. **索引排除** (来自上次报告 7-5)
- .codegraphignore 排除 build/
### 4.2 待实施
4. **错误类型统一** (上次报告 4.1-2)
- 当前: ErrorInfo 和 ErrorList 分散多个模块
- 建议: 统一为 CompilerError 结构体
5. **测试框架扩展** (上次报告 4.1-3)
- 当前: 无 codegen 层测试
- 建议: test_codegen.c + LLVMVerifyModule
6. **调用约定抽象** (上次报告 4.2-6)
- 建议: 抽 abi.h 封装参数传递和返回值处理
---
## 5. 技术债务与风险
| # | 问题 | 状态 | 影响 | 建议 |
|---|------|------|------|------|
| 1 | codegen malloc 混用 arena | **已修复** | -- | -- |
| 2 | 无 .codegraphignore | **已修复** | -- | -- |
| 3 | system("gcc ...") 链接 | **仍存在** | 平台不兼容 | 封装 Linker 接口,支持 ld/lld |
| 4 | 无 codegen 层测试 | **仍存在** | IR 正确性无形式验证 | test_codegen.c |
| 5 | 无优化 pass (mem2reg) | **仍存在** | alloca 效率低 | LLVMRunPassManager |
| 6 | 字符串运行时拼接不工作 | **新增** | "a"+"b" 语义通过但运行时错误 | codegen 中实现 strcat/memcpy |
| 7 | CHANGELOG 未更新 | **新增** | 4 个新 commit 未记录 | 添加 v0.2.0 条目 |
---
## 6. 推荐开发路线图
### v0.2 目标
| 优先级 | 功能 | 预计工时 | 备注 |
|--------|------|---------|------|
| P0 | 修复 str+str 运行时拼接 | 0.5 天 | 阻塞后续 |
| P0 | 复合赋值 += -= *= /= | 0.5 天 | 语法糖,改动面小 |
| P0 | 结构体 struct | 2-3 天 | 解锁 GEP 和复合类型 |
| P0 | for 循环 + range | 1 天 | 去糖为 while |
| P1 | test_codegen.c | 1 天 | 技术债补偿 |
### v0.3 目标
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P1 | 数组 + 索引 | 2 天 |
| P1 | 枚举 (C 风格) | 1 天 |
| P2 | match 表达式 | 2-3 天 |
| P1 | 类型别名 | 0.5 天 |
| P2 | 解释器模式 | 2 天 |
### 长期
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P2 | 自定义 IR 层 | 3-5 天 |
| P2 | 模块系统 | 3-5 天 |
| P3 | 泛型 (单态化) | 5-7 天 |
| P3 | trait / 接口 | 5-7 天 |
| P3 | 自举尝试 | 数周 |
---
## 7. 度量汇总
| 指标 | v0.1 基线 | 当前 (v0.1+) | 变化 |
|------|----------|-------------|------|
| 源文件数 | 19 | 22 | +3 |
| 实现代码行 | ~1,300 | ~1,833 | +~530 |
| Token 类型 | 25 | 30 | +5 |
| AST 节点类型 | 13 | 15 | +2 |
| 类型系统 | 4 种 | 5 种 (+str) | +1 |
| 内置函数 | 3 | 4 (+print_str) | +1 |
| 集成测试 | 5 程序 | 7 程序 | +2 |
| 单元测试 | 65 | 65 | 无变化 |
| LLVM 模块 | 单体 codegen.c | codegen.c + target.c | 解耦 |
| 报告 P0 完成度 | -- | 4/4 | 100% |
---
*本报告由 Codex 自动生成。自上次报告后代码有显著变化 (4 commits, +588/-53 行),上次报告的 4 项 P0 建议全部实现。*