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

11 KiB
Raw Blame History

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)


变更摘要 (自上次报告)

  • P0: let mut + 赋值语句
  • P0: 字符串类型 + 字面量 + print_str
  • 架构: LLVM 目标初始化解耦 -> target.h/c
  • 技术债: codegen malloc -> arena
  • 技术债: 添加 .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 基线功能

  • 基本类型: i64, f64, bool, void
  • 算术运算: + - * / %
  • 比较运算: == != < > <= >=
  • 逻辑运算: && || !
  • 变量声明: let 不可变,类型标注 + 类型推断
  • 控制流: if/else, while
  • 函数定义与调用: 参数、返回类型、递归
  • 内置函数: print_i64, print_f64, print_bool
  • 注释: // 行注释, /* */ 块注释
  • 错误报告: 词法/语法即时终止, 语义错误批量输出
  • 测试: 65 单元测试 + 5 集成测试

2.2 v0.1+ 新增功能

  • let mut 可变变量 -- let mut x: i64 = 0; 声明可变变量
  • 赋值语句 -- x = x + 1; 对可变变量赋值(LLVMBuildStore
  • 可变性检查 -- 对不可变变量赋值报 "不能对不可变变量赋值(需用 let mut 声明)"
  • 字符串类型 str -- 类型系统新增 TYPE_STR
  • 字符串字面量 -- "Hello, L Language!" 双引号字面量,LLVMBuildGlobalStringPtr
  • 字符串拼接 (语义) -- "a" + "b" 类型检查为 str + str -> str
  • print_str 内置函数 -- 委托 printf("%%s\n", str)
  • target.h/c 独立模块 -- LLVM 目标初始化与 Codegen 解耦
  • 集成测试: 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 待实施

  1. 错误类型统一 (上次报告 4.1-2)

    • 当前: ErrorInfo 和 ErrorList 分散多个模块
    • 建议: 统一为 CompilerError 结构体
  2. 测试框架扩展 (上次报告 4.1-3)

    • 当前: 无 codegen 层测试
    • 建议: test_codegen.c + LLVMVerifyModule
  3. 调用约定抽象 (上次报告 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 建议全部实现。