Remarque Lane: J'ai rencontré aujourd'hui sur Twitter un fil très drôle, à première vue. Et puis il a regardé de plus près et s'est rendu compte qu'il était non seulement drôle, mais aussi divertissant. Et comme il est arrivé qu'aujourd'hui soit vendredi, j'ai décidé qu'il valait la peine de partager les résultats avec mes camarades :)
Enregistrez le programme suivant dans /tmp/quine.pl
Illegal division by zero at /tmp/quine.pl line 1.
Exécutez-le avec la commande
perl /tmp/quine.pl
et elle sortira son propre code.
"Quake-tricks" est assez simple à composer dans de nombreux langages de programmation, où une erreur de syntaxe dans la source provoque un analyseur pour produire une erreur qui coïnciderait avec le code source du programme. J'ai
publié plusieurs de ces astuces sur Twitter , notamment les suivantes:
File "quine.py", line 1 File "quine.py", line 1 ^ IndentationError: unexpected indent
Mais l'orge perlé au début de cet article est une astuce d'un tout autre genre - le programme comprend
correctement .
Et ça ne marche pas longtemps, jusqu'à ce qu'on bute sur l'erreur de division par zéro. Ce quine est très sensible à la dénomination des fichiers - par exemple, l'exécution via ./quine.pl ne fonctionnera pas.
Donc, ce message d'erreur est en fait l'ensemble du programme?!
Ce programme utilise une grande partie de l'analyseur de perle-do-what-I-mean-parser.
Le symbole / est très dépendant du contexte d'application et peut être considéré comme un symbole de division ou comme le début d'une expression régulière. Et même de petits changements dans le code de ce programme conduisent à une erreur d'analyse de la régularité et non à l'exécution de code. Dans ce cas, les deux caractères / apparaissent dans le contexte de l'opérateur.
Les autres parties non-dictionnaires de ce programme sont
1.
, qui est interprétée simplement comme un nombre et
.
qui est un opérateur de concaténation.
Alors que signifient les mots?
Les mots en Perl peuvent être des noms de routines, de méthodes, de packages ou de classes. Ou (en mode paresseux) des lignes sans séparateur ou peut-être même quelque chose d'autre que j'ai oublié!
Perl utilise également une syntaxe d'appel de méthode inhabituelle appelée "
syntaxe d'objet indirect ", qui ressemble à ceci:
le plus souvent, vous pouvez voir comment
print $filehandle "message"; my $instance = new Class(args);
bien que pour Perl, la syntaxe suivante est préférable:
$filehandle->print("message"); my $instance = Class->new(args);
La documentation de
perlobj indique:
Perl utilise une heuristique pour analyser ce code, en fonction des noms de packages qu'il connaît, des sous-routines qui existent dans le package actuel, des mots qu'il a rencontrés auparavant et de l'analyse d'autres données d'entrée. Inutile de dire que l'heuristique peut produire des résultats très inattendus!
Comment analyse-t-il ce code?
Partir du côté droit
pl line 1.
analysé comme un appel de méthode
line->pl(1.)
où ligne est le nom du package (classe) et pl est la méthode.
Au milieu, "at", "tmp" et "quine" sont analysés comme des mots simples, c'est-à-dire cordes. L'expression est analysée comme suit:
(("at" / "tmp") / "quine") . line->pl(1.)
À gauche, deux appels de méthode indirecte repliés,
division->Illegal(zero->by( ... ))
L'expression interne exécutée en premier est:
"at" / "tmp"
Et cela provoque instantanément la division par zéro exception.