我已经阅读了有关编译器和口译员之间差异的SO答案。他们中的大多数人在解释口译员的工作原理时都会说:
程序,一次一行,并翻译每一行 在运行它之前:它转换第一行并运行它,然后 翻译第二行并运行它等。
(来自How does an interpreter/compiler work)
令我困惑的是 - 从高级语言到机器代码的翻译称为编译。根据定义(https://en.wikipedia.org/wiki/Compiler)。
那么,说高级语言的解释器是否包含编译器,而不仅仅是翻译器,这是正确的吗?
答案 0 :(得分:1)
不,解释器不是编译器,尤其不是“按定义”。本质上,解释器在编译器转换时执行。解释器接受代码,读取它,然后根据代码改变解释器的状态。它调用编写解释器的语言库来执行网络事务等副作用。另一方面,编译器输出一组指令,这些指令执行代码用不同的“语言”描述的内容,例如x86机器代码。它会删除预先写好的机器代码,以便在正在编译的代码中执行副作用。
然而,这些想法在实践中存在大量重叠,尤其是在最近的语言中,如Python,Java和.NET。通常,代码将被编译为字节码,然后由字节码解释器执行或JIT再次编译为机器代码。例如,在Python中,解释器包含所有这些,使它成为一个解释器,用于记忆.pyc文件中的编译工作。
答案 1 :(得分:0)
实际上,编译器和解释器之间的区别在于输入和输出的类型,而不是它们的工作方式。 简而言之,解释器接受一些程序和输入,并产生一些输出,而编译器接受一些程序,并产生一个程序,给定输入产生一些输出。
你的问题非常有趣,简短的答案是"它可以但不必如此,反过来也可以是真的,但没有",但为了达到目的,我们需要建立一些观念。
编程语言 L 是一种理解它的程序的方法,即将程序 P 解释为"从输入到输入的函数输出&#34 ;. 让我们为此函数写 [[P]] _ L ,即 [[P]] _ L(In)= Out 。 (把这个 [[。]] _ L 想象成"意思是 L "函数,即解释L )。
现在假设您有2种语言, L1 和 L2 (并让 L1 与 L2 不同一般而言,不一定是这样。)
如果您只有解释 L1 程序的方法(例如 L1 是您计算机的机器语言), 还有[其他?]为任何 L2 -program P 计算 [[P]] _ L2 的两种可能性 - 即计算任何 L2 程序的 [[P]] _ L2(In)和任何输入 In :
(1)你有一个 L1 - 程序 INT ,这样 [[INT(P,In)]] _ L1 = Out = [[ P]] _ L2(In),或
(2)你确实有 L1 - 程序 COMP ,这样 [[COMP(P)]] _ L1 = P' 强>,这样 [[P']] _ L1 = [[P]] _ L2 ,即 [[P']] _ L1(In)= [[P] ] _L2(In)用于任何输入 In 。
这个想法的主要简化是 L1 和 L2 都在相同的数据类型上工作,这可能不是这种情况(但是引入了解释其他一些数据类型)会让事情更加扭曲)。 另请注意,输出可能包含副作用(如I / O,或某些db更新/删除,或任何) - 但这现在并不重要。
然后 INT 是L1 中L2的解释器, COMP 是从L2到L1的编译器 ,我相信这是唯一有意义的区别。
INT 没有问题:使用 P 和 In ,使用<编译 P strong> COMP ,在 In 上执行结果,并返回其值。 这就是JIT编译解释器的工作原理。 INT 还可以将 P 编译为某些其他语言 L3 ,然后使用 L3 - 解释器执行它 - 那就是基于VM的口译员的工作方式。
现在,令人兴奋的部分是:你可以生成编译器 COMP (从 L2 到 L1 )通过部分评估具有解释器 INT (对于L1中的L2),作为注释中提到的SK逻辑。 非常简单(阅读:LIES!),请注意 L1 &#34;操作&#34;需要从 In 到 Out 的内容出现在 INT 的代码中。想象一下一些机制,而不是仅执行 INT 的这些部分&#34;将它们写下来&#34;。 最后一堆写下的操作&#34;是一个 L1 - 程序 P&#39; ,它给出 In 产生 Out ,就像原来的一样L2 程序 P 会。换句话说,&#34;汇编是推迟的解释&#34; 。 这就是Futamura Projections的意义所在。您可以在http://readscheme.org/partial-eval/index.html
找到大量论文(其中许多是免费提供的)简而言之,你可以从编译器中创建一个解释器(例如通过jit编译和执行),你可以从解释器中创建一个编译器(例如,通过IInd Futamura投影)。
再一次:差异只是解释器/编译器消耗的内容以及它们产生的内容。他们的工作方式是&#34;他们自己的事业&#34;。