c-实施VM的教程/资源

我想自我教育的目的是为动态语言实现一个简单的虚拟机,更喜欢用C语言。类似Lua VM,Parrot或Python VM的东西,但是更简单。 除了查看现有VM的代码和设计文档以外,是否有任何良好的资源/教程来实现这一目标?

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

zaharpopov asked 2020-08-11T11:47:05Z
6个解决方案
30 votes

我假设您想要的是虚拟机,而不是单纯的解释器。 我认为这是一个连续的两点。 解释器在接近程序原始表示的地方工作。 VM处理更原始的(且自包含的)指令。 这意味着您需要一个编译阶段才能将一个转换为另一个。 我不知道您是否要先进行此操作,或者您是否还打算输入语法。

对于动态语言,您需要一个存储数据(作为键/值对)的地方以及一些对其执行操作的操作。 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”之类的参数,并生成正确的字节码以从字符串常量(而非计算变量)中添加。

Edmund answered 2020-08-11T11:48:02Z
9 votes

嗯,这不是用C语言实现VM,而是因为这是我看到这个问题之前打开的最后一个标签,所以我觉得我需要指出一篇有关使用<canvas>在JavaScript中实现QBASIC字节码编译器和虚拟机的文章。 显示标签。 它包括获得足够的QBASIC实现以运行“半字节”游戏的所有源代码,并且是有关编译器和字节码解释器的系列文章中的第一篇。 这篇文章描述了VM,他也很有希望在以后的文章中描述编译器。

顺便说一句,我没有投票赞成关闭您的问题,但是您获得的接近投票是去年关于如何学习实现虚拟机的一个问题的重复。 我认为这个问题(关于一个教程或相对简单的问题)与那个问题足够不同,应该保持开放状态,但是您可能想参考那个问题以获得更多建议。

Brian Campbell answered 2020-08-11T11:48:29Z
4 votes

另一个需要研究的资源是Lua语言的实现。 它是基于寄存器的VM,在性能方面享有很高的声誉。 源代码在ANSI C89中,并且通常可读性强。

与大多数高性能脚本语言一样,最终用户会看到一种可读的高级动态语言(具有闭包,尾调用,不可变字符串,数字和哈希表等功能作为主要数据类型,并具有一流的值等功能) 。 源文本被编译为VM的字节码,以供VM实现执行,其轮廓大致与Edmund的答案所描述的相同。

为了使VM本身的实现既可移植又高效,已经付出了很多努力。 如果需要更高的性能,则存在针对32位x86的从VM字节代码到本机指令的即时编译器,并且针对64位处于beta版本。

RBerteig answered 2020-08-11T11:48:59Z
2 votes

对于启动(即使不是C,而是C ++),您可以看一下muParser。

这是一个数学表达式解析器,它使用一个简单的虚拟机来执行操作。 我认为即使您也需要时间来了解所有内容; 无论如何,此代码比能够运行真正完整程序的完整VM更简单。 (顺便说一句,我正在C#中设计一个类似的库-这是它的早期阶段,但是下一版本将允许编译成.NET / VM IL或也许是新的简单VM,如muParser)。

另一个有趣的事情是NekoVM(它执行.n个字节码文件)。 这是一个用C编写的开源项目,其主要语言(.neko)被认为是由源到源编译器技术生成的。 本着最后一个主题的精神,请参见同一作者的Haxe(也是开放源代码)。

gsscoder answered 2020-08-11T11:49:29Z
1 votes

像您一样,我也一直在研究虚拟机和编译器,我可以推荐的一本好书是《编译器设计:虚拟机》。 通过为每个VM提供指令集以及有关如何为该VM编译高级语言的教程,它描述了用于命令式,功能性,逻辑和面向对象语言的虚拟机。 我只为命令性语言实现了VM,这已经是非常有用的练习。

如果您只是入门,那么我可以推荐的另一个资源是PL101。 它是JavaScript中的一组交互式课程,可指导您完成为各种语言实现解析器和解释器的过程。

davidk01 answered 2020-08-11T11:49:55Z
-1 votes

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

Nicholas Humphrey answered 2020-08-11T11:50:15Z
translate from https://stackoverflow.com:/questions/2034422/tutorial-resource-for-implementing-vm