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 内存使用优化