用于实现VM的教程/资源
我想要自我教育的目的,为dynamic语言实现一个简单的虚拟机,更喜欢用C.像Lua VM,Parrot或Python VM,但更简单。 除了查看现有虚拟机的代码和devise文档外,是否还有任何好的资源/教程来实现这个目标?
编辑:为什么近距离投票? 我不明白 – 这不是编程。 如果我的问题有特定的问题,请发表评论。
我假设你想要一个虚拟机而不是一个单纯的解释器。 我认为他们是连续统一体的两点。 一名口译员正在接近程序的原始表述。 一个虚拟机工作在更原始的(和独立的)指令上。 这意味着你需要一个编译阶段来将其转换为另一个。 我不知道你是否想先处理,或者如果你甚至有input语法。
对于dynamic语言,您希望某处存储数据(作为键/值对)以及一些操作它的操作。 VM维护商店。 运行的程序是一系列的指令(包括控制stream程)。 您需要定义一组说明。 我会build议一个简单的设置开始,如:
- 基本的算术运算,包括算术比较,访问商店
- 基本控制stream程
- 内置打印
您可能希望使用基于堆栈的计算方法进行算术运算,就像许多VM一样。 上面还没有太多的dynamic。 为了达到这个目的,我们需要两件事:在运行时计算variables名称的能力(这只是表示string操作),以及将代码作为数据处理。 这可能与允许函数引用一样简单。
对虚拟机的input最好是字节码。 如果你还没有编译器,可以从一个基本的汇编程序(可能是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.
处理计算的variables名称可能会非常棘手:指令需要指定计算名称所在的variables。这可以通过允许指令引用input中提供的string常量池来完成。
示例程序(汇编和字节码):
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 xk) 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.
当variables被其他variables命名时,你需要变体(以及间接的级别变得棘手)。 汇编程序查看像“ADD .x,.y,.x”这样的参数并生成正确的字节码,用于从string常量(而不是计算variables)中添加。
那么,这不是关于在C中实现一个虚拟机,而是因为这是我看到这个问题之前打开的最后一个选项卡,我觉得我需要指出一篇关于在JavaScript中使用JavaScript 实现QBASIC字节码编译器和虚拟机的文章 , <canvas>
标签显示。 它包含了所有源代码以获得足够的QBASIC来运行“半字节”游戏,并且是编译器和字节码解释器系列文章中的第一个。 这个描述了虚拟机,他也承诺今后的文章描述编译器。
顺便说一下,我没有投票结束你的问题,但你得到的近距离投票是去年一个关于如何学习实现虚拟机的问题的重复。 我认为这个问题(关于教程或者相对简单的)与那个应该保持开放的问题是不一样的,但是你可能想要提一个更多的build议。
另一个要看的是Lua语言的实现。 这是一个基于注册的虚拟机,在性能方面享有良好的声誉。 源代码在ANSI C89中,通常非常易读。
与大多数高性能脚本语言一样,最终用户将看到一种可读的高级dynamic语言(具有闭包,尾调用,不可变string,数字和散列表作为主要数据types,函数作为第一类值等function) 。 源文本被编译为虚拟机的字节码,由虚拟机执行,其大纲与埃德蒙的回答相似。
虚拟机本身的实现既便携又高效,已经付出了很多努力。 如果需要更高的性能,则32位x86存在一个从VM字节代码到本机指令的即时编译器 ,而在64位版本的beta版本中。
对于启动(即使不是C ,但C ++ ),你可以看看muParser 。
这是一个mathexpression式分析器,它使用一个简单的虚拟机来执行操作。 我想即使你需要时间来理解一切, 无论如何,这个代码比一个能够运行真正的完整程序的完整虚拟机更简单。 (顺便说一下,我正在C#中devise一个类似的库 – 这是它的早期阶段,但下一个版本将允许编译到.NET / VM IL 或者一个像muParser一样的新的简单的VM )。
另一个有趣的事情是NekoVM (它执行.n字节码文件)。 这是一个用C编写的开源项目,它的主要语言(.neko)被认为是由源代码编译器技术生成的。 在最后一个话题的精神,看同一个作者Haxe (开源也是)。
就像你我也一直在研究虚拟机和编译器,我可以推荐的一本好书是编译器devise:虚拟机 。 它通过为每个虚拟机提供指令集以及如何将更高级的语言编译到该虚拟机的教程来描述用于命令式,function性,逻辑和面向对象的语言的虚拟机。 我只为命令式语言实现了虚拟机,已经是一个非常有用的练习。
如果你刚刚开始,那么我可以推荐的另一个资源是PL101 。 它是JavaScript中的一组交互式教程,引导您完成各种语言的parsing器和解释器的实现过程。