Perl是一种解释型编程语言还是编译型编程语言?

28
Perl是一种解释性语言,不编译成机器码。
9个回答

59

你没有提供明确的问题,因此无法得到明确的答案。

Perl始终处于两种状态之一:编译或执行。这就是为什么会出现“在编译时”和“在运行时”的讨论。通常情况下,您会得到一个编译阶段,然后是一个执行阶段,但不一定是这样。

这两个阶段也可以交替进行。 eval STRING是解释器调用编译器的一种方式(do FILErequire也是如此)。BEGIN块是编译器调用解释器的一种方式(useno也是如此)。

当您运行perl -c时,省略了运行时阶段。有各种方法可以跳过编译时阶段,但它们中没有一种特别方便或普遍。 Apache的mod_perl只编译脚本一次,但执行多次。如果您使用Byteloader,则可以做到同样的效果。等等。

关于Perl是编译还是解释语言的正确答案是


非常有帮助。谢谢! - Hunan Rostomyan
同样的话不也适用于任何解释型语言吗?以Python为例。 - matanster

30

这要看你所谓的编译语言是什么意思。也许这就是为什么谷歌搜索没有明确回答你问题的原因。

一个观点是,编译意味着从源代码描述到另一个描述的编译,即代码生成

如果我们接受这些前提条件,那么Perl 6可以被编译,而Perl 5和更早版本则是解释型语言。

Perl 6被专门编译成Parrot字节码。 因此,Perl 6是一种正确的编译语言,就像Java一样。

Perl 5及更早版本将Perl源代码解析为内部列表或树,但我认为除了在理论上可能称之为编译器外,它不应该被称为一个真正的编译器。 它通常不输出与编译器相关联的任何字节码,汇编或实际机器代码。Perl的解析阶段用于检查Perl语法的有效性,以便在运行之前“编译”源文件。

它被调用方式如下:

perl -c myprog.pl

但是如果您查看Perl选项的帮助文档,实际上-c代表"检查"。

-c                check syntax only (runs BEGIN and CHECK blocks)

(更复杂的是,Perl 5原本支持写出内部字节码,但在版本5.10中被移除了。大概是因为有bug吧,我也不知道。)

另一方面,如果你认为编译是将源代码解析成任何其他形式的表示形式的行为,那么这种解析使得Perl成为一种编译语言。在执行之前,Perl必须完全解析源文件。根据这个定义,在解析之前能立即开始执行源文件的任何语言都是一种解释性语言。

第三种看法是从领域专业人士最常使用的“解释”和“编译”这两个词的角度来考虑。我敢打赌,如果一个随机的程序员子集在思考Perl时被要求选择“编译”或“解释”,大多数人会选择“解释”。不是因为对Perl本质的理论争论,而是因为“编译”通常引起“编译”、“链接”、“目标代码”等方面的思考,而“解释”则被理解为“编写代码,试用它”。正确与否,这可能是在试图确定Perl是否真正是解释性或者实际上是编译性时需要知道的。在你的探索过程中,你会遇到很多争论。


10
这并不十分准确。如果Perl没有被编译,那么语法分析树从哪里出来?没有解析器你是无法得到语法分析树的,而这正是编译的全部内容。也许如果问题谈论了本地机器语言的代码生成,你的答案会更加贴切。但问题并没有涉及到这一点,因为代码生成与编译是完全不同的事情。 - tchrist
6
另一方面,如果考虑到几乎所有语言都有解析器,那么几乎所有语言都是编译的。 - Prof. Falken
4
不,解析语法树并不等同于编译。如果你不同意的话,那么你必须认为不存在任何解释的Lisp,因为Lisp会读取像(let ((a b)) c)这样的内容,并将其转换成内存中的一棵树。但是,通过遍历树来运行该语句和生成代码之间有所区别。 - Kaz
2
关于“一种观点认为编译意味着从源代码描述到另一个的编译,即代码生成。如果我们接受这些前提,那么Perl 6可以被编译,而Perl 5和更早版本是解释型语言”,嗯?按照这个定义,Perl 5也是编译的。它产生了由高级操作码组成的汇编程序。/// 关于“它不会输出任何字节码、汇编或与编译器通常相关的真实机器代码”,它确实会;只是它不费心将其写入磁盘。曾经有一个工具可以这样做,但它已经没有维护了。所以按照你们两个的定义,Perl5是编译的。 - ikegami
3
关于Perl的难以达成共识,可能是因为人们错误地认为它必须是解释器或编译器之一。实际上,Perl是一个包含编译器的解释器,它明确执行由解释器系统中的编译器生成的预编译代码。这就是解释器的定义。 - ikegami
显示剩余4条评论

13

Perl5既是编译器又是解释器。Perl5将源代码编译成OPCODE对象,然后解释这些OPCODE对象。下面是详细说明。


维基百科的定义如下:

编译器是一种将用编程语言编写的源代码(源语言)转换为另一种计算机语言(目标语言,通常具有二进制形式,即目标代码)的计算机程序(或一组程序)。

Perl5是一种编译器。它接受Perl5源代码并生成OPCODE对象图。

