This is my humble interpretation at it.
#!/usr/bin/perl
use strict;
## verbosity
my $debug = 0;
# slurp mode, in case we receive a filename
undef $/;
## if there's a filename, read its contents into $_. Otherwise, decode
+ the
## __DATA__. I didn't delve into this as there are no apparent surpris
+es,
## but I must admit that I needed a -MO=Deparse to get to that 's<>><\
+>>e'
## thingy. I still don't understand how can it be equivalent to
## 's//<ARGV>;/e'.
!@ARGV ? $_ = "@{[
map {
chr ($_+43+($_&4)*(3.25+$_%2*7.5))
} map {
(7&-32+ord,-32+ord>>3)
} (<DATA> =~ /[ -_]/g)
]}" : s//<ARGV>;/e;
print "bf program in \$_: $_\n" if $debug;
## with $temp, I deobfuscated $_{$*}, which is initially unset
my $temp;
my %bfhash;
## build the hash %bfhash (character => action, character => action, .
+..)
map {
if ($temp) {
## if $temp has something, this is an even pass, so $_ contains an
## action. Store it into $bfhash{$temp} and cleverly unset $temp a
+t the
## same time
($bfhash{$temp}, $temp) = $_;
} else {
## if $temp hasn't anything, this is an odd pass. Store the bf
## command into it.
$temp = $_;
}
## return a list (character, action, character, action, ...)
## '$&' in the action gets replaced with '$_[$_]'. Deep magic here.
} map {
## $& becomes the first character in each word
/./;
## this eval assigns '$_[$_]' to another instance of $& (the one ins
+ide
## eval scope).
## $' is $POSTMATCH in English, i.e. all characters following $&. Si
+nce $&
## is the first one, $' is everything starting with the second.
## Now, if $' contains the string '$&', it gets replaced with the va
+lue
## that $& has inside the eval, that is, it becomes '$_[$_]'.
($&, eval "q;\$_[\$_]; =~ m'.*'; qq($')")
## this is a list of words which map each character in the brainf*ck
## language into some Perl code. Notice that there are 8 words, and th
+e
## first character of each is one brainf*ck command
} qw/+++$&
,$&=ord+getc;$&$'if!defined$&
---$&
<--\$_
>++\$_
[while($&){
]}
.print(chr$&)
/;
if ($debug) {
use Data::Dumper;
print Data::Dumper->Dump ([\%bfhash], [qw/bfhash/]), "\n";
}
## build the Perl program from $_ and %bfhash. Unset $_.
my @pp;
$_ = !( @pp = (q[@_=()], map $bfhash{$_}, split //) );
## we're going to interpolate @pp into double quotes and want to separ
+ate
## each piece of Perl code with ';'
$" =~ s//;/;
## finally run our Perl code
print "Perl code: @pp\n\n" if $debug;
eval "@pp";
__DATA__
UP DZ6U5&&DGJR@WV5$DPVG\DLRVP@D\VVCLR&&D\NBP6\&CD5VP@DWV:#D5VP&DDW>
>54DPVW5$4VG42S5&DRGBLR&&D\V#@EPR@WSKBBP^$8 V5DP^D 32:@LR&DW>$K2BPG:
| [reply] [d/l] |
Yup, very nice detailed explanation, and there aren't really any surprises in the actual BF interpretation.
## but I must admit that I needed a -MO=Deparse to get to that 's<>><\
+>>e'
## thingy. I still don't understand how can it be equivalent to
## 's//<ARGV>;/e'.
s<>><\>>e is a s///e where the first pair of delimiters is <>, and the second pair is >>. The replacement eval is <>, because the \ in <\> gets removed earlier as it's right before the same character as the delimiter. It's the same form as s()/<>/e.
I hope you liked it.
| [reply] [d/l] [select] |