Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

最近更新 | Last Updated

Prenote

NOTICE: This content is presented as git diff.

更新记录(2026-09-20 08:37:48 +0000 | 86f34865)

Summary

  • Generated at: 2026-09-20 08:37:48 +0000
  • Base commit: 86f34865
  • Diff source: 3d464adf09874b9fa07b8c986f57d9536fd1f515..86f34865a1d2a26d5babbc2835a6d9b81168eaed
  • Changed files: 9
  • Total lines: +706 / -0

Index

  1. src/SUMMARY.md +8 / -0
  2. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十九章:目标代码生成.md +80 / -0
  3. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十一章:调用约定.md +88 / -0
  4. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十三章:冲突图.md +83 / -0
  5. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十二章:活跃变量分析.md +91 / -0
  6. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十五章:栈帧.md +91 / -0
  7. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十六章:生成汇编代码.md +91 / -0
  8. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十四章:寄存器着色与溢出.md +85 / -0
  9. src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十章:指令选择.md +89 / -0

Diffs

src/SUMMARY.md

+8 / -0 Click to expand diff
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 5061ffd4..39de70d5 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -810,6 +810,14 @@
   - [第两百五十六章:函数内联(进阶)](学习与进步/计算机科学极简入门指南/编译原理/第两百五十六章:函数内联(进阶).md)
   - [第两百五十七章:跨过程分析(进阶)](学习与进步/计算机科学极简入门指南/编译原理/第两百五十七章:跨过程分析(进阶).md)
   - [第两百五十八章:优化流水线总装](学习与进步/计算机科学极简入门指南/编译原理/第两百五十八章:优化流水线总装.md)
+  - [第两百五十九章:目标代码生成](学习与进步/计算机科学极简入门指南/编译原理/第两百五十九章:目标代码生成.md)
+  - [第两百六十章:指令选择](学习与进步/计算机科学极简入门指南/编译原理/第两百六十章:指令选择.md)
+  - [第两百六十一章:调用约定](学习与进步/计算机科学极简入门指南/编译原理/第两百六十一章:调用约定.md)
+  - [第两百六十二章:活跃变量分析](学习与进步/计算机科学极简入门指南/编译原理/第两百六十二章:活跃变量分析.md)
+  - [第两百六十三章:冲突图](学习与进步/计算机科学极简入门指南/编译原理/第两百六十三章:冲突图.md)
+  - [第两百六十四章:寄存器着色与溢出](学习与进步/计算机科学极简入门指南/编译原理/第两百六十四章:寄存器着色与溢出.md)
+  - [第两百六十五章:栈帧](学习与进步/计算机科学极简入门指南/编译原理/第两百六十五章:栈帧.md)
+  - [第两百六十六章:生成汇编代码](学习与进步/计算机科学极简入门指南/编译原理/第两百六十六章:生成汇编代码.md)
   - [附加章一:大数据](学习与进步/计算机科学极简入门指南/附加章/大数据.md)
   - [附加章二:数据加密](学习与进步/计算机科学极简入门指南/附加章/数据加密.md)
   - [附加章三:区块链](学习与进步/计算机科学极简入门指南/附加章/区块链.md)

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十九章:目标代码生成.md

