我希望自我教育的目的是为动态语言实现一个简单的虚拟机,更喜欢C语言.比如Lua VM,Parrot或Python VM,但更简单.除了查看现有虚拟机的代码和设计文档之外,是否有任何有关实现此目标的良好资源/教程?
编辑:为什么关闭投票?我不明白 - 这不是编程.如果我的问题有特定问题,请评论.
我假设你想要一个虚拟机而不仅仅是一个解释器.我认为它们是连续统一体的两点.翻译工作在接近程序原始表示的某些东西上.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"之类的参数,并生成正确的字节码,用于从字符串常量(而不是计算变量)中添加.
好吧,这不是关于在C中实现VM,但是因为它是我在看到这个问题之前打开的最后一个标签,我觉得我需要指出一篇关于在JavaScript中使用标签实现QBASIC字节码编译器和虚拟机的文章用于显示.它包含了所有源代码,可以运行"半字节"游戏来实现足够的QBASIC,并且是关于编译器和字节码解释器的系列文章中的第一篇; 这篇文章描述了VM,他也很有希望在未来的文章中描述编译器.
顺便说一下,我没有投票来关闭你的问题,但你得到的结果是与去年关于如何学习实现虚拟机的问题的重复.我认为这个问题(关于一个教程或一些相对简单的东西)与它应该保持开放的那个问题是完全不同的,但你可能想要参考那个问题以获得更多建议.