fanf: (Default)
[personal profile] fanf

Save the following program to /tmp/quine.pl

    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 example ./quine.pl does not work.

This error message is a program?!

This little program gets into a lot of perl's do-what-I-mean parsing.

The / 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, and . 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);

The 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!

How does it parse?

Starting from the right,

    pl line 1.

is parsed as the method call

    line->pl(1.)

where line is a package (class) name and pl is the method.

In the middle of the program, at, tmp, and 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.

This account has disabled anonymous posting.
(will be screened if not on Access List)
(will be screened if not on Access List)
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

June 2025

S M T W T F S
1234567
891011121314
15161718192021
22232425262728
2930     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated 2025-06-08 22:17
Powered by Dreamwidth Studios