[comp.lang.postscript] Dealing with large procedure bodies

fj@iesd.dk (Frank Jensen) (05/06/89)

The problem of dealing with large procedure bodies is treated in
detail in the green book by Adobe.  This book gives two ways of
splitting a large procedure body in order to avoid operand stack
overflow.


The first method is to replace a procedure definition such as

	/x {a b c d e f g h i} def

by a number of named procedures:

	/r {a b c} def
	/s {d e f} def
	/t {g h i} def
	/x {r s t} def


The second method (which is better in case you are generating the
procedure from a program) is as follows: The definition of `x' now looks like

	/x [{a b c} /exec load
	    {d e f} /exec load
	    {g h i} /exec load] cvx def


However, this method seems to be unnecessarily complicated.  The
following definition of `x' seems to work:

	/x {{a b c} exec {d e f} exec {g h i} exec} def


According to my comprehension of the execution model for postScript,
this should work (and indeed it does!).  Obviously, the postScript
interpreter has to keep track of how many unmatched left braces it has
seen, and so the question is when a pair of matching braces is
converted to a procedure (an executable array).  The most natural
place to do this is when the matching right brace is found; this
conversion into an executable array will thus free a lot of operand
stack elements, leaving space for scanning the next subprocedure.
(Section 2.7 in The Green Book seems to confirm this.)

Am I wrong about how the scanning/interpretation process is performed?
If I am, then please feel free to tell me so.


Frank Jensen,   fj@iesd.dk
Department of Mathematics and Computer Science
Aalborg University
DENMARK

greid@adobe.com (Glenn Reid) (05/09/89)

In article <1805@iesd.dk> fj@iesd.dk (Frank Jensen) writes:
>The problem of dealing with large procedure bodies is treated in
>detail in the green book by Adobe.  This book gives two ways of
>splitting a large procedure body in order to avoid operand stack
>overflow.
 ...
>The second method (which is better in case you are generating the
>procedure from a program) is as follows: The definition of `x' now looks like
>
>	/x [{a b c} /exec load
>	    {d e f} /exec load
>	    {g h i} /exec load] cvx def
>
>However, this method seems to be unnecessarily complicated.  The
>following definition of `x' seems to work:
>
>	/x {{a b c} exec {d e f} exec {g h i} exec} def

Well, as the guy who wrote all that stuff in the Green Book, I feel
compelled to respond.  You're right.  This works fine, accomplishes the
task of collapsing procedure bodies, and is cleaner than the
square-bracket version.

There is one advantage to the square-bracket technique.  You can ALWAYS
put the square bracket on the stack (it is equivalent to a "mark") if
you aren't sure how big the procedure will be (for instance if it is
being generated by software).  Then you cover yourself.  If the
procedure is short, you can put the whole thing in one procedure and
just "pop" the mark off the stack.  Otherwise, if your front-end
software does not look ahead, you might end up with a lot of these:

	/x { { a b c } exec } def

which can get pretty inefficient and messy.  If you use the '[' method,
it would look more like this for short-enough procedures:

	/x [ { a b c } exch pop def

I suppose I could have mentioned some of that in the Green Book, but I
didn't realize why I had done it that way until just now.  I had
devised the technique to solve a particular problem, and couldn't
remember why it was different than { {a b c} exec }.

But you still get ten extra points.  In fact, it pleases me to no end
that you understand the language well enough to have made this
intuitive leap yourself.  My biggest hope is/was to explain the
mechanism of the interpreter well enough that people will understand
the language and how to think like the interpreter, rather than looking
at /proc { ... } def as if it were Pascal.  You've made my day.  And
you don't need to read the rest of the Green Book :-)

Regards,
 Glenn Reid
 Adobe Systems

don@brillig.umd.edu (Don Hopkins) (05/10/89)

In article <820@adobe.UUCP> greid@adobe.COM (Glenn Reid) writes:
>In article <1805@iesd.dk> fj@iesd.dk (Frank Jensen) writes:
>>The problem of dealing with large procedure bodies is treated in
>>detail in the green book by Adobe.  This book gives two ways of
>>splitting a large procedure body in order to avoid operand stack
>>overflow.
> ...
>>The second method (which is better in case you are generating the
>>procedure from a program) is as follows: The definition of `x' now looks like
>>
>>	/x [{a b c} /exec load
>>	    {d e f} /exec load
>>	    {g h i} /exec load] cvx def
>>
>>However, this method seems to be unnecessarily complicated.  The
>>following definition of `x' seems to work:
>>
>>	/x {{a b c} exec {d e f} exec {g h i} exec} def
>
>Well, as the guy who wrote all that stuff in the Green Book, I feel
>compelled to respond.  You're right.  This works fine, accomplishes the
>task of collapsing procedure bodies, and is cleaner than the
>square-bracket version.
>
>There is one advantage to the square-bracket technique.  You can ALWAYS
>put the square bracket on the stack (it is equivalent to a "mark") if
>you aren't sure how big the procedure will be (for instance if it is
>being generated by software).  Then you cover yourself.  If the
>procedure is short, you can put the whole thing in one procedure and
>just "pop" the mark off the stack.  Otherwise, if your front-end
>software does not look ahead, you might end up with a lot of these:
>
>	/x { { a b c } exec } def
>
>which can get pretty inefficient and messy.  If you use the '[' method,
>it would look more like this for short-enough procedures:
>
>	/x [ { a b c } exch pop def
>
> [...]
>Regards,
> Glenn Reid
> Adobe Systems

How about the following:

/x [
    { a b c }
    { d e f }
    { g h i }
    { j k l }
  ] % Stack: /x array[4] 
  [ exch /exec /load load /forall load
    % Stack: /x --mark-- array[4] /exec --load-- --forall--
  ] cvx 
  % Stack: /x {array[4] /exec --load-- --forall--}
def

This is more-or-less equivalent to:

/x {
  { % executable arrays: low in calories, high on fiber!
    { a b c }
    { d e f }
    { g h i }
    { j k l }
  } /exec load forall % loads of fun for all!
} def

Except that the former also has the advantage of the '[' method 
Glenn describes for short procedures:

/x [
  { a b c } % gee, that's the only one; let's optimize:
  exch pop
def

PostScript is such a fun programming language! I just gets bad press
because some people have only looked at nasty optimized header files, 
and machine generated PostScript documents, expecting to be able to read 
them like Pascal programs! It really is a dynamic, powerful language! If 
you don't believe me, go read the Blue, Red, and Green PostScriptures! 
Then take a look at the source to Glenn's Distillery! /hashpath -- like 
wow, man! 

And as for the potentials of object oriented PostScript programming:
Just wait till you see the NDE toolkit kit!!

	-Don