第 9 章 · 06 编译器:经典三段式架构
本节摘要:编译器线开始。本节讲编译器的经典三段式:前端(词法+语法+语义,产出 AST)、中端(优化)、后端(代码生成)。讲清这个分层,以及为什么分层(前端只管语言、后端只管机器、中端复用)。本节呼应第 4 章——正则引擎是「前端」的微缩,这里深化。
内容来源:基于编译原理整理的导读,呼应本书第 4 章正则引擎。
学习目标
- 说清编译器三段式:前端(分析)→ 中端(优化)→ 后端(生成)。
- 解释前端的三个阶段:词法、语法、语义。
- 理解 AST(抽象语法树)是前后端的桥梁。
- 说清为什么分层:语言无关的后端、机器无关的中端,可复用。
一、学习价值:编译器是「语言→可执行」的范本
编译器把源码(人读的语言)翻译成机器码(机器跑的语言)。它的三段式架构是「翻译问题」的经典解法,不只编译器用——SQL 引擎、模板引擎、配置解析都借鉴。理解三段式,你不仅会造编译器,更掌握「语言处理」的通用框架。
呼应第 4 章:正则引擎的「正则字符串→NFA」其实就是「前端」的微缩(词法+构造)。第 9 章把它扩展到完整编程语言。
二、认知拆解:三段式
前端:源码 → AST
前端把源码文本分析成抽象语法树(AST):
- 词法分析(lexing):源码字符串 → token 流(标识符/关键字/字面量/符号)。用正则描述 token 模式,正则引擎的用武之地。
- 语法分析(parsing):token 流 → AST,按语法规则递归构造。用「递归下降」或「解析器生成器」(yacc/antlr)。
- 语义分析:类型检查、作用域解析、变量是否声明等「语义」检查。AST 标注类型信息。
输出:带类型信息的 AST。
中端:优化(可选)
在 AST 或「中间表示」(IR)上做优化:常量折叠(2+3→5)、死代码删除、循环优化、内联。中端独立于语言与机器,可跨编译器复用(LLVM 的核心价值)。
第一个编译器可跳过中端,直接前端→后端。
后端:AST/IR → 目标代码
后端把 AST/IR 翻译成目标机器码(或汇编、或字节码):
- 代码生成:遍历 AST,对每种节点生成对应指令。
- 寄存器分配:决定哪些变量放寄存器、哪些放内存。
- 指令调度:优化指令顺序(利用流水线)。
为什么三段式
分层让每部分独立可复用:
- 前端只管「语言」(C/Rust/Python 各一种)。
- 后端只管「机器」(x86/ARM 各一种)。
- 中端只管「优化」(语言与机器无关)。
N 语言 × M 机器,不分层要写 N×M 个编译器;分层只要 N 个前端 + M 个后端 + 1 个中端。LLVM 的 IR 设计正是这个理念的产物。
三、上手第一步
造编译器从「表达式计算器」起步:2 + 3 * 4 → AST → 求值(24)。这是三段式的微缩:词法(切数字符号)→ 语法(按优先级建 AST)→ 后端(遍历 AST 求值)。参考「Crafting Interpreters」前几章。
本节要点回顾
- 三段式:前端(源码→AST)→ 中端(优化)→ 后端(AST→目标码)。
- 前端三步:词法(字符串→token)、语法(token→AST)、语义(类型检查)。
- AST 是桥梁:前后端通过它解耦。
- 分层价值:N 语言 × M 机器,不分层 N×M 编译器,分层 N+M+1。
- 呼应第 4 章:正则引擎是前端的微缩。
推荐上手顺序
- 写表达式计算器(词法+语法+求值),体会三段式。
- 参考「Crafting Interpreters」逐步扩展到变量、控制流、函数。
- (进阶)学 LLVM IR,理解现代编译器分层。
下一节讲代码生成 vs 解释执行。
作者与出处
原作者:灏天文库
来源:codecrafters-io
许可证:CC0-1.0
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习