[comp.lang.postscript] newcomer, need help with forall

jnp@mjolner.tele.nokia.fi (J|rgen N|rgaard) (08/09/89)

Hello everybody,

As I'm quite new to PostScript and having a problem I do not understand
I hope somebody experienced can help me.

Consider the following program:

    /Helvetica findfont 10 scalefont setfont
    100 100 translate
    /en   { gsave 0 0 moveto 1 10 string cvs show grestore } def
    /to   { gsave 0 0 moveto 2 10 string cvs show grestore } def
    /tre  { gsave 0 0 moveto 3 10 string cvs show grestore } def
    /fire { gsave 0 0 moveto 4 10 string cvs show grestore } def

%% method one
    [en to tre fire]{ 0 50 translate exec} forall showpage

    100 100 translate
%% method two 
    [1 2 3 4]{ 0 50 translate 0 0 moveto 10 string cvs show} forall showpage

I would expect "method one" and "method two" to be equivalent. But they are
not, but why ?
(method one prints all characters on top of each other,
 method two prints all characters one above the other:
   4
   3
   2
   1 )
In the PostScript book (Adobe on Addison-Wesley) the "forall" operator
is not (as I understand it) documented to save something.


(Equipment: DEC LN03R, ScriptPrinter Version 47.2)

Hope someone can enlighten me on this.

--                                                                           --
| Regards, J|rgen N|rgaard ('|' is '\o{}' in \LaTeX{})                        |
|    e-mail: jnp@tele.nokia.fi or pedersen%tnclus.dnet@tele.nokia.fi          |
--                telephone: <..>-358-0-511-5671                             --

--
--                                                                           --
| Regards, J|rgen N|rgaard ('|' is '\o{}' in \LaTeX{})                        |
|    e-mail: jnp@tele.nokia.fi or pedersen%tnclus.dnet@tele.nokia.fi          |
--                telephone: <..>-358-0-511-5671                             --

richk@pogo.WV.TEK.COM (Richard G. Knowles) (08/10/89)

