I don't know how the title of this question should be...
I'm working on an interpreter, currently I was looking at error handling. I've seen that there is an $error and errordict dictionary which are stored in systemdict.
The PLRM contains information on which errors may occur and a few steps to handle them. However when I execute this command in ghostscript:
errordict /stackoverflow get ==
I receive this information:
{/stackoverflow {1 --.instopped-- {null --eq-- {--pop-- --pop-- --stop--} --if--} --if-- (I) false --.setdebug-- $error /.inerror --get-- 1 --.instopped-- {--pop--} {--pop-- true} --ifelse-- {.unstoppederrorhandler} --if-- $error /globalmode --.currentglobal-- false --.setglobal-- --put-- $error /.inerror true --put-- $error /newerror true --put-- $error --exch-- /errorname --exch-- --put-- $error --exch-- /command --exch-- --put-- $error /errorinfo --known-- --not-- {$error /errorinfo null --put--} --if-- $error /recordstacks --get-- $error /errorname --get-- /VMerror --ne-- --and-- {--count-- --array-- --astore-- --dup-- $error /ostack 4 -1 --roll-- --countexecstack-- --array-- --execstack-- --dup-- --length-- 2 --sub-- 0 --exch-- --getinterval-- $error /estack 3 -1 --roll-- --countdictstack-- --array-- --dictstack-- $error /dstack 3 -1 --roll-- --put-- --put-- --put-- --aload-- --pop--} {$error /dstack --.undef-- $error /estack --.undef-- $error /ostack --.undef--} --ifelse-- $error /position --currentfile-- --status-- {--currentfile-- {--fileposition--} .internalstopped {--pop-- null} --if--} {$error /command --get-- --dup-- --type-- /filetype --eq-- {{--fileposition--} .internalstopped {--pop-- null} --if--} {--pop-- null} --ifelse--} --ifelse-- --put-- $error /globalmode --get-- $error /.nosetlocal --get-- --and-- --.setglobal-- $error /.inerror false --put-- --stop--} --exec--}
And this seems to be a packedarray:
errordict /stackoverflow get type pstack
result:
packedarraytype
Now where do I find this kind of information (which manual?)? Where are these procedures described so that I can implement them.
It is not only for errors, but other operators also seem to have a packedarray (procedure) as the value, but I can't find the implementation of this procedures in the PLRM.
This will become more clear once you get the book Inside Postscript, but I can summarize somewhat.
It's hard to see just from the dump above, but if you dump several error handlers the same way, it would become obvious that the big procedure body in the middle is the same for all the handlers, and all handlers follow the same pattern of passing the error name to this procedure (with one exception for the
timeout
error). And you'd actually implement the above like this:Where
signalerror
implements the common code. For thetimeout
error (if you choose to implement that one), there is no command to be placed on the stack, so itserrordict
procedure is slightly different.signalerror
(or.error
is the name described in the book) takes snapshots of all the stacks and saves them in the$error
dictionary.So the sequence for an error is usually:
errordict
and executing this procedure.errordict
procedure callssignalerror
, passing it the error name.signalerror
takes snapshots of the stacks, saving the snapshots in$error
, and then callsstop
.stop
pops the exec stack until the nearest enclosing stopped context established by thestopped
operator.stopped { handleerror } if
which was called by the startup code to bracket the whole user program.handleerror
uses the information in$error
to print an error report.BTW, you can implement
packedarray
as read-only arrays. They were needed in the earliest implementations on memory-constrained printers, but I found it too complicated to design a more compact representation of objects. Behaviorally, the only difference from a regular array is that packed arrays must be read-only.