【问题标题】:What is `null vK` in Perl?Perl 中的“null vK”是什么?
【发布时间】:2018-04-05 02:07:38
【问题描述】:

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

if ($a && $b) { exit() }
do { exit() } if ($a && $b)

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

<1> null vK*/1 ->-

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

下面的诗句,

$ 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

【问题讨论】:

  • exit() if ($a &amp;&amp; $b)
  • @RingØ 不会创建无用的词法范围而不是创建无用的词法范围,它有助于分散我的问题。

标签: perl internals opcode


【解决方案1】:

行首的“-”表示该操作不会被执行,使用perl -MO=Concise,-exec也可以看到。

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

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

例如:

> 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

那么那些空值是什么?

它们是来自 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));}
        ;

我们可以在这里看到:

>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

在其他情况下,空值来自 yacc 操作。 显然,这些空值用于帮助管理操作树,并且由于它们从未被执行,我认为 Perl 开发人员不会担心它们的存在。

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

>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

为什么这里是空值?另一个 sn-p 有助于说明清楚:

>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

null vK 似乎已变为not vK。 仔细观察,我们可以看到 Perl 将!$a&amp;&amp;!$b 优化为!($a||$b),其中not(!) 代替了null。 原来 Perl 总是为逻辑表达式保留一个父操作码,如果一个表达式可以用外层not 来简化 Perl 将not 放入父操作码,否则将null 放入。

总结一下:B::Concise 输出中ex- 指示的空操作码由优化器生成,null 指示的空操作码来自语法解析器。它们都不会被处决,也不会受到性能惩罚。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    • 2019-08-15
    • 2023-03-25
    • 1970-01-01
    • 2011-02-12
    相关资源
    最近更新 更多