In article <JNP.89Aug9134311@mjolner.tele.nokia.fi> jnp@mjolner.tele.nokia.fi (J|rgen N|rgaard) writes:
>Consider the following program:
>
>    /Helvetica findfont 10 scalefont setfont
>    100 100 translate
>    /en   { gsave 0 0 moveto 1 10 string cvs show grestore } def
>    /to   { gsave 0 0 moveto 2 10 string cvs show grestore } def
>    /tre  { gsave 0 0 moveto 3 10 string cvs show grestore } def
>    /fire { gsave 0 0 moveto 4 10 string cvs show grestore } def
>
>%% method one
>    [en to tre fire]{ 0 50 translate exec} forall showpage
>
>    100 100 translate
>%% method two 
>    [1 2 3 4]{ 0 50 translate 0 0 moveto 10 string cvs show} forall showpage
>
>I would expect "method one" and "method two" to be equivalent. But they are
>not, but why ?
>(method one prints all characters on top of each other,
> method two prints all characters one above the other:

They are different because method 1 forall recieves an empty array and thus
does not ever execute the proc.  What is happening, however, is that the en,
to, tre, and fire procedures are getting executed instead of being placed
into the array.  Since those procedures leave nothing on the operand stack
the array ends up empty.

Arrays are built, not created verbatim.  Thus the '[' leaves a mark on the
stack, each following token is parsed (and "executed" if executable), and
the ']' packs all objects on the stack down to the mark into an array object.

Correct ways of specifying method one are:

  [//en     //to     //tre     //fire    ] { 0 50 translate exec} forall
  [/en load /to load /tre load /fire load] { 0 50 translate exec} forall
  [/en      /to      /tre      /fire     ] { 0 50 translate load exec} forall

-------- Whatever I say is my fault and no one elses! -----------

Richard G. Knowles                        richk@pogo.WV.TEK.COM
Graphics Printing and Imaging                (503) 685-3860
Tektronix, Inc; D/S 63-356
Wilsonville, Or 97070			or just yell "Hey, Rich!"

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

In article <7725@pogo.WV.TEK.COM> richk@pogo.WV.TEK.COM (Richard G. Knowles) writes:
>In article <JNP.89Aug9134311@mjolner.tele.nokia.fi> jnp@mjolner.tele.nokia.fi (J|rgen N|rgaard) writes:
>>Consider the following program:
>>
>>    /Helvetica findfont 10 scalefont setfont
>>    100 100 translate
>>    /en   { gsave 0 0 moveto 1 10 string cvs show grestore } def
>>    /to   { gsave 0 0 moveto 2 10 string cvs show grestore } def
>>    /tre  { gsave 0 0 moveto 3 10 string cvs show grestore } def
>>    /fire { gsave 0 0 moveto 4 10 string cvs show grestore } def
>>
>>%% method one
>>    [en to tre fire]{ 0 50 translate exec} forall showpage
>>
>>    100 100 translate
>>%% method two 
>>    [1 2 3 4]{ 0 50 translate 0 0 moveto 10 string cvs show} forall showpage
>>
[...]
>Correct ways of specifying method one are:
>
>  [//en     //to     //tre     //fire    ] { 0 50 translate exec} forall
>  [/en load /to load /tre load /fire load] { 0 50 translate exec} forall
>  [/en      /to      /tre      /fire     ] { 0 50 translate load exec} forall
>

Quite right! But you could also go:

{en to tre fire} {0 50 translate exec} forall

That way would be more efficient if it were executed more than once
(if it was wrapped up inside another procedure), since the methods
using [ ... ] create a new literal array every time they're executed,
and the { ... } method always reuses the same (executable) array
(created by the scanner).

"[" is a normal PostScript function, that pushes a mark into the stack
("/[ mark def"). "]" is a normal function that makes an array out of
the things on the stack between the mark and the top of the stack ("/]
{counttomark array astore exch pop} def"). The tokens between [ and ] are
executed normally.

"{" and "}" are handled specially by the scanner. They are not
functions. The scanner does not execute the tokens between "{" and
"}", it just makes an executable array out of them.

So the difference between "{ [ en to tre fire ] }" and "{ { en
to tre fire } }" is that the former is an executable array of six
elements, while the latter is an executable array of one element, and
that one element is an executable array of four elements.

The former creates and returns a new literal array whenever it's
executed. The array it returns is of zero length, because the
procedures "en", "to", "tre", and "fire" are called while the array is
being accumulated on the stack, and they don't leave anything on the
stack. The latter returns the same four-element executable array every
time. The array elements are executable, but weren't executed when the
array was scanned in.  So the "exec" in the forall function will do
the right thing with them at the right time.  And since "forall"
doesn't care if the array you're iterating over is executable or
literal, you can use executable arrays in cases where they array
you're looping over will always be the same, whose elements don't have
to be computed every time.

	-Don

amanda@intercon.uu.net (Amanda Walker) (08/10/89)

In article <18978@mimsy.UUCP>, don@brillig.umd.edu (Don Hopkins) writes:
> Quite right! But you could also go:
> 
> {en to tre fire} {0 50 translate exec} forall

You can also do:

	{en to tre fire} {0 50 translate exec} bind forall

Which will probably be marginally faster (except under NeWS, where the
interpreter will do the "bind" for you by default...).

--
Amanda Walker
InterCon Systems Corporation
--
amanda@intercon.uu.net    |    ...!uunet!intercon!amanda

geof@apolling (Geof Cooper) (08/11/89)

In article <7725@pogo.WV.TEK.COM> richk@pogo.WV.TEK.COM (Richard G. Knowles) writes:
>  [/en      /to      /tre      /fire     ] { 0 50 translate load exec} forall

should be "{ 0 50 translate load cvx exec }".  Otherwise, a great
response to the canonical PostScript "you should have used load" bug.

I guess that the array [/en /to /tre /fire] gets turned into
[/one /two /three /four] by the "translate" operator... :-)

- Geof