Save the following program to
Illegal division by zero at /tmp/quine.pl line 1.
Run it with
perl /tmp/quine.pl and it prints its own source code.
It’s easy to make a “cheating quine” in many languages, where a syntax error in the source provokes the parser to emit an error message that matches the source. I posted several cheating quine examples on Twitter including
File "quine.py", line 1 File "quine.py", line 1 ^ IndentationError: unexpected indent
The Perl quine at the start of this post is a different kind of cheat:
the program parses OK, and it runs briefly until the division by zero
error is raised. It is quite sensitive to details of the filename: for
./quine.pl does not work.
This little program gets into a lot of perl’s do-what-I-mean parsing.
/ character is quite context-sensitive, and can be parsed as a
division operator or the start of a regex. Small perturbations of this
program make it into a regex parse error rather than runnable code. In
this case both
/ appear in an operator context.
The other non-words in this program are
1., which is just a number,
. which is the concatenation operator.
So what do the words mean?
Bare words in Perl can be subroutine names, method names, package or class names, or (in non-strict mode) un-delimited strings, and maybe other things I have forgotten!
Perl also has an unusual method invocation syntax called “indirect object syntax” which has the form
method object args
most frequently seen looking like
print $filehandle "message"; my $instance = new Class(args);
although Perl’s preferred syntax is
$filehandle->print("message"); my $instance = Class->new(args);
perlobj documentation says
To parse this code, Perl uses a heuristic based on what package names it has seen, what subroutines exist in the current package, what barewords it has previously seen, and other input. Needless to say, heuristics can produce very surprising results!
Starting from the right,
pl line 1.
is parsed as the method call
line is a package (class) name and
pl is the method.
In the middle of the program,
quine are parsed
as barewords, i.e. strings. The expression parses as:
(("at" / "tmp") / "quine") . line->pl(1.)
On the left there are two nested indirect object method calls,
division->Illegal(zero->by( ... ))
The innermost expression, which gets evaluated first, is
"at" / "tmp"
And this immediately raises a division by zero exception.