[comp.lang.postscript] PostScript question

brown@vidiot.UUCP (Vidiot) (12/16/89)

I have the three PostScript books, but that still doesn't help me in figuring
out why this works.

As I understand the books, when one opens up a dictionary and starts putting
things in it, the current dictionary is pushed down on the dictionary stack.
All good and dandy.  But, when an end is done, the current dictionary that
was being used is popped from the dictionary stack and its information is lost
forever.  Well, it seems like forever is not true.  I will use as an example
the Adobe prolog for psdit:  (portions thereof)


%!PS-Adobe-1.0
%%Creator: tester
%%Title: stdin (ditroff)
%%CreationDate: Fri Dec 15 13:46:27 1989
%%EndComments
% Start of psdit.pro -- prolog for ditroff translator
% Copyright (c) 1985,1987 Adobe Systems Incorporated. All Rights Reserved. 
% GOVERNMENT END USERS: See Notice file in TranScript library directory
% -- probably /usr/lib/ps/Notice
% RCS: $Header: psdit.pro,v 2.2 87/11/17 16:40:42 byron Rel $

Here is the dictionary in question....

/$DITroff 140 dict def $DITroff begin
/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
/xi {0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
  /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F
  /pagesave save def}def
.
many macro definitions created
.
   /Ybi Ycont Bcontrol i 3 add get 2 div add def
   /Xcont Xcont Bcontrol i 2 add get add def
   /Ycont Ycont Bcontrol i 3 add get add def
   Xbi currentpoint pop sub Ybi currentpoint exch pop sub rcurveto
  }for dstroke}if}def
end

OK, all of these macros were created and then thrown away as nothing was done
inside of $DITroff except creation of definitions.

Then a definition is created for ditstart that does another dictionary for
$DITroff.  This time there isn't an end, so far so good.

/ditstart{$DITroff begin
 /nfonts 60 def			% NFONTS makedev/ditroff dependent!
 /fonts[nfonts{0}repeat]def
 /fontnames[nfonts{()}repeat]def
/docsave save def
}def

.
more dictionaries and macro definitions
.

OK, now to the heart of the document.  The procedure ditstart is called, which
starts the $DITroff dictionary again.

ditstart
(psc)xT
576 1 1 xr
1(NewCenturySchlbk-Roman)xf 1 f
2(NewCenturySchlbk-Italic)xf 2 f
3(NewCenturySchlbk-Bold)xf 3 f
4(NewCenturySchlbk-BoldItalic)xf 4 f
5(Helvetica)xf 5 f
6(Helvetica-Bold)xf 6 f
7(Courier)xf 7 f
8(Courier-Bold)xf 8 f
9(Symbol)xf 9 f
10(DIThacks)xf 10 f
10 s
1 f
xi
%%EndProlog

%%Page: 1 1
10 s 0 xH 0 xS 1 f

body of PostScript pages goes here

%%Trailer
xt

This procedure does the end for the dictionary.

xs



What is my problem you ask?  How can all of the definitions that were created
the first time $DITroff was done be available the second time it is started in
ditstart?  The book say that an end closes the dictionary and the info is popped
from the dictionary stack.  The books even give an example of defining the same
thing inside of a dictionary and how it returns to the old value when the new
dictionary is ended.  Unfortunately, I can't find where/how ended dictionary
information is again available in the future.

Can someone please explain this paradox, and/or point to a page/section in
one of the manuals that does explain this completely?

Thanks in advance.
-- 
                harvard\     att!nicmad\
Vidiot            ucbvax!uwvax..........!astroatc!vidiot!brown
                rutgers/  decvax!nicmad/
        ARPA/INTERNET: <@spool.cs.wisc.edu,@astroatc:brown@vidiot>

woody@rpp386.cactus.org (Woodrow Baker) (12/18/89)

