Question

In Thinking in Postscript (pdf), Chapter 5, exercise 3 (pp. 64-65) asks the reader to refactor this code to not store any dictionary entries:

36 750 moveto /Times-Roman 24 selectfont
% works like “show”, leaving current point at proper location
/ushow
% linethickness lineposition (words) ushow -
{ %def
  LOCAL begin
    /text exch def
    /linepos exch def
    /linethick exch def
    gsave
      0 linepos rmoveto
      text stringwidth rlineto
      linethick setlinewidth stroke
    grestore
    text show
  end
} dup 0 4 dict put def
0.5 -4 (test underlined text) ushow

My question is about LOCAL. Ghostscript runs this code without error, and yet LOCAL is not:

  • Defined in the exercise
  • Documented in the Postcript Language Reference, third edition
  • Documented in PostScript Language Tutorial and Cookbook

What, in PostScript, is LOCAL?

Was it helpful?

Solution

It is nothing defined. The code is a bit sneaky as the code dup 0 4 dict put def will take the executable and replace the LOCAL with the result of 4 dict. The executable block (stuff between {}) is copied mainly because put returns nothing. Since its a reference to the same block your left over with

/ushow {-dict- begin ...rest of the executable...} def

This is all valid because LOCAL is never used anywhere (it is destroyed before its used). It would not matter what you use in place of LOCAL.

OTHER TIPS

As joojaa correctly explains, LOCAL is not defined to anything which is ok since it is replaced before executing. It parses as an executable name during construction of the procedure body (array) and its use here is just to allocate a slot in the array. It could actually be any type, and I've often seen (and written) { 0 begin ...} for the same purpose. Using a name lets you give more semantic information to a human reader of the code. I've also seen it written { DICT begin ... } Here in my matrix functions, I called it STATICDICT, apparently.

There is a convention of using all upper-case for any meta-syntactical tokens like this. It is a nametype token, but meta-syntactically, it refers to a dicttype object to be filled-in later. There's no need (nor even any mechanism) to declare what you're doing for the benefit of the interpreter, but there is much to be gained by preferring DICT over 0. Again, since it will be completely replaced, you could also use a literal name /LOCAL to try to, idunno, relieve the next noob to read your code from the wild-goose-chase of looking for where LOCAL is defined?? To this end, I've also written simply DUMMY for token to-be-filled-in-later. I suppose the choice among these terms is a matter of style or audience or some other intangible quality. sigh... or just a matter of context.

There is another style that works well for making dynamic substitutions in procedure bodies. By placing the dictionary on the dictstack and naming it (within itself, so it's a closed namespace), we can refer to it with an //immediate name

4 dict begin
/mydict currentdict def
/proc {
    //mydict begin
    ...
    end
}

and then remove the dictionary before defining.

end def

Thus defining the procedure normally (in the outer-level dictionary (unnamed here, presumably userdict)), but with the dictionary embedded by name, from having been available by that name while the procedure body was scanned.

This can be extended to more procedures sharing the same private dictionary by juggling the dict off of the stack for each definition.

/enddefbegin { currentdict 3 1 roll end def begin } def

4 dict begin
/mydict currentdict def

/proc1 {
    //mydict begin
    ...
    end
} enddefbegin

/proc2 {
    //mydict begin
    ...
    end
} enddefbegin

end

The enddefbegin end at the end can of course be simplified to end def.

One caveat. The dictionary created this way is recursively contained with itself. Do not try to print it with ghostscript's === operator!

Pg 133 of the "Blue Book" has a slightly easier example of the same technique:

/sampleproc 
{ 0 begin 
  /localvariable 6 def 
  end 
} def 
/sampleproc load 0 1 dict put 

Here the procedure is defined before it is modified. It's a little easier to wrap your mind around. In the original post, the trickiest part for me was the "dup" because I didn't realize that the array on the stack is not an array precisely, it's an array reference (I was thinking copy-by-value, it functions copy-by-reference), so the "put" in the original code affects the array with the first reference (which is consequently consumed from the stack), and the second is used to define the procedure. It was a Newbie mistake, but maybe other newbies can learn from it:

Stack Progression:

...                                               % fast forward
1. ushow --array-- --array-- 0 4 dict | put def   % dict creates a dictionary
2. ushow --array-- --array-- 0 --dict-- | put def % put arrives on stack
3. ushow --array-- --array-- 0 --dict-- put | def % put consumes the array 0 and dict
4. ushow --array-- | def                          % def arrives on stack
5. ushow --array-- def                            % def consumes the remaining tokens
6. 

Sorry for what is probably incorrect notation, I just stared at this for a while, and figured I might be able to save someone a little stare-time. Please let me know if there are any errors or misleading statements that I should fix.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top