1
2
建议制作基于堆栈的VM,因为它们很容易制作。 另一种常见的VM类型是基于寄存器的,其中值存储在寄存器中而不是堆栈中。 口译员和虚拟机还有许多其他变体。您可以有一个生成解析树的编译器和一个解释这些树的解释器(但如果它是使用递归函数实现的,那么可以说它仍然是一个基于堆栈的VM)。 使编译器生成另一种语言的代码而不是生成某种类型的机器代码(用于VM或真实机器)也并不罕见。C语言是这些类型编译器的通用目标语言,因为C语言及其编译器无处不在。但是,你不再有VM或解释器,你只有一个编译器/翻译器。 |
2
1
你的建议有点可能。C实际上不允许您操作堆栈,并且当您调用函数时,它不知道它周围的本地变量,因此您需要在堆上分配一块内存,以保留一些用于脚本语言本地变量的伪“堆栈空间”,并将其传递给每个函数(或将其填充到线程全局)。对于脚本语言的函数调用,还需要该堆栈的基指针。 一旦你做到了这一点,你已经完成了获得基于堆栈的语言所需要做的大部分工作。所以你最好做剩下的。要使用实际的堆栈和基指针,你必须降到机器语言级别。 如果您的语言是基于寄存器的,那么它仍然需要一个用于访问局部变量的堆栈(它只是不太经常使用它),那么您就不需要将它用于指令参数。如果我可以犯罪地简化,基于3地址注册器的虚拟机是基于堆栈的虚拟机的一种特殊情况。 字节码解释器的另一种方法是让指令包含指令ID,然后将其用作函数指针数组的索引,每个函数指针实现一条指令。 显然,这样做会影响性能。如果你的指令做得足够简单,你可以通过直接在机器代码中实现它们来节省CPU周期,并且省去函数调用的开销(通常可以忽略不计),甚至可以使用真正的堆栈而不是假的堆栈。 这取决于你的需要。对于大多数情况,特别是如果这是您的第一个解析器/解释器/VM,我建议使用函数指针数组和伪堆栈。它很简单,不太难调试,而且在现代机器上足够快。你以后总是可以进去写一个优化的版本,做不同的事情。 例如,一种方法是为函数调用生成足够的机器代码,然后在生成的机器代码中插入指向此类函数的指针。因此,每个脚本都成为一个编译代码块,但不必编写完整的编译器。从那时起,您可以通过为单个关键指令生成汇编程序来改进这些指令,将不太常用的东西保留为函数。这稍微改善了代码的局部性,这是一个微小的微优化可以帮助。但只是其中之一。 哦,大约一个月前,我写了一篇博客,从初学者的角度介绍如何制作编译器(和字节码解释器),这可能会有所帮助: http://orangejuiceliberationfront.com/how-to-write-a-compiler/ |
Community wiki · C中有哪些耗时的操作? 1 年前 |
Community wiki · 将所有处理器电源都投入到任务中 1 年前 |
Community wiki · C++为C添加了什么?[已关闭] 1 年前 |
Community wiki · 打印1到1000,不带循环或条件 1 年前 |