From don@brillig.umd.edu Sun Aug 27 15:07:52 1989 Date: Sun, 27 Aug 89 15:07:52 -0400 To: NeWS-makers@brillig.umd.edu Subject: A PostScript interpreter written in PostScript From: Don Hopkins Sender: NeWS-makers-request@brillig.umd.edu (Don Hopkins) Obvious Question: Why would anybody ever write a PostScript interpreter in PostScript? Possible Answers: To use as a debugging tool. To trace and single step through the execution of PostScript code. To serve as a basis for PostScript algorithm animation. To gain a deeper understanding of how PostScript works. To try out some ideas from Structure and Interpreteration. To experiment with extensions to the PostScript language. To demonstrate that PostScript isn't just for breakfast any more. To make PostScript run even slower (but thicker). To avoid programming in C (the portable assembly language of the 80's). To use to interpret its self. To have something nerdish to talk about at parties. The meta-interpreter has its own meta-execution stack, a PostScript array, onto which it pushes continuations for control structures. (forall, loop, stopped, etc...) The continuations are represented as dictionaries in which the state needed by the control structure is stored (plus some other info to help with debugging), as well as a /continue function, and a /continuation type. Before executing any operator, the meta-interpreter looks to see if it's defined in the iexec-operators dict, and if it is, the associated procedure is executed instead. Since the meta-interpreter uses its own execution stack, any operator that effects the execution stack (loop, exit, exec, etc...) must be redefined to use the meta-execution stack instead, so that the meta-interpreter can trace through the execution. The NeWS execution stack is just used to execute the code implementing the meta-interpreter -- the code being meta-interpreted uses the meta-execution stack. The MumbleFrotz function uses the NeWS execution stack to temporarily hold the state of the meta-interpreter (a dict) when it can't be on the dictionary stack, during the execution of primatives. (Or rather, it uses the execution stack of whatever interpreter is interpreting the meta-interpreter! ;-) Some things that are not implemented yet: error handling (which has a lot of potential for being useful :-), pathforall, countexecstack, tracing of the supersend primative in X11/NeWS. I can't think of a way to trace the execution of event manager callback procedures stored in interest Name and Action dictionaries, that awaitevent executes automatically before returning, short of wrapping calls to the interpreter around each of the callbacks (eeugh). The awaitevent operator is the only way to get an event, and sometimes it uses the NeWS execution stack, by pushing event callbacks onto it. This means they get executed by the NeWS interpreter without being traced. (Nothing bad happens, it's just invisible to the meta-interpreter.) Unfortunatly, I'd really like to be able to trace those... What the meta-interpreter needs is a dumbawaitevent operator, that returns the callback instead of executing it (on purpose -- cf sjs's blankscreen comments ;-). Three things that inspired this implementation are: Crispin Goswell's paper, "An Implementation of PostScript", published in the book "WorkStations and Publication Systems", from Springer Verlag; Abelson and Sussman's "Structure and Interpretation of Computer Programs" from MIT Press; and hot steam forced violently past finely ground Cafe' Bellissimo, mixed with lots of steamed milk and brown sugar. -Don