Crafting Interpreters:从零手写两个解释器

Robert Nystrom 的《Crafting Interpreters》项目,在 GitHub 上获得了 10,813 颗 Star:

正文顶部截图

README区域截图

这个仓库是《Crafting Interpreters》一书的配套项目,包含书籍的 Markdown 源码、两个完整的解释器实现,以及将两者编织成最终站点的构建系统。书中的教学语言名为 Lox,读者将分别用 Java 和 C 实现它。

仓库中的两个解释器各有侧重。jlox 是用 Java 编写的高层次解释器,采用树遍历的方式执行代码,结构清晰,适合理解语言设计的基本概念。clox 则是用 C 编写的字节码虚拟机,包含手写的词法分析器、编译器和垃圾回收器,性能更接近生产级实现。

构建系统由 make 和 Dart 脚本驱动。安装 Dart 后,运行 make get 即可下载依赖。执行 make 会同时生成书籍站点和编译两个解释器。编译完成后,可以直接在仓库根目录运行 ./clox./jlox。如果你只想构建书籍,运行 make book 即可。开发时可以用 make serve 启动本地服务器,修改文件后刷新浏览器就能看到更新。

书籍的 Markdown 文件存放在 book/ 目录,Java 和 C 实现分别位于 java/c/ 目录。源码中的特殊注释标记将代码片段与书籍文本关联,构建脚本 tool/bin/build.dart 负责将它们编织成最终的 HTML 页面。生成的 HTML 存放在 site/ 目录,这个目录的内容与线上站点保持一致。

测试套件存放在 test/ 目录,由 Dart 编写的测试运行器 tool/bin/test.dart 驱动。你可以运行 make test 一次性测试两个解释器的最终版本,也可以用 make test_cloxmake test_jlox 分别测试单个解释器。更细致的是,make test_cmake test_java 会测试每个章节结束时的中间版本,确保每章的代码都能正常工作。

仓库提供了一个巧妙的机制来查看每章结束时的代码状态。tool/bin/split_chapters.dart 脚本根据代码片段的注释标记,提取每章已出现的代码,在 gen/ 目录下生成对应章节的完整源码副本。这些副本去除了所有标记注释,阅读起来更加清爽。然后 make c_chapters 会为每个章节单独编译出可执行文件。

如果你自己实现了 Lox,测试运行器支持通过 --interpreter 参数指定外部解释器进行验证。你可以指定解释器的行为应该匹配 clox 还是 jlox,也可以指定只测试到某一章节为止。

仓库还维护了一个 Wiki 页面,收集读者用其他语言实现的 Lox 版本。这些移植版本覆盖了多种编程语言,对想对比不同实现方式的读者很有参考价值。作者欢迎读者提交 Issue 或 Pull Request 来反馈错误和改进建议,即使不配置完整的构建环境也可以直接提交。

整个项目的结构清晰:

  • asset/:Sass 和 jinja2 模板
  • book/:各章节的 Markdown 文本
  • c/:clox 的 C 源码
  • java/:jlox 的 Java 源码
  • site/:生成的静态站点
  • test/:Lox 测试用例
  • tool/:构建、测试等 Dart 脚本

对于想深入理解编译原理的开发者来说,这个项目提供了一条从理论到实践的完整路径。两个解释器的递进式设计让学习者能逐步建立对语言实现的认知,从简单的树遍历解释器过渡到字节码虚拟机。

者能逐步建立对语言实现的认知,从简单的树遍历解释器过渡到字节码虚拟机。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