Resurrect Adobe SubScript.
In an obscure conference procedings volume of forgotton lore, there's a quaint little paper which describes an early effort to implement a published subset of Adobe Postscript. There a line in the bibliography! :) But it cannot be found Nobody's ever heard of it. :(
Adobe Systems, "SubScript Specification", 1984.
But there's obvious utility in such a thing. So this is a hypothetical Micro-Manual Postscript, and its name shall be ASS[*]. :)
ASS is a dynamically-typed stack-based programming language with powerful graphics primitives. It has support for floating-point arithmetic, arrays and dictionaries.
The scanner reads white-space delimited tokens and attempts to interpret the token as a decimal floating-point number with optional sign (+/-). The program may (but is not required to) support exponential notation. Failing to recognize a valid number, the token becomes a name object, an atomic symbol type which is identified by the name (an "interned" string).
Types
As suggested by the scanner behavior and the operator list , there are the following object types:
- floating-point numbers (coerced to integer where appropriate)
- names (usually an index into a string table, for easy comparisons)
- arrays (an indexable sequence of objects)
- dictionaries (a key-value map of objects)
- operators (a pointer to a built-in function)
Operators
Operators are the basic actions predefined in the dynamic name space.
Stack Manipulation
any pop -
pop an object from the operand stack
any1 any2 exch any2 any1
exchange top two elements
anyN anyN-1 ... any0 N index anyN anyN-1 ... any0 anyN
retrieve object from stack by position
where N is treated as an integer.
Arrays.
N array array
create a new array of length N
any0 any1 ... anyN-1 array astore array
fill array with objects from stack
array aload any0 any1 ... anyN-1 array
spill contents of array onto stack
[ any0 any1 ... anyN-1 ] array
construct an array
array index any put -
put a value into array
array index get any
retrieve value from array
where index is treated as an integer.
The typical way to implement the array syntax is using an auxiliary type, the marktype object, and an operator counttomark. This is an implementation detail and is not strictly required but may be found to be convenient.
Then the ] operator may be implemented in terms of the other array operators.
- mark anyN anyN-1 ... any1 ] array
{ counttomark array astore exch pop }
Dictionaries.
N dict dict
create a new dictionary, an associative container with room for N name-value pairs
dict begin -
push dictionary on dictionary stack, making names part of the dynamic name space
- currentdict dict
push copy of topmost dictionary on dictionary stack to the operand stack
- end -
pop and discard the topmost dictionary on the dictionary stack
name any def -
associate name with any value in topmost dictionary
name load any
lookup name in each dictionary in the dictionary stack from the top-down, returning the first match, or error if not found
Matrices and transformations.
A matrix is a 6-number array [a b c d e f]
which represent a left-multiplying affine transformation matrix with the constant right-most column omitted.
a b 0
c d 0 => [a b c d e f]
e f 1
- matrix matrix
returns a new identity matrix [1 0 0 1 0 0]
matrix setmatrix -
make matrix the current transform in the graphics state
- currentmatrix matrix
return current transform from the graphics state
x y transform x′ y′
transform (x,y) pair by current transformation matrix
Transforming a point involves multiplying the homogeneous vector through the transformation matrix:
[a b 0]
[x y 1] * [c d 0] => [x' y' 1]
[e f 1]
or, equivalently
x' = a*x + c*y + e
y' = b*x + d*y + f
Path description.
- - newpath -
- x y moveto -
- x y lineto -
- - closepath -
Clipping.
Painting.
- - erasepage -
- - fill -
- - showpage -
The fill operator is where the magic happens. This operator is responsible for performing all of the graphics algorithms in sequence:
Shape Mapping
Tranform the coordinates of the path from user space to device space using the current transformation matrix.
Shape Clipping
Clip the portions of the path that lie outside the clipping path.
Filling
*Perform a scan-line rasterization of the (may assumed closed-) polygon described by the path into the output frame buffer.
And showpage copies the contents of the framebuffer to the actual output mechanism (window or file as described above).
... need to fill this out a little more. Math, graphics state, errors. Describing stroked lines is too much, I think. I'm not sure if it needs the forall operators for iterating through arrays and dicts. I'd like to avoid any need for overloading different types under the same operator name, and calling back to user code from an operator.
Output may be to a window, or to a file in a simple format, like pgm or even a text-file of hashes and spaces for rough bitmaps. No half-toning. Only bi-level filling of convex polygons will be required. But a program may handle more colors if desired.
This is CW in case anybody wants to help me type-in the basic operators.
Questions
Does it need anything more? Should something be removed as unnecessary? Does anyone have the spec??
Perusing my ps implementations of the graphics portions linked in the comments, I've noticed the following needed operators:
length
sub
roll
add
eq
array copy
mul
div
ne
I think it needs loops, too. It's possible to do with just recursion, of course, but loops are nice. And length
, I think, needs to be polymorphic, operating on array or dict to retrieve the size for making copies and calculating indices. Add sin
and cos
, too.
And this would be a code-challenge.
[*] The moniker "ASS" is not intended as a disparagement of Adobe Systems nor any of their stupendous intellectual property. Rather it is merely intended to express frustration at the encountered difficulty in locating this document.