错误的Perl语法会产生错误的错误消息

Bil*_*osa 1 perl syntax-error

以下(很多精简版)代码有一个明显的错误.

#!/usr/bin/env perl

use strict;
use warnings FATAL=>"all";

my $err_phyle;
my $verb;

sub do_measure
{
  print($error_phyle "xxx");

}

sub dye
{
}

dye "invalid verb \"$verb\"";
Run Code Online (Sandbox Code Playgroud)

您希望错误消息是:

Global symbol "$error_phyle" requires explicit package name at example.pl line 11.
example.pl had compilation errors.
Run Code Online (Sandbox Code Playgroud)

......但实际上......

String found where operator expected at example.pl line 19, near "dye "invalid verb \"$verb\"""
Run Code Online (Sandbox Code Playgroud)

(请注意,第二条错误消息不会添加"example.pl有编译错误.".)

在实际程序中,错误消息指向一行数百行代码,远离实际错误.错误的错误消息指向错误的行,可能会导致尝试追踪语法错误.

通过dye用括号括起函数调用的参数,我可以在上面的程序中"修复"这个,我想我会完成程序并执行此操作.但这是Perl中的一个错误,或者(更可能是这种情况)我错过了关于Perl如何工作的内容吗?

mel*_*ene 6

此问题的根本原因是perl(基于yacc的)解析器尝试恢复并在发生错误后继续.这个策略背后的最初想法是运行编译器曾经是一个缓慢而昂贵的任务,所以你希望它在一次运行中捕获尽可能多的错误,而不仅仅是第一个错误.这就是为什么perl会在放弃并在一次打印之前将解析过程中遇到的错误排队的原因.

然而,与致命警告的不幸相互作用.编译器可以在编译时发出警告,并且致命警告会使其抛出异常.因此,如果解析器处于错误恢复模式并遇到致命警告,则会引发异常并且所有排队的实际错误都将丢失.

String found where operator expected消息是警告(类别syntax).通过致命所有警告,您已将其转换为异常,立即中止解析,丢失所有先前的错误.(顺便说一句,致命所有警告是一个坏主意:查看perldoc strictures哪些警告类别不安全致死.)

即使没有致命警告,您也可以看到某些内容不太正确:String found ...消息的行号为19,但它出现在第11行的语法错误之前.这是因为警告是立即发出的,而不是像解析错误那样排队.

这个问题被报告为bug#122966并在perl 5.22中修复.现在解析期间抛出的致命警告被视为解析错误并以相同方式排队.(作为副作用,它还使错误消息以正确的顺序出现:首先报告第一个错误.)

所以,是的,这种行为是perl中的一个错误,但是已经在以后的版本中修复了.

  • @BillEvansatMariposa第11行出错后,perl进入错误恢复模式.在这种模式下,`sub`定义是"neutered",子程序没有添加到符号表中,所以`sub dye {}`实际上是一个no-op.这就是为什么在最后一行`dye`无法解析和`染色'......"`是一个解析错误. (2认同)