进阶 #compiler#overview
编译器概述与整体结构
编译器(Compiler)是把高级语言翻译成机器语言的"翻译官"——从源码到可执行文件,经历了词法分析、语法分析、语义分析、中间代码生成、优化、目标代码生成等一系列阶段
🔄 “Hello World” 从源码到 CPU 执行——完整的旅程
你在 C 文件里写了 printf("Hello, World!\n");——按下编译运行,屏幕上出现了一行字。
从你写完这行代码到屏幕上出现文字,中间发生了什么?
编译器(Compiler) 就是做这件事的——把高级语言代码逐步翻译成 CPU 能直接执行的机器码,经历一系列阶段(像工厂流水线一样):
🏪 类比:英译中的翻译流程
把一篇英文论文翻译成中文,不是一次性完成的——而是分步走:
- 词法分析 — 先认识每个单词:“apple”→苹果、“eat”→吃
- 语法分析 — 理解句子结构:“I eat apple” 是主谓宾结构
- 语义分析 — 检查逻辑合理性:“I eat apple” 合理,但 “I eat rock” 语法对但语义奇怪
- 中间代码生成 — 把英文句子转换成”抽象语义表示”(脱离了英文语法)
- 优化 — 润色语句,让表达更简洁通顺
- 代码生成 — 写出最终的中文译文
🏭 编译器的”工厂流水线”
源程序(.c 文件)
│
▼
┌─────────────────────┐
│ ① 词法分析(Lexer) │ → Token 序列:int, a, =, 42, ;
│ "单词识别" │
└─────────┬───────────┘
▼
┌─────────────────────┐
│ ② 语法分析(Parser)│ → 抽象语法树(AST)
│ "句子结构分析" │ =
│ │ / \
└─────────┬───────────┘ a +
│ / \
▼ 42 1
┌─────────────────────┐
│ ③ 语义分析 │ → 带类型标注的 AST
│ "逻辑检查" │ a:int, 42:int → 类型匹配 ✅
└─────────┬───────────┘
▼
┌─────────────────────┐
│ ④ 中间代码生成 │ → 三地址码(IR)
│ "翻译成通用表示" │ t1 = 42 + 1
│ │ a = t1
└─────────┬───────────┘
▼
┌─────────────────────┐
│ ⑤ 优化 │ → 优化后的 IR
│ "让代码更高效" │ a = 43(常量折叠)
└─────────┬───────────┘
▼
┌─────────────────────┐
│ ⑥ 代码生成 │ → 目标机器码
│ "生成最终指令" │ MOV R0, #43
│ │ STR R0, [addr_a]
└─────────┬───────────┘
▼
可执行文件
前端(①-④)= 分析阶段——理解程序”什么意思” 后端(⑤-⑥)= 综合阶段——生成”怎么实现”的机器码
📐 一个具体的例子:全程追踪
// 输入的 C 代码
int a = 42 + 1;
经过编译器各阶段的变换:
① 词法分析:
Token 序列:KEYWORD(int) IDENTIFIER(a) OPERATOR(=) NUMBER(42) OPERATOR(+) NUMBER(1) SEMICOLON(;)
② 语法分析(生成 AST):
=
/ \
a +
/ \
42 1
③ 语义分析:
检查 a 是否已声明为 int 类型、42 和 1 都是 int → 类型正确 ✅
④ 中间代码生成(IR):
t1 = 42 + 1
a = t1
⑤ 优化:
a = 43 ← 常量折叠:42+1 在编译时就算出 43,不需要运行时
⑥ 代码生成(x86-64):
mov dword ptr [rbp-4], 43
关键观察:源代码 42 + 1 在编译时就被计算成了 43——这就是编译优化的一个简单例子。运行时没有任何加法。
🧩 编译器 vs 解释器
| 对比 | 编译器(Compiler) | 解释器(Interpreter) |
|---|---|---|
| 工作方式 | 一次性翻译成机器码 | 逐行翻译并执行 |
| 执行速度 | 快(直接跑机器码) | 慢(每次都要翻译) |
| 启动速度 | 慢(先编译再运行) | 快(直接运行) |
| 错误发现 | 编译时发现语法错误 | 运行到错误行才暴露 |
| 代表 | C、C++、Rust、Go | Python、JavaScript、Ruby |
💡 现代趋势:很多语言”混合”两种方式——Java 先编译成字节码(.class),JVM 再解释执行,热点代码用 JIT(即时编译)编译成机器码。Python 也是先编译成 .pyc 字节码再解释执行。
📝 小结
| 阶段 | 输入→输出 | 做什么 |
|---|---|---|
| 词法分析 | 源码→Token 序列 | 识别单词 |
| 语法分析 | Token→AST | 分析句子结构 |
| 语义分析 | AST→带类型AST | 类型检查、逻辑检查 |
| IR 生成 | AST→三地址码 | 翻译成通用中间表示 |
| 优化 | IR→优化IR | 让代码更高效 |
| 代码生成 | IR→机器码 | 生成目标 CPU 指令 |
为什么先学这个? 了解编译器的全景后,深入第一阶段——词法分析与正则表达式。