Warum ist dieses Programm gültig? Ich habe versucht, einen Syntaxfehler zu erstellen

489

Ich verwende ActiveStates 32-Bit- ActivePerl 5.14.2 unter Windows 7. Ich wollte mit einem Git-Pre-Commit-Hook herumspielen, um Programme zu erkennen, die mit Syntaxfehlern eingecheckt werden. (Irgendwie habe ich es gerade geschafft, ein so schlechtes Commit durchzuführen.) Als Testprogramm habe ich dies zufällig notiert:

use strict;
use warnings;

Syntax error!

exit 0;

Es wird jedoch ohne Warnungen kompiliert und ausgeführt, und die Fehlerstufe ist beim Beenden Null. Wie ist diese gültige Syntax?

Bill Ruppert
quelle
121
Haben Sie gerade bewiesen, dass das Eingeben von zufälligen Wörtern in Perl zu Arbeitsprogrammen führt?!?!?!?!
Peter M
10
@PeterM Kaum zufällige Wörter. Ich habe bewiesen, dass ich nicht genug über Perl-Syntax weiß. Jetzt weiß ich ein bisschen mehr.
Bill Ruppert
10
Sie möchten wahrscheinlich verhindern, dass no indirectdiese passieren
LeoNerd
@LeoNerd Danke für den Tipp!
Bill Ruppert
1
Dies ist die berühmteste Perl-Frage aller Zeiten. Noch besser als Schwartz 'Ausschnitt :whatever / 25 ; # / ; die "this dies!";
jm666

Antworten:

540

Perl hat eine Syntax namens "indirekte Methodennotation". Es erlaubt

Foo->new($bar)

geschrieben werden als

new Foo $bar

Das bedeutet also

Syntax error ! exit 0;

ist das gleiche wie

error->Syntax(! exit 0);

oder

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

Es ist nicht nur eine gültige Syntax, es führt auch nicht zu einem Laufzeitfehler, da als erstes ausgeführt wird exit(0).

Ikegami
quelle
1
@ Hassan, warum? Es folgt ein Ausdruck.
Ikegami
3
Ich habe es sogar als "Syntaxfehler! Exit 0;" gelesen, aber ich habe nicht über einen indirekten Aufruf nachgedacht. Verbrachte viel Zeit damit, das zu vergessen!
Bill Ruppert
6
@ Hassan, denken Sie so, !exit(0)kann nicht mehr ein !$xTippfehler sein, als da beide nicht getippt sind.
Ikegami
11
@ Hassan, Die Sprache hat Typen. Insbesondere haben Werte Typen. Operatoren und Subs sind einfach nicht darauf beschränkt, bestimmte Wertetypen zurückzugeben. Dies erweist sich bei geringen Kosten als sehr nützlich (dank Warnungen).
Ikegami
6
@Nawaz, es ist eigentlich sehr beliebt. Es wird von jedem verwendet, der Objekte in Java und C ++ erstellt, und von einer großen Anzahl von Perl-Programmierern, die new Classund print $fh ...anstelle von Class->new(...)und verwenden $fh->print(...). Ich werde Ihnen gewähren, dass es eine seltsame Fehlermeldung verursacht
Ikegami
112

Ich weiß nicht warum, aber das macht Perl daraus:

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

Es scheint, dass der Parser denkt, Sie rufen die Methode Syntaxfür das errorObjekt auf ... In der Tat seltsam!

pavel
quelle
3
Das ist die indirekte Syntax von Methodenaufrufen. Es funktioniert hier (irgendwie), weil das exit(0)zuerst ausgewertet wird und das Programm beendet wird, bevor es versucht, das Ergebnis an zu übergeben 'error'->Syntax().
Abenddämmerung -inaktiv-
6
Perl scheint die "indirekte (Objekt-) Syntax" anzunehmen, die normalerweise wie new Classanstelle von verwendet wird Class->new(). Um die Methode aufzurufen Syntax, wird die exitFunktion ausgeführt, sodass der Laufzeitfehler nie auftritt.
Amon
118
Herzliche Glückwünsche. Sie haben ein Programm gefunden, in dem Sie ein Semikolon hinzufügen müssen, damit die Kompilierung fehlschlägt.
Mob
use strict; use warnings; error->Syntax(! print "hi"); Ausbeuten: Syntax Ok auch für Perl -MO = Deparse, aber use warningsdamit sollte wahrscheinlich etwas gesagt werden, da es herausfinden kann, dass es nicht geladen wird. Stattdessen wird ein Laufzeitfehler "Objektmethode kann nicht gefunden werden ..." ausgegeben.
53

Der Grund, warum Sie keinen Fehler erhalten, ist, dass der erste ausgeführte Code ist

exit(0);

Weil Sie in der ersten Zeile kein Semikolon hatten:

Syntax error!

Der Compiler vermutet (fälschlicherweise), dass dies ein Unterprogrammaufruf mit einem eingeworfenen notOperator ist !. Anschließend führt er die Argumente für dieses Unterprogramm aus. Zu diesem exit(0)Zeitpunkt wird das Programm beendet und die Fehlerstufe auf 0 gesetzt. Es wird nichts anderes ausgeführt , werden also keine Laufzeitfehler mehr gemeldet.

Sie werden feststellen, dass beim Wechsel exit(0)zu etwas wie print "Hello world!"Ihnen eine Fehlermeldung angezeigt wird:

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

und Ihre Fehlerstufe wird eingestellt:

> echo %errorlevel%
255
TLP
quelle
7
>The compiler will guess (incorrectly) Der Compiler kann nichts falsch machen.
Liam Laverty
14
@ LiamLaverty Ja, das kann es. Es kann falsch erraten, was der Mensch meinte.
TLP
4
Der Mensch ist der Falsche in der Gleichung. Der Compiler kann nur "korrekt" oder "defekt" sein. Es wird keine Meinung zur Definition der Sprache oder zur Absicht eines Benutzers abgegeben.
Liam Laverty
4
@LiamLaverty Es wäre ein ziemlich ordentlicher Compiler, wenn er die Absicht des Benutzers in diesem Fall erraten könnte, ja. Daher kann der Compiler nicht richtig raten. Möglicherweise führen Sie eine technische Fachjargonanalyse meiner Aussage durch, die, wie ich hinzufügen möchte, die falsche Art ist, sie zu lesen.
TLP
Ist es nicht ein Dolmetscher? ;-)
Rikki
33

Wie oben erwähnt, wird dies durch die indirekte Methode verursacht, die die Notation aufruft. Sie können darauf warnen:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produziert:

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

Dies erfordert das indirekte CPAN-Modul .

Sie können auch verwenden no indirect "fatal";, um das Programm zum Absterben zu bringen (das ist, was ich tue)

Mark Fowler
quelle
8

Probieren Sie Perl 6 aus , es scheint Ihre Erwartungen leichter zu erfüllen:

===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
moritz
quelle
1

In diesem Artikel möchten wir ein seit langem offenes Problem in der Programmiersprachen-Community beantworten: Ist es möglich, Farbe an die Wand zu streichen, ohne gültiges Perl zu erstellen?

TLDR; Kaum

Holli
quelle
Ich liebe das. Möglicherweise muss ich einige Bilder einscannen.
Bill Ruppert