SICI · 天机门 · 第十八章

编译原理:从高级语言到机器码 · 元婴二层

你以为编译器是翻译器。翻译器至少忠实于原文。可这六层翻译,没有一层是忠实的——每一层都在丢,只是你不知道丢了什么。

语义之渊低语:「你的意图过了这六层,还剩几分?赌一局。」
序章

意图之渊

六层翻译,哪层无损?编译器不过是翻译?

编译殿的门楣上刻着六个字:"意不可直达。"你怀里揣着一张源意符——上面写着一段你亲手写的代码,是你的"意图"。殿中央悬着一台巨大的黑色法器,形如漏斗,六层。

编译之炉,源代码到机器码
诺依曼老祖 诺依曼老祖

「这叫编译器。你的意图在顶,机器在底。中间隔着六层翻译。」

语义之渊 语义之渊

「赌一局。你的意图过了这六层,还剩几分?我赌——剩不了多少。」

翻译无损预测挑战器

反直觉下注(六选一)→ 每层真容浮现 → 信息丢失清单全景拼合

语义之渊逼你下注:六层翻译,哪层不会丢失信息?
第一幕 · 自信→动摇

词法阁 · 断词之刃

字符流→Token流,注释/空白丢失,最大munch规则

石径尽头是一面刻满字符的石壁,字符流如瀑布般向下淌。诺依曼老祖递给你一柄断词刃。

诺依曼老祖 诺依曼老祖

「把这串字符切成 Token。规则你自己定。」

语义之渊 语义之渊

「按空格切嘛。名字里都有'空格'了,它不会骗你的。」

断词刃 · Token切分实验台

预测三选一 → 手动切词(a+++b)→ 信息丢失清单

字符流 int x=a+++b; 怎么切?
第一幕 · 技术发现

文法阁 · 正则之限

正则表达式→NFA→DFA·子集构造·Lex/Flex·嵌套之墙

石壁后是一座陈列阁,阁中悬浮着无数发光的符文模式——正则表达式。诺依曼老祖递给你一面透镜。

诺依曼老祖 诺依曼老祖

「你想让断词刃自动切词?先给它一套规则。正则表达式就是规则的语言。但——每种语言都有它说不出的东西。」

语义之渊 语义之渊

「正则万能嘛。写个模式匹配一切——你信吗?我赌你信。」

正则炼机 · NFA→DFA 子集构造 + 嵌套之墙

输入正则→炼NFA→子集构造转DFA→Lex生成→嵌套括号挑战

第一幕 · 崩塌

语法殿 · 树之歧途

CFG→语法树,dangling-else双树歧义,左递归消除

语法殿中央是一棵悬浮的光树——语法分析树,节点是 Token,枝干是产生式规则。诺依曼老祖递给你一卷文法。

诺依曼老祖 诺依曼老祖

「把 Token 流种进去,让它长成树。规则在这里——上下文无关文法。」

语义之渊 语义之渊

「树长出来就唯一了?你确定?」

语法树构建 · dangling-else 双树对比

表达式树生长 → 左递归消除 → dangling-else 双树歧义崩塌

文法:E → E + T | T | T → T * F | F | F → ( E ) | id
第二幕 · 工具构建

分析器工坊 · 上下之争

LL(1) 自顶向下·LR(0)/SLR(1)/LALR(1) 自底向上·Yacc/Bison

工坊里有两台法器:左台刻"自顶向下",右台刻"自底向上"。诺依曼老祖站在两台之间。

诺依曼老祖 诺依曼老祖

「树歧义是因为文法有二义性。换一种分析方法——让它从根往下长(LL),或者从叶往上拼(LR)。但每种方法都有它嚼不动的文法。」

语义之渊 语义之渊

「LL(1) 和 LR 都试一遍,总有一个能通吃?你赌哪个?我赌——都没有万能的。」

分析器工坊 · LL(1) vs LR + Yacc/Bison

LL(1) 预测分析表 → LR(0) 自动机 → SLR(1)/LALR(1) 冲突消解 → Yacc 生成

左台 · LL(1) 自顶向下

文法:E → T E' | E' → + T E' | ε | T → F T' | T' → * F T' | ε | F → ( E ) | id

右台 · LR(0) 自底向上

文法:E → E + T | T | T → T * F | F | F → ( E ) | id
第二幕 · 误杀

语义渊 · 类型之审

类型检查/隐式转换/作用域遮蔽/符号表

语义殿里悬着一架天平——类型天平。殿壁上挂着一面巨大的符号表,密密麻麻记着每个名字的类型与作用域。

