解释还是编译:有用的区别?


29

在这里,有关解释型和编译型语言工具的问题很多。我想知道区别实际上是否有意义。(实际上,问题通常是关于语言的,但是他们实际上是在考虑那些语言的最流行实现)。

今天,几乎没有任何实现被严格解释。即几乎没有人解析并一次运行一行代码。另外,编译成机器代码的实现也越来越不常见。编译器越来越多地将目标对准某种虚拟机。

实际上,大多数实施都集中在相同的基本策略上。编译器生成字节码,该字节码通过JIT解释或编译为本地代码。它实际上是传统的编译和解释思想的结合。

因此,我问:如今,解释的实现和编译的实现之间是否有有用的区别?


7
@DeadMG并不像您想象的那么新:即时历史 ...
yannis 2012年

4
@DeadMG鉴于过去10年左右引入的大多数新语言主要都在某种VM上运行,我想说他有道理。当然,仍然有(并将在未来几十年内)将语言编译为本机代码,而JIT仍将保持豪华(如果PyPy没错,则不会)。所以是的,可能夸大了,但是我同意主流(目前和可预见的未来)似乎是字节码编译器+可能是JIT。

4
@DeadMG,如果VM模型对您来说是“新的”,那么您必须留白胡子。P-code最早于1966年推出。IBM Aix自1986
SK-logic

6
诸如unix shell,Tcl之类的东西总是会被完全解释,因此,至少在学术CS中,区分才有意义。但是,的确,当编码人员抱怨解释器与编译器时,在大多数情况下它们没有任何意义。
SK-logic

3
@ SK-逻辑,我觉得您的评论是一个更好的答案那么任何实际公布的答案
温斯顿·尤尔特

Answers:


23

重要的是要记住,解释和编译不仅是彼此的替代。最后,您编写的任何程序(包括编译为机器代码的一个程序)都将得到解释。解释代码仅意味着采取一组指令并返回答案。

另一方面,编译意味着将一种语言的程序转换为另一种语言。通常,假定在进行编译时,会将代码编译为“低级”语言(例如,机器代码,某种VM字节码等)。以后仍会解释此编译代码。

关于解释语言和编译语言之间是否存在有用区别的问题,我个人认为每个人都应该对他们在解释过程中编写的代码所发生的事情有基本的了解。因此,如果他们的代码是JIT编译的或字节码缓存的,等等,那么程序员至少应该对这意味着什么有基本的了解。


3
是的,程序员应该有基本的了解。但是我想知道编译/解释的术语是否不会妨碍这一点。
温斯顿·埃韦特'02

2
谢谢!!解释仅是“已执行”的同义词,这就是所有程序的运行方式。
gardenhead

9

这种区别具有深远的意义,因为编译的语言不一定以解释的语言来限制语义。有些解释技术很难(实际上是不可能)进行编译的。

解释后的代码可以执行类似的操作,例如在运行时生成代码,并使该代码对现有范围的词法绑定具有可见性。那是一个例子。另一个是,解释器可以使用解释后的代码扩展,这些代码可以控制代码的评估方式。这是古老的Lisp“ fexprs”的基础:使用未评估的参数调用并决定如何处理这些函数(可以完全访问必要的环境以遍历代码和评估变量等)。在编译语言中,您不能真正使用该技术。您改用宏:在编译时使用未经评估的参数调用的函数,然后翻译代码而不是解释。

围绕这些技术构建了一些语言实现。他们的作者拒绝将编译视为重要目标,而是接受这种灵活性。

作为引导编译器的一种技术,解释将始终是有用的。作为一个具体的例子,请看CLISP(Common Lisp的流行实现)。CLISP具有本身编写的编译器。当您构建CLISP时,将在早期构建步骤中解释该编译器。它用于自身编译,然后在编译后使用编译后的编译器进行编译。

没有解释器内核,您将需要使用一些现有的Lisp进行引导,就像SBCL一样。

通过解释,您可以从汇编语言开始,从头开始开发一种语言。开发基本的I / O和核心例程,然后编写一种评估的静态机器语言。评估后,请使用高级语言进行写作;机器代码内核进行评估。使用此功能可以使用更多例程来扩展库,并还可以编写编译器。使用编译器来编译那些例程和编译器本身。

解释:通往编译之路的重要垫脚石!


1
海事组织,这是最好的答案。我正在使用自己的玩具语言,最后一段描述了我开发玩具的方式。这确实使研究新想法变得容易得多。另外+1表示CLISP引导程序。
思南

