Note Per.: I met today on Twitter a very funny, at first glance, thread. And then I looked and realized that he was not only funny, but also entertaining. And since it so happened that today is Friday, I decided that it was worth sharing what I found with my comrades :)
Save the following program in /tmp/quine.pl
')
Illegal division by zero at /tmp/quine.pl line 1.
Run it with a command
perl /tmp/quine.pl
and she will output her own code.
“Fines” is quite easy to write in many programming languages, where the syntax error in the source code provokes the parser to output an error that would coincide with the source code of the program. I
posted a few of these “tricks” on Twitter , including the following:
File "quine.py", line 1 File "quine.py", line 1 ^ IndentationError: unexpected indent
But the pearl barley quine at the beginning of this note is a snag of a completely different kind - the program is
correctly parsed.
And it does not work long, until it stumbles over the error of dividing by zero. This quine is very sensitive to the naming of the file - for example, launching via ./quine.pl will not work.
So this error message is actually a whole program ?!
This program uses a lot of barley-do-what-I-mean-parser.
The symbol / is very dependent on the context of application and can be regarded as a division symbol, or as the beginning of a regular expression. And even small changes in the code of this program lead to regular parsing error, and not to code execution. In this case, both / characters appear in the context of the statement.
Other non-vocabulary parts of this program are
1.
, which is interpreted simply as a number and
.
which is the concatenation operator.
Then what do the words mean?
Perl words can be subroutine, method, package, or class names. Or (in a non-strict mode) with lines without a separator or maybe even something else that I forgot about!
Perl also uses an unusual method call syntax, called "
indirect object syntax, " which looks like this:
most often can be seen as
print $filehandle "message"; my $instance = new Class(args);
although the following syntax is preferred for Perl:
$filehandle->print("message"); my $instance = Class->new(args);
Perlobj documentation states:
To parse this code, Perl uses heuristics based on which package names are known to it, which subroutines exist in the current package, which words he had met before and by analyzing other input data. Needless to say, heuristics can produce very unexpected results!
How does he parse this code?
Starting from the right side
pl line 1.
understands how to call a method
line->pl(1.)
where line is the name of the package (class), and pl is the method.
In the middle “at”, “tmp” and “quine” are understood as simple words, i.e. lines. The expression is disassembled as follows:
(("at" / "tmp") / "quine") . line->pl(1.)
On the left are two folded indirect method calls,
division->Illegal(zero->by( ... ))
The first internal expression to execute is:
"at" / "tmp"
And this instantly causes the elimination of division by zero.