Skip to content

Instantly share code, notes, and snippets.

@Gro-Tsen
Created May 12, 2025 16:33
Show Gist options
  • Save Gro-Tsen/8ce3f62c0eafe6221ecbd2446a78fb02 to your computer and use it in GitHub Desktop.
Save Gro-Tsen/8ce3f62c0eafe6221ecbd2446a78fb02 to your computer and use it in GitHub Desktop.
A Perl program that prints a Python program that prints back this Perl program
#! /usr/bin/env perl
## This Perl program outputs a Python program that outputs this Perl
## program. The comments should hopefully make it clear how it all
## works and show that this there is nothing tricky going on.
## Written by David A. Madore on 2025-05-12. Public Domain
## See <http://www.madore.org/~david/computers/quine.html> for more on
## the art of writing quines without any tricks.
use strict;
use warnings;
# The variables $data_pre and $data_post contains a textual
# representation of everything up to the definition of $data_pre and
# everything after the definition of $data_post respectively.
# (Presentation is standardized as per print_as_data() below. To
# bootstrap the quine, format the representation however you like it,
# e.g. with a heredoc, then run the program once and it will
# standardize the representation.)
my $data_pre = "#! /usr/bin/env perl\n\n## This Perl program outpu"
. "ts a Python program that outputs this Perl\n## pr"
. "ogram. The comments should hopefully make it cl"
. "ear how it all\n## works and show that this there"
. " is nothing tricky going on.\n\n## Written by Davi"
. "d A. Madore on 2025-05-12. Public Domain\n\n## Se"
. "e <http://www.madore.org/~david/computers/quine."
. "html> for more on\n## the art of writing quines w"
. "ithout any tricks.\n\nuse strict;\nuse warnings;\n\n#"
. " The variables \$data_pre and \$data_post contains"
. " a textual\n# representation of everything up to "
. "the definition of \$data_pre and\n# everything aft"
. "er the definition of \$data_post respectively.\n# "
. "(Presentation is standardized as per print_as_da"
. "ta() below. To\n# bootstrap the quine, format th"
. "e representation however you like it,\n# e.g. wit"
. "h a heredoc, then run the program once and it wi"
. "ll\n# standardize the representation.)\n\n";
my $data_post = "# The variable \$mycode will reconstruct the text"
. "ual representation of\n# the entire program. The"
. " filehandle \$fh is used to conveniently\n# write "
. "into it.\nmy \$mycode;\nopen my \$fh, \">\", \\\$mycode;"
. "\n\nsub print_as_code {\n # Write argument as co"
. "de (i.e., directly).\n my \$s = shift;\n prin"
. "t \$fh \$s;\n}\n\nsub print_as_data {\n # Construct"
. " a string declaration of the first argument (the"
. "\n # variable being named as given by the seco"
. "nd argument).\n my \$s = shift;\n my \$name = "
. "shift;\n print \$fh \"my \\\$\$name = \";\n for ( "
. "my \$i=0 ; \$i<length(\$s) || \$i==0 ; \$i+=48 ) {\n\tm"
. "y \$chunk = substr(\$s, \$i, 48);\n\t# Escape some st"
. "uff that needs to be escaped:\n\t\$chunk =~ s/([\\\\\\"
. "\"\\\$\\\@\\\%])/\\\\\$1/g;\n\t\$chunk =~ s/\\t/\\\\t/g;\n\t\$chunk"
. " =~ s/\\n/\\\\n/g;\n\t\$chunk = \"\\\"\" . \$chunk . \"\\\"\";\n"
. "\tprint \$fh \"\\n . \" if \$i>0;\n\tprint \$fh \$chunk;\n"
. " }\n print \$fh \";\\n\\n\";\n}\n\n# Reconstruct ou"
. "r own code:\nprint_as_code \$data_pre;\nprint_as_da"
. "ta \$data_pre, \"data_pre\";\nprint_as_data \$data_po"
. "st, \"data_post\";\nprint_as_code \$data_post;\nclose"
. " \$fh;\n\n# Now we hold our own code in \$mycode. W"
. "hat do we want to do with it?\n\nsub pythonize {\n "
. " # Construct a Python program that produces th"
. "e given string as\n # output. Nothing smart h"
. "appens here!\n my \$s = shift;\n # Read strin"
. "g line by line:\n open my \$fh, \"<\", \\\$s;\n p"
. "rint \"#! /usr/bin/env python3\\n\";\n while (my "
. "\$line = <\$fh>) {\n\tchomp \$line;\n\t# Escape some st"
. "uff that needs to be escaped:\n\t\$line =~ s/([\\\\\\\""
. "\\'])/\\\\\$1/g;\n\t\$line =~ s/\\t/\\\\t/g;\n\t# Just outpu"
. "t a print command for each line!\n\tprint \"print(\\"
. "\"\", \$line, \"\\\")\\n\";\n }\n close \$fh;\n}\n\npyth"
. "onize \$mycode;\n";
# The variable $mycode will reconstruct the textual representation of
# the entire program. The filehandle $fh is used to conveniently
# write into it.
my $mycode;
open my $fh, ">", \$mycode;
sub print_as_code {
# Write argument as code (i.e., directly).
my $s = shift;
print $fh $s;
}
sub print_as_data {
# Construct a string declaration of the first argument (the
# variable being named as given by the second argument).
my $s = shift;
my $name = shift;
print $fh "my \$$name = ";
for ( my $i=0 ; $i<length($s) || $i==0 ; $i+=48 ) {
my $chunk = substr($s, $i, 48);
# Escape some stuff that needs to be escaped:
$chunk =~ s/([\\\"\$\@\%])/\\$1/g;
$chunk =~ s/\t/\\t/g;
$chunk =~ s/\n/\\n/g;
$chunk = "\"" . $chunk . "\"";
print $fh "\n . " if $i>0;
print $fh $chunk;
}
print $fh ";\n\n";
}
# Reconstruct our own code:
print_as_code $data_pre;
print_as_data $data_pre, "data_pre";
print_as_data $data_post, "data_post";
print_as_code $data_post;
close $fh;
# Now we hold our own code in $mycode. What do we want to do with it?
sub pythonize {
# Construct a Python program that produces the given string as
# output. Nothing smart happens here!
my $s = shift;
# Read string line by line:
open my $fh, "<", \$s;
print "#! /usr/bin/env python3\n";
while (my $line = <$fh>) {
chomp $line;
# Escape some stuff that needs to be escaped:
$line =~ s/([\\\"\'])/\\$1/g;
$line =~ s/\t/\\t/g;
# Just output a print command for each line!
print "print(\"", $line, "\")\n";
}
close $fh;
}
pythonize $mycode;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment