http://qs321.pair.com?node_id=240797


in reply to 59 /e explained
in thread 59 /e

I'm confused about one thing. A lot of it I follow without your explanation, and your explanation makes most of the rest clear, but... well, whatever is going on with the print statement and the chr(shift) has me confounded.

Okay, first my own analysis up to the sticking point...

First thing I realise is that qw is semantically not very different from split, except that it always uses / +/ as the delimiting pattern.

So then, reading from the beginning...

First we set $s to ';pop' and clear $_ to the empty string. After the comment we do something funny with globs that apparently makes @_ and @ARGV synonymous. Then we set @_ (and thus @ARGV I think; yeah, ISTR that @ARGV is settable, but I think Perl allows that just for obfuscatory value) to that list of space-delimited strings. Finally, the substitution does all the work. For every e, apparently, it evaluates $s, and then it substitutes the final result into $_ presumably. So $s gets evaluated n times.

The real trick is figuring out how evaluating $s multiple times has the desired effect. Obviously it pops the last string (each time) off of @_ (also @ARGV), but then what?

How does this arrange for $_ to be evaluated each time?

[Consults camel re: pop()]

OOOOOH. Of course, pop returns the thing it pops off. (Duh.) Which then gets evaluated.

Hmmm... So the first e evaluates $s, which returns ';pop'; The next e evaluates _that_, which returns the last string in @_, namely, '@_=map{s|$|$s|s;$_}@_;pop'.

Err, I'm really not comfortable with map yet, so let's break that down. s|$|$s|s; is a normal substitution, probably not significantly different from s/$/$s/s; After the map the next string back is popped, so that's what gets returned to be evaluated next. But what did the map do?

[Consults camel re: map]

mmmkay, so we have (effectively): map { $_ =~ s/$/$s/s; return $_; }, @_;  pop; $ is of course the end of the string. Oh.

That explains the ; at the beginning of $s that didn't seem necessary before. map returns a list containing all the strings @_ had in it but with ';pop' appended to each one. But that's not what is returned to be evaluated, because pop comes after and pops off the next thing from @_ to be evaluated. What happens to the list map returns?

The camel doesn't say, but I'm supposing it must get assigned to @_, probably due to map's being called in void context. Woo. That makes sense, but is it documented anyplace?

Okay, so @_ now contains the following:

( '4a4a2bfe01ac410d0105f4fd0dae30150dfab448f90208fa0d98;pop', 'pop;pop', 'print+chr(shift);pop', 'print+chr(shift);pop', 'unshift@_,(shift()+shift())x2;pop', 'push@_,(pop,pop)x24;pop', ';;pop', 'unshift@_,(map{unpack'c',$_}split//)[0..25];pop', ';;pop', 's/../chr(hex$&)/eg;pop', );

Additionally, the pop returned '$_=substr(shift,0,52);pop' to be evaluated next. This stores the hex string in $_, removing it from @_, and pops the next string to be evaluated.

Evaluating 's/../chr(hex$&)/eg;pop' is easy enough to follow. $& is the last thing matched, and I just finished using hex in a japh, so we're converting the data in $_ from hex to ASCII. Then of course we pop the next command.

[Consults ASCII chart]

# Umm, let's write that hex string in bytepairs... # 4a 4a 2b fe 01 ac 41 0d 01 05 f4 fd 0d ae 30 15 # 0d fa b4 48 f9 02 08 fa 0d 98
Urgle, these data needs more processing... lots of those aren't printable chars.

Anyway, ;;pop must just be padding to make the lines come out (right?), because I can't figure what it would do other than pop the next string to be evaluated. Which is 'unshift@_,(map{unpack'c',$_}split//)[0..25];pop'

I think we're taking a slice of a list (26 elements worth) and prepending it back to @_ for storage, then we pop the next string for evaluation. Okay, so what's this list we're taking 26 elements from? It comes from splitting $_ (the messy data above) into chars, unpacking each one, and returning that as a list. The unshift takes the slice in list context and prepends all of it to @_ as separate elements, so our @_ now has all those unpacked chars as individual elements.

Now, about that unpacking... 'c' means [consults Camel] a signed char value. That means we're getting numbers from -127 to 127, I guess, or approximitely like that. I can never remember exactly what the bounds are. It doesn't matter here since there are no values very close to 127 anyway.

We're now getting those data as signed (decimal) values. Here's a conversion chart:

4a 4a 2b fe 01 ac 41 0d 01 05 f4 fd 0d 74 74 43 -2 1 -84 65 13 1 5 -12 -3 13 ae 30 15 0d fa b4 48 f9 02 08 fa 0d 98 -82 48 21 13 -6 -76 72 -7 2 8 -6 13 -104

mmmkay, so next instruction (after the NOP) is 'push@_,(pop,pop)x24;pop' Whooooah. The first two pops get these...

And here's where I get lost...

# 'unshift@_,(shift()+shift())x2;pop', # 'print+chr(shift);pop' # Apparently we construct an anonymous list out of those, repeat it 24 # times, and push it (flattened, presumably) onto the tail end of @_. # This means that the next 48 instructions (err, 49) will be those two # instructions alternating. Since the first is pushed first, the # second will be popped first. Also last since It's repeated again # just above the two instructions we popped off to repeat. # WTF is that doing? # Okay, break it down... # print with no args prints $_ on STDOUT and returns... what? # [consults Camel] # print returns 1 if successful, 0 otherwise. # So we're printing $_, removing the next char from the # beginning of @_, taking its numeric value, adding one # to it (or possibly 0, but I think 1), and... throwing # that value away? What? # Also, what's on $_? Isn't it still the messy unprocessed ASCII # version of those hex data? I thought we were done with that after # we converted it and threw the result on @_? But here we're throwing # away the converted data from @_ and going back to (repeatedly) # printing $_? # HUH? # [Consults camel] # [Consults camel more] # [Consults camel yet more] # Losted am I.

Replies are listed 'Best First'.
Re: Confused about one thing (Re: 59 /e explained)
by Anonymous Monk on Mar 06, 2003 at 03:43 UTC
    Err, I (jonadab) posted that. I swear I was logged in when I hit "reply". I'd just voted on a node not twenty minutes previous. So, err, if anyone replies, /msg me. Thanks.