Files
l-language/docs/architecture-analysis-report-2026-06-05.md
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

11 KiB

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)

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

  1. IR 中间表示层

    • 当前: AST 直接生成 LLVM IR, 跳过了"自己设计 IR"这一步
    • 建议: 在 AST 和 LLVM IR 之间加一层自定义 IR (三地址码或 SSA 形式)
    • 学习价值: 理解"IR 是编译器的核心抽象"这句话的真正含义
  2. 解释器模式

    • 建议: 在 codegen/ 旁加一个 interp/ 模块, 直接 walk AST 解释执行
    • 好处: 快速验证语义正确性, 无需 LLVM 编译; 区分编译和解释模式
  3. 调用约定抽象

    • 当前: codegen 直接调 LLVMBuildCall2
    • 建议: 抽一层 abi.h, 封装参数传递和返回值处理

4.3 长期改进

  1. 自举准备

    • 用 L Language 写一个 L Language 编译器的最小实现
    • 分阶段: 先让 L 输出 AST -> 再输出 LLVM IR -> 最终用 L 编译自己
  2. 增量编译

    • 缓存已编译模块的时间戳和符号表
    • 只重新编译有改动的文件

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 小时后。