编译原理
词法分析、语法分析、代码生成 — 高级语言的翻译官
知识结构
学习路径
编译器(Compiler)是把高级语言翻译成机器语言的"翻译官"——从源码到可执行文件,经历了词法分析、语法分析、语义分析、中间代码生成、优化、目标代码生成等一系列阶段
词法分析(Lexical Analysis)是编译的第一个阶段——把源代码的字符流切分成"单词"(Token),交给语法分析器使用
有限自动机(Finite Automaton)是正则表达式的"执行引擎"——它用状态和转移来描述字符串的匹配过程,是词法分析器的理论基础
语法分析(Syntax Analysis / Parsing)是编译的第二阶段——把 Token 序列组织成语法树,检查程序的结构是否符合语言的语法规则
LR 解析器从输入的 Token 序列出发,逐步归约到开始符号——它能处理的文法种类比 LL 更多,是 Yacc/Bison 等解析器生成器使用的方法
抽象语法树(Abstract Syntax Tree, AST)是语法分析的核心输出——它去掉了括号、分号等语法细节,只保留程序的"骨架结构"
语义分析(Semantic Analysis)检查程序的"逻辑合理性"——类型检查、变量是否声明、函数参数是否匹配。符号表(Symbol Table)记录每个标识符的属性信息
类型检查(Type Checking)确保程序中的每个表达式类型一致——整数不能当函数用,字符串不能做除法。类型推导(Type Inference)则能自动推断类型,你不用写 int x = 1 中的 int
中间表示(Intermediate Representation, IR)是编译器前端的输出和后端的输入——它比 AST 更接近机器码,但又独立于具体架构,是"优化"的主战场
代码生成(Code Generation)是编译器的"后端"——把平台无关的 IR 翻译成目标 CPU(x86、ARM、RISC-V)的机器指令。指令选择和寄存器分配是两大核心任务
寄存器分配(Register Allocation)决定哪些变量存寄存器、哪些"溢出"到内存——图着色是最经典的算法,把寄存器分配转化为给"干扰图"着色的问题
编译器优化(Optimization)在不解变程序语义的前提下改进代码——常量折叠、死代码消除、公共子表达式消除等"基本优化"是所有优化的基础
程序 90% 的执行时间花在 10% 的代码上——而循环通常是那 10%。循环优化通过变换循环结构,大幅减少指令执行次数,是最有效的编译器优化之一
指令调度(Instruction Scheduling)在不改变程序语义的前提下重排指令顺序——让 CPU 流水线更顺畅、缓存更友好、利用指令级并行(ILP)提升性能
JIT(Just-In-Time Compilation)在程序运行时把热点代码编译成机器码——结合了解释器的灵活性和编译器的性能。Java JVM、V8(JavaScript)、LuaJIT 都使用 JIT