commit initial

This commit is contained in:
baishi
2026-05-30 07:59:28 +08:00
commit cbefad339f
39 changed files with 7736 additions and 0 deletions

View File

@@ -0,0 +1,392 @@
# Tiny C Compiler in C# - Technical Design
Feature Name: tiny-c-compiler-csharp
Updated: 2026-05-20
## Description
本项目实现一个使用 C# 编写的 C 语言编译器,参考 TCC 的设计理念。编译器将 C 源代码直接编译为 x86/x64 本地机器码,不经过 MSIL 中间层。项目目标是实现一个轻量级、编译速度快的 C 编译器,支持 C99 标准的核心子集。
## Architecture
```mermaid
graph TD
A["C Source Code\n.c files"] --> B["Preprocessor\n预处理"]
B --> C["Lexer\n词法分析"]
C --> D["Parser\n语法分析"]
D --> E["Semantic Analyzer\n语义分析"]
E --> F["IR Generator\n中间表示生成"]
F --> G["Code Generator\n代码生成 x86/x64"]
G --> H["Object File\nPE/ELF"]
H --> I["Executable\n可执行文件"]
J["Error Handler"] -.-> B
J -.-> C
J -.-> D
J -.-> E
J -.-> F
J -.-> G
K["Symbol Table"] -.-> E
K -.-> F
K -.-> G
L["Type System"] -.-> E
L -.-> F
```
### Architecture Overview
编译器采用传统的单遍或多遍编译架构,分为以下主要阶段:
1. **预处理阶段**:处理宏展开、条件编译、头文件包含
2. **前端阶段**:词法分析、语法分析、语义分析
3. **中间阶段**IR 生成与优化
4. **后端阶段**x86/x64 代码生成与可执行文件输出
## Components and Interfaces
### 1. Preprocessor (预处理器)
**职责**
- 处理 `#include` 指令,展开头文件
- 处理 `#define` 宏定义和宏展开
- 处理条件编译 `#ifdef``#ifndef``#endif``#if`
- 处理 `#pragma` 指令
**接口**
```csharp
public interface IPreprocessor
{
string Preprocess(string sourceCode, string sourceFile);
void AddIncludePath(string path);
void DefineMacro(string name, string? value);
}
```
### 2. Lexer (词法分析器)
**职责**
- 将预处理后的源代码分解为 token 流
- 识别关键字、标识符、字面量、运算符、分隔符
- 跳过注释和空白
- 报告词法错误
**接口**
```csharp
public interface ILexer
{
IEnumerable<Token> Tokenize(string source);
}
public enum TokenType
{
Keyword, Identifier, IntLiteral, FloatLiteral,
CharLiteral, StringLiteral, Operator, Separator,
EOF, Error
}
public record Token(
TokenType Type,
string Lexeme,
object? Value,
SourceLocation Location
);
```
### 3. Parser (语法分析器)
**职责**
- 实现递归下降解析器
- 构建抽象语法树AST
- 处理 C 语言的运算符优先级
- 报告语法错误
**接口**
```csharp
public interface IParser
{
AstNode Parse();
}
public abstract record AstNode(SourceLocation Location);
public record ProgramNode(List<DeclarationNode> Declarations, SourceLocation Location) : AstNode(Location);
public record FunctionDeclarationNode(
TypeNode ReturnType,
string Name,
List<ParameterNode> Parameters,
BlockStatementNode Body,
SourceLocation Location
) : AstNode(Location);
```
### 4. Semantic Analyzer (语义分析器)
**职责**
- 类型检查与类型推断
- 符号表管理
- 作用域管理
- 语义错误报告
**接口**
```csharp
public interface ISemanticAnalyzer
{
void Analyze(AstNode root);
}
public interface ISymbolTable
{
void EnterScope();
void ExitScope();
void AddSymbol(string name, Symbol symbol);
Symbol? Lookup(string name);
}
```
### 5. IR Generator (中间表示生成器)
**职责**
- 将 AST 转换为三地址码形式的 IR
- 构建控制流图CFG
- 支持基本优化(常量折叠、死代码消除)
**接口**
```csharp
public interface IIrGenerator
{
IrProgram Generate(AstNode ast);
}
public record IrProgram(List<IrFunction> Functions);
public record IrFunction(string Name, List<IrBasicBlock> BasicBlocks);
public record IrBasicBlock(string Label, List<IrInstruction> Instructions);
public abstract record IrInstruction;
```
### 6. Code Generator (代码生成器)
**职责**
- 将 IR 转换为 x86/x64 机器码
- 寄存器分配
- 栈帧管理
- 遵循平台调用约定
**接口**
```csharp
public interface ICodeGenerator
{
byte[] Generate(IrProgram program, TargetArchitecture architecture);
}
public enum TargetArchitecture { X86, X64 }
```
### 7. Object File Writer (目标文件写入器)
**职责**
- 生成 PE 格式文件Windows
- 生成 ELF 格式文件Linux
- 处理重定位信息
- 设置入口点
**接口**
```csharp
public interface IObjectFileWriter
{
byte[] WriteExecutable(byte[] machineCode, TargetPlatform platform);
}
public enum TargetPlatform { WindowsX86, WindowsX64, LinuxX86, LinuxX64 }
```
### 8. Compiler Driver (编译器驱动)
**职责**
- 协调各个编译阶段
- 处理命令行参数
- 错误汇总与报告
- 管理编译流程
**接口**
```csharp
public class CompilerDriver
{
public int Run(string[] args);
public CompilationResult Compile(CompilationOptions options);
}
```
## Data Models
### Token 模型
```csharp
public readonly struct SourceLocation
{
public string FileName { get; }
public int Line { get; }
public int Column { get; }
}
public enum TokenType
{
// 关键字
Int, Char, Float, Double, Long, Short, Void,
If, Else, While, For, Do, Switch, Case, Default,
Break, Continue, Return, Struct, Union, Typedef,
// 字面量
IntLiteral, FloatLiteral, CharLiteral, StringLiteral,
// 标识符
Identifier,
// 运算符
Plus, Minus, Star, Slash, Percent,
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
Assign, PlusAssign, MinusAssign, StarAssign, SlashAssign,
And, Or, Not, BitAnd, BitOr, BitXor,
LeftShift, RightShift,
// 分隔符
LeftParen, RightParen, LeftBrace, RightBrace,
LeftBracket, RightBracket,
Semicolon, Comma, Dot, Arrow, Colon,
// 预处理器
HashInclude, HashDefine, HashIf, HashIfdef, HashIfndef, HashElse, HashEndif,
// 特殊
EOF, Error
}
```
### Type System 模型
```csharp
public abstract record CType(string Name);
public record PrimitiveType(TypeKind Kind) : CType(Kind.ToString())
{
public enum TypeKind { Void, Char, Short, Int, Long, Float, Double }
}
public record PointerType(CType BaseType) : CType($"{BaseType}*");
public record ArrayType(CType ElementType, int Size) : CType($"{ElementType}[{Size}]");
public record StructType(string Name, List<FieldDeclaration> Fields) : CType(Name);
public record FunctionType(CType ReturnType, List<CType> ParameterTypes) : CType("function");
```
### IR 指令模型
```csharp
public abstract record IrInstruction;
public record IrBinaryOp(IrTemp Dest, IrBinaryOpType Op, IrValue Left, IrValue Right) : IrInstruction;
public record IrUnaryOp(IrTemp Dest, IrUnaryOpType Op, IrValue Source) : IrInstruction;
public record IrLoad(IrTemp Dest, IrValue Address) : IrInstruction;
public record IrStore(IrValue Address, IrValue Value) : IrInstruction;
public record IrCall(IrTemp? Dest, string FunctionName, List<IrValue> Arguments) : IrInstruction;
public record IrJump(string TargetLabel) : IrInstruction;
public record IrBranch(IrValue Condition, string TrueLabel, string FalseLabel) : IrInstruction;
public record IrReturn(IrValue? Value) : IrInstruction;
public record IrLabel(string LabelName) : IrInstruction;
public enum IrBinaryOpType { Add, Sub, Mul, Div, Mod, And, Or, Xor, Shl, Shr, Eq, Ne, Lt, Gt, Le, Ge }
public enum IrUnaryOpType { Neg, Not, BitNot, Deref }
public abstract record IrValue;
public record IrTemp(string Name, CType Type) : IrValue;
public record IrConstant(long Value, CType Type) : IrValue;
public record IrGlobal(string Name, CType Type) : IrValue;
```
## Correctness Properties
### 不变量
1. **类型安全**: 所有 IR 指令的操作数类型必须匹配
2. **作用域正确性**: 符号查找必须遵循词法作用域规则
3. **控制流完整性**: 所有基本块必须有明确的前驱和后继
4. **寄存器一致性**: 代码生成前后寄存器状态必须一致
### 约束条件
1. 生成的机器码必须符合 x86/x64 指令集规范
2. 函数调用必须遵循目标平台的 ABIApplication Binary Interface
3. 栈帧布局必须保证栈指针对齐x64 要求 16 字节对齐)
4. 可执行文件格式必须符合 PE 或 ELF 规范
## Error Handling
### 错误分类
| 错误类型 | 阶段 | 处理方式 |
|---------|------|---------|
| 词法错误 | Lexer | 报告错误位置,跳过错误 token |
| 语法错误 | Parser | 报告期望的 token尝试错误恢复 |
| 类型错误 | Semantic | 报告类型不匹配详情 |
| 未声明符号 | Semantic | 报告符号名称和位置 |
| 代码生成错误 | CodeGen | 报告不支持的 IR 指令 |
### 错误报告接口
```csharp
public record ErrorInfo(
ErrorLevel Level, // Warning, Error, Fatal
string Message,
SourceLocation Location,
string? Suggestion = null
);
public interface IErrorReporter
{
void Report(ErrorInfo error);
bool HasErrors { get; }
IEnumerable<ErrorInfo> GetErrors();
}
```
## Test Strategy
### 单元测试
1. **Lexer 测试**:验证各种 token 的正确识别
2. **Parser 测试**:验证各种 C 语法的 AST 构建
3. **Semantic 测试**:验证类型检查和符号表
4. **IR 测试**:验证 AST 到 IR 的转换
5. **CodeGen 测试**:验证 IR 到机器码的转换
### 集成测试
1. **端到端测试**:编译简单 C 程序并验证输出
2. **回归测试**:使用 TCC 测试套件进行对比测试
3. **性能测试**:测量编译速度和生成代码质量
### 测试用例示例
```c
// test_hello.c
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
// test_arithmetic.c
int add(int a, int b) {
return a + b;
}
int main() {
int result = add(3, 4);
return result - 7; // should return 0
}
// test_control_flow.c
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
```
## References
[^1]: (TCC Source) - Tiny C Compiler 源码 https://repo.or.cz/tinycc.git
[^2]: (PE Format) - Microsoft PE 和 COFF 规范 https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
[^3]: (ELF Format) - ELF 规范 https://refspecs.linuxfoundation.org/elf/elf.pdf
[^4]: (x64 ABI) - System V AMD64 ABI https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
[^5]: (x86 Calling Conventions) - x86 调用约定 https://en.wikipedia.org/wiki/X86_calling_conventions