When you create a dictionary with  /exampledict 100 dect def you
essentially set aside enough memory to hold 100 keys (names) and definitions.
A dictionary is like any other composite object.  It can be accessed like an
array.  It stays around like other composite objects.  When you do a 
exampledict begin, what happens is that a pointer to the dictionary is put
on the dict stack (essentially anyway, but it might be implemented diffrently)
All unknown tokens are searched for in the dictionaries that are active on the
stack.  Upon doing an exit, the pointer (if you will) is popped off the stack
and the dictionary stays around in memory.  It is like the stdlib in 'C' in
a perverse sort of way, but can also be thought of (a bit more accuratly)
as a 'C' function, that does a caseswitch on the keyword passed to it, and
then calls a routine to do that function.  Think of them as a collection
of proceedures like a library.  You simply activate and deactivate the 
library.  You can replace things in the library, just make it active, and
PUT or STORE them there.  Doing a DEF creates an entry.  Apparently, each
dictionary entry occupies 20 or so bytes, (create a 100 element dictionary)
and look at the vm before and after, to see how much.

Hope this helps, and if any of this is wrong, I appologize, but it's the
way I view dictionaries.

I may have a detail or two wrong.  Dictionaries were the muddiest sort
of things, until I started working on emulators, and them I came to  understand
them.  My favorite way of thinking about them is a file or library that
can be "opened" with begin, and "closed" with end.

Hope this helps.

Cheers
Woody

henry%angel@Sun.COM (Henry McGilton -- Software Products) (12/19/89)

In article <314@vidiot.UUCP>, brown@vidiot.UUCP (Vidiot) writes:

    *  I have the three PostScript books,

Me too, plus a lot more that I wish I'd never bought.

    *  but that still doesn't help me in figuring out
    *  why this works.

    *  As I understand the books, when one opens up a
    *  dictionary and starts putting things in it,

To be a little bit more precise, when you do a begin, the
dictionary named in the begin is pushed onto the dictionary stack.

    *  the current dictionary is pushed down on the dictionary stack.

Yes.

    *  All good and dandy.  But, when an end is done, the
    *  current dictionary that was being used is popped from
    *  the dictionary stack and its information is lost forever.

It doesn't work that way.  The dictionary at the top of the stack
is popped, true.  But that dictionary is still around, to be used
again, if you wish, by doing another begin.  And the things you
defined in that dictionary are still in there.

None of the books say that the `information is lost forever'.

The Red Book says that end:
    `pops the current dictionary off the dictionary stack'.

The Blue Book says:
    `Once the new dictionary is popped from the dictionary stack,
     the values for names defined within the context of this
     dictionary will no longer be found', etc, etc.

I don't read either as stating that the values are gone forever.
    
    *  Well, it seems like forever is not true.

Correct.

    <   . . .large amounts of psdit prolog deleted,
	reading psdit prolog fries the brain.  >

    *  OK, all of these macros were created and then thrown
    *  away as nothing was done inside of $DITroff except
    *  creation of definitions.
Great -- now you have a dictionary full of definitions.
It just isn't on the dictionary stack right now.

    *  Then a definition is created for ditstart that does
    *  another dictionary for $DITroff.  This time there isn't
    *  an end, so far so good.

	*  /ditstart{$DITroff begin
	*  /nfonts 60 def
	*  /fonts[nfonts{0}repeat]def
	*  /fontnames[nfonts{()}repeat]def
	*  /docsave save def
	*  }def
The $DITroff begin sequence inside the definition of ditstart doesn't
do anything until such time as distart is actually executed.

    *  OK, now to the heart of the document.  The procedure
    *  ditstart is called, which starts the $DITroff
    *  dictionary again.

ditstart pushes $DITroff onto the dictionary stack.

    *  What is my problem you ask?  How can all of the
    *  definitions that were created the first time $DITroff
    *  was done be available the second time it is started in
    *  ditstart?
See the explanation above.
    *  The book say that an end closes the dictionary and the
    *  info is popped from the dictionary stack.
Just the dictionary is popped -- the dictionary, plus its
associated key/value pairs, remains.

    *  Can someone please explain this paradox, and/or point
    *  to a page/section in one of the manuals that does
    *  explain this completely?
The Red Book.

One last item.  You might ask, `if the dictionary hangs around,
how come we don't run out of VM?'.  Placing the entire sequence
inside a save/restore pair reclaims the VM.

This is my understanding of the mechanisms.  I'm sure the REAL
PostScript wizards out there will no doubt correct me if I'm wrong.
Here's a test program that demonstrates the concepts well enough:

===========================  cut here  =================================
%!PS

/FirstDict 1 dict def	%  define two dictionaries, each big enough
/SecondDict 1 dict def	%  to hold one item each.

