因此,例如,Python 和 Java 有一个 VM,而 C 和 Haskell 则没有。(如我错了请纠正我)
想着线路两边都有哪些语言,找不到原因。Java 在很多方面都是静态的,而 Haskell 提供了很多动态特性。
因此,例如,Python 和 Java 有一个 VM,而 C 和 Haskell 则没有。(如我错了请纠正我)
想着线路两边都有哪些语言,找不到原因。Java 在很多方面都是静态的,而 Haskell 提供了很多动态特性。
这与静态与动态无关。
相反,它是关于独立于底层硬件平台(“构建一次,到处运行” - 理论上......)
实际上,这也与语言无关。可以编写一个为 JVM 生成字节码的 C 编译器。可以编写一个生成 x86 机器代码的 Java 编译器。
让我们暂时忘记虚拟机(我保证,我们会回到下面的那些),并从这个重要的事实开始:
对于提供垃圾收集的语言,必须有某种“运行时” /运行时环境/事物来执行它。
这就是为什么 Python、Java 和 Haskell 需要“运行时”,而 C 不需要,可以直接编译为本机代码。
请注意,psyco是一个 Python 优化器,可以将 Python 代码编译为机器代码,但是,许多机器代码包含对 C-Python 运行时函数的调用,例如PyImport_AddModule
、PyImport_GetModuleDict
等。
Haskell/GHC 与 psyco 编译的 Python 类似。Int
s 作为简单的机器指令添加,但分配对象等更复杂的东西会调用运行时。
还有什么?
如果我们要向 C 添加异常,我们生成的机器代码将需要为每个函数和每个函数调用做一些事情。
如果我们再添加“闭包”,就会添加更多的东西。
现在,不是在每个函数中重复这个样板机器代码,我们可以让它调用一个子过程来做必要的事情,比如PyErr_Occurred
.
所以现在,基本上每个原始源代码行都映射到对某些函数的一些调用和一个较小的独特部分。
这是一个想法(顺便说一句,我们称这个想法为“虚拟机”)。
让我们代表您的 Python 代码,例如:
def has_no_letters(text):
return text.upper() == text.lower()
作为内存数据结构,例如:
{ 'func_name': 'has_no_letters',
'num_args': 1,
'kwargs': [],
'codez': [
('get_attr', 'tmp_a', 'arg_0', 'upper'), # tmp_a = arg_0.upper
('func_call', 'tmp_b', 'tmp_a', []), # tmp_b = tmp_a() # tmp_b = arg_0.upper()
('get_attr', 'tmp_c', 'arg_0', 'lower'),
('func_call', 'tmp_d', 'tmp_c', []),
('get_global', 'tmp_e', '=='),
('func_call', 'tmp_f', 'tmp_e', ['tmp_b', 'tmp_d']),
('return', 'tmp_f'),
]
}
现在,让我们编写一个解释器来执行这个内存数据结构。
让我们讨论一下直接来自文本解释器的好处,然后讨论编译成机器代码的好处。
wt(f, d(o, e), s) <= th(i, s) + cr(a, p * d + o)
VM(虚拟机)实际上是语言设计人员在编写语言实现时避免一些复杂性的工具。
基本上是虚拟计算机的规范,以及所述计算机的每一部分将如何与另一部分交互。您可以在本规范中编写一些可以被实际语言使用或不使用的假设。
在本规范中,您通常定义处理器/处理器的工作方式、内存的工作方式、可能的读/写障碍等,以及与之交互的更简单的汇编语言。
最终语言通常从您正在编写的文本文件中翻译(编译)为为该机器编写的表示形式。
这有一些优点:
还有酷的因素:看马我做了一个虚拟机:)。
虚拟机基本上是一种解释器,可以解释更接近机器代码的语言。当真实机器解释真实机器代码时,虚拟机解释一个虚构的机器代码。一些 VM-s 解释实际计算机的机器代码——这些被称为仿真器。
为简单的类汇编语言编写解释器更容易,然后为完整的高级语言编写解释器。此外,许多高级代码结构通常只是一些基本原则的语法糖。因此,编写一个将所有这些复杂概念转换为简单 VM 语言的编译器会更容易,因此我们不必编写复杂的解释器,但可以使用简单的解释器(VM)。然后你有更多的时间来优化虚拟机。
这基本上就是当今大多数语言(不编译成真正的机器代码)的实现方式。
解释器 (VM) 和编译器可以是单独的程序(如java
和javac
),也可以只是一个程序(如 Ruby 或 Python)。
没有“需要”,这些语言中的任何一种都提供了直接发出机器代码的编译器,以在给定的架构中实现其语言的语义。
虚拟机的想法是抽象出所有不同硬件和软件制造商之间的架构差异,以便开发人员只有一台机器可以写入。
Java 和 python 可以以保持平台独立性的方式进行编译。这甚至适用于 C#。优点是 VM 能够将这种主要是强类型字节码转换为非常好的平台特定代码,并且开销相对较低。由于 Java 旨在“构建一次 - 随处运行”,因此创建了 JVM。
想象一下,您创建了一种编程语言:您弄清楚了语言语义并开发了一种很好的语法。
但是,文本表示是不够的:在执行程序时必须一次又一次地解析文本效率低下,因此添加内存中的二进制表示是很自然的。将其与自定义内存管理器相结合,您基本上就拥有了一个虚拟机。
现在,为了额外的点,要么开发一个字节码格式来序列化你的内存表示和一个运行时加载器,或者,如果你想走脚本语言的道路,一个eval()
函数。
对于大结局,添加 JIT。