用于实现VM的教程/资源

时间:2010-01-09 18:30:53

标签: c vm-implementation

我希望自我教育的目的是为动态语言实现一个简单的虚拟机,更喜欢C语言。比如Lua VM,Parrot或Python VM,但更简单。除了查看现有虚拟机的代码和设计文档外,是否有任何有关实现此目标的良好资源/教程?

编辑:为什么要近距离投票?我不明白 - 这不是编程。如果我的问题有特定问题,请发表评论。

6 个答案:

答案 0 :(得分:30)

我假设你想要一个虚拟机而不仅仅是一个解释器。我认为它们是连续统一体的两点。翻译工作在接近程序原始表示的某些东西上。 VM可以处理更原始(和自包含)的指令。这意味着您需要一个编译阶段将一个转换为另一个。我不知道你是否想要先解决这个问题,或者你是否考虑过输入语法。

对于动态语言,您需要存储数据的某个位置(作为键/值对)以及对其执行操作的某些操作。 VM维护商店。在其上运行的程序是一系列指令(包括控制流程)。您需要定义一组指令。我建议一个简单的开头,比如:

  • 基本算术运算,包括算术比较,访问商店
  • 基本控制流程
  • 内置打印

您可能希望使用基于堆栈的计算方法来算术,就像许多虚拟机一样。上面还没有太多动态。为了实现这一目标,我们需要两件事:在运行时计算变量名称的能力(这只是表示字符串操作),以及代码作为数据的一些处理。这可能就像允许函数引用一样简单。

VM的输入理想情况下是字节码。如果你还没有编译器,那么可以从基本汇编程序(可能是VM的一部分)生成。

VM本身由循环组成:

1. Look at the bytecode instruction pointed to by the instruction pointer.
2. Execute the instruction:
   * If it's an arithmetic instruction, update the store accordingly.
   * If it's control flow, perform the test (if there is one) and set the instruction pointer.
   * If it's print, print a value from the store.
3. Advance the instruction pointer to the next instruction.
4. Repeat from 1.

处理计算变量名称可能很棘手:指令需要指定计算名称所在的变量。这可以通过允许指令引用输入中提供的字符串常量池来完成。

示例程序(在汇编和字节码中):

offset  bytecode (hex)   source
 0      01 05 0E         //      LOAD 5, .x
 3      01 03 10         // .l1: LOAD 3, .y
 6      02 0E 10 0E      //      ADD .x, .y, .x
10      03 0E            //      PRINT .x
12      04 03            //      GOTO .l1
14      78 00            //      .x: "x"
16      79 00            //      .y: "y"

隐含的指令代码是:

"LOAD x, k" (01 x k) Load single byte x as an integer into variable named by string constant at offset k.
"ADD k1, k2, k3" (02 v1 v2 v3) Add two variables named by string constants k1 and k2 and put the sum in variable named by string constant k3.
"PRINT k" (03 k) Print variable named by string constant k.
"GOTO a" (04 a) Go to offset given by byte a.

当变量由其他变量等命名时,您需要变量(并且间接的级别变得棘手)。汇编程序查看“ADD .x,.y,.x”之类的参数,并生成正确的字节码,以便从字符串常量(而不是计算变量)中添加。

答案 1 :(得分:9)

嗯,这不是关于在C中实现VM,但是因为它是我在看到这个问题之前打开的最后一个选项卡,我觉得我需要使用{{1}在JavaScript中指出article about implementing a QBASIC bytecode compiler and virtual machine用于显示的标签。它包含了所有源代码,可以运行“半字节”游戏来实现足够的QBASIC,并且是关于编译器和字节码解释器的系列文章中的第一篇;这篇文章描述了VM,他也很有希望在未来的文章中描述编译器。

顺便说一下,我没有投票来关闭你的问题,但你得到的结果是关于如何学习实现虚拟机的question from last year的重复。我认为这个问题(关于一个教程或一些相对简单的东西)与它应该保持开放的那个问题是完全不同的,但你可能想要参考那个问题以获得更多的建议。

答案 2 :(得分:4)

要查看的另一个资源是Lua language的实施。它是一个基于寄存器的VM,具有良好的性能声誉。 source code在ANSI C89中,通常非常易读。

与大多数高性能脚本语言一样,最终用户看到一种可读的高级动态语言(具有闭包,尾调用,不可变字符串,数字和散列表等功能作为主要数据类型,作为一等值,和更多)。源文本被编译为VM的字节码,供VM实现执行,其概要几乎与Edmund's answer描述的一样。

为保持VM本身的实现既便携又高效,已经付出了很多努力。如果需要更高的性能,则从32位x86存在从VM字节代码到本机指令的just in time compiler,并且处于64位的beta版本中。

答案 3 :(得分:2)

要开始(即使不是 C ,但 C ++ ),您可以查看muParser

这是一个使用简单虚拟机来执行操作的数学表达式解析器。我想即使你需要时间来理解一切;无论如何,这个代码比能够运行真正的完整程序的完整VM更简单。 (顺便说一句,我在C#中设计了一个similar lib - 它是早期阶段,但是下一个版本将允许编译到.NET / VM IL 或者像muParser这样的新简单虚拟机 )。

另一个有趣的事情是NekoVM(它执行.n字节码文件)。它是一个开源项目written in C,它的主要语言(.neko)被认为是由source-to-source compiler技术生成的。本着上一主题的精神,请参阅同一作者的Haxe(也是开源)。

答案 4 :(得分:1)

和我一样,我也一直在研究虚拟机和编译器,我推荐的一本好书是Compiler Design: Virtual Machines。它通过为每个VM提供指令集以及如何将更高级语言编译到该VM的教程来描述命令式,功能性,逻辑和面向对象语言的虚拟机。我只针对命令式语言实现了VM,并且它已经是一个非常有用的练习。

如果您刚刚开始,那么我建议的其他资源是PL101。它是JavaScript中的一组交互式课程,可指导您完成为各种语言实现解析器和解释器的过程。

答案 5 :(得分:-1)

我参加聚会很晚,但我还是建议您掌握Game Scripting Mastering,它可以帮助您从零开始编写有效的脚本语言及其VM。而且前提条件很少。