以下(大量精简版)代码有明显错误。
#!/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\"";
您希望错误消息为:
Global symbol "$error_phyle" requires explicit package name at example.pl line 11.
example.pl had compilation errors.
......但实际上......
String found where operator expected at example.pl line 19, near "dye "invalid verb \"$verb\"""
(请注意,第二条错误消息没有添加" example.pl有编译错误。"。)
在实际程序中,错误消息指向一行,距离实际错误数百行代码。错误的错误消息,指向错误的行,可能会导致尝试追踪语法错误。
我可以"修复"这个在上面的程序中用括号括起函数dye
的参数,我想我会完成这个程序。但这是Perl中的一个错误,或者(更可能是这种情况)我错过了关于Perl如何工作的内容吗?
答案 0 :(得分:6)
此问题的根本原因是perl(基于yacc的)解析器尝试恢复并在发生错误后继续。这个策略背后的最初想法是运行编译器曾经是一个缓慢而昂贵的任务,所以你希望它在一次运行中捕获尽可能多的错误,而不仅仅是第一个错误。这就是为什么perl会在放弃并在一次打印它们之前将解析过程中遇到的错误排队的原因。
然而,与致命警告的不幸相互作用。编译器可以在编译时发出警告,并且致命警告会使其抛出异常。因此,如果解析器处于错误恢复模式并遇到致命警告,则会抛出异常并且所有排队的实际错误都将丢失。
alias History = Tuple!(string, "gps", string, "sensor");
History historyTuple;
消息是警告(类别String found where operator expected
)。通过致命所有警告,您已将其变为异常,立即中止解析,丢失所有先前的错误。 (顺便说一句,致命所有警告都是一个坏主意:请参阅perldoc strictures
警告类别不安全致死。)
即使没有致命警告,您也可以看到某些内容并不完全正确:syntax
消息的行号为19,但它出现在第11行的语法错误之前。这是因为警告是立即发出,不像解析错误那样排队。
此问题报告为bug #122966并已在perl 5.22中修复。现在解析期间抛出的致命警告被视为解析错误并以相同方式排队。 (作为副作用,它还会使错误消息以正确的顺序出现:首先报告第一个错误。)
所以,是的,这种行为是perl中的一个错误,但是在以后的版本中已经修复了这个错误。
答案 1 :(得分:1)
您可以使用diagnostics pragma获取有关错误的更多信息。
diagnostics
Pragma该模块扩展了通常由两者发出的简洁诊断 perl编译器和perl解释器(从带有-w的perl运行) 切换或使用警告),用更多的解释来扩充它们 和
perldiag
中的可爱描述。像其他的pragmata, 它会影响程序的编译阶段而不仅仅是 执行阶段。要在程序中用作编译指示,只需调用use diagnostics;
程序的开始(或接近开始)。 (注意,这确实启用了perl的-w标志。)您的整个编译 然后将(ed :-)加入到增强型诊断中。这些仍然 走出STDERR。
根据您的评论:这也可以使旧版本的perl显示错误消息,这可以节省一些调试工作来查找真实错误的位置。