我的第一个 LLVM 前端语言教程

要求:本教程假设您了解 C++,但无需任何编译器经验。

欢迎来到“我的第一个 LLVM 前端语言”教程。在这里,我们将逐步实现一个简单的语言,展示它可以多么有趣和简单。本教程将帮助您快速上手,并展示一个使用 LLVM 生成代码的具体示例。

本教程介绍了简单的“Kaleidoscope”语言,并通过几个章节逐步构建它,展示了它是如何随着时间推移而构建的。这使我们能够涵盖一系列语言设计和 LLVM 特定的概念,并在整个过程中展示和解释其代码,并减少了 upfront 细节的压倒性数量。我们强烈建议您使用此代码 - 制作副本并对其进行修改和实验。

警告:为了专注于教授编译器技术和 LLVM 本身,本教程不会展示软件工程原则中的最佳实践。例如,代码普遍使用全局变量,不使用访问者模式等…,而是保持简单并专注于手头的主题。

本教程被划分为涵盖各个主题的章节,允许您根据需要跳过章节。

  • 第 1 章:Kaleidoscope 语言和词法分析器 - 这展示了我们的目标以及我们想要构建的基本功能。词法分析器也是构建语言解析器的第一步,我们使用一个简单的 C++ 词法分析器,易于理解。

  • 第 2 章:实现解析器和 AST - 词法分析器就位后,我们可以讨论解析技术和基本的 AST 构造。本教程描述了递归下降解析和运算符优先级解析。

  • 第 3 章:生成 LLVM IR 代码 - AST 准备就绪后,我们将展示生成 LLVM IR 是多么容易,并展示一种将 LLVM 集成到您的项目中的简单方法。

  • 第 4 章:添加 JIT 和优化器支持 - LLVM 的一个优点是它支持 JIT 编译,因此我们将直接深入探讨并向您展示添加 JIT 支持只需 3 行代码。后面的章节将展示如何生成 .o 文件。

  • 第 5 章:扩展语言:控制流 - 基本语言运行起来后,我们将展示如何使用控制流操作('if' 语句和 'for' 循环)对其进行扩展。这使我们有机会讨论 SSA 构造和控制流。

  • 第 6 章:扩展语言:用户定义运算符 - 本章扩展了语言,允许用户定义任意一元和二元运算符 - 并可分配优先级!这使我们能够将“语言”的重要部分构建为库例程。

  • 第 7 章:扩展语言:可变变量 - 本章讨论了添加用户定义的局部变量以及赋值运算符。这展示了在 LLVM 中构造 SSA 形式是多么容易:LLVM要求您的前端构造 SSA 形式才能使用它!

  • 第 8 章:编译到目标文件 - 本章解释了如何获取 LLVM IR 并将其编译成目标文件,就像静态编译器一样。

  • 第 9 章:调试信息 - 真实的语言需要支持调试器,因此我们添加了调试信息,允许在 Kaleidoscope 函数中设置断点、打印出参数变量并调用函数!

  • 第 10 章:结论和其他细节 - 本章总结了本系列,讨论了扩展语言的方法,并包含指向有关“特殊主题”的信息指针,例如添加垃圾回收支持、异常、调试、支持“意大利面条堆栈”等。

在本教程结束时,我们将编写不到 1000 行(非注释、非空白)代码。通过这少量代码,我们将构建一个用于非平凡语言的不错的编译器,包括手写的词法分析器、解析器、AST 以及代码生成支持 - 静态和 JIT!这证明了 LLVM 的优势,并说明了为什么它如此受语言设计者和其他需要高性能代码生成的人员欢迎。