第 9 章 · 07 代码生成 vs 解释执行


第 9 章 · 07 代码生成 vs 解释执行

本节摘要:拿到 AST 后,有两种实现策略:编译(把 AST 翻译成机器码,跑得快但平台相关)与解释(直接遍历 AST 执行,慢但跨平台)。还有折中:字节码 + 虚拟机(先编译成字节码,再由 VM 解释/ JIT)。本节讲清三种策略的取舍,让你为自己的语言选对实现路线。

内容来源:基于编程语言实现整理的导读。

学习目标

  1. 说清「编译成机器码」与「解释执行」两种策略。
  2. 解释各自的取舍:性能 vs 跨平台 vs 实现复杂度。
  3. 理解「字节码 + 虚拟机」折中方案(Java/Python 的选择)。
  4. 简述 JIT(即时编译)的概念。

一、学习价值:为你的语言选对实现

你造一门语言(第 9 章编译器线),拿到 AST 后,选哪种执行策略决定它的性格:

  • 追求极致性能(C/Go/Rust):编译成机器码。
  • 追求快速开发/跨平台(Python 早期/Ruby/Lua):解释执行。
  • 折中(Java/Python 当前/C#):字节码 + VM(可能配 JIT)。

理解这三者,你为自己设计的语言能做出合适选择,也理解为什么不同语言性能差异巨大。

二、认知拆解:三种策略

1. 编译成机器码(AOT,Ahead-Of-Time)

AST → 生成目标机器码(或汇编→汇编器→机器码)。生成的可执行文件直接跑在 CPU 上。

  • 优点:性能最好(无解释开销)。
  • 缺点:每平台一份(x86/ARM 各编译一次);实现复杂(要懂目标架构指令集、寄存器分配)。
  • 代表:C/C++/Go/Rust。

2. 解释执行(树遍历解释器)

AST → 直接遍历执行每个节点。if 节点 就判断条件、+节点 就把两子节点求值相加。

  • 优点:实现简单(不用懂机器码);跨平台(只要宿主语言跨)。
  • 缺点:慢(每次执行都遍历 AST,重复工作)。
  • 代表:Python 早期、Ruby、Lua 早期、本书建议你第一个语言用这策略。

3. 字节码 + 虚拟机(折中)

AST → 编译成「字节码」(一组紧凑的虚拟指令,如 LOAD/PUSH/ADD)→ 一个「虚拟机」程序解释执行字节码。

  • 优点:字节码比 AST 紧凑、遍历快(线性指令流),跨平台(字节码平台无关,VM 移植即可)。
  • 缺点:仍比机器码慢(VM 解释有开销)。
  • 代表:Java(JVM 字节码)、Python(.pyc 字节码)、Lua。

进阶:JIT(Just-In-Time 即时编译)

在运行时,把「热点」字节码动态编译成机器码执行。兼顾跨平台(分发字节码)与性能(热点跑机器码)。Java HotSpot、JavaScript V8、PyPy、C# CLR 都用 JIT。实现复杂,第一个语言不必做。

为你的语言选哪种

  • 第一个语言:树遍历解释器(最简单,「Crafting Interpreters」前半本教这个)。
  • 想追求性能:升级到字节码 VM(同书后半本)。
  • 进阶:JIT。

三、上手第一步

造第一个语言:实现树遍历解释器。eval(ast) 递归求值每个节点。变量存环境(作用域字典),控制流(if/while)直接对应遍历。参考「Crafting Interpreters」。

本节要点回顾

  1. 编译(AOT):AST→机器码,快但平台相关、实现复杂(C/Go)。
  2. 解释(树遍历):直接遍历 AST 执行,慢但简单跨平台(Python 早期)。
  3. 字节码+VM:AST→字节码→VM 解释,折中(Java/Python 当前)。
  4. JIT:运行时把热点字节码编译成机器码,兼顾跨平台与性能(V8/HotSpot),实现复杂。
  5. 第一个语言选树遍历解释器,参考「Crafting Interpreters」。

推荐上手顺序

  1. 实现树遍历解释器(eval AST)。
  2. 支持变量、if、while、函数。
  3. (进阶)设计字节码,写 VM 解释字节码。
  4. (高阶)实现简单 JIT。

下一节是全书收尾——经典学习路径与书目。

作者与出处
原作者:灏天文库
来源:codecrafters-io
许可证:CC0-1.0
整理人: 灏天文库整理
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习
发布者: 作者: 灏天文库 转发
评论区 (0)
U