- 编程语言
- 解释器
- 编译器
- 语言运行时
- 教程
【免费下载链接】craftinginterpreters
Repository for the book "Crafting Interpreters"
本文是craftinginterpreters仓库(《Crafting Interpreters》一书的配套代码库)的完整技术指南,覆盖从环境准备、一键构建到按章节编译、测试套件运行与自定义 Lox 实现验证的完整工作流。读者读完将掌握:如何构建并运行两套解释器(Java 版 jlox 与 C 版 clox)、如何理解"Markdown 正文 + 源码片段织入"的站点生成机制、以及如何用仓库自带测试运行器(tool/bin/test.dart)验证任意 Lox 实现。
仓库定位:一本书、两套解释器、一套构建系统
本仓库是还在创作中的书籍《Crafting Interpreters》的配套仓库,集中存放三类核心资产:全书 Markdown 正文(book/)、两套解释器的完整实现,以及把二者"织入"成最终网站(site/)的构建系统。
两条技术主线贯穿全书:
- jlox:位于 java/com/craftinginterpreters/lox,用 Java 编写的树遍历解释器,从词法扫描、语法解析一路实现到类与继承,读者在书中前半部分(Part I–II)逐步搭建;
- clox:位于 c,用 C99 编写的单遍编译 + 字节码虚拟机,覆盖 chunk、扫描器、编译器、哈希表、闭包、垃圾回收、类与超类等完整实现,对应书中后半部分(Part III)。
仓库采用 POSIX 环境 + make 编排整个工作流,绝大多数构建与测试逻辑都由make驱动,而构建脚本、测试运行器等工具则统一用 Dart 编写(见 tool/bin)。
环境准备:Dart、make、C 编译器与 javac
README 明确的前提条件是:任何 POSIX 系统(作者开发环境为 macOS)均可工作;Windows 需要额外努力。安装好 Dart(并在 PATH 中)后,第一步是拉取工具依赖:
$ make get该命令等价于在 tool 目录下执行dart pub get(见 Makefile),用于下载构建脚本与测试脚本依赖的所有 Dart 包。另外,要编译两套解释器,还需要 PATH 中包含C 编译器(编译 clox)与javac(编译 jlox)。
从 tool/pubspec.yaml 可以确认工具包依赖的核心库——sass、shelf、glob、args、path 等——这些正是站点构建(Sass 编译)、开发服务器(HTTP 服务)与测试参数解析的基础。
一键构建:make 同时产出站点与两套解释器
环境就绪后,在仓库根目录运行:
$ make根据 Makefile 的默认目标default: book clox jlox,这一条命令会完成三件事:
- 生成整本书的网站(
book); - 编译 C 版解释器 clox(
clox); - 编译 Java 版解释器 jlox(
jlox)。
构建完成后,可以直接从仓库根目录运行任意一个解释器:
$ ./clox $ ./jlox值得注意的实现细节:jlox目标依赖generate_ast(Makefile)——先用com.craftinginterpreters.tool.GenerateAst生成 AST 节点源码,再编译java/com/craftinginterpreters/lox下的.java文件;而clox目标则通过 util/c.make 以-std=c99编译(并启用-Wall -Wextra -Werror),release 模式还追加-O3 -flto,编译产物会复制到仓库根目录的clox可执行文件(Makefile)。
站点生成机制:Markdown 与源码片段的"织入"
正文与代码如何合二为一
仓库的最终 HTML 站点(site/)已经直接提交在仓库中,但它不是手写的,而是由一套自写的静态站点生成器构建的。这套生成器起源于作者上一本书(《Game Programming Patterns》)的一个微型 Python 脚本,在本书中演化为一个 Dart 程序。构建输入分两部分:
- 正文:
book/目录下的章节 Markdown(如 book/chunks-of-bytecode.md); - 代码:从 java 与 c 两套实现中提取的源码片段。
二者的"粘合剂"是源代码里那些看似奇怪的注释标记。以 c/compiler.c 中的// [negative]、c/debug.c 中的// [debug]、java/com/craftinginterpreters/lox/Interpreter.java 中的// [void]为例,这些形如// [tag]的标记正是生成器判断"哪一段代码插入到书中的哪个位置"的依据。
生成入口与两种运行方式
执行生成的脚本是 tool/bin/build.dart,其main()依次调用_buildSass()(把 asset 下的 Sass 编译为site/*.css)与_buildPages()(逐页渲染 Markdown、织入代码片段、套用 asset/mustache 模板并写出 HTML)。可以直接运行:
$ make book这条命令会一次性批量生成整个站点。构建过程还会输出统计信息——每页的散文词数、织入的代码行数与总词数,供作者校对书稿长度使用(tool/bin/build.dart)。
增量开发模式:make serve
如果正在一章一章地推进书稿,推荐启动开发服务器:
$ make serve其背后是dart build.dart.snapshot --serve(Makefile)。build.dart检测到--serve参数后,会在localhost:8000启动一个 HTTP 服务器,根目录指向site/(tool/bin/build.dart)。关键特性是按需增量重建:每当浏览器请求一个.html页面,服务器会先检查该页的 Markdown、解释器源码、模板与资源文件是否有改动,只重新生成源文件发生过变化的页面;请求.css时同样只重编对应 Sass。因此可以保持服务常驻、本地编辑文件、刷新浏览器即可看到改动,而不必每次全量构建。
构建解释器:最终版与逐章版
最终版本
$ make clox $ make jlox分别产出书中对应部分结束时的最终版 clox 与 jlox。jlox 的最终版可通过java -cp build/java com.craftinginterpreters.lox.Lox运行,clox 则直接是build/clox可执行文件。
逐章版本:split_chapters 与 gen/ 目录
仓库还支持查看"每章结束时解释器长什么样"(作者用它确认书中途各章代码也能工作)。驱动脚本是 tool/bin/split_chapters.dart,它复用同一套代码注释标记,解析出"到某章结束为止已出现的代码片段",把源码按章节切分输出到gen/目录——每个章节一个子目录。切分后的源码还顺带剥离了那些干扰视线的标记注释,阅读更清爽。
然后可以分别编译每个章节的版本:
$ make c_chapters这会在build/目录下为每个章节生成可执行文件,命名形如chap14_chunks、chap15_virtual……直至chap30_optimization(完整清单见 Makefile)。同样:
$ make java_chapters会把 Java 代码编译成build/gen/下按章节组织的 class 文件(对应章节从chap04_scanning到chap13_inheritance,见 Makefile)。这一机制也意味着:你可以直接阅读gen/chapXX_*下的源码,观察某个特性(例如第 25 章的闭包、第 26 章的垃圾回收)加入前后解释器的完整形态。
测试:从 make 目标到期望注释协议
测试目标族
仓库内置一整套 Lox 测试套件,测试用例全部位于 test,按语言特性组织成子目录(如closure/、class/、inheritance/、method/、super/、limit/等)。运行测试的入口是 Dart 程序 tool/bin/test.dart,它会逐个运行测试文件、解析结果并与期望值比对。Makefile 提供了六个测试目标:
$ make test # 最终版 clox 与 jlox $ make test_clox # 仅最终版 clox $ make test_jlox # 仅最终版 jlox $ make test_c # clox 每个章节的版本 $ make test_java # jlox 每个章节的版本 $ make test_all # 以上全部测试文件如何表达"期望"
测试用例本身是带注释的 Lox 程序,注释承担了断言职责。从 tool/bin/test.dart 可以看到运行器解析的几种标记协议:
// expect: <输出>——期望程序打印到 stdout 的某行输出(多行依次匹配);// Error ...——期望出现的编译错误(对应退出码 65,即EX_DATAERR);// [line N] Error ...——带行号的编译错误,可通过[java ]/[c ]前缀限定仅在某套解释器上生效(因为两套解释器的 panic 恢复略有差异,级联错误可能不同);// expect runtime error: <消息>——期望运行时错误及其所在行(对应退出码 70,即EX_SOFTWARE),运行器还会校验堆栈追踪中的行号。
Suite(套件)决定期望边界
运行器通过"套件名"区分测试期望:行为与 jlox 一致就用jlox,与 clox 一致就用clox;如果你的实现只完成到书中某一章,也可以直接用该章作为套件名,例如chap10_functions。所有套件名定义在 tool/bin/test.dart,与 Makefile 的章节命名一一对应。各套件内部用skip映射排除"该阶段尚未实现特性"的测试(例如 jlox 没有硬编码上限,就跳过test/limit/下的用例;早期章节没有函数/类,就跳过对应测试目录),这正是"同一套测试文件可以验证不同完成度实现"的关键设计。
用测试套件验证你自己的 Lox 实现
仓库欢迎读者把测试套件与运行器用于自己的 Lox 实现。运行器支持--interpreter指定自定义解释器可执行文件,例如实现位于my_code/boblox:
$ dart tool/bin/test.dart clox --interpreter my_code/boblox如果你的解释器需要额外命令行参数,用--arguments传入,运行器会原样转发:
$ dart tool/bin/test.dart jlox --interpreter my_code/boblox --arguments --flag1 --flag2注意仍需先指定套件名(clox、jlox或某个章节名)来确定测试期望;若提供自定义参数但未指定解释器,运行器会直接报错(tool/bin/test.dart)。测试执行时,test.dart会跳过benchmark目录并识别// nontest标记的非测试文件(tool/bin/test.dart)。
仓库布局速查
README 的 Repository Layout 章节给出了顶层目录职责,结合源码可进一步细化:
| 目录 | 内容与说明 |
|---|---|
| asset | Sass 样式与 Jinja2 模板,站点生成的样式与页面骨架来源 |
| book | 每章正文的 Markdown 文本 |
| build | 构建中间产物(build/debug、build/release、class 文件、diff 等),不提交到 Git |
| c | clox 的 C 源码,另含 Xcode 工程 |
| gen | split_chapters.dart切分出的逐章 Java 源码目录(亦供GenerateAst.java输出),不提交 |
| java | jlox 的 Java 源码 |
| note | 研究笔记、TODO 与杂项 |
| note/answers | 书中各章挑战题的参考答案 |
| site | 最终生成的站点,内容与 craftinginterpreters.com 直接对应;除由生成器产出的 HTML/CSS 外,字体、图片与 JS 也一并提交 |
| test | Lox 实现的全套测试用例 |
| tool | 包含构建、测试等脚本的 Dart 包(入口在tool/bin/) |
此外,Makefile 还隐藏着一些不常见但实用的目标:make cpplox会把 clox 以-std=c++11编译成 C++ 版本(利用 GCC/Clang 对指定初始化器的扩展,见 util/c.make);make generate_ast单独运行 AST 生成器;make diffs生成相邻章节之间的代码 diff(如build/diffs/chap25_closures.diff),方便对比特性演进;make xml则输出用于导入 InDesign 的 XML。make clean可清空build/与gen/中间产物。
如何参与
仓库以公开接受反馈的方式协作:发现错误或有不清晰之处可在仓库提交 issue;愿意提交 pull request 的读者无需预先搭建完整构建系统——作者在合入时会自行重新生成 HTML。另一种参与方式是分享自己的 Lox 移植实现:README 将各语言的 Lox 移植称为"尤其有用"的贡献(毕竟并非所有读者都喜欢 Java 与 C),并邀请作者把移植添加到项目 wiki 的 Lox implementations 列表。
对想要深入验证或扩展仓库的读者,建议按如下路径实践:先make get拉取 Dart 依赖,再make完成全量构建,接着用make serve体验增量站点生成,最后用dart tool/bin/test.dart clox --interpreter 你的解释器把仓库测试套件变成你自己的回归测试。
- 编程语言
- 解释器
- 编译器
- 语言运行时
- 教程
【免费下载链接】craftinginterpreters
Repository for the book "Crafting Interpreters"
相关推荐
tchMaterial-parser|电子课本下载
tchMaterial parser|电子课本下载 周三晚上,张老师想把周五要用的三本教材提前存到平板里,但平台只提供电子课本在线预览,没有 PDF 保存入口。
编程语言解释器编译器语言运行时教程5分钟跑通 timm:PyTorch 预训练视觉模型安装实战
5分钟跑通 timm:PyTorch 预训练视觉模型安装实战 不想自己训练,只想给一张图片打上分类标签?最快的路是直接拿一个预训练视觉模型跑一次前向,几秒内拿到
编程语言解释器编译器语言运行时教程2025最新:从零构建解释器!Crafting Interpreters中的Lox语言核心设计与实现指南
2025最新:从零构建解释器!Crafting Interpreters中的Lox语言核心设计与实现指南 你还在为理解编程语言底层原理而苦恼?本文将带你深入解析
编程语言解释器编译器语言运行时教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考