Monday, July 11, 2011

A usefull Postscript Trick

In this blog post I will share a Postscript trick which I use a lot.

Postscript is best known as a page description language. It is a very powerful language, in fact, Postscript is Turing-complete. The language is stack-oriented so you will see a lot of stack operators like dup, exch and roll. These operators can be used to perform all necessary (and possible) stack operations. But it can be very tasking for a programmer to use them correctly.

For example, the following code draws a rectangle perpendicular to the coordinate axis with its lower left vertex at (x,y) and a width of w and height of h. In the comments an impression of the stack is given.

/rectangle {     % stack: h w x y
  moveto         % stack: h w
  dup            % stack: h w w
  3 -1 roll      % stack: w h w
  0 rlineto      % stack: w h
  0 exch rlineto % stack: w
  neg 0 rlineto  % stack:
  closepath      % stack:
  stroke         % stack:
} def
You can easily get lost in all these stack manipulations. Make one mistake and it is likely that your expectations are not met.

Luckily you can solve this problem within postscript. If you look at the above code again, you may notice that a definition is made. The symbol "/rectangle" is associated with the code-block by the def operation. One can associated other values with this operator. You can use it to simplify the above code.

/rectangle {      % stack: h w x y
  /y exch def     % stack: h w x
  /x exch def     % stack: h w
  /w exch def     % stack: h
  /h exch def     % stack: 
  x y moveto      % stack: 
  w 0 rlineto     % stack:
  0 h rlineto     % stack:
  w neg 0 rlineto % stack:
  closepath       % stack:
  stroke          % stack:
} def
There is one problem with this solution. It defines, and possibly overrides, associations for the symbols "/x", "/y", "/w" and "/h". This method leaks its variable in to the context in which it is called. Again, postscript can solve this problem. Initially the associations are made in the dictionary userdict. By using an other dictionary and throwing the dictionary away after it's service, we avoid polluting the userdict. (In the following code examples I will omit the impression of the stack.)
/rectangle {
  4 dict begin
    /y exch def
    /x exch def
    /w exch def
    /h exch def
    x y moveto 
    w 0 rlineto
    0 h rlineto
    w neg 0 rlineto
} def
Here we first define a dictionary for four keys with 4 dict. Start using it with begin. When we are done we discard it with end. This nicely allows the usage a variable with out polluting the userdict. Because I used this trick so often I polished it up a little. I left out the "body" of this method so you can concentrate an the scaffolding.

/rectangle {
  [/y /x /w /h] dup length 0 add dict begin {exch def} forall
} def
That one-liner signals the variable names used in this method, creates a dictionary and initialises it with values from the stack. The 0 add is there to easily add local variable. I the body of the method is using a local variable add one the the integer to ensure the size of the dictionary.

This wraps up this Postscript type. I explained how you can use variable in methods without polluting the userdict.

No comments:

Post a Comment