$ perl -MO=Concise,-exec -E'for (1..3) { say "Hello, World!" }'
1  <0> enter 
2  <;> nextstate(main 48 -e:1) v:%,2048
3  <0> pushmark s
4  <$> const(IV 1) s
5  <$> const(IV 3) s
6  <$> gv(*_) s
7  <{> enteriter(next->c last->f redo->8) lKS/8
d  <0> iter s
e  <|> and(other->8) vK/1
8      <;> nextstate(main 47 -e:1) v:%,2048
9      <0> pushmark s
a      <$> const(PV "Hello, World!") s
b      <@> say vK
c      <0> unstack v
           goto d
f  <2> leaveloop vK/2
g  <@> leave[1 ref] vKP/REFC
-e syntax OK
然而,Perl5编译器并不会生成机器码。那么OPCODE图是如何执行的呢?根据维基百科的一个定义,解释器是指“显式地执行由解释器系统中编译器生成的存储的预编译代码”,这意味着OPCODE图是被解释执行的。目前正在进行工作,以提供将Perl5编译为LLVM字节码的选项。然后,可以将其JIT编译为机器码。这与Java使用的方法相同。

1
专业人士使用此答案中给出的定义。新手往往使用更模糊的东西。 - tchrist
3
@tchrist,我不认为一个专业人士会用“解释型”或“编译型”这样的术语来讨论编程语言。 - ikegami
@ikegami 我会这样做。有语义上的差异。解释性语言中的程序可以做编译无法实现的事情。如果这种用法在语言的用户中占主导地位,那么它就是严格的解释性语言。例如,解释性语言可以允许用户定义的程序使用自定义解释例程扩展解释器。没有编译器能够确定这些例程做什么(或者它们是否甚至对于给定的输入集合停止),以便发出等效的代码。 - Kaz
@ikegami 嗯,试着在谷歌上搜索“fexpr”,那可能更好。 - Kaz
1
@ikegami 问题不在于fexpr的主体是否被编译,而在于fexpr的操作是否可以被代码生成所替代,从而不再使用fexpr。也就是说,编译器查看代码并看到“啊哈,这是调用一个循环fexpr。根据那个fexpr的代码,它是一个循环。因此,我将只生成一个不再调用fexpr的循环”。如果您可以在语言本身中编译用户定义的fexpr,则使fexprs变得不必要。当您已经在编译时,为什么还要优化解释器呢? - Kaz
1
@Kaz,抱歉,我不知道你刚才说了什么,更重要的是,我仍然看不出fexprs如何引导专业人士从编译或解释语言的角度讨论语言。 - ikegami

2

Raku(Perl 6)具有与Perl 5的兼容模式,因此可以使用Rakudo将Perl 5编译为JVM和Parrot。我希望能够使用LLVM进行编译!


0
Perl是一种解释性语言。然而,它会在内部编译成p-code以提高效率。

我认为通常称为p-code的内容(http://en.wikipedia.org/wiki/P-code_machine)不能与Perl通常解析成的内容相比较。 - Prof. Falken
P-Code就像ByteCode一样。P-Code-Machine就像JVM一样。翻译状态的实际结构取决于Perl的实现。顺便说一句,也有一个针对JVM的Perl实现:http://www.javainc.com/projects/jperl/ 同样地,还有使用CLR ByteCode的实现。 - Shamit Verma
啊,我现在明白了关于ByteCode的事情。谢谢。JPerl很有趣。但是它似乎只是解释Perl?如果它能将Perl编译成类文件就更酷了(但我猜可能更难)。 - Prof. Falken
3
Perl5生成一个操作码对象的图表,它产生的不是可移植的p-code或某些虚拟机的指令。 - ikegami

0

来自维基百科:“Perl是一种高级、通用、解释型、动态编程语言”。Perl 6也允许编译(同样,请参见维基百科)。


谢谢你在该死的页面上给出唯一直接的答案。 - Dylan Richards

-1

这是一个可以在不需要C的情况下编译的虚拟机。然而,它的虚拟机比Java快得多,因此没有任何东西可以与之相比。

缺点 - 它像C++一样推崇成为全能瑞士军刀。在Perl的情况下,它去掉了训练轮、安全和边界。例如,在大多数面向对象编程语言中,您必须在使用对象之前声明一个类,在Perl中,对于您可以混合和匹配的类型没有限制,从而将任何东西转换为对象或将对象转换为任何东西。如果您已经了解面向对象编程,这个概念非常令人困惑,没有限制既是强大的也是Perl的缺点。因此,无论语言是否编译,问题都不在于您是否能够有效地推理出某些内容,而在于您是否会破坏整个世界。另一个问题是Perl是只写的,因此一旦编写,所有内容看起来都像乱码,并且变得难以分析甚至调试。


-1

两者都有。首先,Perl 6脚本被编译成字节码(并进行了优化)。然后执行它(但是,您仍然需要Perl解释器)。 字节码是一种可执行代码,与其运行的环境无关(相同的字节码可以在ARM处理器上的Unix环境、x86架构的Windows系统和x64架构的Haiku上运行)。

Perl 6可以编译为Parrot VM(虚拟机)字节码。Python和Ruby也使用Parrot VM。

这就是使Perl、Ruby和Python比PHP更快的原因,因为PHP只是解释执行的(也可以编译,但需要第三方组件)。


Perl 6 的想法。抱歉,我会修复它的。 - Dr McKay
我撤回之前的说法,看起来它被编译成了某种字节码,尽管在5.10中已经删除了将字节码写入文件的官方支持。 - Prof. Falken
我不会真的称它为字节码。这些文本可能会解释它:https://www.socialtext.net/perl5/optree_guts http://perldoc.perl.org/perlguts.html#Compiled-code - Dr McKay
@Amigable Clark Kant,您提到了perlccperlcc试图序列化Perl5的操作码。它从未是执行Perl5代码过程的一部分。 - ikegami
1
在描述 perlcc 时不要使用过去式。它只是从核心中分离出来,而不是被淘汰了。对它进行了大量的工作。 - tchrist
1
@tchrist,我印象中它甚至不能运行在更新版本的Perl上。你是在说我记错了(完全有可能)还是现在不是这种情况了?(PS-如果你不标记我,我将不会收到通知。) - ikegami

-2

你能定义一下“most often”这个词吗? :) - Mr. L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接