为什么该程序有效?我试图创建语法错误


489

我正在Windows 7上运行ActiveState的32位ActivePerl 5.14.2。我想弄乱Git预提交钩子来检测正在检查的语法错误程序。(以某种方式,我只是设法做出了这样的错误提交。)因此,作为测试程序,我随机记下了这一点:

use strict;
use warnings;

Syntax error!

exit 0;

但是,它编译并执行时没有任何警告,并且退出时错误级别为零。这个有效的语法如何?


121
您只是证明在perl中键入随机单词会产生有效的程序吗?!!?!?!?!
彼得M

10
@PeterM几乎没有随机的单词。我证明我对Perl语法不了解。现在我知道更多了。
比尔·鲁伯特

10
您可能想no indirect阻止这些事件的发生
LeoNerd 2014年

@LeoNerd感谢您的提示!
比尔·鲁伯特

1
这是有史以来最著名的 perl问题。甚至whatever / 25 ; # / ; die "this dies!";
更像

Answers:


540

Perl的语法称为“间接方法表示法”。它允许

Foo->new($bar)

被写成

new Foo $bar

所以这意味着

Syntax error ! exit 0;

是相同的

error->Syntax(! exit 0);

要么

error->Syntax(!exit(0));

它不仅是有效的语法,而且不会导致运行时错误,因为执行的第一件事是exit(0)


1
@哈桑,为什么?其后是一个表达式。
ikegami 2012年

3
我读到的内容是“语法错误!退出0;”,但我没有考虑间接调用。花了很多时间忘记了!
比尔·鲁伯特

6
@Hassan,以这种方式考虑,!exit(0)再也不能是类型错误,而!$x不能输入任何错误。
ikegami 2012年

11
@Hassan,该语言具有类型。具体来说,值具有类型。运算符和subs完全不限于返回特定类型的值。事实证明,这非常有用,而且花费很少(感谢警告)。
ikegami,2012年

6
@Nawaz,它实际上很受欢迎。它使用的每个人都在Java和C ++结构对象,以及大量的Perl程序员使用的new Classprint $fh ...,而不是Class->new(...)$fh->print(...)。我会向您保证,这会导致奇怪的错误消息
ikegami 2012年

112

我不知道为什么,但这就是Perl所做的:

perl -MO=Deparse -w yuck
BEGIN { $^W = 1; }
use warnings;
use strict 'refs';
'error'->Syntax(!exit(0));
yuck syntax OK

似乎解析器认为您正在调用-object ... Syntax上的方法,error确实很奇怪!


3
那是间接的方法调用语法。之所以在这里工作,exit(0)是因为首先评估,使程序在尝试将结果传递给之前退出'error'->Syntax()
duskwuff -inactive- 2012年

6
Perl似乎采用了“间接(对象)语法”,通常用new Class代替Class->new()。要调用该方法Syntax,将exit执行该函数,因此永远不会发生运行时错误。
阿蒙2012年

118
恭喜你 您找到了一个需要添加分号才能使编译失败的程序。
暴民

use strict; use warnings; error->Syntax(! print "hi"); 收益率:语法perl -MO = Deparse也可以,但use warnings由于它可以指出未加载,因此它应该说些什么。而是抛出运行时错误“找不到对象方法..”。

53

您没有收到错误的原因是,第一个执行的代码是

exit(0);

因为您在第一行没有分号:

Syntax error!

编译器将(错误地)猜测这是一个带not操作符的子例程调用!。然后,它将执行该子例程的参数,恰好是exit(0),此时程序退出并将错误级别设置为0。 ,因此不会再报告运行时错误。

您会发现,如果更改exit(0)为类似的选项,print "Hello world!"则会收到错误消息:

Can't locate object method "Syntax" via package "error" ...

您的错误级别将设置为:

> echo %errorlevel%
255

7
>The compiler will guess (incorrectly) 编译器不能做任何错误的事情。
Liam Laverty 2015年

14
@LiamLaverty是的,可以。它可以错误地猜出人类的意思。
TLP

4
人是等式中不正确的人。编译器只能是“正确的”或“损坏的”。它对语言的定义或用户的意图没有意见。
Liam Laverty 2015年

4
@LiamLaverty如果可以在这种情况下猜测用户的意图,那将是一个非常简洁的编译器。因此,编译器无法正确猜测。您可能正在对我的声明进行一些技术性的行话分析,这可能是我添加的不正确的阅读方式。
TLP

这不是翻译吗?;-)
Rikki's

33

如上所述,这是由间接方法调用符号引起的。您可以对此发出警告:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

产生:

Indirect call of method "Syntax" on object "error" at - line 5.

这需要间接CPAN模块

您还可以使用它no indirect "fatal";来导致程序死机(这是我所做的)


8

试用Perl 6,它似乎更容易满足您的期望:

===SORRY!=== Error while compiling synerror.p6
Negation metaoperator not followed by valid infix
at synerror.p6:1
------> Syntax error!⏏<EOL>
    expecting any of:
        infix
        infix stopper

1

本文中,我们旨在回答编程语言社区中一个长期存在的开放性问题:是否可以在不创建有效Perl的情况下将油漆涂抹在墙上?

TLDR;几乎不


我喜欢那个。我可能需要扫描一些图片。
比尔·鲁伯特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.