Pourquoi ce programme est-il valable? J'essayais de créer une erreur de syntaxe


489

J'exécute ActivePerl 5.14.2 32 bits d' ActiveState sur Windows 7. Je voulais jouer avec un crochet de pré-validation Git pour détecter les programmes en cours d'enregistrement avec des erreurs de syntaxe. (D'une manière ou d'une autre, j'ai juste réussi à faire un mauvais commit.) Donc, en tant que programme de test, j'ai noté au hasard ceci:

use strict;
use warnings;

Syntax error!

exit 0;

Cependant, il compile et s'exécute sans avertissement et le niveau d'erreur est nul à la sortie. Comment est cette syntaxe valide?


121
Vous venez de prouver que taper des mots aléatoires en perl produit des programmes de travail ??!?!?!?!
Peter M

10
@PeterM Mots peu aléatoires. J'ai prouvé que je ne connaissais pas assez la syntaxe Perl. Maintenant j'en sais un peu plus.
Bill Ruppert

10
Vous voulez probablement no indirectempêcher ces événements de se produire
LeoNerd

@LeoNerd Merci pour le conseil!
Bill Ruppert

1
C'est la question Perl la plus connue de tous les temps. Encore mieux que l'extrait de Schwartz :whatever / 25 ; # / ; die "this dies!";
jm666

Réponses:


540

Perl a une syntaxe appelée "notation de méthode indirecte". Il permet

Foo->new($bar)

être écrit comme

new Foo $bar

Donc ça signifie

Syntax error ! exit 0;

est le même que

error->Syntax(! exit 0);

ou

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

Non seulement sa syntaxe est valide, mais elle n'entraîne pas d'erreur d'exécution car la première chose exécutée est exit(0).


1
@Hassan, pourquoi? Elle est suivie d'une expression.
ikegami

3
Je suis allé jusqu'à le lire comme "Erreur de syntaxe! Exit 0;", mais je n'ai pas pensé à l'invocation indirecte. J'ai passé beaucoup de temps à oublier ça!
Bill Ruppert

6
@Hassan, Pensez-y de cette façon, !exit(0)ne peut pas plus être une erreur de type que !$xpuisque ni l'un ni l'autre ne sont tapés.
ikegami

11
@Hassan, La langue a des types. Plus précisément, les valeurs ont des types. Les opérateurs et les sous-marins ne sont tout simplement pas limités à renvoyer des types de valeurs spécifiques. Cela s'avère très utile à peu de frais (grâce aux avertissements).
ikegami

6
@Nawaz, c'est en fait assez populaire. Il est utilisé par tous ceux qui construisent des objets en Java et C ++, et par un grand nombre de programmeurs Perl qui utilisent new Classet print $fh ...au lieu de Class->new(...)et $fh->print(...). Je vous accorde que cela provoque des messages d'erreur étranges, cependant
ikegami

112

Je ne sais pas pourquoi, mais c'est ce que Perl en fait:

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

Il semble que l'analyseur pense que vous appelez la méthode Syntaxsur le error-object ... Étrange en effet!


3
C'est la syntaxe d'appel de méthode indirecte. Cela fonctionne (en quelque sorte) ici car le exit(0)est évalué en premier, ce qui fait que le programme se termine avant d'essayer de transmettre le résultat à 'error'->Syntax().
duskwuff -inactive-

6
Perl semble assumer la "syntaxe indirecte (objet)", généralement utilisée comme new Classau lieu de Class->new(). Pour appeler la méthode Syntax, la exitfonction est exécutée, donc l'erreur d'exécution ne se produit jamais.
amon

118
Toutes nos félicitations. Vous avez trouvé un programme dans lequel vous devez ajouter un point-virgule pour que la compilation échoue.
mob

use strict; use warnings; error->Syntax(! print "hi"); Donne: Syntaxe Ok sur perl -MO = Deparse aussi, mais avec use warningselle devrait probablement dire quelque chose car il peut comprendre que ce n'est pas en cours de chargement. Au lieu de cela, il génère une erreur d'exécution "Impossible de localiser la méthode d'objet ..".

53

La raison pour laquelle vous n'obtenez pas d'erreur est que le premier code exécuté est

exit(0);

Parce que vous n'aviez pas de point-virgule sur la première ligne:

Syntax error!

Le compilateur devinera (à tort) qu'il s'agit d'un appel de sous-programme avec un notopérateur !ajouté. Il exécutera ensuite les arguments de ce sous-programme, qui se trouve être exit(0), à quel moment le programme se termine et définit le niveau d'erreur à 0. Rien d'autre n'est exécuté , donc plus aucune erreur d'exécution n'est signalée.

Vous remarquerez que si vous passez exit(0)à quelque chose comme print "Hello world!"vous obtenez une erreur:

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

et votre niveau d'erreur sera défini:

> echo %errorlevel%
255

7
>The compiler will guess (incorrectly) Le compilateur ne peut rien faire de mal.
Liam Laverty

14
@LiamLaverty Oui, c'est possible. Il peut deviner incorrectement ce que l'humain voulait dire.
TLP

4
L'humain est incorrect dans l'équation. Le compilateur ne peut être que "correct" ou "cassé". Il n'obtient pas d'opinion sur la définition de la langue ou l'intention d'un utilisateur.
Liam Laverty

4
@LiamLaverty Ce serait un compilateur assez soigné s'il pouvait deviner l'intention de l'utilisateur dans ce cas, oui. Par conséquent, le compilateur ne peut pas deviner correctement. Vous faites peut-être une analyse du jargon technique de ma déclaration, qui est, je pourrais ajouter, la mauvaise façon de la lire.
TLP

N'est-ce pas un interprète? ;-)
Rikki

33

Comme indiqué ci-dessus, cela est dû à la méthode indirecte appelant la notation. Vous pouvez avertir à ce sujet:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produit:

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

Cela nécessite le module CPAN indirect .

Vous pouvez également utiliser no indirect "fatal";pour provoquer la mort du programme (c'est ce que je fais)


8

Essayez Perl 6 , il semble répondre plus facilement à vos attentes:

===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

Dans ce article , nous visons à répondre à un problème ouvert de longue date dans la communauté des langages de programmation: est-il possible d'étaler de la peinture sur le mur sans créer de Perl valide?

TLDR; À peine


J'aime ça. Je devrai peut-être numériser certaines images.
Bill Ruppert
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.