- 自己动手构建编程语言:如何设计编译器、解释器和DSL
- (美)克林顿·L.杰弗瑞
- 2765字
- 2024-05-11 19:44:55
Preface前言
虽然高级语言的开发已经有60年之久,但编程仍然非常困难。随着硬件不断进步,软件规模不断增长,软件复杂性也越来越高,而编程语言的进步则要慢得多。为特定用途创建新的编程语言是解决这种软件危机的一剂良药。
本书主要研究如何构建一种新的编程语言。书中将介绍编程语言设计方面的主题,并重点介绍编程语言实现。本书的新颖之处在于将传统的编译器-编译器工具(Flex和BYACC)与两种更高级的实现语言融合。一种非常高级的语言(Unicon)可以像黄油一样穿透编译器的数据结构和算法,而另一种主流的现代语言(Java)则展示了如何在更典型的生产环境中实现相同的代码。
有一个问题直到我上完大学编译器课程都没有真正理解:编译器只是编程语言实现的一部分。更高级的语言,包括大多数较新的语言,都有一个运行时系统令其编译器相形见绌。为此,本书的后半部分花了大量篇幅介绍语言运行时系统的各个方面,从字节码解释器到垃圾收集。
本书读者对象
本书面向对发明编程语言或开发领域特定语言(Domain-Specific Languages, DSL)感兴趣的软件开发人员。学习编译器构建课程的计算机科学系学生也会发现这本书非常适合作为语言实现的实用指南,可以为理论教材提供有益补充。为了更好地学习本书知识,读者需要具有中等高级语言(如Java或C++)知识水平和使用经验。
本书主要内容
第1章讨论何时构建编程语言,以及何时设计函数库或类库。本书的读者大都想构建自己的编程语言,或者想设计一个库。
第2章介绍如何精确定义编程语言,这在试图构建编程语言之前了解是非常重要的。这包括语言的词法和语法特征以及语义的设计,好的语言设计通常尽可能多地使用熟悉语法。
第3章介绍词法分析,包括正则表达式表示法及UFlex和JFlex这两个工具。最后,我们将打开源代码文件,逐个字符地读取源代码,并将其内容作为标记(token)流报告。标记流由源文件中的单个单词、运算符和标点符号组成。
第4章介绍语法分析,包括上下文无关文法及iyacc和BYACC/J这两个工具。我们将学习如何对文法中阻挠解析的问题进行调试,并在出现语法错误时报告错误。
第5章介绍语法树。解析过程的主要副产品是构造表示源代码逻辑结构的树数据结构,树节点的构造发生在对每个文法规则执行的语义动作中。
第6章展示如何构造符号表,将符号插入其中,并使用符号表来识别两种语义错误:未声明的变量和非法重新声明的变量。为了理解可执行代码中的变量引用,必须跟踪每个变量的范围和生存期。这是通过辅助语法树的表数据结构实现的。
第7章对类型检查进行介绍,这是大多数编程语言所面临的主要任务。类型检查可以在编译时或运行时执行。本章将介绍对基本类型(也称为原子或标量类型)进行静态编译时类型检查的常见情况。
第8章介绍如何对Java Jzero子集中的方法调用的数组、参数和返回类型执行类型检查。当涉及多个或复合类型时,类型检查更困难。当必须检查具有多个参数类型的函数,或者必须检查数组、哈希表、类实例或其他复合类型时,就是这种情况。
第9章通过剖析由Jzero语言编写的示例,介绍如何生成中间代码。在生成要执行的代码之前,大多数编译器将语法树转换为与机器无关的中间代码指令列表。此时将处理控制流的关键方面,例如标签和goto指令的生成。
第10章介绍将语法分析的信息合并到IDE中,以便解决提供语法着色和有关语法错误的视觉反馈时所遇到的一些挑战。编程语言不仅需要编译器或解释器,还需要开发人员的工具生态系统。这个生态系统包括调试器、联机帮助或集成开发环境。本章是一个来自Unicon IDE的Unicon示例。
第11章介绍设计指令集和执行字节码的解释器。一种新的领域特定语言可能包括主流CPU不直接支持的高级域编程特性。为许多语言生成代码的最实用方法是为抽象机器生成字节码,其指令集直接支持域,然后通过解释该指令集来执行程序。
第12章继续介绍代码生成,从第9章中提取中间代码,并从中生成字节码。从中间代码到字节码的转换需要遍历一个巨大的链表,将每个中间代码指令转换为一个或多个字节码指令。通常,这是一个遍历链表的循环,每个中间代码指令都有不同的代码块。
第13章介绍如何为x64生成本机代码。一些编程语言需要本机代码来实现其性能要求。本机代码生成类似于字节码生成,但更复杂,涉及寄存器分配和内存寻址模式。
第14章介绍如何通过添加内置在语言中的运算符和函数来支持领域特定语言的高级特性。领域特定语言的高级特性通常最好由内置在语言中的运算符和函数来表示,而不是库函数。添加内置函数可能会简化编程语言,提高其性能,或者在语言语义中产生副作用,否则这些副作用是很难或不可能产生的。本章中的示例来自Unicon,因为它是比Java更高级的语言,并且在其内置函数中实现了更复杂的语义。
第15章介绍何时需要新的控制结构,并提供使用字符串扫描处理文本和渲染图形区域的控制结构示例。前几章中的通用代码涵盖了基本的条件和循环控制结构,但领域特定语言通常具有独特或自定义的语义,它们为此引入了新的控制结构。添加新的控制结构比添加新的函数或运算符要困难得多,但这使得领域特定语言值得开发,而不仅仅是编写类库。
第16章介绍两种方法,我们可以使用这些方法在编程语言中实现垃圾收集。内存管理是现代编程语言最重要的内容之一,所有很酷的编程语言都具有通过垃圾收集进行自动内存管理的特性。本章提供两种方法来在编程语言中实现垃圾收集,包括引用计数以及标记-清理垃圾收集。
第17章对书中介绍的主要内容进行回顾,并启发我们深思。本章主要介绍可以从这本书中学到的东西,并给出延伸阅读建议。
附录A介绍的Unicon编程语言知识是以帮助你理解书中使用的Unicon示例。大多数示例都同时给出了Unicon和Java版本,但Unicon版本通常更短,更容易阅读。
附录B提供部分章节知识要点。
如何充分利用这本书
为了学习、理解本书的内容,读者应该是Java或类似语言的中级或高级程序员,理解面向对象语言的C语言程序员也行。
本书中关于安装和使用这些工具的说明稍微有些分散,以减少大家学习起步阶段的工作量,这些工具的安装和使用说明在第3章和第5章介绍。如果你在技术上很有天赋,那么你可以在macOS上运行所有这些工具,但在本书的写作过程中我并没有使用或测试过。
下载示例代码文件
你可以从GitHub下载本书的示例代码文件,网址为https://github.com/Packt-Publishing/Build-Your-Own-Programming-Language。代码更新将在GitHub存储库中进行。
彩色图像下载
我们还提供了一个PDF文件,其中包含本书中使用的屏幕截图和彩色图表,你可以从https://static.packt-cdn.com/downloads/9781800204805_ColorImages.pdf下载。
排版约定
本书中使用了如下排版约定。
文本中的代码:表示文本中的代码文字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入和Twitter句柄。例如:“必须将相应的Java main()放在类中。”
代码块设置如下:
当我们希望提醒读者注意代码块的特定部分时,会将相关行或对象设置成粗体,例如:
命令行输入或输出都写成如下形式:
粗体:表示我们在屏幕上看到的新术语、重要单词或短语。例如,菜单或对话框中的单词以粗体显示。例如:“选择管理面板中的系统信息。”
提示或重要说明
提示或重要说明以文本框显示。