什么是Perl中的`null vK`?

Eva*_*oll 4 perl internals opcode

使用Perl,我有两个类似的语法,

if ($a && $b) { exit() }
do { exit() } if ($a && $b)
Run Code Online (Sandbox Code Playgroud)

我认为这些应该是相同的,但最上面的一个创建一个null vK操作码,

<1> null vK*/1 ->-
Run Code Online (Sandbox Code Playgroud)

它的意义是null vK什么,它有什么作用?

$ perl -MO=Concise -e'if ($a && $b) { exit() }'
8  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
-     <1> null vK/1 ->8
6        <|> and(other->7) vK/1 ->8
-           <1> null sK/1 ->6
4              <|> and(other->5) sK/1 ->8
-                 <1> ex-rv2sv sK/1 ->4
3                    <#> gvsv[*a] s ->4
-                 <1> ex-rv2sv sK/1 ->-
5                    <#> gvsv[*b] s ->6
-           <@> scope vK ->-
-              <;> ex-nextstate(main 3 -e:1) v ->7
7              <0> exit v* ->8
-e syntax OK
Run Code Online (Sandbox Code Playgroud)

以下是经文,

$ perl -MO=Concise -e'do { exit() } if ($a && $b)'
8  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
-     <1> null vK/1 ->8
6        <|> and(other->7) vK/1 ->8
-           <1> null sKP/1 ->6
4              <|> and(other->5) sK/1 ->8
-                 <1> ex-rv2sv sK/1 ->4
3                    <#> gvsv[*a] s ->4
-                 <1> ex-rv2sv sK/1 ->-
5                    <#> gvsv[*b] s ->6
-           <1> null vK*/1 ->-
-              <@> scope vK ->-
-                 <;> ex-nextstate(main 2 -e:1) v ->7
7                 <0> exit v* ->8
Run Code Online (Sandbox Code Playgroud)

wol*_*ats 5

该行开头的" - "表示操作不会被执行,也可以使用perl -MO=Concise,-exec.

也就是说,B :: Concise输出中的null vK...null sK...操作码并不意味着某些操作已经被优化掉了.perldoc在B :: Concise上清楚地表明这种优化ex-在输出中表示:

Nullops显示为"ex-opname",其中opname是由perl优化的op.它们显示的序列号为" - ",因为它们没有被执行(它们没有出现在前面的例子中),它们在这里打印,因为它们反映了解析.

例如:

> perl  -MO=Concise -e "$a"
4  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
-     **<1> ex-rv2sv vK/1 ->4**
3        <#> gvsv[*a] s ->4
Run Code Online (Sandbox Code Playgroud)

那么这些空值是什么呢?

它们是来自Perl用于解析代码的yacc语法的真正空值,并且它们从一开始就不打算执行.

在你的情况下,超出部分null vk直接来自以下do BLOCK语法规则(perly.y):

termdo  :       DO term %prec UNIOP                     /* do $filename */
            { $$ = dofile($2, $1);}
    |   DO block    %prec '('               /* do { code */
            { $$ = newUNOP(OP_NULL, OPf_SPECIAL, op_scope($2));}
        ;
Run Code Online (Sandbox Code Playgroud)

我们可以在这里看到它:

>perl -MO=Concise -e "do{}"
4  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 -e:1) v:{ ->3
-     <1> null vK*/1 ->4
-        <@> scope vK ->-
3           <0> stub v ->4
Run Code Online (Sandbox Code Playgroud)

在其他情况下,空值来自yacc操作.显然,这些空值用于帮助管理操作树,因为它们永远不会执行,我认为Perl开发人员不会为他们的存在而烦恼.

以下是解析布尔表达式产生的null操作示例:

>perl  -MO=Concise -e "$a||$b"
6  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
-     <1> null vK/1 ->6
4        <|> or(other->5) vK/1 ->6
-           <1> ex-rv2sv sK/1 ->4
3              <#> gvsv[*a] s ->4
-           <1> ex-rv2sv vK/1 ->-
5              <#> gvsv[*b] s ->6
Run Code Online (Sandbox Code Playgroud)

为什么这里为空?另一个片段有助于说清楚:

>perl -MO=Concise -e "!$a&&!$b"
7  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
6     <1> not vK/1 ->7
4        <|> or(other->5) sK/1 ->6
-           <1> ex-not sK/1 ->4
-              <1> ex-rv2sv sK/1 ->-
3                 <#> gvsv[*a] s ->4
-           <1> ex-not sK/1 ->6
-              <1> ex-rv2sv sK/1 ->-
5                 <#> gvsv[*b] s ->6
Run Code Online (Sandbox Code Playgroud)

它似乎null vK已成为not vK.仔细看,我们可以看到的Perl优化!$a&&!$b!($a||$b)not(!)正在发生的null.事实证明,Perl总是保留逻辑表达式的父操作码,并且如果表达式可以简化,外部not Perl放入not父操作码,null否则.

总结:通过显示NULL操作码ex-B::Concise输出是由优化程序和NULL操作码以表示null来自语法分析器.它们都不会被执行,也不会带来任何性能损失.