このプログラムはなぜ有効なのですか?構文エラーを作成しようとしました


489

私はActiveStateの32ビットActivePerl 5.14.2をWindows 7で実行しています。構文エラーでチェックインされているプログラムを検出するために、Gitのプリコミットフックをいじくり回したいと思いました。(どういうわけか私はなんとかそのような悪いコミットをすることができました。)それで私はテストプログラムとしてこれをランダムに書きました:

use strict;
use warnings;

Syntax error!

exit 0;

ただし、警告なしでコンパイルおよび実行され、終了時のエラーレベルはゼロです。この有効な構文はどうですか?


121
perlにランダムな単語を入力すると、動作するプログラムが生成されることを証明しただけですか??!?!?!?!
Peter M

10
@PeterMほとんどランダムな単語。私はPerl構文について十分に知らないことを証明しました。今、私はもう少し知っています。
Bill Ruppert

10
あなたはおそらくno indirectそれらの出来事を阻止したいでしょう
LeoNerd 14年

@LeoNerd先端をありがとう!
Bill Ruppert

1
これは、これまでで最も有名な Perlの質問です。シュワルツのスニペットとしてさらに良い:whatever / 25 ; # / ; die "this dies!";
jm666

回答:


540

Perlには、「間接メソッド表記」と呼ばれる構文があります。それはできます

Foo->new($bar)

と書かれる

new Foo $bar

つまり

Syntax error ! exit 0;

と同じです

error->Syntax(! exit 0);

または

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

有効な構文であるだけでなく、最初に実行されるのはであるため、実行時エラーにはなりませんexit(0)


1
@ハッサン、なぜ?その後に式が続きます。
池上

3
「Syntax error!exit 0;」と読むことはできましたが、間接呼び出しについては考えていませんでした。それを忘れて多くの時間を費やしました!
Bill Ruppert、2007

6
@ハッサン、このように考えてください。どちらもタイプされていない!exit(0)ので、タイプエラーになることはありません!$x
池上

11
@ハッサン、言語にはタイプがあります。具体的には、値にはタイプがあります。演算子とサブルーチンは、特定のタイプの値を返すことに限定されません。これは少しのコストで非常に便利であることがわかりました(警告のおかげです)。
池上2012

6
@Nawaz、それは実際にかなり人気があります。JavaとC ++でオブジェクトを構築するすべての人、およびnew Classandのprint $fh ...代わりにClass->new(...)and を使用する多数のPerlプログラマーが使用し$fh->print(...)ます。私はかかわらず、それは奇妙なエラーメッセージが発生することを許可する
池上

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()。メソッドを呼び出すにはSyntaxexit関数が実行されるため、実行時エラー決してoccures。
2012

118
おめでとう。コンパイルを失敗させるためにセミコロンを追加する必要があるプログラムを見つけました。
mob

use strict; use warnings; error->Syntax(! print "hi"); 収量:perl -MO = Deparseでも構文Ok 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 2015年

4
人間は方程式の中で正しくない人です。コンパイラは、「正しい」または「壊れた」だけである場合があります。言語の定義やユーザーの意図についての意見は得られません。
Liam Laverty 2015年

4
@LiamLavertyこの場合、ユーザーの意図を推測できれば、かなりきちんとしたコンパイラになります。したがって、コンパイラは正しく推測できません。あなたは私の声明のいくつかの専門的な専門用語の分析を行っているかもしれません、つまり、私はそれを読む間違った方法です。
TLP 2015年

通訳じゃないですか?;-)
Rikki

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; ほとんどない


私はそれが好きです。一部の画像をスキャンする必要がある場合があります。
ビルルパート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.