FirstDict begin		%  push FirstDict on dictionary stack
/shape {		%  define a shape -- happens to be a square
    0 0 moveto
    100 0 lineto
    100 100 lineto
    0 100 lineto
    closepath
} def
end			%  pop FirstDict off dictionary stack

SecondDict begin	%  push SecondDict on dictionary stack
/shape {		%  define a shape -- happens to be a triangle
    0 0 moveto
    100 0 lineto
    50 100 lineto
    closepath
} def
end			%  pop SecondDict off dictionary stack

FirstDict begin		%  push FirstDict on dictionary stack
144 144 translate
gsave
shape stroke		%  execute shape operator -- should be square
grestore

SecondDict begin	%  push SecondDict on dictionary stack
144 144 translate
gsave
shape stroke		%  execute shape operator -- should be triangle
grestore
end			%  pop SecondDict off dictionary stack
   			%  Now we should be back to FirstDict

144 144 translate
gsave
shape stroke		%  execute shape operator -- should be square
grestore
end			%  pop FirstDict off dictionary stack

showpage
===========================  cut here  =================================

	............... Henry
+-------------------+---------------------------+---------------------------+
| Henry McGilton    | I'll bet those people who |                           |
| Sun Microsystems  | put control-D characters  | arpa: hmcgilton@sun.com   |
| 2550 Garcia       | in PostScript files also  | uucp: ...!sun!angel!henry |
| Mountain View, CA | put beans in their chili. |                           |
+-------------------+---------------------------+---------------------------+

brown@vidiot.UUCP (Vidiot) (12/21/89)

