为什么Perl会在此警告消息中提供误导性的行号?

Ste*_*hen 10 perl

我已经分离了一个案例,其中Perl在警告消息中提供了一个非常误导性的行号.我在Strawberry Perl 5.16.3中测试了以下内容.

use strict;
use warnings;

my $choice = 0;

while ($choice == 0){

    #This is not numeric
    $choice = '5,6,7';

    if ($choice eq '-4'){
        print "This isn't going to happen\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

运行此操作时,您将收到警告消息Argument "5,6,7" isn't numeric in numeric eq (==) at example.pl line 11.但是第11行对应的行if ($choice eq '-4'){不能引起此警告消息,因为它不包含数字比较.

实际上发生的事情似乎是Perl进入下一个比较while ($choice == 0){,但是用于警告消息的行计数器没有前进.

使这种特殊情况更糟的是,由于"坏"比较是循环条件,它实际上远离提供的线.在我的(预简化)脚本中,它距离提供的行号数百行.

这是一个错误还是解析器的一个不幸的限制?

ike*_*ami 17

存储每个运算符实例的位置将是昂贵的.作为妥协,Perl只跟踪语句的位置.它通过在每个语句的开头添加位置设置操作码来实现.该if语句是$choice == 0执行之前要启动的最后一个语句,因此警告将报告为来自该行.

$ perl -MO=Concise,-exec a.pl
1  <0> enter
2  <;> nextstate(main 3 a.pl:4) v:*,&,{,x*,x&,x$,$
3  <$> const[IV 0] s
4  <0> padsv[$choice:3,12] sRM*/LVINTRO
5  <2> sassign vKS/2
6  <;> nextstate(main 4 a.pl:6) v:*,&,{,x*,x&,x$,$           <--- Location set to line 6
7  <{> enterloop(next->k last->p redo->8) v                  <--- Start of while loop
l  <0> padsv[$choice:3,12] s                                 <--- $choice == 0
m  <$> const[IV 0] s
n  <2> eq sK/2
o  <|> and(other->8) vK/1
8      <;> nextstate(main 6 a.pl:9) v:*,&,x*,x&,x$,$
9      <$> const[PV "5,6,7"] s
a      <0> padsv[$choice:3,12] sRM*
b      <2> sassign vKS/2
c      <;> nextstate(main 6 a.pl:11) v:*,&,x*,x&,x$,$        <--- Location set to line 11
d      <0> padsv[$choice:3,12] s                             <--- Start of if statement
e      <$> const[PV "-4"] s
f      <2> seq sK/2
g      <|> and(other->h) vK/1
h          <0> pushmark s
i          <$> const[PV "This isn't going to happen\n"] s
j          <@> print vK
k      <0> unstack v
           goto l                                            <--- Jump back to loop expr
p  <2> leaveloop vKP/2
q  <@> leave[1 ref] vKP/REFC
a.pl syntax OK
Run Code Online (Sandbox Code Playgroud)

这是一个已知的限制.我不知道他们为什么不简单地nextstate在循环表达式中加入op.


mob*_*mob 12

显然,从Perl 5.008开始,解释器开始省略一个操作码,让解释器知道当前的行号.

使用极简主义脚本:

while ($choice == 0) {
    $choice = '5,6,7';
}
Run Code Online (Sandbox Code Playgroud)

我们从Perl 5.6获得此输出并且B::Concise:

$ perl506 -MO=Concise badwarnline.pl
f  <@> leave[t1] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 badwarnline.pl:1) v ->3
e     <2> leaveloop vK/2 ->f
3        <{> enterloop(next->8 last->e redo->4) v ->a
-        <1> null vK/1 ->e
d           <|> and(other->4) vK/1 ->e
c              <2> eq sK/2 ->d
-                 <1> ex-rv2sv sK/1 ->b
a                    <$> gvsv(*choice) s ->b
b                 <$> const(IV 0) s ->c
-              <@> lineseq vKP ->-
4                 <;> nextstate(main 1 badwarnline.pl:2) v ->5
7                 <2> sassign vKS/2 ->8
5                    <$> const(PV "5,6,7") s ->6
-                    <1> ex-rv2sv sKRM*/1 ->7
6                       <$> gvsv(*choice) s ->7
8                 <0> unstack v ->9
9                 <;> nextstate(main 2 badwarnline.pl:1) v ->a
Run Code Online (Sandbox Code Playgroud)

和Perl v5.008的输出:

$ perl508 -MO=Concise badwarnline.pl
e  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 badwarnline.pl:1) v ->3
d     <2> leaveloop vK/2 ->e
3        <{> enterloop(next->8 last->d redo->4) v ->9
-        <1> null vK/1 ->d
c           <|> and(other->4) vK/1 ->d
b              <2> eq sK/2 ->c
-                 <1> ex-rv2sv sK/1 ->a
9                    <#> gvsv[*choice] s ->a
a                 <$> const[IV 0] s ->b
-              <@> lineseq vKP ->-
4                 <;> nextstate(main 1 badwarnline.pl:2) v ->5
7                 <2> sassign vKS/2 ->8
5                    <$> const[PV "5,6,7"] s ->6
-                    <1> ex-rv2sv sKRM*/1 ->7
6                       <#> gvsv[*choice] s ->7
8                 <0> unstack v ->9
Run Code Online (Sandbox Code Playgroud)

这些输出之间的主要区别是5.006产生的最后一行:

9                 <;> nextstate(main 2 badwarnline.pl:1) v ->a
Run Code Online (Sandbox Code Playgroud)

在5.008输出中省略.