+80 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\347\233\256\346\240\207\344\273\243\347\240\201\347\224\237\346\210\220.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\347\233\256\346\240\207\344\273\243\347\240\201\347\224\237\346\210\220.md"
new file mode 100644
index 00000000..c0594810
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\347\233\256\346\240\207\344\273\243\347\240\201\347\224\237\346\210\220.md"
@@ -0,0 +1,80 @@
+# 目标代码生成
+
+## 复习
+
+- 优化流水线总装:优化后的中间表示
+- 中间表示:与具体机器无关
+- 编译器:前端、中端、后端的划分
+
+## TL;DR
+
+- 后端把与机器无关的 IR,变成具体机器的代码
+- 它要处理指令选择、寄存器分配、栈帧等
+- 目标代码必须忠实实现 IR 的语义
+- 后端与具体机器架构强相关
+
+## 正文
+
+  优化做完,程序的中间表示已经“又快又干净”了。但 IR 是抽象的,机器却只认它自己那套指令。把 IR 落到真实机器上,就是**后端**的工作。
+
+### 前端讲“通用”,后端讲“这台机器”
+
+  前面说过,IR 的一大好处就是**与具体机器无关**:不管目标是什么 CPU,前面那些分析和优化都能照做。
+
+  到了后端,画风一转:它要**盯着一台具体的机器**来办事了。不同的 CPU,指令集、寄存器数量、寻址方式都不一样。同一个 IR 操作,在不同机器上可能要生成不同的指令。**“机器无关”的红利到此为止,从这里开始,全是机器细节。**
+
+### 后端要做的事
+
+  把一个 IR 程序变成机器代码,后端大致要解决这几件事:
+
+- **指令选择**:把 IR 的每个操作,映射成合适的机器指令
+- **寄存器分配**:决定每个值放在哪个寄存器里
+- **栈帧安排**:为函数调用准备栈上的空间
+- **指令排序**:在保证语义的前提下,把指令排到合适的顺序
+- 最后**生成汇编或机器码**
+
+  这几件事互相牵制:指令选择影响寄存器需求,寄存器不够又要溢出到栈……所以后端不是“一条直线”,而是一组需要反复协调的决定。接下来的章节,就逐一拆开看。
+
+  但无论怎么安排,都有一条底线和前端一样:**生成的目标代码,必须忠实实现 IR 的语义。** 前端辛苦建立的“行为一致”,不能在后端丢掉。**正确,永远是第一位。**
+
+ **思考题 1** 
+
+>   后端与前端最大的区别,在于什么?
+
+ **思考题 2** 
+
+>   后端为什么必须“忠实”实现 IR 的语义?
+
+## 小结
+
+### 知识点
+
+- 后端把机器无关的 IR 变成具体机器代码
+- 主要工作:指令选择、寄存器分配、栈帧、指令排序
+- 后端与具体机器架构强相关
+- 目标代码必须忠实实现 IR 语义
+
+### 参考资料
+
+1. [Wikipedia(zh):代码生成](https://zh.wikipedia.org/wiki/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90_(%E7%BC%96%E8%AF%91%E5%99%A8)):编译器后端把中间表示转为目标代码
+2. [Wikipedia(zh):编译器](https://zh.wikipedia.org/wiki/%E7%B7%A8%E8%AD%AF%E5%99%A8):前端、中端与后端的划分
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  前端(以及中端)处理的是与具体机器无关的形式,读源码、建结构、做优化;后端则紧盯一台具体机器,处理指令集、寄存器、寻址方式等机器细节。也就是从“通用”转向“特定机器”。
+
+#### 思考题 2
+
+  因为 IR 的语义就是程序应有的行为。后端若不能忠实实现它,优化阶段辛苦维持的“行为不变”就会丢失,程序结果可能出错。正确是底线,速度只是在此之上的加分。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/目标代码生成.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十一章:调用约定.md

+88 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\350\260\203\347\224\250\347\272\246\345\256\232.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\350\260\203\347\224\250\347\272\246\345\256\232.md"
new file mode 100644
index 00000000..fe9dc9e1
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\350\260\203\347\224\250\347\272\246\345\256\232.md"
@@ -0,0 +1,88 @@
+# 调用约定
+
+## 复习
+
+- 目标代码生成:后端的总任务
+- 函数调用与运行栈:调用时如何保存信息
+- 寄存器分配:决定值的存放
+
+## TL;DR
+
+- 调用约定规定函数之间怎样传参、怎样返回
+- 它约定参数与返回值放哪里,以及谁负责保存旧值
+- 调用双方必须遵守同一套约定
+- 它让不同模块、甚至不同语言编译出的代码也能协作
+
+## 正文
+
+  函数之间要互相调用。可一个函数被调用时,参数放哪、结果从哪拿、哪些寄存器要小心保护——这些如果没有统一规定,调用方和被调方就会“对不上暗号”。这套规定,就是**调用约定**(calling convention)。
+
+### 约定些什么
+
+  调用约定通常要讲清几件事:
+
+- **参数怎么传**:放进特定的寄存器,还是压到栈上?顺序如何?
+- **返回值怎么给**:放在哪个寄存器或内存位置?
+- **谁来保护寄存器**:调用方还是要保存现场?
+- **栈由谁清理**:调用结束后,谁负责把栈恢复
+
+  其中“保护寄存器”有个重要区分:
+
+- **调用者保存**(caller-saved):调用方若还需要某个寄存器里的值,就得自己先存好
+- **被调用者保存**(callee-saved):被调函数若要改动某个寄存器,必须先用后恢复,保证调用方不受影响
+
+### 为什么必须统一
+
+  调用约定最大的意义,是**让“调用”这件事变成一个双方都懂的接口**。
+
+  只要大家都遵守同一套约定:
+
+- 一个函数可以安全地调用另一个
+- 由不同程序员、甚至**不同语言**编译出来的模块,也能互相调用
+- 库函数被任何人调用,都不会“读错参数”
+
+  这套“跨模块、跨语言的公共约定”,在系统层面常被称为 **ABI**(应用二进制接口)。它是比源码接口更底层的一种契约。
+
+  **接口与实现分离**的老思想,在这里又出现了一次:**约定的接口稳定了,各路实现才能自由协作。**
+
+ **思考题 1** 
+
+>   调用约定通常规定了哪些内容?
+
+ **思考题 2** 
+
+>   为什么调用约定必须由调用双方共同遵守?
+
+## 小结
+
+### 知识点
+
+- 调用约定规定传参、返回值与寄存器保护等
+- 区分调用者保存与被调用者保存
+- 统一约定让不同模块、语言能互相调用
+- 系统层面的这类约定常称为 ABI
+
+### 参考资料
+
+1. [Wikipedia(zh):调用约定](https://zh.wikipedia.org/wiki/%E8%B0%83%E7%94%A8%E7%BA%A6%E5%AE%9A):函数间如何传递参数与返回值
+2. [Wikipedia(zh):应用二进制接口](https://zh.wikipedia.org/wiki/%E5%BA%94%E7%94%A8%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%8E%A5%E5%8F%A3):二进制层面的跨模块接口约定
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  它通常规定:参数通过哪些寄存器或栈传递、返回值放在哪里、哪些寄存器由调用方保存、哪些由被调用方保存,以及调用结束后由谁清理栈等内容。
+
+#### 思考题 2
+
+  因为调用是一个交互过程:调用方按约定放参数,被调方按约定取参数,返回时再按约定交结果、恢复寄存器与栈。只有双方遵守同一套约定,参数、返回值才不会被“理解错”,调用才能正确完成。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/调用约定.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十三章:冲突图.md

+83 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\345\206\262\347\252\201\345\233\276.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\345\206\262\347\252\201\345\233\276.md"
new file mode 100644
index 00000000..0b1ea9fc
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\345\206\262\347\252\201\345\233\276.md"
@@ -0,0 +1,83 @@
+# 冲突图
+
+## 复习
+
+- 活跃变量分析:得到各变量的活跃区间
+- 图:用节点和边表示关系
+- 寄存器分配:把值映射到寄存器
+
+## TL;DR
+
+- 冲突图把“不能共用寄存器”的变量连起来
+- 节点是变量,边表示它们的活跃区间重叠
+- 寄存器分配由此变成图的着色问题
+- 它把分配问题抽象成了图论问题
+
+## 正文
+
+  上一章得到了每个变量的活跃区间。现在要把“谁和谁不能共用寄存器”这件事,画成一张图——**冲突图**(interference graph),也叫干涉图。
+
+### 同时活着,就画一条边
+
+  冲突图的构造非常直接:
+
+- **节点**:每个变量是一个节点
+- **边**:如果两个变量的活跃区间**有重叠**(也就是它们会同时活着),就在它们之间连一条边
+
+  这条边代表“冲突”:**这两个变量不能共用同一个寄存器**,否则一个会把另一个的值覆盖掉。
+
+  反过来,没有边的两个变量,就说明它们的活跃区间不重叠,**可以共用同一个寄存器**。
+
+### 分配 = 着色
+
+  有了冲突图,“分配寄存器”这个问题就变了个模样:
+
+> 给每个节点上一种“颜色”,颜色代表寄存器;要求**相邻的节点颜色不同**。
+
+  这就是图论里的**着色问题**(graph coloring)。可用颜色的数量,就等于可用的寄存器数量。
+
+  这么一转化,好处太大了:寄存器分配本来是个零碎的工程问题,现在成了一个**有成熟算法和图论结论**的问题。**把实际问题抽象成已知的数学问题**,正是计算机科学里屡试不爽的招数。
+
+  那么,如果颜色不够用(寄存器不够),该怎么办?下一章揭晓。
+
+ **思考题 1** 
+
+>   冲突图的节点和边,分别代表什么?
+
+ **思考题 2** 
+
+>   为什么寄存器分配可以转化成“图着色”?
+
+## 小结
+
+### 知识点
+
+- 冲突图以变量为节点
+- 活跃区间重叠的两个变量之间连边
+- 有边表示不能共用寄存器
+- 寄存器分配等价于给冲突图着色
+
+### 参考资料
+
+1. [Wikipedia(zh):寄存器分配](https://zh.wikipedia.org/wiki/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D):以冲突图为基础的分配
+2. [Wikipedia(zh):图着色问题](https://zh.wikipedia.org/wiki/%E5%9B%BE%E7%9D%80%E8%89%B2%E9%97%AE%E9%A2%98):给相邻节点着不同颜色
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  节点代表一个变量(一个需要存放的值);边表示这两个变量的活跃区间重叠、会同时存活,因而不能共用同一个寄存器。
+
+#### 思考题 2
+
+  因为“不能共用寄存器”正好对应“相邻节点颜色要不同”:把寄存器看成颜色,只要相邻节点异色,就保证同时存活的变量不会共用寄存器。于是分配问题就等价于给冲突图着色。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/冲突图.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十二章:活跃变量分析.md

+91 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\346\264\273\350\267\203\345\217\230\351\207\217\345\210\206\346\236\220.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\346\264\273\350\267\203\345\217\230\351\207\217\345\210\206\346\236\220.md"
new file mode 100644
index 00000000..b0c63e87
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\346\264\273\350\267\203\345\217\230\351\207\217\345\210\206\346\236\220.md"
@@ -0,0 +1,91 @@
+# 活跃变量分析
+
+## 复习
+
+- 数据流分析:沿控制流追踪信息
+- 控制流图:表示执行流向
+- 寄存器分配:决定值放在哪个寄存器
+
+## TL;DR
+
+- 活跃变量分析判断某点上变量之后是否还会被使用
+- 它沿控制流**反向**传播信息
+- 两个变量的活跃区间若重叠,就不能共用同一个寄存器
+- 它是寄存器分配的基础
+
+## 正文
+
+  寄存器是有限的,而我们想尽量把值放在寄存器里(因为快)。要决定哪些值能共用同一个寄存器,得先知道:**每个值在程序的哪些位置还“活着”。** 这就是**活跃变量分析**(liveness analysis)。
+
+### 什么叫“活跃”
+
+  一个变量在某点是**活跃**的,意思是:**从这一点往后,它的值还会被用到**(在被重新赋值覆盖之前)。反过来,如果往后都不会再用它当前的值,它就是“死的”。
+
+  看个例子:
+
+```text
+x = 1
+y = 2
+用 x        ← 这里 x 活跃;y 从没被用过,一直不活跃
+x = 3
+```
+
+  `y = 2` 之后,`y` 再没被用过,所以这段里 `y` 一点都不“活跃”——它其实是死代码。
+
+### 为什么要反向分析
+
+  注意:要判断“现在这个值以后还会不会用”,得看**后面的代码**。所以活跃变量分析是**反向**的数据流分析:从程序的出口往回推,一路传播“哪些变量此刻是活跃的”。
+
+  这和前面“可达定义”那种从前向后传播的方向相反,但套路一样:**在控制流图上迭代,直到稳定。** 方向换一下,工具还是那套工具。
+
+### 它为什么是寄存器分配的前提
+
+  活跃信息把“谁能共用寄存器”这件事说清楚了:
+
+- 一个变量活跃的那段范围,叫它的**活跃区间**
+- 如果两个变量的活跃区间**有重叠**,说明它们同时“活着”,**不能塞进同一个寄存器**——否则一个会覆盖另一个
+- 只有活跃区间不重叠的变量,才有机会共用寄存器
+
+  于是,“怎样分配寄存器”就转化成了“怎样安排这些活跃区间”。下一章会用一张图,把这个问题画得清清楚楚。
+
+ **思考题 1** 
+
+>   “活跃”是什么意思?为什么这个分析是反向的?
+
+ **思考题 2** 
+
+>   活跃变量分析为什么是寄存器分配的基础?
+
+## 小结
+
+### 知识点
+
+- 活跃指变量从某点往后还会被使用
+- 它沿控制流反向传播,迭代到稳定
+- 每个变量的活跃区间是一段范围
+- 活跃区间重叠的变量不能共用寄存器
+
+### 参考资料
+
+1. [Wikipedia(zh):活跃变量分析](https://zh.wikipedia.org/wiki/%E6%B4%BB%E8%B7%83%E5%8F%98%E9%87%8F%E5%88%86%E6%9E%90):判断变量之后是否还会被使用
+2. [Wikipedia(zh):寄存器分配](https://zh.wikipedia.org/wiki/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D):把变量映射到寄存器
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  活跃指某个变量在某点之后、被重新赋值之前,它的值还会被使用。因为要判断“以后还会不会用”,必须看后面的代码,所以分析方向是从出口往入口的反向传播。
+
+#### 思考题 2
+
+  因为只有知道每个变量在哪些位置“活着”,才能判断哪些变量会同时存活。同时存活的变量不能共用寄存器,只有活跃区间不重叠的才能共享。确定这些之后,才能正确地分配有限的寄存器。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/活跃变量分析.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十五章:栈帧.md

+91 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\346\240\210\345\270\247.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\346\240\210\345\270\247.md"
new file mode 100644
index 00000000..19e71f3d
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\346\240\210\345\270\247.md"
@@ -0,0 +1,91 @@
+# 栈帧
+
+## 复习
+
+- 调用约定:函数之间如何传参与返回
+- 栈:后进先出
+- 寄存器着色与溢出:部分值要放到内存
+
+## TL;DR
+
+- 栈帧是函数调用时在栈上开辟的一块空间
+- 它保存局部变量、被保护的寄存器、返回地址等
+- 每次调用压入一个栈帧,返回时弹出
+- 溢出到内存的变量,也放在栈帧里
+
+## 正文
+
+  函数调用时,需要一块地方来安置“这次调用特有的东西”。这块空间,就是**栈帧**(stack frame)。它建在栈上,正好契合函数调用的“嵌套”特性。
+
+### 一帧里装什么
+
+  一个栈帧通常包含:
+
+- **返回地址**:函数执行完,该回到调用处的哪里
+- **保存的寄存器**:按调用约定,被调函数要保护的寄存器旧值
+- **局部变量**:这个函数自己的局部数据
+- **溢出的值**:放不进寄存器、只能暂存内存的那些变量
+
+  所以,栈帧不仅装“数据”,还装“回来的路”和“现场的备份”。
+
+### 调用压入,返回弹出
+
+  栈帧和函数调用是同步的:
+
+- **调用一个函数**:为它压入一个新的栈帧
+- **函数执行**:用的是自己这一帧里的数据
+- **返回**:弹出这一帧,控制权交还调用者,调用者继续用它的帧
+
+  因为函数调用是“一层套一层”的,栈帧也一层压一层——这正好是**栈**(后进先出)的用武之地。一个函数调用了另一个,新帧就压在旧帧上面;后者返回,就把它弹掉。
+
+### 和前面的呼应
+
+  栈帧把前面好几个概念串了起来:
+
+- 它体现**调用约定**(谁保存哪些寄存器)
+- 它是**函数调用运行栈**在机器层面的具体样子
+- 它收留**溢出**的值
+
+  到这里,“值放在哪”这件事就彻底落实了:能放寄存器的放寄存器,放不下的放栈帧。位置都定了,就可以真正动手写汇编了。
+
+ **思考题 1** 
+
+>   栈帧里通常保存哪些东西?
+
+ **思考题 2** 
+
+>   栈帧和函数调用的“嵌套”有什么关系?
+
+## 小结
+
+### 知识点
+
+- 栈帧是函数调用时在栈上开辟的空间
+- 内含返回地址、保存的寄存器、局部变量、溢出的值
+- 调用时压入,返回时弹出
+- 栈帧契合函数调用的嵌套结构
+
+### 参考资料
+
+1. [Wikipedia(zh):调用栈](https://zh.wikipedia.org/wiki/%E8%B0%83%E7%94%A8%E6%A0%88):函数调用信息的栈式存储
+2. [Wikipedia(zh):栈帧](https://zh.wikipedia.org/wiki/%E6%A0%88%E5%B8%A7):一次函数调用占用的栈空间
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  通常包括:返回地址、按约定需要保护的寄存器旧值、函数的局部变量,以及无法放进寄存器、被溢出到内存的那些值。
+
+#### 思考题 2
+
+  函数调用是一层套一层的:调用一个函数会压入一个新栈帧,返回时再弹出。这种“后进先出”的嵌套关系正好对应栈结构,所以栈帧用栈来组织最自然。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/栈帧.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十六章:生成汇编代码.md

+91 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\347\224\237\346\210\220\346\261\207\347\274\226\344\273\243\347\240\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\347\224\237\346\210\220\346\261\207\347\274\226\344\273\243\347\240\201.md"
new file mode 100644
index 00000000..4c6f186e
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\347\224\237\346\210\220\346\261\207\347\274\226\344\273\243\347\240\201.md"
@@ -0,0 +1,91 @@
+# 生成汇编代码
+
+## 复习
+
+- 指令选择:决定用哪些机器指令
+- 寄存器着色与溢出:决定值放在哪里
+- 栈帧:函数调用时的栈布局
+
+## TL;DR
+
+- 生成汇编,是把前面所有决定落成具体的文本
+- 此时指令、寄存器、栈位置都已确定
+- 汇编之后还要经汇编器变成机器码
+- 后端到此基本完成
+
+## 正文
+
+  这是后端代码生成的最后一步。前面的决定——用哪些指令、每个值放哪个寄存器、栈帧怎么摆——都做好了,现在要做的,是把它们**写成具体的汇编代码**。
+
+### 把决定“抄”下来
+
+  到了这一步,其实“思考”已经基本结束,剩下的更像“誊写”:
+
+- 指令选择已经定了 ××× 用哪条指令
+- 寄存器分配已经定了每个变量待在哪个寄存器
+- 栈帧布局已经定了局部变量和溢出值在栈上的偏移
+
+  生成汇编,就是把这些决定,按机器的语法一字一句写出来。
+
+### 一个例子
+
+  比如这样一段简单代码 `a = b + c`,经过前面的处理,可能被生成成:
+
+```text
+load  r1, [b]     ; 把 b 从内存读进寄存器 r1
+load  r2, [c]     ; 把 c 读进 r2
+add   r3, r1, r2  ; r3 = r1 + r2
+store [a], r3     ; 把结果写回 a
+```
+
+  原本一句 `a = b + c`,被拆成了“取数、取数、相加、存回”几条指令。这和我们前面讲三地址码时的“拆解”,思路一脉相承——只不过这次拆的是**真正的机器指令**。
+
+  如果 `b`、`c` 已经在寄存器里,或者机器支持“基址 + 偏移”的寻址模式,生成的指令还会更少。**具体长什么样,取决于前面指令选择和寄存器的决定。**
+
+### 之后还有什么
+
+  汇编代码并不是终点。它还要交给**汇编器**,翻译成二进制的机器码,生成**目标文件**;再经过**链接**,才能变成可执行文件。
+
+  这两步——汇编和链接——我们在讲程序与编程基础时提过,当时当作黑箱。现在我们已经走到了它们的门口。**下一组,就正式打开链接这个黑箱。**
+
+ **思考题 1** 
+
+>   到“生成汇编”这一步,哪些决定已经确定了?
+
+ **思考题 2** 
+
+>   生成的汇编,之后还要经过什么,才能变成可执行文件?
+
+## 小结
+
+### 知识点
+
+- 生成汇编把指令、寄存器、栈布局落成文本
+- 简单语句会被展开成多条机器指令
+- 汇编再经汇编器变为机器码,生成目标文件
+- 之后还需链接才能得到可执行文件
+
+### 参考资料
+
+1. [Wikipedia(zh):汇编语言](https://zh.wikipedia.org/wiki/%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80):与机器指令对应的低级语言
+2. [Wikipedia(zh):代码生成](https://zh.wikipedia.org/wiki/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90_(%E7%BC%96%E8%AF%91%E5%99%A8)):后端生成目标代码的过程
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  指令选择(用哪些机器指令)、寄存器分配(每个值放在哪个寄存器或内存)、以及栈帧布局(局部变量与溢出值在栈上的位置)都已经确定,生成汇编只是把这些决定写成具体的汇编文本。
+
+#### 思考题 2
+
+  汇编代码要先经汇编器翻译成二进制机器码,形成目标文件;多个目标文件还要再经过链接,解决符号与地址的引用,才能最终得到可执行文件。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/生成汇编代码.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十四章:寄存器着色与溢出.md

+85 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\345\257\204\345\255\230\345\231\250\347\235\200\350\211\262\344\270\216\346\272\242\345\207\272.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\345\257\204\345\255\230\345\231\250\347\235\200\350\211\262\344\270\216\346\272\242\345\207\272.md"
new file mode 100644
index 00000000..ea955c45
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\345\257\204\345\255\230\345\231\250\347\235\200\350\211\262\344\270\216\346\272\242\345\207\272.md"
@@ -0,0 +1,85 @@
+# 寄存器着色与溢出
+
+## 复习
+
+- 冲突图:把分配问题变成图着色
+- 图:节点、边与着色
+- 目标代码生成:后端的任务
+
+## TL;DR
+
+- 寄存器分配就是给冲突图着色,颜色数等于寄存器数
+- 若图无法用这么多颜色着色,就需要“溢出”
+- 溢出把部分变量暂存到内存(栈)里
+- 本质上是用访存的时间,换寄存器的紧张
+
+## 正文
+
+  有了冲突图,寄存器分配就变成了“用有限的颜色给图上色”。可现实很骨感:**寄存器往往不够用。**
+
+### 颜色不够怎么办
+
+  给冲突图着色时,可能出现一种情况:**当前的颜色数量(寄存器数),怎么都塞不下这张图**——总有一个节点,它的邻居们已经把可用的颜色用光了,没色可分。
+
+  这时候,编译器不能“摆烂”,而要采取措施:**把一部分变量从寄存器里请出去,放到内存(栈)里。** 这个动作,就叫**溢出**(spilling)。
+
+### 溢出:把值暂存到内存
+
+  被“溢出”的变量,平时存在内存中;要用到它时,先从内存读进一个临时寄存器,用完再写回去。
+
+  它带来的变化很直接:
+
+- **好处**:缓解了寄存器不够的压力,让着色能继续
+- **代价**:每次访问都要多一次内存读写(虽然现代机器有缓存,但仍比寄存器慢)
+
+  所以,溢出不是免费的。编译器会尽量**挑那些“用途少、不常访问”的变量**去溢出,把代价降到最低。选谁溢出,本身也是一个小优化问题。
+
+### 又是那个交换
+
+  你大概已经看出来了:溢出本质上是一次**用时间换空间**(更准确地说,是用访存的时间,换寄存器的紧张)。
+
+  寄存器快但少,内存慢但多。当“快资源”不够时,就用“慢资源”来补——这和缓存、虚拟内存的套路如出一辙。**整部教程里,这种“稀缺资源不足时用富余资源顶上”的思路,反复出现。**
+
+  着色完成后,每个变量就都拿到了具体的寄存器(或确定要溢出到内存)。接下来要落的,就是函数调用时那块**栈**怎么摆——也就是栈帧。
+
+ **思考题 1** 
+
+>   为什么会出现“寄存器溢出”?
+
+ **思考题 2** 
+
+>   溢出本质上是一种怎样的交换?
+
+## 小结
+
+### 知识点
+
+- 寄存器分配等价于用固定颜色数给冲突图着色
+- 颜色不够时必须溢出部分变量
+- 溢出把变量暂存到内存,用时再读写
+- 溢出是用访存时间换寄存器空间的权衡
+
+### 参考资料
+
+1. [Wikipedia(zh):寄存器分配](https://zh.wikipedia.org/wiki/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D):包含寄存器溢出处理
+2. [Wikipedia(zh):寄存器溢出](https://zh.wikipedia.org/wiki/%E5%AF%84%E5%AD%98%E5%99%A8%E6%BA%A2%E5%87%BA):寄存器不足时把值放入内存
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  因为寄存器数量有限,而冲突图可能需要比可用寄存器更多的“颜色”。当着色时某个节点无法找到与邻居都不同的颜色,就说明寄存器不够,必须把部分变量移出寄存器、暂存到内存。
+
+#### 思考题 2
+
+  它是用时间换空间:寄存器快但数量少,内存慢但容量大。寄存器不足时,把部分变量放到内存,每次访问多一次读写(花时间),从而缓解寄存器的紧张。这与缓存、虚拟内存的思路一致。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/寄存器着色与溢出.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百六十章:指令选择.md

+89 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\347\253\240\357\274\232\346\214\207\344\273\244\351\200\211\346\213\251.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\347\253\240\357\274\232\346\214\207\344\273\244\351\200\211\346\213\251.md"
new file mode 100644
index 00000000..04aa7a6e
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\205\255\345\215\201\347\253\240\357\274\232\346\214\207\344\273\244\351\200\211\346\213\251.md"
@@ -0,0 +1,89 @@
+# 指令选择
+
+## 复习
+
+- 目标代码生成:后端的总任务
+- 中间表示:三地址码
+- 树:用树表示表达式结构
+
+## TL;DR
+
+- 指令选择把 IR 操作映射为具体的机器指令
+- 同一操作可能有多种指令组合,要选更优的
+- 常用“模式匹配”:把 IR 看成树,用指令模板覆盖
+- 选择时还要考虑指令的代价与特点
+
+## 正文
+
+  后端第一件事,是决定“每个 IR 操作到底用哪些机器指令来实现”。这就是**指令选择**(instruction selection)。
+
+### 一个操作,可能有好几种写法
+
+  最直接的映射,比如 `a = b + c`,在大多数机器上就是一条加法指令搞定。
+
+  但复杂表达式就没这么简单了。比如 `a = b + c * d`,机器可能:
+
+- 先算 `c * d`,再和 `b` 相加
+- 也可能某台机器有“乘加”一条指令,一次搞定
+
+  再比如取数组元素、访问结构体,往往有专门的**寻址模式**,能一条指令完成“基址 + 偏移”的加载。**同一件事,可以有很多种指令组合,选哪种直接影响最终代码的效率和长度。**
+
+### 用“模式匹配”来做
+
+  怎么系统地做选择?常见办法是把 IR 表达式看成一棵**树**,而每一条机器指令,对应一个能覆盖这棵树的“小图案”(模板)。指令选择就变成了:
+
+> 用这些图案,把整棵树**覆盖**起来。
+
+  一种覆盖方式,就是一种指令序列。覆盖方式往往不止一种,于是再根据每条指令的**代价**(执行快慢、长度)来挑总代价最小的那种。**这又是一个在树/图上做选择的优化问题**——前面的图论工具,在这里又派上了用场。
+
+### 机器细节在这里登场
+
+  指令选择是最能体现“面向具体机器”的环节之一:
+
+- 这台机器有哪些指令?
+- 有哪些寻址方式?
+- 哪条指令更便宜?
+
+  这些都得一一考虑。所以,为不同 CPU 编译,生成的指令可能很不一样——**同一份源代码,同一套优化,最后落成的机器码却可能各不相同。** 这正是后端存在的意义。
+
+ **思考题 1** 
+
+>   指令选择在做什么?
+
+ **思考题 2** 
+
+>   为什么同一个 IR 操作,可能有多种指令实现,需要“选择”?
+
+## 小结
+
+### 知识点
+
+- 指令选择把 IR 操作映射为机器指令
+- 同一操作常有多种指令组合
+- 常用模式匹配,把 IR 树用指令模板覆盖
+- 依据指令代价选择更优的方案
+
+### 参考资料
+
+1. [Wikipedia(zh):指令选择](https://zh.wikipedia.org/wiki/%E6%8C%87%E4%BB%A4%E9%80%89%E6%8B%A9):把中间表示映射为机器指令
+2. [Wikipedia(zh):树覆盖](https://zh.wikipedia.org/wiki/%E6%A0%91%E8%A6%86%E7%9B%96):用指令模板覆盖表达式树
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  它在把 IR 的每个操作翻译成具体机器上的指令。对于复杂表达式,需要决定用哪几条指令、以什么顺序组合来实现它,并尽量选效率高、代价小的方案。
+
+#### 思考题 2
+
+  因为同一件事在机器上常有多种实现方式,例如是否有“乘加”指令、是否能利用寻址模式,都会影响指令组合。不同组合在速度、长度上各有差异,所以要“选择”出更优的那种。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/指令选择.png)
+
+> 设计师 | 南国微雪

更新记录(2026-09-20 08:34:53 +0000 | 3d464adf)

Summary

  • Generated at: 2026-09-20 08:34:53 +0000
  • Base commit: 3d464adf
  • Diff source: be8a25ec0e8f0ada698fb674d2953d689303f591..3d464adf09874b9fa07b8c986f57d9536fd1f515
  • Changed files: 9
  • Total lines: +741 / -0

Index

  1. src/SUMMARY.md +8 / -0
  2. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十一章:优化为什么必须保留行为.md +91 / -0
  3. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十七章:跨过程分析(进阶).md +91 / -0
  4. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十三章:无用代码删除.md +94 / -0
  5. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十二章:常量折叠与常量传播.md +89 / -0
  6. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十五章:循环优化.md +93 / -0
  7. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十八章:优化流水线总装.md +90 / -0
  8. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十六章:函数内联(进阶).md +92 / -0
  9. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十四章:公共子表达式消除.md +93 / -0

Diffs

src/SUMMARY.md

+8 / -0 Click to expand diff
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 93155a69..5061ffd4 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -802,6 +802,14 @@
   - [第两百四十八章:控制流图](学习与进步/计算机科学极简入门指南/编译原理/第两百四十八章:控制流图.md)
   - [第两百四十九章:数据流分析(进阶)](学习与进步/计算机科学极简入门指南/编译原理/第两百四十九章:数据流分析(进阶).md)
   - [第两百五十章:静态单赋值形式(进阶)](学习与进步/计算机科学极简入门指南/编译原理/第两百五十章:静态单赋值形式(进阶).md)
+  - [第两百五十一章:优化为什么必须保留行为](学习与进步/计算机科学极简入门指南/编译原理/第两百五十一章:优化为什么必须保留行为.md)
+  - [第两百五十二章:常量折叠与常量传播](学习与进步/计算机科学极简入门指南/编译原理/第两百五十二章:常量折叠与常量传播.md)
+  - [第两百五十三章:无用代码删除](学习与进步/计算机科学极简入门指南/编译原理/第两百五十三章:无用代码删除.md)
+  - [第两百五十四章:公共子表达式消除](学习与进步/计算机科学极简入门指南/编译原理/第两百五十四章:公共子表达式消除.md)
+  - [第两百五十五章:循环优化](学习与进步/计算机科学极简入门指南/编译原理/第两百五十五章:循环优化.md)
+  - [第两百五十六章:函数内联(进阶)](学习与进步/计算机科学极简入门指南/编译原理/第两百五十六章:函数内联(进阶).md)
+  - [第两百五十七章:跨过程分析(进阶)](学习与进步/计算机科学极简入门指南/编译原理/第两百五十七章:跨过程分析(进阶).md)
+  - [第两百五十八章:优化流水线总装](学习与进步/计算机科学极简入门指南/编译原理/第两百五十八章:优化流水线总装.md)
   - [附加章一:大数据](学习与进步/计算机科学极简入门指南/附加章/大数据.md)
   - [附加章二:数据加密](学习与进步/计算机科学极简入门指南/附加章/数据加密.md)
   - [附加章三:区块链](学习与进步/计算机科学极简入门指南/附加章/区块链.md)

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十一章:优化为什么必须保留行为.md

+91 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\344\274\230\345\214\226\344\270\272\344\273\200\344\271\210\345\277\205\351\241\273\344\277\235\347\225\231\350\241\214\344\270\272.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\344\274\230\345\214\226\344\270\272\344\273\200\344\271\210\345\277\205\351\241\273\344\277\235\347\225\231\350\241\214\344\270\272.md"
new file mode 100644
index 00000000..cab0afbf
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\344\274\230\345\214\226\344\270\272\344\273\200\344\271\210\345\277\205\351\241\273\344\277\235\347\225\231\350\241\214\344\270\272.md"
@@ -0,0 +1,91 @@
+# 优化为什么必须保留行为
+
+## 复习
+
+- 数据流分析:为优化提供“情报”
+- 静态单赋值形式:让分析和优化更简单
+- 中间表示:优化的载体
+
+## TL;DR
+
+- 优化可以改写程序,但绝不能改变可观察的行为
+- 这是优化的第一原则
+- 常见被禁止的改动:改变结果、改变副作用顺序等
+- 只有在“等价”的写法里挑更快的,才是安全的优化
+
+## 正文
+
+  终于来到优化了。前面讲了那么多分析,就是为了这一刻:**让程序跑得更快。**
+
+  但在动手之前,必须先立下一条规矩,而且它是**第一原则**——优化可以改写法,但**绝不能改变程序的行为**。
+
+### 什么叫“行为不变”
+
+  程序的行为,指的是它**对外可观察的一切**:
+
+- 最终的输出结果
+- 副作用的产生与顺序(比如打印、写文件、修改共享状态)
+- 是否抛出异常、在哪一步抛出
+
+  一行代码哪怕“看起来毫无用处”,只要它有副作用,就不能随便删;一段计算哪怕“看起来可以重排”,只要改变了副作用顺序,就可能出事。**优化器手里是一把刀,但只能切那些切了不影响的肉。**
+
+### 一个反例
+
+  举个常见的坑:浮点数加法不满足结合律。
+
+  数学上 `(a + b) + c` 等于 `a + (b + c)`,于是优化器可能想把它们重排以方便计算。但在浮点运算里,由于精度舍入,**两种顺序的结果可能不同**。如果语言规定必须按原顺序算,那么这种“重排”就会改变行为,是不允许的。
+
+  类似地,把一个“结果没人用”的函数调用删掉,如果这个调用内部有副作用(比如打印了一行字),删了就会改变行为。
+
+### 先想清楚“等价”,再想“更快”
+
+  所以,优化的正确姿势是:
+
+1. 先判断两种写法是否**等价**(对所有合法输入,可观察行为都相同)
+2. 只有在等价的前提下,才选出更快的那种
+
+  **“更快”永远排在“行为一致”之后。** 一个变快却算错的程序,比一个慢但正确的程序糟糕得多——正确是底线,性能是加分项。
+
+  有了这条底线,接下来的各种优化,就可以放心地一条条来看了。
+
+ **思考题 1** 
+
+>   为什么说“优化可以改写法,但不能改行为”?
+
+ **思考题 2** 
+
+>   举一个“看起来能优化、其实会改变行为”的例子。
+
+## 小结
+
+### 知识点
+
+- 行为指可观察的结果、副作用与异常
+- 优化必须保持行为不变
+- 有副作用的代码不能随意删除或重排
+- 先判定等价,再选择更快的写法
+
+### 参考资料
+
+1. [Wikipedia(zh):编译器优化](https://zh.wikipedia.org/wiki/%E7%BC%96%E8%AF%91%E5%99%A8%E4%BC%98%E5%8C%96):在保持语义的前提下改进程序
+2. [Wikipedia(zh):副作用 (计算机科学)](https://zh.wikipedia.org/wiki/%E5%89%AF%E4%BD%9C%E7%94%A8_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)):函数对外部状态的改变
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  因为优化只是让程序更高效,而不是改变它的含义。程序的输出、副作用和异常等可观察行为,必须与优化前一致,否则优化后的程序就不再是原来那个程序了,用户会得到错误结果。
+
+#### 思考题 2
+
+  例如把“结果没人用”的打印函数调用删掉——它看似没产出,却有输出这个副作用;再如重排浮点加减的顺序,可能因舍入导致结果变化。这些都“看起来能优化”,实则改变了行为。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/优化为什么必须保留行为.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十七章:跨过程分析(进阶).md

+91 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\267\250\350\277\207\347\250\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\267\250\350\277\207\347\250\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
new file mode 100644
index 00000000..cd9095f1
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\267\250\350\277\207\347\250\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -0,0 +1,91 @@
+# 跨过程分析(进阶)
+
+## 复习
+
+- 函数内联:把调用与被调函数拉到同一上下文
+- 静态单赋值形式:简化分析
+- 优化为什么必须保留行为:等价是前提
+
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
+## TL;DR
+
+- 跨过程分析跨越函数边界来观察程序
+- 它能发现“只盯一个函数”看不到的优化机会
+- 但分析范围越大,代价越高
+- 它常与内联配合使用
+
+## 正文
+
+  前面讲的优化,大多是在**一个函数内部**做的。可有些问题,只有**跨过函数边界**才能看清。这类分析叫**跨过程分析**(interprocedural analysis)。
+
+### 越过边界,看得更全
+
+  举个典型的例子:
+
+```text
+函数 计算(x): 返回 x * x
+主程序: 计算(10)
+```
+
+  如果只分析“计算”这个函数本身,你不知道 `x` 会是什么;但如果跨过程看,发现它总是被传 10,就可能**为这个调用点做特化**——直接算出结果 100。
+
+  这类“某个参数在很多调用处总是同一个常量”“某个函数从不返回错误”“某个变量跨函数也不变”等结论,只有把多个函数连起来看,才能得出。**内联把代码合到一起,跨过程分析则让优化能看到更大的图景。**
+
+### 代价:范围越大越贵
+
+  但跨过程分析不是没有代价的:
+
+- **分析范围爆炸**:函数相互调用,可能的组合非常多,分析成本急剧上升
+- **编译更慢、内存更多**:为了全局信息,编译器要保存和处理更多数据
+- **重新编译的连锁**:一个函数改了,依赖它的分析结论可能都要重做
+
+  所以,实际的编译器往往在“看多远”上做折中:有的只做过程内的优化,有的在模块内做,有的则在**链接时**做(常称为链接时优化,LTO)——把整个程序合起来再分析一遍,代价更大,收益也可能更大。
+
+### 同一个主题
+
+  你会发现,跨过程分析又一次落入那个熟悉的结构:**看得越全,能优化的越多,但代价也越大。**
+
+  这和处理器的乱序执行、缓存的大小、线程的数量……都是同一种味道:**没有免费的全局视野。** 关键在于,找到收益与代价最匹配的那个范围。
+
+ **思考题 1** 
+
+>   跨过程分析相比过程内分析,多看到了什么?
+
+ **思考题 2** 
+
+>   跨过程分析的代价是什么?
+
+## 小结
+
+### 知识点
+
+- 跨过程分析跨越函数边界观察程序
+- 它能发现过程内看不到的优化机会
+- 代价是分析成本高、编译更慢
+- 常与内联、链接时优化配合
+
+### 参考资料
+
+1. [Wikipedia(zh):过程间优化](https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90):跨越函数边界的分析与优化
+2. [Wikipedia(zh):链接时优化](https://zh.wikipedia.org/wiki/%E9%93%BE%E6%8E%A5%E6%97%B6%E4%BC%98%E5%8C%96):在链接阶段进行的全局优化
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  它能看到函数之间的相互关系,例如某个参数在调用处总是同一个常量、某函数从不返回错误、某值跨函数保持不变等。这些结论在只分析单个函数时是看不到的,因此能带来额外的优化机会。
+
+#### 思考题 2
+
+  代价是分析成本高:函数互相调用使可能的组合急剧增多,编译器需保存更多全局信息、编译更慢,某个函数改动还可能使相关分析结论失效而要重做。因此只能在“看多远”上做折中。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/跨过程分析.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十三章:无用代码删除.md

+94 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\346\227\240\347\224\250\344\273\243\347\240\201\345\210\240\351\231\244.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\346\227\240\347\224\250\344\273\243\347\240\201\345\210\240\351\231\244.md"
new file mode 100644
index 00000000..70c094cc
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\346\227\240\347\224\250\344\273\243\347\240\201\345\210\240\351\231\244.md"
@@ -0,0 +1,94 @@
+# 无用代码删除
+
+## 复习
+
+- 常量传播:把确定是常量的变量替换为常量
+- 数据流分析:活跃变量分析
+- 控制流图:判断可达性
+
+## TL;DR
+
+- 无用代码指永远不会执行、或结果没人使用的代码
+- 分为不可达代码与死代码两类
+- 它们依赖可达性分析和活跃变量分析来发现
+- 删除它们能减小体积、提升速度
+
+## 正文
+
+  常量传播常常会“算死”一些分支,从而暴露出那些永远不会执行的代码。把这些没用的代码删掉,就是**无用代码删除**(dead code elimination)。
+
+### 两类“没用”
+
+  “没用”分两种:
+
+- **不可达代码**:根本执行不到。比如某个条件在编译期就能判定恒假,它包住的那段代码永远不会运行
+- **死代码**:会执行,但**结果没有人用**。比如算出一个值,却从来没有被读取过
+
+  前者是“走不到”,后者是“白算了”。
+
+### 靠分析来发现
+
+  怎么知道哪些代码没用?还是靠前面的分析:
+
+- 用**可达性分析**:从入口出发,哪些块根本到不了,就是不可达代码
+- 用**活跃变量分析**:某个变量算出来之后,后面还有没有人用;没人用,那段计算就是死代码
+
+  举个小例子:
+
+```text
+x = 1
+x = 2
+用 x
+```
+
+  第一次给 `x` 赋的 `1`,立刻被 `2` 覆盖了,从没被读过——这就是死代码,可以删掉。
+
+### 小心副作用
+
+  但删“结果没人用”的代码时,必须格外小心一件事:**它有没有副作用?**
+
+  如果那行代码虽然结果没人用,却会打印、写文件、修改共享状态,那它就不能被当成“没用”删掉——因为它对外的影响是有人“用”的。**只有真正“纯”的计算,才允许因为结果没人用而被删除。**
+
+  这也再次呼应了优化的第一原则:**删可以,但行为不能变。**
+
+ **思考题 1** 
+
+>   “不可达代码”和“死代码”,有什么区别?
+
+ **思考题 2** 
+
+>   删除“结果没人用”的代码时,为什么还要小心?
+
+## 小结
+
+### 知识点
+
+- 无用代码分为不可达代码与死代码
+- 可达性分析发现不可达代码
+- 活跃变量分析发现死代码
+- 有副作用的代码不能因“结果没人用”而删除
+
+### 参考资料
+
+1. [Wikipedia(zh):死代码消除](https://zh.wikipedia.org/wiki/%E6%AD%BB%E4%BB%A3%E7%A0%81%E6%B6%88%E9%99%A4):移除不会影响结果的代码
+2. [Wikipedia(zh):活跃变量分析](https://zh.wikipedia.org/wiki/%E6%B4%BB%E8%B7%83%E5%8F%98%E9%87%8F%E5%88%86%E6%9E%90):判断变量之后是否还会被使用
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  不可达代码是根本执行不到的代码(例如恒假条件包住的代码);死代码是会执行、但产生的结果没有任何人使用。前者“走不到”,后者“白算了”。
+
+#### 思考题 2
+
+  因为有些代码虽然结果没人用,却带有副作用(打印、写文件、改共享状态等)。这些副作用是外部的可观察行为,删除它会改变程序行为,违反优化原则。所以只有纯计算才允许删。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/无用代码删除.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十二章:常量折叠与常量传播.md

+89 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\345\270\270\351\207\217\346\212\230\345\217\240\344\270\216\345\270\270\351\207\217\344\274\240\346\222\255.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\345\270\270\351\207\217\346\212\230\345\217\240\344\270\216\345\270\270\351\207\217\344\274\240\346\222\255.md"
new file mode 100644
index 00000000..8baacab5
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\345\270\270\351\207\217\346\212\230\345\217\240\344\270\216\345\270\270\351\207\217\344\274\240\346\222\255.md"
@@ -0,0 +1,89 @@
+# 常量折叠与常量传播
+
+## 复习
+
+- 优化为什么必须保留行为:等价是前提
+- 数据流分析:判断某点的值是否为常量
+- 三地址码:优化作用的中间表示
+
+## TL;DR
+
+- 常量折叠:编译时把常量运算直接算出来
+- 常量传播:把“其实是常量”的变量替换成常量
+- 两者常配合使用,能省掉大量运行时的计算
+- 前提是能确定它一定是常量
+
+## 正文
+
+  优化里最直观的一类,是处理“常量”。既然编译时就知道结果,何必留到运行时再算?这有两个动作:**常量折叠**和**常量传播**。
+
+### 常量折叠:能算的先算掉
+
+  **常量折叠**(constant folding)很直白:如果一个运算的操作数都是编译时已知的常量,那就直接把它算出来,把运算替换成结果。
+
+```text
+x = 2 + 3        →        x = 5
+```
+
+  反正结果固定,运行时就别再算 `2 + 3` 了。这不需要任何分析,只要看到常量运算就能折叠。
+
+### 常量传播:把常量传出去
+
+  **常量传播**(constant propagation)更进一步:如果某个变量在某处**一定是常量**,就把用到它的地方替换成那个常量。
+
+```text
+x = 5
+y = x + 1       →        y = 6
+```
+
+  因为 `x` 确定是 5,`x + 1` 就确定是 6,于是它也能被折叠。**常量传播把“常量”从一个地方,扩散到了它被使用的地方**,从而制造出更多可折叠的机会。
+
+### 前提:得确定“它一定是”
+
+  这里有个关键前提:**必须确认这个变量在那一点上“一定是常量”。**
+
+  如果 `x` 在别处可能被改过,或者来自一个不确定的输入,那就不能传。判断“某点上变量是否一定是常量”,正是**数据流分析**的活儿——它沿着控制流,看 `x` 的值在所有可能路径上是否都只有一个确定的值。
+
+  所以你看,**优化不是拍脑袋,而是建立在分析之上的。** 折叠和传播这对搭档,常常是优化的第一步:把常量算掉之后,往往会暴露出更多可优化的空间。
+
+ **思考题 1** 
+
+>   常量折叠和常量传播,分别做什么?
+
+ **思考题 2** 
+
+>   常量传播为什么需要先确认“它一定是常量”?
+
+## 小结
+
+### 知识点
+
+- 常量折叠把常量运算在编译期算掉
+- 常量传播把确定是常量的变量替换为常量
+- 两者配合能触发更多折叠
+- “一定是常量”由数据流分析判定
+
+### 参考资料
+
+1. [Wikipedia(zh):常量折叠](https://zh.wikipedia.org/wiki/%E5%B8%B8%E9%87%8F%E6%8A%98%E5%8F%A0):在编译期计算常量表达式
+2. [Wikipedia(zh):常量传播](https://zh.wikipedia.org/wiki/%E5%B8%B8%E9%87%8F%E4%BC%A0%E6%92%AD):把常量值传播到使用处
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  常量折叠把操作数都是常量的运算在编译期直接算出结果,例如 `2+3` 变成 `5`;常量传播则判断某个变量在某点一定是常量,把使用它的地方替换成该常量,例如把 `x+1` 换成 `6`。
+
+#### 思考题 2
+
+  因为只有当该变量在那一点确定是常量时,替换才不改变程序行为。如果它在别处可能被修改,或来自不确定的输入,替换就会算错。因此需要数据流分析来确认“所有路径上它都是同一个确定值”。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/常量折叠与常量传播.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十五章:循环优化.md

+93 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\345\276\252\347\216\257\344\274\230\345\214\226.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\345\276\252\347\216\257\344\274\230\345\214\226.md"
new file mode 100644
index 00000000..46fb3041
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\345\276\252\347\216\257\344\274\230\345\214\226.md"
@@ -0,0 +1,93 @@
+# 循环优化
+
+## 复习
+
+- 公共子表达式消除:复用相同的计算
+- 数据流分析:为循环优化提供依据
+- 控制流图:循环表现为环
+
+## TL;DR
+
+- 循环是程序的热点,优化收益最大
+- 常见手段:循环不变量外提、强度削弱、循环展开
+- 目标都是减少循环内的重复工作
+- 但必须小心循环次数为 0 或 1 等边界
+
+## 正文
+
+  如果说优化要挑重点,那**循环**几乎永远排第一。因为循环里的代码会被反复执行,哪怕省下一点点,乘以循环次数,收益就很可观。这也呼应了效率优化里的老经验:**盯着热点下手。**
+
+### 循环不变量外提
+
+  有一种很常见的浪费:**循环里有些计算,每次算出来都一样。** 那就不该在循环里反复算,而应搬到循环外面只算一次。这叫**循环不变量外提**(loop-invariant code motion)。
+
+```text
+循环 { y = a * b; 用 y ... }   →   t = a * b
+                                   循环 { y = t; 用 y ... }
+```
+
+  只要 `a`、`b` 在循环期间不变,`a * b` 就是“不变量”,可以外提。
+
+### 强度削弱与循环展开
+
+  还有两个常用手法:
+
+- **强度削弱**(strength reduction):把“贵”的运算换成“便宜”的。比如循环里反复算 `i * 4`,可以改成每次加 4 的累加(乘法变加法)
+- **循环展开**(loop unrolling):把循环体复制几份,一次处理多个元素,从而减少循环控制(判断、跳转、自增)的开销
+
+  目标都是一致的:**让循环内部做的事更少、更便宜。**
+
+### 别踩边界
+
+  循环优化威力大,但也容易出错,尤其是**边界情况**:
+
+- 循环可能一次都不执行(次数为 0)
+- 也可能只执行一次
+- 外提的不变量,真的全程不变吗
+
+  如果外提把“本来不执行的代码”变成“执行了”(比如循环次数为 0,但外提的计算有副作用),行为就变了。所以,每一种循环优化,都要仔细验证在**所有边界下**依然等价。
+
+  **收益越大,越要小心。** 循环优化是编译器里最能体现“性能和正确性拉锯”的地方之一。
+
+ **思考题 1** 
+
+>   为什么优化通常优先盯住循环?
+
+ **思考题 2** 
+
+>   把循环内的不变量移到外面,需要小心什么?
+
+## 小结
+
+### 知识点
+
+- 循环是热点,优化收益大
+- 循环不变量外提把不变的计算移到循环外
+- 强度削弱用便宜运算替换昂贵运算
+- 循环展开减少循环控制开销
+- 必须小心次数为 0 或 1 等边界
+
+### 参考资料
+
+1. [Wikipedia(zh):循环优化](https://zh.wikipedia.org/wiki/%E5%BE%AA%E7%8E%AF%E4%BC%98%E5%8C%96):针对循环的各种优化
+2. [Wikipedia(zh):循环不变量](https://zh.wikipedia.org/wiki/%E5%BE%AA%E7%8E%AF%E4%B8%8D%E5%8F%98%E9%87%8F):循环中保持不变的计算
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  因为循环里的代码会被反复执行,单位优化收益要乘以循环次数,因此同样的改动在循环上带来的速度提升远大于在只执行一次的地方。优化优先盯热点,收益最高。
+
+#### 思考题 2
+
+  需要小心循环次数为 0 或 1 等边界情况,以及“变量是否真的全程不变”。如果被外提的计算带有副作用,而原循环可能一次都不执行,外提就会让这段计算被执行,从而改变程序行为。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/循环优化.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十八章:优化流水线总装.md

+90 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\344\274\230\345\214\226\346\265\201\346\260\264\347\272\277\346\200\273\350\243\205.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\344\274\230\345\214\226\346\265\201\346\260\264\347\272\277\346\200\273\350\243\205.md"
new file mode 100644
index 00000000..a540de0e
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\344\274\230\345\214\226\346\265\201\346\260\264\347\272\277\346\200\273\350\243\205.md"
@@ -0,0 +1,90 @@
+# 优化流水线总装
+
+## 复习
+
+- 常量折叠与常量传播:把常量算掉、传开
+- 无用代码删除:去掉白算或走不到的代码
+- 循环优化与函数内联:减少重复工作,并为其它优化创造机会
+
+## TL;DR
+
+- 优化不是一步完成,而是一条“流水线”
+- 多个优化依次进行,还会相互配合、互相引出机会
+- 一轮常常不够,要反复几轮直到稳定
+- 每一步都必须保持行为不变
+
+## 正文
+
+  这一章是优化部分的收尾。前几章分别讲了常量折叠、无用代码删除、公共子表达式消除、循环优化、内联、跨过程分析……它们不是各自独立的,而是**串成一条流水线,协同工作**。
+
+### 优化会“互相喂饭”
+
+  单个优化已经有用,但它们真正的威力,来自**彼此配合**:
+
+- 常量传播把变量变成常量后,常量折叠又能算掉更多表达式
+- 折叠之后,一些条件变成恒真或恒假,无用代码删除就能砍掉整段分支
+- 删掉分支后,控制流变简单,公共子表达式消除和循环优化又有了新空间
+
+  你看,**一个优化制造出的新局面,常常正是另一个优化想要的。** 所以,编译器会把这些优化按一定顺序排好,让它们一个接一个地跑。
+
+### 一轮不够,要反复跑
+
+  更麻烦的是:**跑一轮往往不够。**
+
+  因为某种优化可能为前面已经跑过的优化,制造出**新的机会**。比如常量传播在最后又暴露出一个可折叠的表达式,那就得再折一次。于是,编译器的做法是**反复运行这条流水线,直到程序不再发生变化**(达到一个“不动点”)。
+
+  这和前面数据流分析“迭代到稳定”,是同一个思路:**只要还能改进,就继续,直到改不动为止。** 当然,为了不让编译时间失控,实际编译器也会设一个轮数上限。
+
+### 快,也是要权衡的
+
+  最后提醒一件事:**优化并不是越多越好、级别越高越快。**
+
+  - 优化会让**编译变慢**:分析、改写都要花时间
+  - 越激进的优化,**收益越不确定**,有时甚至因代码膨胀而变慢
+  - 所以编译器提供不同**优化级别**:开发时用低级别图快,发布时用高级别图快(运行快)
+
+  **又是取舍。** 编译器的“快”,分两种:编译过程本身要快,还是生成出来的程序要快。两者常常此消彼长。
+
+  至此,“把程序改快”这一阶段就完成了。接下来,我们要把优化好的中间表示,真正**落到机器指令上**——这就是编译器的后端。
+
+ **思考题 1** 
+
+>   为什么优化通常要“反复几轮”,而不是一遍过?
+
+ **思考题 2** 
+
+>   优化级别越高,生成出来的程序一定越快吗?
+
+## 小结
+
+### 知识点
+
+- 多个优化串成流水线,彼此配合
+- 一种优化常为另一种制造新机会
+- 需反复运行直到程序不再变化
+- 优化级别是编译时间与运行性能的权衡
+
+### 参考资料
+
+1. [Wikipedia(zh):编译器优化](https://zh.wikipedia.org/wiki/%E7%BC%96%E8%AF%91%E5%99%A8%E4%BC%98%E5%8C%96):优化流水线与级别
+2. [Wikipedia(zh):优化编译器](https://zh.wikipedia.org/wiki/%E4%BC%98%E5%8C%96%E7%BC%96%E8%AF%91%E5%99%A8):执行多种优化的编译器
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  因为某种优化常常为已经跑过的优化制造出新的机会,例如常量传播在后续又暴露出可折叠的表达式。若只跑一遍就会漏掉这些新机会,所以要反复运行,直到程序不再变化为止。
+
+#### 思考题 2
+
+  不一定。更高的优化级别通常让运行更快,但可能使编译时间显著增加,而且越激进的优化收益越不确定,有时还会因代码体积膨胀、缓存不友好而变慢。所以“更高级别”不等于“一定更快”,仍需权衡。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/优化流水线总装.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十六章:函数内联(进阶).md

+92 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\345\207\275\346\225\260\345\206\205\350\201\224\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\345\207\275\346\225\260\345\206\205\350\201\224\357\274\210\350\277\233\351\230\266\357\274\211.md"
new file mode 100644
index 00000000..a1ae04de
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\345\207\275\346\225\260\345\206\205\350\201\224\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -0,0 +1,92 @@
+# 函数内联(进阶)
+
+## 复习
+
+- 循环优化:减少循环内的重复工作
+- 函数调用与运行栈:调用本身有开销
+- 优化为什么必须保留行为:等价是前提
+
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
+## TL;DR
+
+- 内联把被调函数的代码直接嵌入调用处
+- 它省去调用开销,并为更多优化创造条件
+- 代价是代码体积膨胀
+- 是否内联,需要权衡
+
+## 正文
+
+  函数调用不是免费的:要传参、要保存返回地址、要跳转、要建立栈帧、要返回。对于**很小又被频繁调用**的函数,这些开销甚至可能超过函数体本身的工作量。
+
+  一个直接的办法是:**别调了,把函数体直接“塞”进调用处。** 这就是**函数内联**(function inlining)。
+
+### 好处不止是省调用
+
+  内联最直接的好处,是省掉调用的一整套开销。但更妙的是,它常常能**打开新的优化空间**:
+
+```text
+函数 加一(x): 返回 x + 1
+调用处: a = 加一(5)
+```
+
+  内联之后,变成了 `a = 5 + 1`,再一折叠就是 `a = 6`。**内联把“跨越函数边界”的计算,拉到了同一个上下文里**,于是常量传播、公共子表达式消除、死代码删除等优化,都更容易施展。
+
+  这也是为什么内联常被视为“优化的放大器”:它自己不总是最亮眼的那个,却让别的优化更有用武之地。
+
+### 代价:代码变大
+
+  但内联不是白来的,代价是**代码体积膨胀**。一个函数被调十次,内联后就复制了十份。代码变大,可能带来两个问题:
+
+- 占更多内存,**指令缓存**更容易装不下,反而变慢
+- 编译产物变大,编译时间也可能增加
+
+  所以,内联不是“越多越好”,而是一次精打细算的取舍。
+
+### 怎么决定
+
+  编译器通常会挑**小函数**和**热点函数**(被频繁调用的)优先内联,对体积大、调用少的函数则保守一些。此外,**递归函数不能无限内联**——否则会无限展开下去,必须设一个界限。
+
+  “用体积换速度,还是保体积”,又一次是那个熟悉的权衡。**关键看那点速度值不值得那些体积。**
+
+ **思考题 1** 
+
+>   函数内联能带来哪些好处?
+
+ **思考题 2** 
+
+>   函数内联的代价是什么?
+
+## 小结
+
+### 知识点
+
+- 内联把函数体嵌入调用处,省去调用开销
+- 它常为其他优化创造条件
+- 代价是代码体积膨胀,可能影响指令缓存
+- 通常优先内联小函数与热点函数
+
+### 参考资料
+
+1. [Wikipedia(zh):内联函数](https://zh.wikipedia.org/wiki/%E5%86%85%E8%81%94%E5%87%BD%E6%95%B0):把函数体嵌入调用处的优化
+2. [Wikipedia(zh):编译器优化](https://zh.wikipedia.org/wiki/%E7%BC%96%E8%AF%91%E5%99%A8%E4%BC%98%E5%8C%96):内联所属的优化范畴
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  一是省去函数调用的开销(传参、跳转、建栈、返回等);二是把调用与被调函数的代码拉到同一上下文,使常量传播、公共子表达式消除等优化更容易施展,从而间接带来更多优化收益。
+
+#### 思考题 2
+
+  代价是代码体积膨胀:函数被调用多少次就复制多少份,占用更多内存,可能使指令缓存命中率下降,编译产物与编译时间也可能增加。因此内联需要权衡,并非越多越好。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/函数内联.png)
+
+> 设计师 | 南国微雪

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十四章:公共子表达式消除.md

+93 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\345\205\254\345\205\261\345\255\220\350\241\250\350\276\276\345\274\217\346\266\210\351\231\244.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\345\205\254\345\205\261\345\255\220\350\241\250\350\276\276\345\274\217\346\266\210\351\231\244.md"
new file mode 100644
index 00000000..8dc1b45c
--- /dev/null
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\345\205\254\345\205\261\345\255\220\350\241\250\350\276\276\345\274\217\346\266\210\351\231\244.md"
@@ -0,0 +1,93 @@
+# 公共子表达式消除
+
+## 复习
+
+- 无用代码删除:去掉白算的代码
+- 数据流分析:判断表达式的可用性
+- 静态单赋值形式:让分析更简单
+
+## TL;DR
+
+- 公共子表达式指重复出现的相同计算
+- 只算一次,之后复用结果
+- 前提是这中间没有改变相关变量的值
+- SSA 让这种分析和复用更容易
+
+## 正文
+
+  程序里常常出现同样的计算被反复做。既然结果一样,做一次就够了——这就是**公共子表达式消除**(common subexpression elimination)。
+
+### 算一次,到处用
+
+  看一个例子:
+
+```text
+a = x + y
+...
+b = x + y
+```
+
+  中间如果没有改动 `x` 或 `y`,那么 `x + y` 两次算出来必然相同。于是第二次可以直接复用第一次的结果:
+
+```text
+t = x + y
+a = t
+...
+b = t
+```
+
+  一次计算,两处使用。省下的不只是一次加法——如果这个表达式很复杂、位于循环里,收益还会被放大。
+
+### 前提:中间不能变
+
+  复用的前提非常关键:**从第一次算,到下一次用,相关变量的值必须没有改变过。**
+
+  如果中间有 `x = 100` 这样的赋值,那么第二次的 `x + y` 已经和第一次不是一回事了,自然不能复用。所以,编译器需要一套分析(判断“某个表达式在某点是否一定已经被算出且仍然有效”),来确认这一点。
+
+  在 **SSA** 里,这件事会简单很多:因为每个变量名字只对应一个定义,“`x + y` 里的 `x` 有没有变过”这种问题,看一眼名字就知道,不必反复追踪。**这也是 SSA 让优化更轻松的一个典型例子。**
+
+### 一次小优化,可能引出更多
+
+  别小看这一步。当重复计算被合并后,往往会有旧的临时变量变得“没人用”,从而触发无用代码删除;而删除之后,控制结构可能又变得更简单。**优化之间常常互相成全**,这正是下一章“优化流水线”要讲的主题。
+
+ **思考题 1** 
+
+> 公共子表达式消除,到底在“省”什么?
+
+ **思考题 2** 
+
+> 为什么必须确认“中间没有改变相关变量”,才能复用结果?
+
+## 小结
+
+### 知识点
+
+- 公共子表达式是重复出现的相同计算
+- 消除后只算一次、复用结果
+- 前提是相关变量在此期间未改变
+- SSA 让这类分析更直接
+
+### 参考资料
+
+1. [Wikipedia(zh):公共子表达式消除](https://zh.wikipedia.org/wiki/%E5%85%AC%E5%85%B1%E5%AD%90%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B6%88%E9%99%A4):复用相同计算的结果
+2. [Wikipedia(zh):静态单赋值形式](https://zh.wikipedia.org/wiki/%E9%9D%99%E6%80%81%E5%8D%95%E8%B5%8B%E5%80%BC%E5%BD%A2%E5%BC%8F):简化此类分析的形式
+
+### 思考题答案(仅供参考)
+
+#### 思考题 1
+
+  它在省重复的计算:同一个表达式算了多次,只保留一次,其余使用第一次的结果,从而减少运行时的运算量与相关开销。
+
+#### 思考题 2
+
+  因为复用的前提是两次计算的结果相同。如果中间有赋值改变了参与运算的变量,第二次的表达式已经是另一个值,复用就会得到错误结果。所以必须确认相关变量在这期间没有被修改。
+
+## 协议
+
+  本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+![](https://raw.githubusercontent.com/TinySnow/computer-science-guide-resources/master/computer-science-guide/cover/编译原理/公共子表达式消除.png)
+
+> 设计师 | 南国微雪

更新记录(2026-09-20 08:28:48 +0000 | be8a25ec)

Summary

  • Generated at: 2026-09-20 08:28:48 +0000
  • Base commit: be8a25ec
  • Diff source: cdef84c68b17f4fcddf9b3f6bfd58ca9fc118f49..be8a25ec0e8f0ada698fb674d2953d689303f591
  • Changed files: 21
  • Total lines: +41 / -1

Index

  1. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百七十一章:双向链表与循环链表(进阶).md +2 / -0
  2. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百九十七章:负权边与 Bellman–Ford(进阶).md +2 / -0
  3. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百九十八章:并查集(进阶).md +2 / -0
  4. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百八十五章:平衡树(进阶).md +2 / -0
  5. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百八十八章:字典树(进阶).md +2 / -0
  6. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百六十四章:摊还分析(进阶).md +2 / -0
  7. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第两百零七章:计数排序与基数排序(进阶).md +2 / -0
  8. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第两百零九章:外部排序(进阶).md +2 / -0
  9. src/学习与进步/计算机科学极简入门指南/数据结构与算法/第两百零八章:比较排序的下限(进阶).md +2 / -0
  10. src/学习与进步/计算机科学极简入门指南/编译原理/第两百三十一章:预测分析(进阶).md +2 / -0
  11. src/学习与进步/计算机科学极简入门指南/编译原理/第两百三十二章:移进归约分析(进阶).md +2 / -0
  12. src/学习与进步/计算机科学极简入门指南/编译原理/第两百二十三章:手写词法分析器.md +1 / -1
  13. src/学习与进步/计算机科学极简入门指南/编译原理/第两百二十五章:有限自动机(进阶).md +2 / -0
  14. src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十章:静态单赋值形式(进阶).md +2 / -0
  15. src/学习与进步/计算机科学极简入门指南/编译原理/第两百四十九章:数据流分析(进阶).md +2 / -0
  16. src/学习与进步/计算机科学极简入门指南/编译原理/第两百四十二章:类型推断(进阶).md +2 / -0
  17. src/学习与进步/计算机科学极简入门指南/计算机网络/第一百一十一章:无线网络(进阶).md +2 / -0
  18. src/学习与进步/计算机科学极简入门指南/计算机网络/第一百三十七章:拥塞控制(进阶).md +2 / -0
  19. src/学习与进步/计算机科学极简入门指南/计算机网络/第一百三十八章:连接关闭与 TIME_WAIT(进阶).md +2 / -0
  20. src/学习与进步/计算机科学极简入门指南/计算机网络/第一百二十七章:自治系统与 BGP(进阶).md +2 / -0
  21. src/学习与进步/计算机科学极简入门指南/计算机网络/第一百二十三章:IPv6(进阶).md +2 / -0

Diffs

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百七十一章:双向链表与循环链表(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\270\203\345\215\201\344\270\200\347\253\240\357\274\232\345\217\214\345\220\221\351\223\276\350\241\250\344\270\216\345\276\252\347\216\257\351\223\276\350\241\250\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\270\203\345\215\201\344\270\200\347\253\240\357\274\232\345\217\214\345\220\221\351\223\276\350\241\250\344\270\216\345\276\252\347\216\257\351\223\276\350\241\250\357\274\210\350\277\233\351\230\266\357\274\211.md"
index b7f19696..b920f023 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\270\203\345\215\201\344\270\200\347\253\240\357\274\232\345\217\214\345\220\221\351\223\276\350\241\250\344\270\216\345\276\252\347\216\257\351\223\276\350\241\250\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\270\203\345\215\201\344\270\200\347\253\240\357\274\232\345\217\214\345\220\221\351\223\276\350\241\250\344\270\216\345\276\252\347\216\257\351\223\276\350\241\250\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 引用与指针:保存数据的位置而非内容
 - 数组与链表:连续与链式各有取舍
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 双向链表每个节点还保存指向前一个的指针

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百九十七章:负权边与 Bellman–Ford(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\344\270\203\347\253\240\357\274\232\350\264\237\346\235\203\350\276\271\344\270\216 Bellman\342\200\223Ford\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\344\270\203\347\253\240\357\274\232\350\264\237\346\235\203\350\276\271\344\270\216 Bellman\342\200\223Ford\357\274\210\350\277\233\351\230\266\357\274\211.md"
index e1ce3ce7..f02929e4 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\344\270\203\347\253\240\357\274\232\350\264\237\346\235\203\350\276\271\344\270\216 Bellman\342\200\223Ford\357\274\210\350\277\233\351\230\266\357\274\211.md"	
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\344\270\203\347\253\240\357\274\232\350\264\237\346\235\203\350\276\271\344\270\216 Bellman\342\200\223Ford\357\274\210\350\277\233\351\230\266\357\274\211.md"	
@@ -6,6 +6,8 @@
 - 图:带权图
 - 松弛操作:用新信息更新距离
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 负权边会让 Dijkstra 的贪心判断失效

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百九十八章:并查集(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\345\205\253\347\253\240\357\274\232\345\271\266\346\237\245\351\233\206\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\345\205\253\347\253\240\357\274\232\345\271\266\346\237\245\351\233\206\357\274\210\350\277\233\351\230\266\357\274\211.md"
index efc62c71..ff17b524 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\345\205\253\347\253\240\357\274\232\345\271\266\346\237\245\351\233\206\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\344\271\235\345\215\201\345\205\253\347\253\240\357\274\232\345\271\266\346\237\245\351\233\206\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 图:由节点和边组成
 - 树:用父子关系表示层次
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 并查集维护“哪些元素属于同一组”

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百八十五章:平衡树(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\344\272\224\347\253\240\357\274\232\345\271\263\350\241\241\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\344\272\224\347\253\240\357\274\232\345\271\263\350\241\241\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 07b8cc48..667c5112 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\344\272\224\347\253\240\357\274\232\345\271\263\350\241\241\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\344\272\224\347\253\240\357\274\232\345\271\263\350\241\241\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 删除节点与树的退化:插入顺序不好会退化成链表
 - 树:用父子关系表示层次
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 平衡树通过旋转,让树始终保持矮而匀称

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百八十八章:字典树(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\345\205\253\347\253\240\357\274\232\345\255\227\345\205\270\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\345\205\253\347\253\240\357\274\232\345\255\227\345\205\270\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md"
index d43855ca..03b597d5 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\345\205\253\347\253\240\357\274\232\345\255\227\345\205\270\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\253\345\215\201\345\205\253\347\253\240\357\274\232\345\255\227\345\205\270\346\240\221\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 字符串:字符的序列
 - 集合与映射:以键索引值的抽象
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 字典树按字符逐层组织字符串

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第一百六十四章:摊还分析(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\346\221\212\350\277\230\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\346\221\212\350\277\230\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 9c431959..5c21585e 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\346\221\212\350\277\230\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\200\347\231\276\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\346\221\212\350\277\230\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 最坏与平均:最坏情况是一种保证,平均情况依赖输入假设
 - 时空权衡:用空间常常可以换时间
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 摊还分析看的是一连串操作的平均代价

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第两百零七章:计数排序与基数排序(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\270\203\347\253\240\357\274\232\350\256\241\346\225\260\346\216\222\345\272\217\344\270\216\345\237\272\346\225\260\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\270\203\347\253\240\357\274\232\350\256\241\346\225\260\346\216\222\345\272\217\344\270\216\345\237\272\346\225\260\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 904b58d3..aa51fecd 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\270\203\347\253\240\357\274\232\350\256\241\346\225\260\346\216\222\345\272\217\344\270\216\345\237\272\346\225\260\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\270\203\347\253\240\357\274\232\350\256\241\346\225\260\346\216\222\345\272\217\344\270\216\345\237\272\346\225\260\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 数组:可按下标存取
 - 归并与快排:基于比较的 `O(n log n)`
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 计数排序不比较元素,而是统计每个取值出现的次数

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第两百零九章:外部排序(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\271\235\347\253\240\357\274\232\345\244\226\351\203\250\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\271\235\347\253\240\357\274\232\345\244\226\351\203\250\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 7d541655..88a45f06 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\271\235\347\253\240\357\274\232\345\244\226\351\203\250\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\344\271\235\347\253\240\357\274\232\345\244\226\351\203\250\346\216\222\345\272\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 存储层次:内存快、磁盘慢
 - 文件:数据可以长期存放在磁盘上
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 数据大到放不进内存时,就需要外部排序

src/学习与进步/计算机科学极简入门指南/数据结构与算法/第两百零八章:比较排序的下限(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\345\205\253\347\253\240\357\274\232\346\257\224\350\276\203\346\216\222\345\272\217\347\232\204\344\270\213\351\231\220\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\345\205\253\347\253\240\357\274\232\346\257\224\350\276\203\346\216\222\345\272\217\347\232\204\344\270\213\351\231\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
index cbf1412e..f788f07c 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\345\205\253\347\253\240\357\274\232\346\257\224\350\276\203\346\216\222\345\272\217\347\232\204\344\270\213\351\231\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\254\254\344\270\244\347\231\276\351\233\266\345\205\253\347\253\240\357\274\232\346\257\224\350\276\203\346\216\222\345\272\217\347\232\204\344\270\213\351\231\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 归并排序与快速排序:`O(n log n)`
 - 大 O 记号:描述增长量级
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 只靠两两比较的排序,至少要 `Ω(n log n)` 次比较

src/学习与进步/计算机科学极简入门指南/编译原理/第两百三十一章:预测分析(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\270\200\347\253\240\357\274\232\351\242\204\346\265\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\270\200\347\253\240\357\274\232\351\242\204\346\265\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
index e9d64b8f..ed931272 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\270\200\347\253\240\357\274\232\351\242\204\346\265\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\270\200\347\253\240\357\274\232\351\242\204\346\265\213\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 上下文无关文法:产生式与推导
 - 前瞻:递归下降遇到分支时需要提前看,才能选对产生式
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 预测分析只向前看固定的词数,就能决定用哪条产生式

src/学习与进步/计算机科学极简入门指南/编译原理/第两百三十二章:移进归约分析(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\272\214\347\253\240\357\274\232\347\247\273\350\277\233\345\275\222\347\272\246\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\272\214\347\253\240\357\274\232\347\247\273\350\277\233\345\275\222\347\272\246\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
index e444610e..29b79c7c 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\272\214\347\253\240\357\274\232\347\247\273\350\277\233\345\275\222\347\272\246\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\270\211\345\215\201\344\272\214\347\253\240\357\274\232\347\247\273\350\277\233\345\275\222\347\272\246\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 上下文无关文法:产生式与推导
 - 栈:后进先出
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 移进归约从输入出发,逐步归约成起始符号

src/学习与进步/计算机科学极简入门指南/编译原理/第两百二十三章:手写词法分析器.md

+1 / -1 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232\346\211\213\345\206\231\350\257\215\346\263\225\345\210\206\346\236\220\345\231\250.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232\346\211\213\345\206\231\350\257\215\346\263\225\345\210\206\346\236\220\345\231\250.md"
index 4f72aa92..6032fe3c 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232\346\211\213\345\206\231\350\257\215\346\263\225\345\210\206\346\236\220\345\231\250.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232\346\211\213\345\206\231\350\257\215\346\263\225\345\210\206\346\236\220\345\231\250.md"
@@ -21,7 +21,7 @@
 
   词法分析器的主干非常朴素:**用一个大循环,从头到尾扫描字符。**
 
-每一轮大致做几件事:
+  每一轮大致做几件事:
 
 1. 跳过空白和注释
 2. 看当前字符属于哪一类(字母?数字?符号?)

src/学习与进步/计算机科学极简入门指南/编译原理/第两百二十五章:有限自动机(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\272\224\347\253\240\357\274\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\272\224\347\253\240\357\274\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 52fb70ca..de96ac79 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\272\224\347\253\240\357\274\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\214\345\215\201\344\272\224\347\253\240\357\274\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 手写词法分析器:本质是一个状态机
 - 语言与文法:用规则描述语言
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 有限自动机是只有有限状态的识别机器

src/学习与进步/计算机科学极简入门指南/编译原理/第两百五十章:静态单赋值形式(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\347\253\240\357\274\232\351\235\231\346\200\201\345\215\225\350\265\213\345\200\274\345\275\242\345\274\217\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\347\253\240\357\274\232\351\235\231\346\200\201\345\215\225\350\265\213\345\200\274\345\275\242\345\274\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
index f1c9222a..150ce2e8 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\347\253\240\357\274\232\351\235\231\346\200\201\345\215\225\350\265\213\345\200\274\345\275\242\345\274\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\344\272\224\345\215\201\347\253\240\357\274\232\351\235\231\346\200\201\345\215\225\350\265\213\345\200\274\345\275\242\345\274\217\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 控制流图:分支与汇合
 - 名字解析:每个名字指向一个定义
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - SSA 要求每个变量只被赋值一次

src/学习与进步/计算机科学极简入门指南/编译原理/第两百四十九章:数据流分析(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\346\225\260\346\215\256\346\265\201\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\346\225\260\346\215\256\346\265\201\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 6d0f77c5..46a7c476 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\346\225\260\346\215\256\346\265\201\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\346\225\260\346\215\256\346\265\201\345\210\206\346\236\220\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 集合与映射:分析中常用的工具
 - 图:在图上传播信息
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 数据流分析追踪某个信息在程序各点上的状态

src/学习与进步/计算机科学极简入门指南/编译原理/第两百四十二章:类型推断(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\347\261\273\345\236\213\346\216\250\346\226\255\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\347\261\273\345\236\213\346\216\250\346\226\255\357\274\210\350\277\233\351\230\266\357\274\211.md"
index e5c5ab98..874b6f94 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\347\261\273\345\236\213\346\216\250\346\226\255\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\274\226\350\257\221\345\216\237\347\220\206/\347\254\254\344\270\244\347\231\276\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\347\261\273\345\236\213\346\216\250\346\226\255\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 表达式的类型检查:沿语法树检查
 - 名字解析:确定名字指向的定义
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 类型推断让编译器从上下文推导出类型

src/学习与进步/计算机科学极简入门指南/计算机网络/第一百一十一章:无线网络(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\200\345\215\201\344\270\200\347\253\240\357\274\232\346\227\240\347\272\277\347\275\221\347\273\234\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\200\345\215\201\344\270\200\347\253\240\357\274\232\346\227\240\347\272\277\347\275\221\347\273\234\357\274\210\350\277\233\351\230\266\357\274\211.md"
index e6b229a7..a3599a78 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\200\345\215\201\344\270\200\347\253\240\357\274\232\346\227\240\347\272\277\347\275\221\347\273\234\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\200\345\215\201\344\270\200\347\253\240\357\274\232\346\227\240\347\272\277\347\275\221\347\273\234\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 共享信道与冲突:共享介质会带来冲突,需要接入规则
 - 以太网:规定了有线局域网的帧格式与接入方式
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 无线网络共享空气,接入点协调设备接入和发送机会

src/学习与进步/计算机科学极简入门指南/计算机网络/第一百三十七章:拥塞控制(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\346\213\245\345\241\236\346\216\247\345\210\266\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\346\213\245\345\241\236\346\216\247\345\210\266\357\274\210\350\277\233\351\230\266\357\274\211.md"
index aaf9c0b1..031fd87b 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\346\213\245\345\241\236\346\216\247\345\210\266\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\346\213\245\345\241\236\346\216\247\345\210\266\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 滑动窗口:窗口大小决定在途的数据量
 - 流量控制:接收方限制发送速率
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 拥塞控制让发送方自己试探网络的承载能力

src/学习与进步/计算机科学极简入门指南/计算机网络/第一百三十八章:连接关闭与 TIME_WAIT(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\350\277\236\346\216\245\345\205\263\351\227\255\344\270\216 TIME_WAIT\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\350\277\236\346\216\245\345\205\263\351\227\255\344\270\216 TIME_WAIT\357\274\210\350\277\233\351\230\266\357\274\211.md"
index ae7fd24d..54ccfb70 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\350\277\236\346\216\245\345\205\263\351\227\255\344\270\216 TIME_WAIT\357\274\210\350\277\233\351\230\266\357\274\211.md"	
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\350\277\236\346\216\245\345\205\263\351\227\255\344\270\216 TIME_WAIT\357\274\210\350\277\233\351\230\266\357\274\211.md"	
@@ -6,6 +6,8 @@
 - 序号与确认:双方各自维护收发进度
 - TCP 为什么需要连接:连接是双方的共同状态
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 关闭连接也要有约定步骤,不能单方面说停就停

src/学习与进步/计算机科学极简入门指南/计算机网络/第一百二十七章:自治系统与 BGP(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\262\273\347\263\273\347\273\237\344\270\216 BGP\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\262\273\347\263\273\347\273\237\344\270\216 BGP\357\274\210\350\277\233\351\230\266\357\274\211.md"
index f264ae04..eabd04af 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\262\273\347\263\273\347\273\237\344\270\216 BGP\357\274\210\350\277\233\351\230\266\357\274\211.md"	
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\262\273\347\263\273\347\273\237\344\270\216 BGP\357\274\210\350\277\233\351\230\266\357\274\211.md"	
@@ -6,6 +6,8 @@
 - 距离向量路由:与邻居交换距离向量
 - 路径选择问题:把网络抽象成带权图选路
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - 互联网由许多独立的“自治系统”组成

src/学习与进步/计算机科学极简入门指南/计算机网络/第一百二十三章:IPv6(进阶).md

+2 / -0 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232IPv6\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232IPv6\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 86616718..e5c06554 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232IPv6\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\254\254\344\270\200\347\231\276\344\272\214\345\215\201\344\270\211\347\253\240\357\274\232IPv6\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -6,6 +6,8 @@
 - 子网与 CIDR:用前缀长度表示地址范围
 - 路由表与最长前缀匹配:路由器按前缀转发
 
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
+
 ## TL;DR
 
 - IPv6 用 128 位地址,从根本上缓解地址枯竭