解析树与字节码一样吗?

时间:2012-05-02 15:21:31

标签: perl

字节码和解析树之间究竟有什么区别,特别是Perl使用的那个?他们实际上是指同一个概念,还是有区别?

我熟悉Python和Java的字节码概念,但在阅读Perl时,我已经了解到它应该在其解释器中执行解析树(而不是字节码)。

如果实际存在区别,Perl不使用字节码(或Python不使用解析树)的原因是什么?它主要是历史的,还是需要不同的编译/执行模型的语言之间存在差异? Perl(具有合理的努力和执行性能)是否可以通过使用字节码解释器来实现?

2 个答案:

答案 0 :(得分:9)

Perl使用的不是parse tree,至少不是维基百科如何定义它。这是一个操作码树。

>perl -MO=Concise -E"for (1..10) { say $i }"
g  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 49 -e:1) v:%,{,2048 ->3
f     <2> leaveloop vK/2 ->g
7        <{> enteriter(next->c last->f redo->8) lKS/8 ->d
-           <0> ex-pushmark s ->3
-           <1> ex-list lK ->6
3              <0> pushmark s ->4
4              <$> const[IV 1] s ->5
5              <$> const[IV 10] s ->6
6           <#> gv[*_] s ->7
-        <1> null vK/1 ->f
e           <|> and(other->8) vK/1 ->f
d              <0> iter s ->e
-              <@> lineseq vK ->-
8                 <;> nextstate(main 47 -e:1) v:%,2048 ->9
b                 <@> say vK ->c
9                    <0> pushmark s ->a
-                    <1> ex-rv2sv sK/1 ->b
a                       <#> gvsv[*i] s ->b
c                 <0> unstack v ->d
-e syntax OK

除了被称为树之外,它不是真正的树。注意箭头?这是因为它实际上是一个类似于列表的操作码图(就像任何其他可执行文件一样)。

>perl -MO=Concise,-exec -E"for (1..10) { say $i }"
1  <0> enter
2  <;> nextstate(main 49 -e:1) v:%,{,2048
3  <0> pushmark s
4  <$> const[IV 1] s
5  <$> const[IV 10] 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      <#> gvsv[*i] s
b      <@> say vK
c      <0> unstack v
           goto d
f  <2> leaveloop vK/2
g  <@> leave[1 ref] vKP/REFC
-e syntax OK

Perl的操作码和Java的字节码之间的区别在于Java的字节码设计为可序列化的(存储在文件中)。

答案 1 :(得分:7)

解析树是程序的标记,存储在显示其嵌套的结构中(哪些参数属于哪些函数调用,哪些语句在哪些循环内等),而字节码是转换为二进制表示法的程序代码在虚拟机中更快地执行。例如,如果您使用虚构语言具有以下代码:

loop i from 1 to 10 {
    print i
}

解析树可能看起来像:

loop
    variable
        i
    integer
        1
    integer
        10
    block
        print
            variable
                i

同时,为面向堆栈的虚拟机编译的原始和符号形式的字节码可能如下所示:

0x01 0x01    PUSH 1
             START:
0x02         DUP
0x03         PRINT
0x05         INCREMENT
0x02         DUP
0x01 0x0a    PUSH 10
0x04         LESSTHAN
0x06 0xf9    JUMPCOND START

编译程序时,首先需要解析源代码(通常生成一个解析树),然后将其转换为字节码。跳过第二步并直接从解析树执行可能更容易。此外,如果语言语法非常多(例如它允许修改代码),那么生成字节码会变得更加复杂。如果存在执行任何代码的eval类型函数,则必须将整个编译器与应用程序一起分发以使用虚拟机来执行此类代码。仅包括解析器更简单。

在Perl 6中,perl的下一个版本,代码应该被编译为字节码并在Parrot虚拟机上运行。它有望提高性能。字节码相当简单,可以进一步编译到处理器的本机指令(这称为JIT编译器),以接近C等编译语言的速度。

相关问题