从理论上讲,可以通过生成一个EXE文件来将任何“解释”语言制成一种“编译”语言,该EXE文件由解释器加上所解释程序的源代码或字节码组成。但是,效率可能不是很高。
dan04 '26

阅读有关Wirth等人如何发明P代码以简化将PASCAL移植到新的机器体系结构的信息。那是在1970年代初期。
约翰·斯特罗姆

1
我怀疑您的开篇会混淆静态和动态行为的编译和解释,但是我会带给您疑问的好处,并只要求提供一种示例语言,其语义“实际上是不可能”进行编译的。关于引导编译器,的确,第一个实现需要使用您正在实现的语言之外的其他语言编写,但是它不必是解释器,它可以是用另一种语言编写的编译器。
8bittree '17

1

实际上,语言的许多实现仍然严格地进行了解释,您可能还不知道它们。仅举几例:UNIX shell语言,Windows cmd和PowerScript shell,Perl,awk,sed,MATLAB,Mathematica等。


3
我相信Perl是在内部编译为字节码的,至少可以编译Mathematica。并没有什么决定awk和sed的实现(我相信某些GNU coreutils在执行前将正则表达式编译为有限自动机,可以说将它们归入“编译为中间表示,解释该类别”)。

1
实际上,我非常确定Perl,MATLAB,Mathematica都可以编译为字节码。我对PowerScript不熟悉,您是说Powershell吗?如果是这样,则使用CLR的方法也将使用字节码。
Winston Ewert'2

@WinstonEwert,对不起,我的意思是PowerShell。我的理解是翻译成中间形式并不意味着某些内容不会被解释。原始的达特茅斯BASIC解释器Heck在解释之前将源代码转换为令牌。我提到的每个工具都有一种模式,其中1)读取一行代码; 2)将这一行转换为可执行形式(可能是一些中间代码,而不是本机代码); 3)执行该行的代码; 4)循环回到1)。这与我对口译员的理解相对应。
查尔斯E.格兰特

2
字节码确实暗示已编译。字节码编译器只是一个获取源并将其转换为字节码的程序。因此,字节码的所有使用都必须涉及字节码编译器。但是字节码也必须被解释(或JITted)。因此,任何使用字节码的东西都是解释器/编译器的混合体。
Winston Ewert'2

4
确实,我的想法是,人们在不了解实现的情况下抛出了“解释了python”和“编译了Java”之类的语句。我要问的是,用这些术语描述实现是否有用。事实通常更复杂,将其简化为解释/编译的过程没有用。
温斯顿·埃韦特

1

我认为:绝对可以

实际上,大多数实施都集中在相同的基本策略上

实际上,C ++旨在将通常传递给解释器的一些高级概念移植到编译器领域,但它只占少数地位。


2
等到Clang + LLVM成为最受欢迎的编译器工具链。
SK-logic

@ SK-logic,尽管有名字,但我相信Clang + LLVM会生成本机代码。
温斯顿·埃韦特

1
@Winston Ewert,仅在您需要时。您可以停止LLVM IR级别,然后对它进行任何所需的操作-解释,JIT编译,以任何您喜欢的方式对其进行检测。您甚至可以将其翻译为Javascript,然后通过解释器:github.com/kripken/emscripten/wiki
SK-logic,

@ SK-logic,整洁的东西!不知道LLVM可以做到这一点。
温斯顿·埃韦特

1
llvm的优点在于前端和后端之间的这种故意分离。以及在针对指令集之前操纵中间件的工具。您可以将整个项目合并为字节码,然后在整个过程中进行优化,而与其他编译器一起使用时,您将需要一个文件源或至少一个文件源,包括从源代码树向下遍历的路径,以便编译器对一个组合的源起作用。同样,llvm下的一组工具对所有目标都是通用的,您不必为每个目标构建,一个编译器就可以适合所有目标(至少适合目标的asm)。
old_timer 2012年

-1

有用的区别:解释程序可以通过在运行时添加或更改函数来修改自身。


8
废话。自修改(机器)代码是本书中最古老的技巧。再有,有些人甚至争论说,甚至本机代码最终也将由嵌入到硅片(CPU)中的解释器来解释。但是,如果我们以此为前提,那么所有代码​​都会被解释,并且没有区别。

2
@delnan是正确的。我要补充一点,现代语言可以通过动态创建新类并加载/卸载库(例如,.NET中的“程序集”)来进行
自我修改

5
Common Lisp已编译,但您仍然可以在运行时轻松替换函数定义。
SK-logic

这是一个非常有趣且必要的解释功能(例如在Prolog中)。
CapelliC 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.