鹦鹉虚拟机/Squaak教程/简介
第一集: 简介
第二集: 深入编译器内部
第三集: Squaak细节和第一步
第四集: PAST节点和更多语句
第五集: 变量声明和作用域
第六集: 作用域和子程序
第七集: 运算符和优先级
第八集: 哈希表和数组
第九集: 总结和结论
这是关于使用鹦鹉编译器工具构建编译器的教程系列的第一集。如果您对虚拟机感兴趣,您可能听说过鹦鹉虚拟机。鹦鹉是一个通用的虚拟机,专为动态语言而设计。这与 Java 虚拟机 (JVM) 和微软的公共语言运行时 (CLR) 相反,它们都是为运行静态语言而设计的。JVM 和微软(通过动态语言运行时 - DLR)都在添加对动态语言的支持,但他们的主要关注点仍然是静态语言。
虚拟机的主要目的是运行程序。这些程序通常是用某种高级语言 (HLL) 编写的。一些众所周知的动态语言(有时称为脚本语言)包括 Lua、Perl、PHP、Python、Ruby 和 Tcl。鹦鹉被设计为能够运行所有这些语言。鹦鹉托管的每种语言都需要一个编译器来解析语言的语法并生成鹦鹉指令。
如果您从未实现过编程语言(即使您可能实现过一种语言),您可能会认为编写编译器有点像黑魔法。我知道我以前就是这么想的。你知道吗?事实的确如此。编译器是复杂的程序,实现一种语言可能非常困难。
事实:1) 鹦鹉适合运行几乎所有已知的动态语言,但在此之前,必须编写编译器,2) 编写编译器相当困难。
这就是鹦鹉编译器工具包 (PCT) 的用武之地。为了使鹦鹉成为语言开发者的一个有趣目标,构建编译器的过程应该得到合适工具的支持。正如任何一项建筑工作,如果你拥有合适的工具,就会变得容易得多(你不会只用双手来建造一座房子,对吧?),对于构建编译器来说也是如此。PCT 的设计就是为了做到这一点:提供强大的工具,使为鹦鹉编写编译器变得轻而易举。
本教程将通过演示使用 PCT 以多么容易的方式为鹦鹉实现一种(简单)语言来介绍 PCT。该案例研究语言并不像现实世界中的语言那样复杂,但本教程旨在激发您的兴趣,并展示 PCT 的强大功能。本教程还将介绍一些您可以探索的练习,以便学习本教程中未涵盖的 PCT 的更多细节。
我们将要在鹦鹉上实现的案例研究语言名为 Squaak,它将是一个功能齐全的编译器,可以将程序从源代码编译成鹦鹉中间表示 (PIR)(或立即运行 PIR)。它也可以用作命令行解释器。Squaak 演示了一些常见的语言结构,但同时也缺少一些其他看似简单的功能。例如,我们的语言将没有 return、break 或 continue 语句(或您最喜欢的语法中的等效项)。
Squaak 将具有以下功能
- 全局变量和局部变量
- 基本类型:整数、浮点数和字符串
- 聚合类型:数组和哈希表
- 运算符:+、-、/、*、%、<、<=、>、>=、==、!=、..、and、or、not
- 子程序和参数
- 赋值和各种控制语句,如“if”和“while”
如您所见,缺少一些常见的(更高级的)功能。最值得注意的是
- 类和对象
- 异常控制语句,如 break 和 return
- 高级控制语句,如 switch
- 闭包(嵌套子程序和访问外部作用域中的局部变量)
我们将用来实现 Squaak 的鹦鹉编译器工具包括以下部分
- 鹦鹉语法引擎 (PGE)。PGE 是一个用于正则表达式的先进引擎。除了 Perl 5 中的正则表达式之外,它还可以用于定义语言语法,使用 Perl 6 语法。(查看参考资料了解规范。)
- 鹦鹉抽象语法树 (PAST)。PAST 节点是一组类,用于定义表示常见语言结构的通用抽象语法树节点。
- HLLCompiler 类。此类是所有基于 PCT 的编译器的编译器驱动程序。
- 几乎不是 Perl (6) (NQP)。NQP 是一种受 Perl 6 启发的轻量级语言,可以用来编写解析阶段必须执行的方法,就像您可以在 Yacc/Bison 输入文件中编写操作一样。
在本教程中,假设您已经成功编译了鹦鹉(也许还运行了测试套件)。如果您浏览鹦鹉源代码树中的 languages 目录,您会发现许多语言实现。其中大多数尚未完成;有些正在积极维护,而另一些则没有。如果您在阅读完本教程后想为这些语言中的任何一种做出贡献,您可以查看邮件列表或加入 IRC(有关详细信息,请参见参考资料部分)。
languages 子目录是放置我们语言实现的合适位置。鹦鹉带有一个特殊的 Perl5 脚本,用于生成语言实现所需的必要文件。在运行它之前,必须安装鹦鹉以进行开发。从鹦鹉的根目录开始,输入
$ make install-dev
为了生成一个包含我们语言文件的目录,输入(假设您在鹦鹉的根目录中)
$ perl tools/dev/mk_language_shell.pl Squaak
(注意:如果您在 Windows 上,则应使用反斜杠。) 这将在一个名为“squaak”的目录中生成文件,并将“Squaak”用作语言的名称。之后,转到此目录并输入
$ parrot setup.pir test
这将编译生成的文件并运行测试套件。如果您想了解更多关于生成哪些文件的信息,请查看本集末尾的参考资料。
请注意,我们没有编写一行代码,但是已经有了基本的架构来帮助我们开始。当然,生成的编译器甚至不像我们将要实现的语言,但现在没关系。稍后我们将调整语法以接受我们的语言。
现在,您可能想用这个编译器实际运行一个简单的脚本。启动您最喜欢的编辑器,并输入以下语句
say "Squaak!";
保存文件(例如保存为 test.sq),然后键入
$ parrot squaak.pbc test.sq
这将运行 Parrot,指定 squaak.pbc 为 Parrot 要运行的文件,该文件接受一个参数:文件 test.sq。如果一切顺利,您应该看到以下输出
$ parrot squaak.pbc test.sq Squaak!
除了运行脚本文件之外,您还可以以交互式解释器的形式运行 Squaak 编译器。在不指定脚本文件的情况下运行 Squaak 编译器,并输入与您在文件中编写的相同语句
$ parrot squaak.pbc say "Squaak!";
它将打印
Squaak!
本教程的第一部分主要是对即将发生的事情的概述。希望您现在已经对 Parrot 编译器工具是什么以及如何使用它们构建针对 Parrot 的编译器有了全局的了解。如果您想查看 PCT 的一些实际应用,请查看 Rakudo(Parrot 上的 Perl 6)或 Pynie(Parrot 上的 Python)。
接下来的部分将重点介绍我们语言的逐步实现,包括以下主题
- 基于 PCT 的编译器的结构
- 使用 PGE 规则定义语言语法
- 使用运算符优先级表实现运算符优先级
- 使用 NQP 编写嵌入式解析操作
- 实现语言库例程
在此期间,请自行尝试。欢迎您加入我们 IRC 频道(有关详细信息,请参阅参考部分)。感谢您对本教程的任何反馈。
练习在本文档的每一部分末尾提供。为了使本教程的长度在可接受的范围内,并非所有内容都能得到详细讨论。这些练习的答案或解决方案将在该部分发布后几天内发布。
- 问题 1 高级交互模式
启动您最喜欢的编辑器,查看文件 src/Squaak/Compiler.pm,该文件仍位于目录 squaak 中。此文件是用 Not Quite Perl(“NQP”)编写的,当您运行 parrot setup.pir test 时,它会被编译为 src/gen_compiler.pir。它包含编译器的设置。类 HLL::Compiler 定义了用于在编译器以交互模式运行时设置命令行横幅和提示的方法。例如,当您以交互模式运行 Python 时,您将看到
Python 2.6.5 (r265:79063, Apr 1 2010, 05:28:39) [GCC 4.4.3 20100316 (prerelease)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
或类似的东西(取决于您的 Python 安装和版本)。此文本称为命令行横幅。在交互模式下运行时,每一行将以
>>>
开头,这称为提示。对于 Squaak,我们希望在交互模式下运行时看到以下内容(当然,您可以根据自己的喜好更改它)
$ ../../parrot squaak.pbc Squaak for Parrot VM. >
在文件 Compiler.pm 中添加代码以实现此功能。
- 提示:请注意,NQP 中只有双引号字符串可以解释转义字符,如 '\n'。
- 答案
鉴于提供的提示,找到解决方案可能并不困难,该解决方案如下所示。此代码可以在文件 Compiler.pm 中找到。相关行以粗体显示。
INIT { Squaak::Compiler.language('Squaak'); Squaak::Compiler.parsegrammar(Squaak::Grammar); Squaak::Compiler.parseactions(Squaak::Actions); Squaak::Compiler.commandline_banner("Squaak for Parrot VM.\n"); Squaak::Compiler.commandline_prompt('> '); }
HLL::Compiler 类提供了更多您可以设置的选项,您应该探索所有选项。
- Parrot 邮件列表:[email protected]
- IRC:加入 irc.perl.org 上的 #parrot 频道
- PCT 入门:docs/pct/gettingstarted.pod
- Parrot 抽象语法树 (PAST):docs/pct/past_building_blocks.pod
- 使用 PCT 进行运算符优先级解析:docs/pct/pct_optable_guide.pod
- Perl 6/PGE 规则语法:Synopsis 5