In article <129367@sun.Eng.Sun.COM> henry%angel@Sun.COM (Henry McGilton -- Software Products) writes:
<In article <314@vidiot.UUCP>, brown@vidiot.UUCP (Vidiot) writes:
<
<    *  All good and dandy.  But, when an end is done, the
<    *  current dictionary that was being used is popped from
<    *  the dictionary stack and its information is lost forever.
<
<It doesn't work that way.  The dictionary at the top of the stack
<is popped, true.  But that dictionary is still around, to be used
<again, if you wish, by doing another begin.  And the things you
<defined in that dictionary are still in there.
<
<None of the books say that the `information is lost forever'.
<
<The Red Book says that end:
<    `pops the current dictionary off the dictionary stack'.
<
<The Blue Book says:
<    `Once the new dictionary is popped from the dictionary stack,
<     the values for names defined within the context of this
<     dictionary will no longer be found', etc, etc.
<
<I don't read either as stating that the values are gone forever.

Well, I did.  Why, because it didn't say in the same area of the book that
if the dictionary name is used again, that the original definitions are also
still there.  To me, "will no longer be found" means just that.

This points out a major problem with manuals.  The people that write them
know what is happening, but they just can't get it all on paper.  They (Adobe)
should have started another paragraph in the same section that says BUT....
I look toward a manual to tell me how it works, not a lesson in how to read
between the lines.

<    *  to a page/section in one of the manuals that does
<    *  explain this completely?
<The Red Book.

I have looked at that read book, but never got the info described from it.
Adobe also used the word popped when describing taking the currently dictionary
off the stack.  OK, every microcomputer chip that I have programmed loses any
data that is popped off of a stack, unles you move it somewhere else.  I can't
find in the red book where it says that when the current dictionary is popped
of the stack it is actually saved somewhere (like VM). 

I just feel that it could have been explained better in the books.

Thanks for the explanation and the example, it is appreciated.
-- 
                harvard\     att!nicmad\
Vidiot            ucbvax!uwvax..........!astroatc!vidiot!brown
                rutgers/  decvax!nicmad/
        ARPA/INTERNET: <@spool.cs.wisc.edu,@astroatc:brown@vidiot>

jmr@nada.kth.se (Jan Michael Rynning) (12/21/89)

In article <342@vidiot.UUCP> brown@vidiot.UUCP (Vidiot) writes:
>I have looked at that read book, but never got the info described from it.
>Adobe also used the word popped when describing taking the currently dictionary
>off the stack.  OK, every microcomputer chip that I have programmed loses any
>data that is popped off of a stack, unles you move it somewhere else.  I can't
>find in the red book where it says that when the current dictionary is popped
>of the stack it is actually saved somewhere (like VM). 

A directory is a composite object, just like a string or an array.  The
PostScript interpreter will never push a composite object on any stack,
only a pointer to it.  So, when you do

  20 dictionary

the interpreter creates a dictionary which can hold up to 20 entries, and
pushes a pointer to that dictionary on the operand stack.  Then, when you
do

  begin

the interpreter pops that pointer from the operand stack and pushes it on
the dictionary stack.  Finally, when you do

  end

the interpreter pops the pointer from the dictionary stack and throws it
away.  It does not destroy the dictionary that the pointer points to, so
if you have saved away a copy of the pointer in some other place, you can
still access that dictionary.

Jan Michael Rynning,			jmr@nada.kth.se
Department of Numerical Analysis	If you can't fully handle domains:
  and Computing Science,		ARPA: jmr%nada.kth.se@uunet.uu.net
Royal Institute of Technology,		UUCP: {uunet,mcvax,...}!nada.kth.se!jmr
S-100 44 Stockholm,			BITNET: jmr@sekth
Sweden.					Phone: +46-8-7906288

mike@ntmtka.mn.org (Mike Tietel) (12/22/89)

In article <314@vidiot.UUCP>, brown@vidiot.UUCP (Vidiot) writes:
> 
> /$DITroff 140 dict def $DITroff begin

The above line is the key to the misunderstanding.  The
"/$DITroff 140 dict def" creates a dictionary named "$DITroff"
with enough space for 140 key-value pairs.  The "$DITroff begin"
just makes the dictionary "$DITroff" current (i.e., puts the
dictionary "$DITroff" on top of the dictstack).  Placing the
dictionary on top of the dictstack allows you to place key-value
pairs in the dictionary using the "def" operator instead of the
"put" operator (i.e., "/hi (hello) def" instead of
"$DITroff /hi (hello) put").

> .
> many definitions created
> .
> end

The "end" pops the topmost dictionary off of the dictstack, note
however that this dictionary is still known by the name "$DITroff".
All that has been done up to this point is define a few key-value
pairs in the dictionary "$DITroff". NOTHING HAS BEEN THROWN AWAY!
The end does not cause this dictionary to be lost forever, because
the dictionary is known by the name "$DITroff"!!!

> Then a definition is created for ditstart that does another dictionary for
> $DITroff.  This time there isn't an end, so far so good.
> 
> /ditstart{$DITroff begin

The above line does not "do another dictionary" it makes the
"$DITroff" dictionary current so that some new key-value pairs
may be added to it.

>  /nfonts 60 def			% NFONTS makedev/ditroff dependent!
>  ...
> }def
> .
> more dictionaries and macro definitions
> .
> ditstart
> (psc)xT
> 576 1 1 xr
> ...
> 1 f
> xi
> %%EndProlog
> %%Page: 1 1
> 10 s 0 xH 0 xS 1 f
> %body of PostScript pages goes here
> %%Trailer
> xt
> %This procedure does the end for the dictionary.
> xs
> 

Note from the red book that:
dict - *creates* an *empty* dictionary and places it on the operand stack
begin - pushes a dictionary on the dictstack
end - pops a dictionary off the dictstack

If I write a program like the following:

    2 dict begin
	/hi (hello) def
	/bye (goodbye) def
    end

the dictionary created *is* lost forever.
However, if I write a program:

    /mydict 2 dict def	% create a dict called "mydict"
    mydict begin
	% define key-value pairs
	/hi (hello) def
	/bye (goodbye) def
    end

the dictionary is not lost because we have named it "mydict".
We could also have written this program as follows:

    /mydict 2 dict def	% create a dict called "mydict"
    mydict /hi (hello) put	% define one key-value pair
    mydict /bye (goodbye) put	% define one key-value pair

or:

    /mydict 2 dict def	% create a dict called "mydict"
    mydict begin /hi (hello) def	% define one key-value pair
    mydict begin /bye (goodbye) def	% define one key-value pair

In all three cases "mydict" will contain the same key-value pairs.

If there are more questions, don't hesitate...
mjt
-- 
Mike Tietel
Northern Telecom, Inc.       (612) 932-8017
9701 Data Park, H-200        mike@ntmtka.mn.org
Minnetonka, MN 55343         {rosevax,bungia}!ntmtka!mike