Just for completeness (if I'm collecting, maybe someone else is too), here's the way I worked this one out (and also Russ's explanation). My solution was similar to Michael Schwern's but I concentrated on different aspects. (I never calculated the precise character translation table. cool) > #!/usr/bin/perl -- Russ Allbery, Just Another Perl Hacker > $^=q;@!>~|{>krw>yn{u<$$<[~||<Juukn{=,<S~|}<Jwx}qn{<Yn{u<Qjltn{ > 0gFzD gD, > 00Fz, 0,,( 0hF 0g)F/=, 0> "L$/GEIFewe{,$/ 0C$~> "@=,m,|,(e 0.), 01,pnn,y{ > rw} >;,$0=q,$,,($_=$^)=~y,$/ C-~><@=\n\r,-~$:-u/ #y,d,s,(\$.),$1,gee,print > > ^ > | > why does it even *see* > the print statement? Because that isn't a comment, it's a sharp sign ;-) He's fooling you, making you see things that aren't there. It's a classic magic trick. Try it like this: #!/usr/bin/perl -- Russ Allbery, Just Another Perl Hacker $^ = q; @!>~|{>krw>yn{u<$$<[~||<Juukn{=,<S~|}<Jwx}qn{<Yn{u<Qjltn{ > 0gFzD gD, 00Fz, 0,,( 0hF 0g)F/=, 0> "L$/GEIFewe{,$/ 0C$~> "@=,m,|,(e 0.), 01,pnn,y{ rw} > ; , $0 = q,$, , ($_=$^) =~ y,$/ C-~><@=\n\r,-~$:-u/ #y,d , s,(\$.),$1,gee , print I _think_ what's going on is this (I haven't walked it all the way through): 1) $^ = q; <------ this isn't a semicolon, this is a delimiter 2) The ; could have been anything as long as it is eventually matched 3) There are no actual statement-ending ; in the whole thing. 4) He also makes plentiful use of the side effects of the comma operator Try looking at this: $^ = q/hey/, $0 = q/$/ , ($_=$^) =~ y/a/b/d, s/(\$.)/$1/gee, print I think it's essentially the same format (different content and results, of course). That # is probably what's printing the # in #!.... in the output # To: Vicki Brown <vlb@cfcl.com> # Subject: Re: JAPH # From: Russ Allbery <rra@stanford.edu> # Date: 15 Feb 1999 03:20:47 -0800 # Lines: 96 # # Vicki Brown <vlb@cfcl.com> writes: # # > A co-worker forwarded me your sig (which I have been trying to ignore # > :-) # # *laugh* # # > Here's my breakdown. Am I close? # # Yup! Very. # # > I _think_ what's going on is this (I haven't walked it all the way # > through): # # > 1) $^ = q; <------ this isn't a semicolon, this is a delimiter # > 2) The ; could have been anything as long as it is eventually matched # > 3) There are no actual statement-ending ; in the whole thing. # # Yup. # # > 4) He also makes plentiful use of the side effects of the comma # > operator. # # I'm actually just using it for all of: a quoting symbol with q, a # delimiter with both y/// and s///, and as a statement separator. # # > Try looking at this: # # > $^ = q/hey/, $0 = q/$/ , ($_=$^) =~ y/a/b/d, s/(\$.)/$1/gee, print # # Ayup. # # > That # is probably what's printing the # in #!.... in the output # # Sort of. It's what @ signs get mapped to. Here's the "official" # explanation that I wrote up a while back since I get asked how it works in # e-mail on a periodic basis: # #!/usr/bin/perl -- Russ Allbery, Just Another Perl Hacker $^=q;@!>~|{>krw>yn{u<$$<[~||<Juukn{=,<S~|}<Jwx}qn{<Yn{u<Qjltn{ > 0gFzD gD, 00Fz, 0,,( 0hF 0g)F/=, 0> "L$/GEIFewe{,$/ 0C$~> "@=,m,|,(e 0.), 01,pnn,y{ rw} >;,$0=q,$,,($_=$^)=~y,$/ C-~><@=\n\r,-~$:-u/ #y,d,s,(\$.),$1,gee,print # # The first thing to notice is that it actually begins with a variable # assignment, and quite a bit of the rest is a quoted string (starting with # q) that uses ; as the quote character. So this is a single assignment: # $^=q;@!>~|{>krw>yn{u<$$<[~||<Juukn{=,<S~|}<Jwx}qn{<Yn{u<Qjltn{ > 0gFzD gD, 00Fz, 0,,( 0hF 0g)F/=, 0> "L$/GEIFewe{,$/ 0C$~> "@=,m,|,(e 0.), 01,pnn,y{ rw} >; # # Then we do this: # $0=q,$, # # which just assigns '$' to $0. Now.... # ($_=$^)=~y,$/ C-~><@=\n\r,-~$:-u/ #y,d # # makes a copy of the first string that we assigned to $^, puts it in $_ # (the default variable for the print we're going to do later), and then # does a y/// on it (same as a tr///). I use , as the delimiter for y///. # This is the part that decodes the string. The mapping is: # $/ C-~><@= # ...maps to... -~$:-u/ #y # # Note that there's a range in there; the range C-~ maps to :-u. You need # an ASCII chart to see precisely what that does, but you can apply that # transform to the string and get something that looks much more familiar # (it includes the string "#!/usr/bin/perl -- Russ Allbery"..., for example. # # It also deletes \r and \n characters, to strip off the line endings. # s,(\$.),$1,gee # # is a substitute on the decoded string. $ followed by a single character # is replaced by that string evaluated twice (/ee) globally (/g). This # causes $0 to turn into $ (so we can escape $'s in the string as $0) and # more importantly replaces $^ with the original quoted string. That's the # magic that allows the whole thing to be self-printing; the trick to # writing self-printing programs is to find a way to use the same string # twice in the output. The quoted string that we put in $^ becomes the text # at the beginning and end of the sig after it was decoded, and then the # original encoded string is embedded in the middle again to get the # original sig back. Note that $/ is also present in the decoded string and # becomes \n to preserve the original line endings. # # Finally: # # print # # just prints out $_, which at this point contains the entire sig. # # -- # Russ Allbery (rra@stanford.edu) <URL:http://www.eyrie.org/~eagle/> -- -- |\ _,,,---,,_ Vicki Brown <vlb@cfcl.com> ZZZzz /,`.-'`' -. ;-;;,_ Journeyman Sourceror: Scripts & Philtres |,4- ) )-,_. ,\ ( `'-' P.O. Box 1269 San Bruno CA 94066 '---''(_/--' `-'\_) http://www.cfcl.com/~vlb http://www.macperl.org ==== Want to unsubscribe from this list? (Don't you love us anymore?) ==== Well, if you insist... Send mail with body "unsubscribe" to ==== fwp-request@technofile.org </x-flowed>