View File

@@ -0,0 +1,116 @@
# Requirements Document
## Introduction
本项目旨在开发一个使用 C# 语言编写的 C 语言编译器,参考 TCCTiny C Compiler的设计理念。编译器将 C 源代码直接编译为 x86/x64 本地机器码,而非 MSILMicrosoft Intermediate Language。目标是实现一个轻量级、快速的 C 编译器,支持 C99 标准的核心特性。
## Glossary
- **TCC**: Tiny C Compiler一个小型、快速的 C 编译器
- **本地代码**: 直接可在 CPU 上执行的机器码x86/x64
- **MSIL**: Microsoft Intermediate Language.NET 平台的中间语言
- **代码生成**: 将中间表示转换为目标机器码的过程
- **词法分析**: 将源代码分解为 token 流的过程
- **语法分析**: 将 token 流构建为抽象语法树AST的过程
- **语义分析**: 验证 AST 的语义正确性并进行类型检查
- **目标平台**: x86 (32-bit) 和 x64 (64-bit) Windows/Linux
## Requirements
### Requirement 1: 词法分析器
**User Story:** AS 一个 C 编译器开发者I WANT 实现词法分析器SO THAT 可以将 C 源代码转换为 token 流
#### Acceptance Criteria
1. WHEN 接收到 C 源代码文件,词法分析器 SHALL 输出 token 流
2. WHEN 遇到 C 语言关键字if, else, while, for, int, char 等),词法分析器 SHALL 识别为关键字 token
3. WHEN 遇到标识符,词法分析器 SHALL 识别为标识符 token
4. WHEN 遇到字面量(整数、浮点数、字符、字符串),词法分析器 SHALL 识别为相应的字面量 token
5. WHEN 遇到注释(单行 // 和多行 /* */),词法分析器 SHALL 忽略注释内容
6. WHEN 遇到词法错误,词法分析器 SHALL 报告错误位置和错误信息
### Requirement 2: 语法分析器
**User Story:** AS 一个 C 编译器开发者I WANT 实现语法分析器SO THAT 可以将 token 流构建为抽象语法树AST
#### Acceptance Criteria
1. WHEN 接收到 token 流,语法分析器 SHALL 构建 AST
2. WHEN 遇到语法错误,语法分析器 SHALL 报告错误位置和错误描述
3. WHILE 解析表达式,语法分析器 SHALL 正确处理运算符优先级
4. WHEN 解析函数定义,语法分析器 SHALL 识别函数名、参数列表和函数体
5. WHEN 解析控制流语句if, while, for, switch语法分析器 SHALL 构建对应的控制流 AST 节点
### Requirement 3: 语义分析器
**User Story:** AS 一个 C 编译器开发者I WANT 实现语义分析器SO THAT 可以验证 AST 的语义正确性
#### Acceptance Criteria
1. WHEN 接收到 AST语义分析器 SHALL 执行类型检查
2. WHEN 遇到未声明的变量,语义分析器 SHALL 报告错误
3. WHEN 遇到类型不匹配的赋值或运算,语义分析器 SHALL 报告类型错误
4. WHEN 遇到函数调用,语义分析器 SHALL 验证函数签名和参数类型
5. WHILE 解析作用域,语义分析器 SHALL 正确管理变量的作用域
### Requirement 4: 中间表示IR生成
**User Story:** AS 一个 C 编译器开发者I WANT 生成中间表示SO THAT 可以优化并转换为目标机器码
#### Acceptance Criteria
1. WHEN 接收到语义分析后的 ASTIR 生成器 SHALL 输出三地址码形式的 IR
2. WHEN 生成 IRIR 生成器 SHALL 处理控制流图的构建
3. WHILE 生成 IRIR 生成器 SHALL 支持基本的数据流分析
### Requirement 5: 代码生成器x86/x64
**User Story:** AS 一个 C 编译器开发者I WANT 实现代码生成器SO THAT 可以将 IR 转换为 x86/x64 本地机器码
#### Acceptance Criteria
1. WHEN 接收到 IR代码生成器 SHALL 输出 x86/x64 机器码
2. WHEN 处理函数调用,代码生成器 SHALL 遵循目标平台的调用约定calling convention
3. WHEN 处理局部变量,代码生成器 SHALL 分配栈空间
4. WHEN 处理全局变量,代码生成器 SHALL 在数据段分配空间
5. IF 目标平台为 x64代码生成器 SHALL 使用 x64 寄存器
6. IF 目标平台为 x86代码生成器 SHALL 使用 x86 寄存器
### Requirement 6: 可执行文件生成
**User Story:** AS 一个 C 编译器用户I WANT 编译器生成可执行文件SO THAT 可以直接运行编译后的程序
#### Acceptance Criteria
1. WHEN 编译完成,编译器 SHALL 生成 PEWindows或 ELFLinux格式的可执行文件
2. WHEN 生成 PE 文件,编译器 SHALL 包含正确的 PE 头和节表
3. WHEN 生成 ELF 文件,编译器 SHALL 包含正确的 ELF 头和节头
4. WHEN 生成的可执行文件被操作系统加载,操作系统 SHALL 能够正确执行程序
### Requirement 7: 命令行接口
**User Story:** AS 一个 C 编译器用户I WANT 使用命令行编译 C 文件SO THAT 可以方便地集成到构建系统中
#### Acceptance Criteria
1. WHEN 用户提供源文件路径,编译器 SHALL 编译并生成可执行文件
2. WHEN 用户指定输出文件名,编译器 SHALL 使用指定的文件名
3. WHEN 用户指定目标架构x86/x64编译器 SHALL 生成对应架构的代码
4. IF 编译过程中发生错误,编译器 SHALL 输出错误信息并返回非零退出码
5. WHEN 用户请求帮助信息,编译器 SHALL 显示使用说明
### Requirement 8: C99 核心特性支持
**User Story:** AS 一个 C 程序员I WANT 编译器支持 C99 核心特性SO THAT 可以编译现有的 C 代码
#### Acceptance Criteria
1. WHEN 编译 C99 代码,编译器 SHALL 支持基本数据类型int, char, float, double, long, short
2. WHEN 编译 C99 代码,编译器 SHALL 支持指针和数组
3. WHEN 编译 C99 代码,编译器 SHALL 支持结构体struct和联合体union
4. WHEN 编译 C99 代码,编译器 SHALL 支持函数定义和调用
5. WHEN 编译 C99 代码,编译器 SHALL 支持控制流语句if, else, while, for, do-while, switch, break, continue, return
6. WHEN 编译 C99 代码,编译器 SHALL 支持宏定义(#define)和条件编译(#ifdef, #ifndef, #endif
7. WHEN 编译 C99 代码,编译器 SHALL 支持头文件包含(#include
8. IF 使用 C99 特性(如单行注释 //),编译器 SHALL 正确解析

View File

@@ -0,0 +1,96 @@
# Implementation Task List
## Phase 1: 项目初始化与基础架构
- [ ] 1.1 创建 .NET 8 控制台项目结构
- [ ] 1.2 配置项目解决方案和模块划分
- [ ] 1.3 实现基础的错误报告系统ErrorReporter
- [ ] 1.4 实现源代码位置追踪SourceLocation
## Phase 2: 预处理器实现
- [ ] 2.1 实现 #include 指令处理
- [ ] 2.2 实现 #define 宏定义和宏展开
- [ ] 2.3 实现条件编译(#ifdef, #ifndef, #if, #else, #endif
- [ ] 2.4 实现头文件搜索路径管理
## Phase 3: 词法分析器实现
- [ ] 3.1 定义所有 TokenType 枚举
- [ ] 3.2 实现 Token 结构
- [ ] 3.3 实现 Lexer 主类
- [ ] 3.4 实现关键字识别
- [ ] 3.5 实现标识符识别
- [ ] 3.6 实现整数字面量识别
- [ ] 3.7 实现浮点数字面量识别
- [ ] 3.8 实现字符和字符串字面量识别
- [ ] 3.9 实现运算符识别
- [ ] 3.10 实现注释跳过
- [ ] 3.11 编写 Lexer 单元测试
## Phase 4: 语法分析器实现
- [ ] 4.1 定义 AST 节点层次结构
- [ ] 4.2 实现递归下降解析器框架
- [ ] 4.3 实现表达式解析(处理运算符优先级)
- [ ] 4.4 实现语句解析
- [ ] 4.5 实现函数声明解析
- [ ] 4.6 实现类型声明解析
- [ ] 4.7 实现控制流语句解析if, while, for, switch
- [ ] 4.8 实现结构体和联合体解析
- [ ] 4.9 实现错误恢复机制
- [ ] 4.10 编写 Parser 单元测试
## Phase 5: 语义分析器实现
- [ ] 5.1 实现类型系统CType 层次结构)
- [ ] 5.2 实现符号表SymbolTable
- [ ] 5.3 实现作用域管理
- [ ] 5.4 实现类型检查
- [ ] 5.5 实现函数签名验证
- [ ] 5.6 实现变量声明检查
- [ ] 5.7 编写 Semantic Analyzer 单元测试
## Phase 6: 中间表示IR生成
- [ ] 6.1 定义 IR 指令集
- [ ] 6.2 实现基本块BasicBlock结构
- [ ] 6.3 实现控制流图CFG
- [ ] 6.4 实现 AST 到 IR 转换
- [ ] 6.5 实现临时变量管理
- [ ] 6.6 实现常量折叠优化
- [ ] 6.7 编写 IR Generator 单元测试
## Phase 7: x86/x64 代码生成器
- [ ] 7.1 定义目标架构抽象
- [ ] 7.2 实现寄存器管理
- [ ] 7.3 实现栈帧管理
- [ ] 7.4 实现 x86 指令编码
- [ ] 7.5 实现 x64 指令编码
- [ ] 7.6 实现 IR 到机器码转换
- [ ] 7.7 实现函数调用约定cdecl, sysv64
- [ ] 7.8 实现寄存器分配
- [ ] 7.9 编写 CodeGen 单元测试
## Phase 8: 可执行文件生成
- [ ] 8.1 实现 PE 文件格式写入Windows
- [ ] 8.2 实现 ELF 文件格式写入Linux
- [ ] 8.3 实现节表管理
- [ ] 8.4 实现重定位处理
- [ ] 8.5 实现入口点设置
## Phase 9: 编译器驱动与 CLI
- [ ] 9.1 实现命令行参数解析
- [ ] 9.2 实现编译流程编排
- [ ] 9.3 实现错误汇总与报告
- [ ] 9.4 实现多文件编译支持
## Phase 10: 测试与优化
- [ ] 10.1 编写端到端测试
- [ ] 10.2 使用 TCC 测试套件进行回归测试
- [ ] 10.3 性能测试与优化
- [ ] 10.4 内存使用优化

View File

@@ -0,0 +1,461 @@
# TinyCC 编译器改进计划
Feature Name: 2026-05-20-tinycc-improvements
Updated: 2026-05-20
## Description
本改进计划涵盖 TinyCC 编译器的 9 个核心改进方向,分为三个阶段:
- **阶段一(基础完善)**:端到端测试、错误报告增强、仓库清理
- **阶段二(功能完善)**:语义分析、预处理器集成、代码生成优化
- **阶段三(高级特性)**DWARF 调试信息、PE 格式支持、性能基准
## Architecture
```mermaid
graph TD
subgraph "阶段一:基础完善"
A1[E2E 测试框架] --> A2[测试用例集合]
B1[ErrorReporter 增强] --> B2[代码上下文格式化]
C1[.gitignore 更新] --> C2[移除误提交文件]
end
subgraph "阶段二:功能完善"
D1[SemanticAnalyzer 完善] --> D2[类型系统增强]
D1 --> D3[作用域管理优化]
E1[Preprocessor 集成] --> E2[宏展开引擎]
E1 --> E3[头文件搜索机制]
F1[优化 CodeGen] --> F2[寄存器分配器]
F1 --> F3[指令选择优化]
end
subgraph "阶段三:高级特性"
G1[DWARF 生成器] --> G2[调试信息编码]
G1 --> G3[行号表生成]
H1[PE Writer 完善] --> H2[PE 头生成]
H1 --> H3[重定位表生成]
I1[性能基准] --> I2[编译时间测量]
I1 --> I3[执行时间测量]
end
A2 -. 验证 .-> D1
B2 -. 集成 .-> D1
D3 -. 输入 .-> F2
E3 -. 输出 .-> A2
```
### 改进架构概览
改进计划遵循渐进式实现策略,每个阶段的输出为下一阶段提供基础:
1. **阶段一**建立测试基础设施和用户体验改进
2. **阶段二**完善编译器核心功能
3. **阶段三**添加高级特性和性能监控
## Components and Interfaces
### 1. 端到端测试框架
**职责**
- 编译测试 C 源文件并验证生成的可执行文件
- 管理测试用例输入和预期输出
- 报告测试通过/失败状态
**接口**
```csharp
public interface IE2ETestRunner
{
Task<TestResult> RunTestAsync(TestCase testCase);
IEnumerable<TestCase> LoadTestsFromDirectory(string directory);
}
public record TestCase(
string Name,
string SourceCode,
int ExpectedExitCode,
string? ExpectedOutput = null
);
public record TestResult(
string TestCaseName,
bool Passed,
int ActualExitCode,
string? ActualOutput = null,
string? ErrorMessage = null
);
```
**实现策略**
- 使用 `CompilerDriver` 编译源代码到临时 ELF 文件
- 使用 `Process` 类执行生成的可执行文件
- 比较实际输出/退出码与预期值
### 2. 错误报告增强
**职责**
- 格式化错误信息,包含代码上下文
- 生成可视化错误位置标记
- 支持多错误汇总输出
**接口扩展**
```csharp
public record ErrorInfo(
ErrorLevel Level,
string Message,
SourceLocation Location,
string? SourceLine = null, // 新增:出错的源代码行
int? ColumnOffset = null, // 新增:错误在行内的偏移
string? Suggestion = null // 新增:修复建议
);
public sealed class ErrorReporter : IErrorReporter
{
private readonly List<ErrorInfo> _errors = new();
private readonly Dictionary<string, string[]> _sourceCache = new(); // 新增:源代码缓存
public void Report(ErrorInfo error);
public void SetSourceLines(string fileName, string[] lines); // 新增:设置源代码行
public string FormatErrors(); // 新增:格式化所有错误
}
```
**格式化输出示例**
```
test.c:3:5: error: expected ';' before 'return'
2 | int add(int a, int b) {
3 | int x = a + b
| ^^^^^^^^
4 | return x;
| ~~~~~
help: add ';' at the end of the statement
```
### 3. 语义分析器完善
**职责扩展**
- 实现完整的类型检查系统
- 支持嵌套作用域管理
- 检测函数签名不匹配
**新增组件**
```csharp
public sealed class TypeChecker
{
public CType? CheckBinaryOperation(TokenType op, CType left, CType right, SourceLocation loc);
public CType? CheckUnaryOperation(TokenType op, CType operand, SourceLocation loc);
public bool IsCompatible(CType source, CType target);
public CType? PromoteType(CType type); // 类型提升
}
public sealed class ScopeManager
{
private readonly Stack<Dictionary<string, Symbol>> _scopes = new();
public void EnterScope();
public void ExitScope();
public void DeclareSymbol(string name, Symbol symbol);
public Symbol? LookupSymbol(string name);
public bool IsDeclared(string name);
}
```
**类型检查规则**
| 操作 | 左操作数 | 右操作数 | 结果类型 |
|------|---------|---------|---------|
| 算术运算 | 整数/浮点 | 整数/浮点 | 提升后的类型 |
| 比较运算 | 数值类型 | 数值类型 | int |
| 赋值 | 类型 T | 类型 S | TS 必须可转换为 T |
### 4. 预处理器集成
**职责**
- 处理 `#include``#define`、条件编译
- 管理头文件搜索路径
- 宏展开和参数替换
**接口**
```csharp
public interface IPreprocessor
{
string Preprocess(string sourceCode, string sourceFile);
void AddIncludePath(string path);
void DefineMacro(string name, string? value);
void UndefineMacro(string name);
}
public sealed class Macro
{
public string Name { get; }
public string? Value { get; }
public List<string>? Parameters { get; } // 函数宏参数
public string? Body { get; }
}
```
**集成到 CompilerDriver**
```csharp
// 在 CompilerDriver.Compile 中
var preprocessor = new Preprocessor(_errorReporter);
foreach (var includePath in options.IncludePaths)
{
preprocessor.AddIncludePath(includePath);
}
var preprocessedSource = preprocessor.Preprocess(options.SourceFile);
var lexer = new Lexer(preprocessedSource, options.SourceFile, _errorReporter);
```
### 5. 代码生成优化
**职责**
- 实现图着色寄存器分配
- 指令选择和调度
- 栈帧布局优化
**寄存器分配器接口**
```csharp
public sealed class GraphColoringAllocator
{
private readonly Dictionary<IrValue, HashSet<IrValue>> _interferenceGraph = new();
private readonly Dictionary<IrValue, string> _allocation = new();
private readonly HashSet<IrValue> _spilledVars = new();
public void Allocate(IrFunction function, string[] availableRegs);
public string? GetRegister(IrValue value);
public bool IsSpilled(IrValue value);
}
```
**优化验证策略**
- 比较优化前后生成的机器码长度
- 验证优化后程序的执行结果正确性
- 测量溢出变量数量
### 6. DWARF 调试信息生成器
**职责**
- 生成 DWARF 调试信息节
- 编码源文件路径和行号映射
- 生成变量和类型调试信息
**接口**
```csharp
public sealed class DwarfGenerator
{
private readonly List<DwarfInfo> _debugInfo = new();
private readonly List<DwarfLine> _lineTable = new();
public void AddFile(string fileName);
public void AddLineEntry(int fileIndex, int line, int address);
public void AddVariable(string name, CType type, int scopeLevel, int offset);
public byte[] GenerateDebugSection();
public byte[] GenerateLineSection();
}
```
**ELF 集成**
-`ElfWriter` 中添加 `.debug_info``.debug_line`
- 更新节头表和字符串表
### 7. PE 写出器完善
**职责**
- 生成完整的 PE32+ 文件头
- 创建 `.text``.data`
- 处理重定位和导入表
**PE 文件结构**
```
DOS Header (64 bytes)
PE Signature ("PE\0\0")
COFF File Header (20 bytes)
Optional Header (PE32+, 112 bytes)
Data Directories (16 entries)
Section Headers (40 bytes per section)
.text Section (代码)
.data Section (数据)
```
### 8. 性能基准测试框架
**职责**
- 测量编译时间
- 测量生成代码执行时间
- 生成统计报告
**接口**
```csharp
public sealed class BenchmarkRunner
{
public BenchmarkResult RunCompilationBenchmark(string sourceFile, int iterations = 10);
public BenchmarkResult RunExecutionBenchmark(string executable, int iterations = 100);
}
public record BenchmarkResult(
string TestName,
double MeanTimeMs,
double MedianTimeMs,
double StdDevMs,
int Iterations
);
```
## Data Models
### 错误信息模型(增强)
```csharp
public enum ErrorLevel
{
Warning,
Error,
Fatal
}
public readonly struct SourceLocation
{
public string FileName { get; }
public int Line { get; }
public int Column { get; }
public int Length { get; } // 新增:错误跨度
}
```
### 测试用例模型
```csharp
public record TestCase(
string Name,
string SourceCode,
int ExpectedExitCode,
string? ExpectedOutput = null,
string? ExpectedErrorPattern = null // 期望的错误模式
);
```
### DWARF 调试信息模型
```csharp
public record DwarfInfoEntry(
uint Offset,
uint AbbrevCode,
Dictionary<uint, object> Attributes
);
public record DwarfLineEntry(
int Address,
int FileIndex,
int Line,
int Column,
bool IsStatement,
bool IsEndOfSequence
);
```
## Correctness Properties
### 不变量
1. **测试覆盖完整性**: 每个 C 语言特性至少有一个 E2E 测试用例
2. **错误信息准确性**: 错误位置标记必须指向正确的源代码行和列
3. **类型检查健全性**: 类型检查必须拒绝所有类型错误的程序
4. **寄存器分配正确性**: 分配的寄存器不能干涉活跃变量
5. **调试信息一致性**: 调试信息中的行号必须与实际代码位置匹配
### 约束条件
1. E2E 测试必须在 Linux x64 环境下运行
2. 错误报告格式化器必须处理多字节字符
3. 寄存器分配器必须遵循 System V AMD64 ABI
4. DWARF 信息必须兼容 gdb 7.0+
5. PE 文件必须兼容 Windows 10+ 加载器
## Error Handling
### 错误场景与处理策略
| 错误场景 | 检测阶段 | 处理方式 |
|---------|---------|---------|
| 头文件不存在 | 预处理 | 报告错误,提供搜索路径 |
| 宏重复定义 | 预处理 | 报告警告,使用新定义 |
| 未声明变量 | 语义分析 | 报告错误,标记位置 |
| 类型不匹配 | 语义分析 | 报告错误,显示期望和实际类型 |
| 寄存器溢出 | 代码生成 | 溢出到栈,更新栈帧布局 |
| DWARF 编码失败 | 调试信息生成 | 报告错误,继续编译 |
| PE 头生成失败 | 目标文件写入 | 报告错误,终止编译 |
### 错误恢复策略
- **词法/语法错误**: 尝试跳过错误 token继续解析
- **语义错误**: 收集所有错误,一次性输出
- **代码生成错误**: 立即终止,报告详细错误信息
## Test Strategy
### 单元测试
1. **错误报告测试**: 验证错误信息格式化和代码上下文显示
2. **类型检查测试**: 验证各种类型场景的检查逻辑
3. **寄存器分配测试**: 验证图着色算法正确性
4. **DWARF 编码测试**: 验证调试信息编码正确性
### 集成测试
1. **端到端测试**: 编译并运行测试 C 程序,验证输出
2. **预处理器集成测试**: 验证宏展开和头文件包含
3. **PE 格式测试**: 在 Windows 环境验证生成的 PE 文件
### E2E 测试用例集合
```c
// test_arithmetic.c - 算术运算测试
int add(int a, int b) { return a + b; }
int main() { return add(3, 4) == 7 ? 0 : 1; }
// test_control_flow.c - 控制流测试
int main() {
int sum = 0;
for (int i = 1; i <= 10; i++) sum += i;
return sum == 55 ? 0 : 1;
}
// test_functions.c - 函数调用测试
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
int main() { return factorial(5) == 120 ? 0 : 1; }
// test_pointers.c - 指针测试
int main() {
int x = 42;
int *p = &x;
return *p == 42 ? 0 : 1;
}
// test_arrays.c - 数组测试
int main() {
int arr[3] = {1, 2, 3};
return arr[1] == 2 ? 0 : 1;
}
// test_macro.c - 宏测试
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main() { return MAX(3, 5) == 5 ? 0 : 1; }
```
### 性能基准测试
- **编译时间基准**: 测量编译标准 C 文件的时间(如 `factorial.c`, `sort.c`
- **执行时间基准**: 测量生成代码执行时间,与 gcc/clang 对比
- **内存使用基准**: 测量编译过程中的内存峰值
## References
[^1]: (DWARF Spec) - DWARF 调试标准格式 https://dwarfstd.org
[^2]: (PE Spec) - Microsoft PE 和 COFF 规范 https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
[^3]: (System V AMD64 ABI) - x64 调用约定 https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
[^4]: (ELF Spec) - ELF 规范 https://refspecs.linuxfoundation.org/elf/elf.pdf
[^5]: (CompilerDriver.cs#L18) - 当前编译器驱动实现 src/TinyCC.Core/CompilerDriver.cs
[^6]: (ErrorReporter.cs#L6) - 当前错误报告器实现 src/TinyCC.Core/Diagnostics/ErrorReporter.cs
[^7]: (SemanticAnalyzer.cs#L11) - 当前语义分析器实现 src/TinyCC.Core/Semantic/SemanticAnalyzer.cs
[^8]: (OptimizedX64CodeGenerator.cs#L12) - 当前优化代码生成器实现 src/TinyCC.Core/CodeGen/OptimizedX64CodeGenerator.cs

View File

@@ -0,0 +1,123 @@
# Requirements Document
## Introduction
本改进计划涵盖 TinyCC 编译器的 9 个核心改进方向包括端到端测试、错误报告增强、代码清理、语义分析完善、预处理器集成、代码生成优化、调试信息支持、PE 格式支持及性能基准测试。
## Glossary
- **TinyCC**: 本项目实现的轻量级 C 编译器
- **E2E 测试**: 端到端测试,验证完整编译流程
- **ELF**: Executable and Linkable FormatLinux 可执行文件格式
- **PE**: Portable ExecutableWindows 可执行文件格式
- **DWARF**: 调试信息格式,支持源码级调试
- **ABI**: Application Binary Interface应用二进制接口
## Requirements
### Requirement 1: 端到端编译测试
**User Story:** AS 一个编译器开发者I WANT 验证完整编译流程生成的可执行文件能够正确运行SO THAT 确保编译器各组件协同工作正常
#### Acceptance Criteria
1. WHEN 提供包含 `main` 函数的 C 源代码,编译器 SHALL 生成可在 Linux 上执行的 ELF 文件
2. WHEN 运行生成的 ELF 文件,程序 SHALL 返回正确的退出码
3. WHEN 编译包含算术运算的 C 程序,执行程序 SHALL 输出正确的计算结果
4. WHEN 编译包含函数调用的 C 程序,执行程序 SHALL 正确调用函数并返回结果
5. WHEN 编译包含控制流语句if/while/for的 C 程序,执行程序 SHALL 正确执行控制流
### Requirement 2: 增强错误报告
**User Story:** AS 一个 C 程序员I WANT 编译器提供包含代码上下文和位置提示的错误信息SO THAT 能够快速定位和修复代码问题
#### Acceptance Criteria
1. WHEN 报告编译错误,错误信息 SHALL 包含文件名、行号和列号
2. WHEN 报告语法错误,错误信息 SHALL 显示出错代码行及错误位置标记
3. WHEN 报告类型错误,错误信息 SHALL 说明期望的类型和实际提供的类型
4. WHEN 报告多个错误,编译器 SHALL 汇总所有错误并一次性输出
5. IF 错误信息包含建议,建议 SHALL 提供可能的修复方向
### Requirement 3: 清理误提交文件
**User Story:** AS 一个仓库维护者I WANT 从版本控制中移除构建产物和临时文件SO THAT 保持仓库整洁并减小仓库体积
#### Acceptance Criteria
1. WHEN 提交代码,构建目录 `bin/``obj/` SHALL 被 `.gitignore` 排除
2. WHEN 提交代码,临时测试文件 `test_output` SHALL 从版本控制中移除
3. WHEN 提交代码,本地测试文件 `test.c` SHALL 从版本控制中移除
### Requirement 4: 语义分析器完整实现
**User Story:** AS 一个 C 编译器开发者I WANT 语义分析器能够验证程序的语义正确性SO THAT 拒绝语义错误的 C 程序
#### Acceptance Criteria
1. WHEN 遇到未声明的变量,语义分析器 SHALL 报告"未声明的标识符"错误
2. WHEN 遇到类型不匹配的赋值操作,语义分析器 SHALL 报告类型不匹配错误
3. WHEN 遇到函数调用参数数量不匹配,语义分析器 SHALL 报告参数数量错误
4. WHEN 遇到函数调用参数类型不匹配,语义分析器 SHALL 报告参数类型错误
5. WHILE 处理嵌套作用域,语义分析器 SHALL 正确解析变量的词法作用域
6. WHEN 遇到重复的函数声明,语义分析器 SHALL 报告重复定义错误
### Requirement 5: 预处理器集成到编译流程
**User Story:** AS 一个 C 编译器用户I WANT 编译器正确处理预处理指令SO THAT 可以编译包含宏和头文件的 C 程序
#### Acceptance Criteria
1. WHEN 遇到 `#include` 指令,预处理器 SHALL 展开并包含指定头文件的内容
2. WHEN 遇到 `#define` 宏定义,预处理器 SHALL 在后续代码中展开宏
3. WHEN 遇到 `#ifdef`/`#ifndef` 条件编译,预处理器 SHALL 根据宏定义情况选择编译分支
4. WHEN 预处理完成后,编译器驱动 SHALL 将预处理后的源代码传递给词法分析器
5. IF 头文件不存在,预处理器 SHALL 报告错误并提供搜索路径信息
### Requirement 6: 代码生成优化验证
**User Story:** AS 一个编译器开发者I WANT 验证优化后的代码生成器能够正确分配寄存器并生成高效代码SO THAT 提升生成程序的执行性能
#### Acceptance Criteria
1. WHEN 使用优化代码生成器编译函数,寄存器分配算法 SHALL 为活跃变量分配物理寄存器
2. WHEN 寄存器数量不足,寄存器分配算法 SHALL 正确地将变量溢出到栈
3. WHEN 生成优化后的机器码,程序执行结果 SHALL 与未优化版本一致
4. WHILE 分配寄存器,寄存器分配算法 SHALL 遵循调用约定保留被调用者保存的寄存器
5. IF 代码生成器生成溢出代码,溢出区域 SHALL 正确管理栈帧布局
### Requirement 7: DWARF 调试信息生成
**User Story:** AS 一个 C 程序员I WANT 编译器生成 DWARF 调试信息SO THAT 可以使用 gdb 对生成的可执行文件进行源码级调试
#### Acceptance Criteria
1. WHEN 启用调试信息选项,编译器 SHALL 在 ELF 文件中生成 `.debug_info`
2. WHEN 生成调试信息,调试信息 SHALL 包含源文件路径和行号映射
3. WHEN 生成调试信息,调试信息 SHALL 包含变量名称、类型和作用域信息
4. WHEN 使用 gdb 加载生成的可执行文件gdb SHALL 能够显示源代码并设置断点
5. IF 未启用调试信息选项,编译器 SHALL 不生成调试信息以减小文件体积
### Requirement 8: PE 格式可执行文件支持
**User Story:** AS 一个 Windows 用户I WANT 编译器生成 Windows PE 格式的可执行文件SO THAT 可以在 Windows 系统上运行编译后的程序
#### Acceptance Criteria
1. WHEN 指定目标平台为 Windows x64编译器 SHALL 生成 PE32+ 格式的可执行文件
2. WHEN 生成 PE 文件PE 文件 SHALL 包含正确的 DOS 头和 PE 签名
3. WHEN 生成 PE 文件PE 文件 SHALL 包含有效的节表(`.text``.data`
4. WHEN 运行生成的 PE 文件Windows 操作系统 SHALL 能够加载并执行程序
5. WHEN 生成 PE 文件PE 文件 SHALL 设置正确的入口点Entry Point
### Requirement 9: 编译性能基准测试
**User Story:** AS 一个编译器开发者I WANT 建立编译性能基准SO THAT 可以量化编译器性能变化并识别性能瓶颈
#### Acceptance Criteria
1. WHEN 运行性能基准测试,测试 SHALL 测量编译器处理标准 C 文件的编译时间
2. WHEN 运行性能基准测试,测试 SHALL 测量生成代码的执行时间
3. WHEN 运行性能基准测试,测试 SHALL 输出编译时间和执行时间的统计报告
4. WHILE 进行性能优化,开发者 SHALL 能够对比优化前后的基准测试结果
5. IF 性能基准测试发现回归,测试结果 SHALL 标记性能下降的模块

View File

@@ -0,0 +1,80 @@
# TinyCC 改进计划 - 任务列表
Feature Name: 2026-05-20-tinycc-improvements
Created: 2026-05-20
## 阶段一:基础完善
### Task 1.1: 创建端到端测试框架
- [ ] 1.1.1 创建 `TinyCC.E2ETests` 测试项目,配置 xUnit 测试框架
- [ ] 1.1.2 实现 `E2ETestRunner` 类,支持编译 C 源代码并执行生成的 ELF 文件
- [ ] 1.1.3 实现测试用例管理,支持从嵌入式代码或文件加载测试用例
- [ ] 1.1.4 编写基础测试用例:算术运算、控制流、函数调用
- [ ] 1.1.5 运行端到端测试,验证当前编译器功能,记录失败项
### Task 1.2: 增强错误报告
- [ ] 1.2.1 扩展 `ErrorInfo` 结构,添加 `SourceLine``ColumnOffset``Suggestion` 字段
- [ ] 1.2.2 在 `ErrorReporter` 中实现源代码行缓存机制
- [ ] 1.2.3 实现错误信息格式化器,支持代码上下文和位置标记显示
- [ ] 1.2.4 集成到 `CompilerDriver`,在编译前缓存源代码行
- [ ] 1.2.5 编写单元测试验证错误格式化输出
### Task 1.3: 清理误提交文件
- [ ] 1.3.1 更新 `.gitignore`,确保 `bin/``obj/``test.c``test_output/` 被排除
- [ ] 1.3.2 从 git 历史中移除 `test_output``test.c` 文件
- [ ] 1.3.3 验证 `git status` 输出清洁,无构建产物
## 阶段二:功能完善
### Task 2.1: 完善语义分析器
- [ ] 2.1.1 实现完整的 `TypeChecker` 类,支持类型兼容性检查和类型提升
- [ ] 2.1.2 完善 `ScopeManager`,支持嵌套作用域和符号查找
- [ ] 2.1.3 实现函数签名验证,检测参数数量和类型不匹配
- [ ] 2.1.4 实现重复声明检测(函数和全局变量)
- [ ] 2.1.5 编写单元测试验证类型检查和作用域管理
### Task 2.2: 预处理器集成到编译流程
- [ ] 2.2.1 完善 `Preprocessor` 类,支持 `#include` 头文件搜索和展开
- [ ] 2.2.2 实现 `#define` 宏定义和宏展开(包括函数宏)
- [ ] 2.2.3 实现条件编译 `#ifdef`/`#ifndef`/`#endif`/`#if`/`#else`/`#elif`
- [ ] 2.2.4 集成预处理器到 `CompilerDriver.Compile` 流程
- [ ] 2.2.5 编写单元测试和 E2E 测试验证预处理功能
### Task 2.3: 代码生成优化验证
- [ ] 2.3.1 完善 `GraphColoringAllocator` 寄存器分配器实现
- [ ] 2.3.2 实现变量溢出到栈的逻辑和栈帧布局管理
- [ ] 2.3.3 集成优化代码生成器到 `CompilerDriver`
- [ ] 2.3.4 编写测试验证优化前后代码执行结果一致性
- [ ] 2.3.5 比较优化前后生成的机器码长度和寄存器使用情况
## 阶段三:高级特性
### Task 3.1: DWARF 调试信息生成
- [ ] 3.1.1 实现 `DwarfGenerator` 类,支持 DWARF 调试信息编码
- [ ] 3.1.2 实现行号表生成(`.debug_line` 节)
- [ ] 3.1.3 实现变量和类型调试信息(`.debug_info` 节)
- [ ] 3.1.4 集成到 `ElfWriter`,添加调试信息节到 ELF 文件
- [ ] 3.1.5 使用 gdb 验证生成的调试信息可正确显示源码和设置断点
### Task 3.2: PE 格式可执行文件支持
- [ ] 3.2.1 完善 `PeWriter`,生成完整的 PE32+ 文件头
- [ ] 3.2.2 实现 `.text``.data` 节创建和填充
- [ ] 3.2.3 实现 PE 入口点设置和重定位处理
- [ ] 3.2.4 集成 PE 写出器到 `CompilerDriver` 的 Windows 平台分支
- [ ] 3.2.5 验证生成的 PE 文件可在 Windows 环境加载执行
### Task 3.3: 编译性能基准测试
- [ ] 3.3.1 实现 `BenchmarkRunner` 类,支持编译时间和执行时间测量
- [ ] 3.3.2 创建标准测试用例集合factorial、sort 等)
- [ ] 3.3.3 实现统计报告生成(均值、中位数、标准差)
- [ ] 3.3.4 集成到测试框架,支持一键运行基准测试
- [ ] 3.3.5 记录初始基准数据,建立性能基线