Embedded Decoder
A Postscript program has a unique(?) ability to read it's own program text as data. This is normally used by the image
operator which receives a data-acquisition-procedure as input, and this procedure often uses currentfile
followed by readline
, readstring
, or readhexstring
. But seen another way, image
is just another looping operator, so any loop can read-ahead. An example is the line-printer emulator from the Green Book.
Using the token
operator invokes the scanner on a file or string, pulling off a number or space- (or otherwise-: see other answer) -delimited name.
A simple PS interpreter in PS:
{currentfile token not {exit} if dup type /arraytype ne {exec} if }loop
Binary Operator String Decoder
Since I can't seem to get raw binary tokens to work for me (see other answer), I've made use of the "embedded decoding" idea to exploit the binary token mechanism to pack code into 8-bit strings, and then manipulate and parse the commands from the string on the fly.
/.{
<920> % two-byte binary-encoded name template with 0x92 prefix
dup 1 4 3 roll put % insert number into string
cvx exec % and execute it
}def
/${
//. %the /. procedure body defined above
73 . %"forall" (by code number)
}def
The .
procedure takes a number from the stack and inserts it as the second byte in a two-byte string, the first byte being the prefix-byte for a binary token, specifying an executable system name. We save a byte in the hexstring by using a rule of the scanner that an odd number of nibbles in the hexstring is padded with an extra 0 nibble, so 3 hex nibbles produces a 2-byte string. The string is then marked executable and called with exec
which invokes the scanner, produces the desired executable system name, and then loads the name and executes the operator. The $
does this on each byte of a string on the stack, using the .
procedure twice, once as the loop body, and then to execute the looping operator forall
by number.
More compactly, these procedures look like this:
/.{<920>dup 1 4 3 roll put cvx exec}def/${//. 73 .}def
%123457890123456789012345678901234567890123456789012345
% 1 2 3 4 5
So, 55 chars buys binary token strings. Or, for 6 (maybe 7, if you terminate it with a space) chars, you can load the G library with (G)run
which defines .
and $
as above (+ a few others to extend the range of ascii-reachable codes).
Further illustrated in my crossword puzzle answercrossword puzzle answer.