# L Language 架构与代码审查报告 > 日期: 2026-06-07 | 全面手动审查 | HEAD: `35e2691` ## 1. 项目概览 | 指标 | 数值 | |------|------| | 版本 | v0.6 | | 语言 | C17 (`-Wall -Wextra -g`) | | 后端 | LLVM 22.x C API | | 链接器 | clang+lld (fallback gcc) | | 平台 | Windows 11 + MinGW-w64 | | 总源码行数 | 5,039 (32 .c + 20 .h) | | 单元测试 | 197 断言 (4 文件, 42 测试函数) | | 集成测试 | 36 程序 | | 构建警告 | **0** | ## 2. 编译流水线 ``` 源码(.l) → Lexer → Parser(+Desugar) → Sema → Codegen → Target → clang+lld → .exe 72 Token 27 AST 节点 类型标注 LLVM IR .o 文件 可执行文件 ``` ### 2.1 各阶段文件清单 | 阶段 | 文件 | 行数 | 职责 | |------|------|------|------| | **include/** | l_lang.h | 55 | TypeKind 枚举 (14), TypeInfo, SourceLoc | | **lexer/** | lexer.c (180) + token.c (60) + .h (55+13) | 308 | 手写状态机, 72 Token 类型 | | **parser/** | parser.c (564) + expr.c (484) + desugar.c (109) + parse_internal.h (71) + .h (13+30) | 1,271 | 递归下降+Pratt, 5 种去糖独立化 | | **ast/** | ast.c (284) + ast.h (183) + visit.c (17) + visit.h (25) | 509 | 27 AST 节点 + 工厂函数 + Visitor dispatch | | **sema/** | typeck.c (652) + sema.c (500) + symbol.c (172) + type_table.c (36) + .h (57+84+22) | 1,535 | 类型推断+检查, 泛型单态化, 数据驱动类型表 | | **codegen/** | codegen.c (453) + cg_expr.c (440) + target.c (35) + .h (83+15+21) | 1,047 | LLVM IR 生成, 目标输出, 符号表 | | **driver/** | main.c (232) + error.c (49) + .h (26) | 307 | 流水线串联, 错误报告 | | **util/** | arena.c (45) + arena.h (17) | 62 | Bump allocator (8MB) | ### 2.2 文件大小分布 所有核心 .c 文件均 ≤ 652 行(限制 800): ``` typeck.c 652 ████████████████████ parser.c 564 █████████████████ sema.c 500 ████████████████ expr.c 484 ███████████████ codegen.c 453 ██████████████ cg_expr.c 440 ██████████████ ``` ## 3. 类型系统 ### 3.1 Token 类型: 72 种 | 类别 | 数量 | 示例 | |------|------|------| | 关键字 | 20 | fn, let, var, if, else, while, for, in, return, guard, struct, type, enum, extend, match, pub, mod, use, trait, Self | | 类型 | 8 | i32, i64, u64, f64, bool, char, str, void | | 字面量 | 6 | INT_LIT, FLOAT_LIT, CHAR_LIT, true, false, STR_LIT | | 标识符 | 2 | IDENT, UNDERSCORE | | 算术 | 5 | + - * / % | | 比较 | 6 | == != < > <= >= | | 逻辑 | 4 | && \|\| \|> ! | | 箭头 | 3 | -> to => | | 复合赋值 | 4 | += -= *= /= | | 括号 | 4 | ( ) { } | | 方括号 | 2 | [ ] | | 分隔符 | 4 | , : ; = | | 特殊 | 4 | . :: EOF ERROR | ### 3.2 TypeKind: 14 种 - 内置: i32, i64, u64, f64, bool, char, str, void - 复合: struct, enum, array - 内部: GENERIC (泛型参数), UNKNOWN (未推断), ERROR (类型错误) ### 3.3 TypeTable 数据驱动 `type_table.c` 统一管理类型元数据(promote_rank, bit_width, is_signed, is_numeric),promote/can_implicit_convert/is_numeric/is_comparable 全部查表。新增类型只需在 TABLE[] 加一行。 ## 4. AST 节点: 27 种 | 类别 | 节点 | |------|------| | 程序结构 | PROGRAM, FUNCTION, PARAMETER, BLOCK, MOD_DECL, USE_DECL | | 语句 | LET_STMT, ASSIGN_STMT, IF_STMT, WHILE_STMT, RETURN_STMT, EXPR_STMT, ARRAY_ASSIGN_STMT | | 表达式 | BINARY_EXPR, UNARY_EXPR, CALL_EXPR, LITERAL_EXPR, IDENT_EXPR, FIELD_ACCESS, INDEX_EXPR, METHOD_CALL | | 类型/声明 | STRUCT_DECL, STRUCT_INIT, TYPE_ALIAS, ENUM_DECL, ENUM_VARIANT, IMPL_BLOCK, TRAIT_DECL | 新增节点流程:ast.h 加枚举 → ast.c 加工厂 → typeck.c 的 analyze_expr_init() 加一行 handler → 编译器检查未初始化的函数指针。 ## 5. 已实现功能 ### 5.1 P0 基础 (10 项) 基础类型 (i64/f64/bool/void), 控制流 (if/else/while/return), let/var 变量, str 类型+拼接, for..in 去糖, struct 声明+初始化+字段访问 ### 5.2 P1 类型与抽象 (5 项) type 别名, enum 声明+变体, 固定数组+索引, impl/extend 方法块, match 去糖 ### 5.3 P0 扩展 (5 项) i32/u64/char, guard 守卫, 命名参数, 管道 |>, 字符串插值 ### 5.4 P2 (6 项) — 全部完成 ADT 枚举关联数据, 表达式作为值 (if-expr), if let, 模块系统 (mod), 泛型单态化, trait 接口 ## 6. 测试覆盖 | 测试文件 | 函数 | 断言 | 覆盖范围 | |----------|------|------|----------| | test_lexer.c | 3 | 41 | 基础 token, 关键字, 运算符 | | test_parser.c | 20 | 54 | 全语法特性 | | test_sema.c | 24 | 74 | 类型检查, 错误检测 | | test_codegen.c | 10 | 28 | LLVM IR 生成验证 | | **单元合计** | **57** | **197** | | | programs/*.l | — | 36 | 端到端集成 | 全部通过,零失败,零构建警告。 ## 7. 近期重构成果 | 重构 | 效果 | |------|------| | parser.c 1211→564+484+109 | 表达式/语句/去糖分离 | | sema.c 1129→500+652 | 入口/表达式检查分离 | | codegen.c 947→453+440 | 语句/表达式生成分离 | | desugar.c 独立化 | match/guard/for/if-let/复合赋值 5 种去糖提取 | | TypeTable 数据驱动 | promote/convert/numeric 查表,新增类型 7→3-4 文件 | | AST Visitor dispatch | analyze_expr switch→vtable,新增节点加一行 | | error.c arena 化 | 消除项目唯一 malloc/realloc/strdup | | test_parser.c 5→20 函数 | 15→54 断言,覆盖全语法特性 | ## 8. 代码质量 ### 8.1 优点 - **零编译警告**: `-Wall -Wextra` 干净 - **全测试通过**: 197 单元 + 36 集成 - **内存管理统一**: 全部通过 Arena bump allocator,无散落 malloc/free(除 driver 文件读取) - **文件大小受控**: 所有核心 .c ≤ 652 行 - **模块边界清晰**: 5 阶段流水线,内部头文件隔离实现细节 - **新增类型/节点低摩擦**: TypeTable 一行注册,Visitor 一行注册 - **去糖独立化**: 5 种语法糖从 parser 内联提取为纯函数,可独立测试 - **LLVM 22 适配**: 显式 Context 管理,CreateProcess 替代 system() ### 8.2 待改进 | # | 严重度 | 位置 | 问题 | 建议 | |---|--------|------|------|------| | 1 | **中** | parser/expr.c:195, parser/parser.c:497,520 | 3 处 `sprintf` 未使用 `snprintf` | 替换为 snprintf,防止标识符过长溢出 | | 2 | **中** | parser/parser.c:535 | `use` 语句跳过解析,符号导入未实现 | 实现 use 语句的符号导入语义 | | 3 | **低** | main.c:192 | `strcpy(p, ld_args[i])` | 用 memcpy+长度检查替代 | | 4 | **低** | codegen/cg_expr.c | 表达式生成仍用 switch (440 行) | 后续可转为 Visitor dispatch | | 5 | **低** | sema/typeck.c:652 | typeck.c 略超 650 行 | 泛型单态化可提取为 mono.c | | 6 | **信息** | 全局 | 固定数组 [64]/[256] 带边界检查 | 当前均有 if (n>=N) 保护,长期可换动态分配 | ## 9. 安全审计 | 检查项 | 状态 | |--------|------| | 缓冲区溢出 | ✅ 全部使用 snprintf(sizeof) 或有边界检查 | | 格式化字符串 | ✅ 无用户输入直接作为格式串 | | 空指针解引用 | ✅ 所有 arena_alloc 返回值有 NULL 检查 | | 内存泄漏 | ✅ Arena bump allocator 统一释放 | | 栈溢出 | ✅ MAX_PARSE_DEPTH/MAX_CODEGEN_DEPTH 限制递归 | | LLVM 验证 | ✅ codegen_module 调用 LLVMVerifyModule | ## 10. 架构评估 **评分: 8.5/10** - 流水线设计清晰,每阶段独立可测试 - 近期重构显著改善模块化(文件拆分、去糖独立、数据驱动类型表) - AST 节点新增流程标准化(枚举→工厂→handler 注册) - 测试覆盖充足(197 单元 + 36 集成) - 剩余问题均为中低优先级,无阻塞性缺陷 - 主要不足:codegen 表达式层仍为巨型 switch、use 语句未实现 --- *本报告手动审查生成于 2026-06-07。*