Phase 1:
I ran the code through
perltidy and then through
perl -MO=Deparse. I appended to each tidied line the corresponding deparse output after a
#. Key to understanding what's going on here is the fact that a bareword is a subroutine call only after the subroutine is declared.
#!/usr/bin/perl
STDOUT; # '???';
{ # {
END { BEGIN } # sub END { (); }
BEGIN { STDOUT } # sub BEGIN { 'STDOUT'; }
STDOUT; # '???';
STDIN; # '???';
} # }
{ # {
FINISH; # '???';
END { print "hacker," } # sub END { print 'hacker,'; }
END;
STDOUT(); # STDOUT();
BEGIN;
OK; # '???';
sub ::END { print " " } # sub END { print ' '; }
sub SDTOUT { # sub SDTOUT {
local $_ = "@_"; # local $_ = "@_";
SUB; # '???';
BUS(@_); # &BUS(@_);
SDINT; # 'SDINT';
} # }
sub BUS ($;) { print @_ } # sub BUS ($;) { print @_; } ;
}; # }
sub print { print } # sub print { print $_; }
sub STDOUT { print "Just" } # sub STDOUT { print 'Just'; }
{ # {
{ # {
BEGIN { # sub BEGIN {
$SUB = sub { # $SUB = sub {
print @_; # print @_;
0; # 0;
} # } ;
} # }
sub SUB { END; STDERR; SUB; print } # sub SUB { '???'; '???';
+print $_; }
$_ = $"; # $_ = $";
} # }
END { # sub END {
{ # {
SUB && &$SUB(another) || &print; # &print unless SUB and
+&$SUB('another');
Perl; # '???';
STDIN; # '???';
Perl; # '???';
SDTOUT Perl; # SDTOUT 'Perl';
sub STDIN { } # sub STDIN { (); } ;
} # }
} # } ;
} # }
{ *BEING = BEGIN } # { *BEING = 'BEGIN'; }
{ END } # {sub END ; ;};
STDERR; # '???';
Phase 2: We remove all the constants in void context and empty
BEGIN; and
END; statements.
#!/usr/bin/perl
{ # {
END { BEGIN } # sub END { (); }
BEGIN { STDOUT } # sub BEGIN { 'STDOUT'; }
} # }
{ # {
END { print "hacker," } # sub END { print 'hacker,'; }
STDOUT(); # STDOUT();
sub ::END { print " " } # sub END { print ' '; }
sub SDTOUT { # sub SDTOUT {
local $_ = "@_"; # local $_ = "@_";
BUS(@_); # &BUS(@_);
SDINT; # 'SDINT';
} # }
sub BUS ($;) { print @_ } # sub BUS ($;) { print @_; } ;
}; # }
sub print { print } # sub print { print $_; }
sub STDOUT { print "Just" } # sub STDOUT { print 'Just'; }
{ # {
{ # {
BEGIN { # sub BEGIN {
$SUB = sub { # $SUB = sub {
print @_; # print @_;
0; # 0;
} # } ;
} # }
sub SUB { print } # sub SUB { print $_; }
$_ = $"; # $_ = $";
} # }
END { # sub END {
{ # {
SUB && &$SUB(another) || &print; # &print unless SUB and
+&$SUB('another');
SDTOUT Perl; # SDTOUT 'Perl';
sub STDIN { } # sub STDIN { (); } ;
} # }
} # } ;
} # }
{ *BEING = BEGIN } # { *BEING = 'BEGIN'; }
Phase 3: We remove the first
END block and the first
BEGIN block (and the enclosing braces) since they don't do anything. We remove the return value of
SDTOUT subroutine since it is never used. We also remove the
local $_ = "@_" statement since
$_ is not used again in that scope. We remove the
STDIN subroutine since it is never called. We remove the initialization of
*BEING since it is never used.
#!/usr/bin/perl
{ # {
END { print "hacker," } # sub END { print 'hacker,'; }
STDOUT(); # STDOUT();
sub ::END { print " " } # sub END { print ' '; }
sub SDTOUT { # sub SDTOUT {
BUS(@_); # &BUS(@_);
} # }
sub BUS ($;) { print @_ } # sub BUS ($;) { print @_; } ;
}; # }
sub print { print } # sub print { print $_; }
sub STDOUT { print "Just" } # sub STDOUT { print 'Just'; }
{ # {
{ # {
BEGIN { # sub BEGIN {
$SUB = sub { # $SUB = sub {
print @_; # print @_;
0; # 0;
} # } ;
} # }
sub SUB { print } # sub SUB { print $_; }
$_ = $"; # $_ = $";
} # }
END { # sub END {
{ # {
SUB && &$SUB(another) || &print; # &print unless SUB and
+&$SUB('another');
SDTOUT Perl; # SDTOUT 'Perl';
} # }
} # } ;
} # }
Phase 4: We move the remaining
BEGIN and
END blocks to the beginning and end of the program to correspond to the order of execution. Note that
END blocks are executed in reverse order of their declaration. We also remove unnecessary braces since there are no local variables left.
BEGIN { # sub BEGIN {
$SUB = sub { # $SUB = sub {
print @_; # print @_;
0; # 0;
} # } ;
} # }
#!/usr/bin/perl
STDOUT(); # STDOUT();
sub SDTOUT { # sub SDTOUT {
BUS(@_); # &BUS(@_);
} # }
sub BUS ($;) { print @_ } # sub BUS ($;) { print @_; } ;
sub print { print } # sub print { print $_; }
sub STDOUT { print "Just" } # sub STDOUT { print 'Just'; }
sub SUB { print } # sub SUB { print $_; }
$_ = $"; # $_ = $";
END { # sub END {
SUB && &$SUB(another) || &print; # &print unless SUB and
+&$SUB('another');
SDTOUT Perl; # SDTOUT 'Perl';
} # } ;
sub ::END { print " " } # sub END { print ' '; }
END { print "hacker," } # sub END { print 'hacker,'; }
Execution proceeds as follows:
The
BEGIN block initializes
$SUB to refer to a subroutine that prints its arguments and returns false. In the body of the code
STDOUT is called and prints "Just". Various subroutines are defined and
$_ is set to
$" which is a space.
The first END block calls SUB which prints a space and returns true, so it calls &$SUB(another) which prints "another" and returns false, so it calls &print which prints a space again. It then calls SDTOUT Perl which prints "Perl" by way of BUS(@_).
The second
END block prints a space. The third
END block prints "hacker,".