从零开始编程语言:完整实现指南

发布: (2026年1月4日 GMT+8 23:19)
9 min read
原文: Dev.to

Source: Dev.to

你是否曾想过 Python、JavaScript 或 Go 在底层是如何工作的?

我花了几个月时间研究和实现不同的语言设计,并将所有内容汇编成一本全面指南,带你从基础词法分析一直到 JIT 编译。

您将构建的内容

通过本指南,您将创建一个完整的编程语言实现,从一个简单的计算器开始,逐步添加:

  • 词法分析器 & 语法解析器 – 将源代码转换为抽象语法树(AST)
  • 解释器 – 直接执行 AST(最简方式)
  • 字节码虚拟机 – 基于栈的虚拟机,类似 Python 的 CPython
  • LLVM 集成 – 生成本机机器代码
  • 垃圾回收 – 自动内存管理策略

为什么本指南与众不同

大多数编译器教程只提供片段。本指南提供 完整、可运行的 Go 代码,您可以实际执行并进行修改。

实际性能数据

没有夸大其词。指南包含实际基准测试:

Tree‑Walking Interpreter:  10‑100× slower than native
Bytecode VM:               5‑50× slower than native
JIT Compiled:              1‑5× slower (can match native)
AOT Compiled:              Baseline (native speed)

实际案例 – 斐波那契(40)

  • C(gcc -O3): 0.5 s
  • Python(CPython): 45 s (≈90× slower)
  • Python(PyPy JIT): 2.5 s (≈5× slower)

渐进学习路径

指南按照逐步增加的复杂度结构化:

周次目标
第 1 周构建解释器 – 从树遍历解释器开始,这是最简单的执行模型。你将在周末结束时拥有一个可工作的语言。
第 2 周添加字节码虚拟机 – 编译为字节码并构建基于栈的虚拟机。了解 Python 和 Java 的内部工作原理。
第 3‑4 周本机代码生成 – 使用 LLVM 生成优化的机器码。学习 Rust 和 Swift 快速的原因。
更进一步即时编译 (JIT) – 研究 V8 和 HotSpot 如何通过运行时优化实现接近本机的性能。

完整可运行示例

指南包括完整的计算器语言实现,包含:

  • 词法分析器(标记化)
  • 递归下降解析器
  • 抽象语法树(AST)生成
  • 树遍历解释器
source := `
x = 10
y = 20
z = x + y * 2
`

lexer := NewLexer(source)
parser := NewParser(lexer)
ast := parser.Parse()

interpreter := NewInterpreter()
interpreter.Eval(ast)

fmt.Printf("z = %d\n", interpreter.vars["z"]) // z = 50

这不是伪代码——它是可以直接运行的 Go 代码,你可以在此基础上进行构建。

覆盖内容

编译流水线

  • Lexical Analysis – 将源代码拆分为标记
  • Syntax Analysis – 构建抽象语法树
  • Semantic Analysis – 类型检查和符号解析
  • Code Generation – 字节码、LLVM IR 或直接解释

执行模型深度解析

  • Interpreters

    • 直接执行 AST
    • 实现最简单
    • 适用于脚本语言和配置语言
  • Virtual Machines

    • 基于栈 vs 基于寄存器的架构
    • 字节码设计与指令集
    • 函数调用与栈帧
    • 控制流实现
  • LLVM Integration

    • 生成 LLVM IR
    • 类型系统映射
    • 优化 passes
    • 跨平台本地代码生成
  • JIT Compilation (Advanced)

    • Profiling 与热点路径检测
    • 运行时代码生成
    • 反优化(De‑optimization)策略
    • 类型专化

垃圾回收

深入自动内存管理:

  • Reference Counting – 立即回收,无法处理循环
  • Mark‑and‑Sweep – 能处理循环,存在 stop‑the‑world 暂停
  • Copying / Generational – 性能最佳,复杂度最高

每种方法都提供可运行实现和权衡分析。

实际案例洞察

本指南不仅讲理论,还解释实际决策:

  • 为什么 Python 使用字节码而不是直接解释?
  • JavaScript 如何实现接近原生的性能?
  • Go 的编译速度为何如此之快?
  • Rust 的借用检查器是如何实现的?

权衡一目了然

AspectInterpreterBytecode VMJIT CompilerAOT with LLVM
Development Complexity周末项目1‑2 周数月2‑4 周
Execution Speed比原生慢 10‑100 倍比原生慢 5‑50 倍比原生慢 1‑5 倍(可匹配原生)原生速度
Startup Time即时非常快较慢(需要热身)即时(预编译)

关键要点

完整实现

每个主要组件都包含完整、可工作的代码:

  • 带有位置跟踪和错误处理的词法分析器
  • 带有运算符优先级的递归下降解析器
  • 完整指令集的基于栈的虚拟机
  • 带有控制流的 LLVM IR 生成

不含空洞

本指南解决了难点:

  • 为 JIT 编译创建可执行内存
  • 平台特定的调用约定
  • 为什么引用计数无法处理循环引用
  • 管理指令指针和调用栈

实用示例

学习实现:

  • 变量和赋值
  • 具有正确优先级的算术表达式
  • 字节码中的控制流(if / while
  • 带有正确栈帧的函数调用
  • 类型检查和语义分析

谁适合阅读

如果你符合以下情况,请阅读本篇:

  • 想了解编程语言的工作原理
  • 正在构建 DSL 或配置语言
  • 对编译器设计感兴趣,但被《龙书》吓倒
  • 想为语言项目(Rust、Go、Python)做贡献
  • 需要为你的应用实现脚本系统

前置条件

  • 熟悉 Go(或能够阅读并改写代码)
  • 基本了解数据结构(树、栈)
  • 对底层实现原理充满好奇

需要计算机科学学位

假设没有任何编译器知识。

学习路径推荐

  1. 从完整的计算器示例开始 – 立即让它工作。
  2. 添加控制流 – 使用字节码示例实现 if 语句和循环。
  3. 添加函数 – 使用提供的 call‑frame 实现。
  4. 探索 LLVM – 当你准备好提升性能时,生成本机代码。
  5. 学习 GC – 了解自动内存管理。

每一步都建立在前一步之上,你将在每个阶段拥有一个可工作的语言。

您将获得的收益

  • 深入了解解释器、编译器和虚拟机的工作原理。
  • 实践经验从零构建复杂系统。
  • 对语言设计权衡的认识
  • 为参与真实语言项目奠定基础
  • 自信构建领域特定语言。

包含的资源

  • “Crafting Interpreters” 作者 Bob Nystrom
  • LLVM 教程和文档
  • 真实世界的语言实现供学习
  • 性能基准测试技术

入门

完整的指南以及所有代码示例均可在 GitHub 上获取:

github.com/codetesla51/how-to-build-a-programming-language

克隆仓库,运行示例,今天就开始构建自己的语言吧。

欢迎反馈

这是一份持续更新的指南。如果你发现问题、有什么疑问,或想贡献改进,请在 GitHub 上打开 issue 或提交 PR。

构建一门编程语言是计算机科学中最有成就感的项目之一。它能够揭开整个软件栈的神秘面纱,并为你提供理解任何代码库的超能力。

  • 从小做起。先实现一个计算器。
  • 逐步添加功能。
  • 打破它们,然后修复。

这就是学习的方式。

祝语言构建愉快!

Back to Blog

相关文章

阅读更多 »

函数

!Lahari Tennetihttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%...

递归的迭代

将简化 HTML 转换为 Markdown 并使用语法树 在我的一个副项目或“宠物”项目中,我编写了一个小型 parser,用于简化 HTML,p...

Go.sum 不是锁文件

文章 URL: https://words.filippo.io/gosum/ 评论 URL: https://news.ycombinator.com/item?id=46537095 得分: 17 评论: 4