诺依曼老祖 诺依曼老祖

「语法树只管结构对不对。'int 加 float 等于什么'——这归语义管。」

语义之渊 语义之渊

「类型检查抓错,天经地义——它怎么会改你的程序?」

类型天平 · 符号表作用域

类型检查(int+float隐式转换)→ 作用域遮蔽查询 → 属性文法标注

把表达式拖入类型天平
第二幕 · 折中

中码塔 · 三地址之桥

语法树→三地址码,控制流展平,SSA与phi函数

中间码殿里有一座桥——桥这头是语法树,桥那头是机器码。诺依曼老祖指着桥面。

诺依曼老祖 诺依曼老祖

「树太高级,机器太低级。中间需要一座桥——中间代码。但过桥要交费——你的 if-else、for 循环,全要被展平成跳转和赋值。」

三地址码生成 · SSA变换

语法树逐节点翻译为三地址码 → SSA变量版本化 → phi函数插入 → CFG构建

if (a > b) x = a; else x = b;
第二幕 · 诱饵

优化坊 · 常量之蚀

常量折叠/死代码消除/循环优化——看似无害的提速

优化殿中央是一台巨大的熔炉——优化器。炉壁上刻着"更快、更小、更好"。语义之渊盘在熔炉上,声音甜得发腻。

语义之渊 语义之渊

「优化只提速不改义,这不是明摆着吗?把代码丢进去。」

诺依曼老祖 诺依曼老祖

「先丢几段看起来无害的试试。别急。」

优化熔炉 · 常量折叠与死代码消除

投入代码片段 → 优化前后对比 → 看似无害的提速

第二幕 · 全景

编译流水线动画器

六阶段完整编译流程可视化 · 词法→语法→语义→中间代码→优化→代码生成

殿中央的六层漏斗重新亮起,这一次你看得更清楚了——每一层都是一个独立的变换阶段。

诺依曼老祖 诺依曼老祖

「你走过的每一层,拼起来就是完整的编译流水线。看一遍——源代码怎么一步步变成机器码。」

编译流水线动画器

逐阶段点击 → 每阶段输入/输出/变换展示 → 完整流水线串联

第二幕 · 第二崩塌

优化三旋钮实验台 · 意图之蚀

优化级别/浮点重排/UB利用——优化改写可观察行为

优化殿的熔炉火力全开。三只旋钮浮在炉口:优化级别、浮点重排、UB利用。诺依曼老祖退后一步,看着你。

语义之渊 语义之渊

「旋钮都给你了。-O3、-ffast-math,拉满它。更快就是更好,不是吗?」

优化三旋钮 · 可观察行为差异检测器

三旋钮(优化级别/浮点重排/UB利用)→ 优化熔炉前后对比 → 浮点重排崩塌

优化级别
浮点重排
UB利用
第三幕 · 全链

链接殿 · 落地为器

目标代码生成/链接器/加载器/运行时环境

代码生成殿是一条长廊,尽头是一台正在运转的机器——真正的 CPU。诺依曼老祖指着长廊上的三道门。

诺依曼老祖 诺依曼老祖

「优化过的中间码还不能跑。它要经过三道门:生成、链接、运行。走一遍。」

代码生成 · 链接 · 运行时

寄存器分配(图着色)→ 链接器符号解析 → 栈帧/堆/GC运行时

第三幕 · 最高潮

Boss 战 · 语义之渊

三问对决 · 排除法收网 · 变换链顿悟

长廊灯火齐灭。灰雾从四面八方压过来,凝成一张巨大的、没有五官的脸——由无数行断裂的代码构成。

语义之渊 语义之渊

「我是语义之渊。我不住在你的语法错误里——那些你编译时就抓到了。我住在你'以为翻译无损'的地方。三问。答错一题,渊就深一分。」

渊账累计 0 笔 · 三问全对后清零

第三幕 · 收束

尾声 · 编译之桥

元婴二层·语言通译·圆满——下一章:织脉之门

渊散尽时编译殿灯火重明,你手里的源意符微微发光——不是它变回了原样,是它带着所有变换的痕迹,成了另一种完整。上面的蚀痕还在,像一枚枚没说出口的印章。

诺依曼老祖 诺依曼老祖

「你通译了。不是因为你答对了三问——答对的会忘。是因为你走过的每一层翻译,都刻在你手上了。但——你的程序编译完了,可它要在两台机器之间传输。那条路,叫计算机网络。」

知识图谱点亮 · 编译之悟

点亮全章8块碎片 → 变换链剪影定格 → 境界突破