### PostScript: the beauty of thinking backwards

Lately, while snooping around within old coding stuff, I rediscovered
an ancient treasure: *the PostScript programming language*.
It's older than dirt and situated deep down under the bottom of Adobe's PDF
technology. Intended to be an efficient and highly flexible printer
instruction language, it's actually a Turing-complete programming language,
based on a very clear and suprisingly simple stack-oriented concept,
outputting geometric results to suitable devices.

Everything is on a stack here. That is, operators reduce items on the operand stack, where operands are objects of various type. Thus, calculations are denoted in reverse polish notation:

3 1 sub 2 div % (3 - 1) / 2

or, equivalently, and even more polish

2 3 1 sub exch div % (3 - 1) / 2

where exch exchanges the two topmost operands.
PostScript procedures are *executable arrays*, i.e. objects consisting of a series of
operators and operands, enclosed in braces:

{ 2 div } 3 1 sub exch exec % (3 - 1) / 2

Executable objects may be executed at any time using the exec operator. Hence, functional concepts such as lambda expressions and lazy evaluation immediately suggest themselves. A complete script using certain font and graphic operators might look as follows:

%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 0 0 170 50 % load standard font 24 /TimesBold findfont exch scalefont setfont .25 setlinewidth 1 setgray % white gsave % push graphic state { % push lambda expression gsave % push graphic state (transformations) dup % duplicate string 0 0 moveto show % print filled 0 setgray % set black 0 0 moveto true charpath stroke % print outlined grestore % pop graphic state } .6 .05 1.1 { % loop condition setgray % using loop iterator .8 dup 13 dup translate scale % matrix transformation -4 rotate dup exec % execute expression } for % loop operator grestore % pop graphic state exec % finally pop and execute 0 setgray % black [-1 0 0 1 150 30] concat % matrix transformation (affine) 0 0 moveto show % print showpage %%EOF

Rendering is globally controlled by a transformation matrix, defining an affine transformation (i.e. a linear mapping plus translation) that can be modified either by the translate, scale, and rotate operators or by explicit left-sided matrix multiplication using the concat operator.

A named procedure in the usual manner is obtained as an *executable literal*
that can be stored within the current dictionary.
That is, the def operator is used to manage the symbol table:

/div2 { 2 div } def 3 1 sub div2 % (3 - 1) / 2

Now, as an apprentice piece of recursive geometry, let's see how Koch's famous Snowflake works:

% t s koch => - /koch { dup depth le { % s < depth 1 add exch % s => s+1 3 div exch % t => t/3 % prepare stack: % t/3 s+1 60 t/3 s+1 240 t/3 s+1 60 t/3 s+1 60 3 copy 180 add 3 copy 180 sub 3 copy pop koch rotate koch rotate koch rotate koch } { pop 0 rlineto } % draw ifelse } def

The koch function reduces a step and a length parameter from the stack, while depth is defined in the global dictionary. The decision of whether dive into recursion incrementing the step value or stop and draw a line segment is made by help of the ifelse operator. So,

/depth 5 def newpath 0 0 moveto 100 1 koch stroke

displays the curve of length 100 with a recursion depth of 5.

For reference, see the PostScript Language Reference Manual, the Blue Book, and also Thinking In PostScript by Glenn Reid.

## 1 comment

## Zora

*impressed*