Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Reid G.C.Thinking in PostScript.1990.pdf
Скачиваний:
17
Добавлен:
23.08.2013
Размер:
846.44 Кб
Скачать

Chapter 10

Using Dictionaries

Dictionaries are the basic form of storage in the PostScript language. Whenever you use the def operator, you are storing something into a dictionary. Each time you use a name like moveto or call up one of your procedures named L, you are retrieving data out of a dictionary.

To fully understand how dictionaries store data, it is necessary to realize that all PostScript data types are represented by objects. These objects are all the same size, even if the data that they represent are too big to fit inside the object. A dictionary is a place to make key–value pairs of objects. (Remember: the value is the object you want to store, and the key is the name under which you store it.) To get the value back, you need the key again. If your value is a composite object (such as a string, an array, or another dictionary) the data will actually be in memory that has been previously allocated to hold it, and the object stored in the dictionary points to it. Example 10.1 is a simple example of a dictionary entry.

119

Example 10.1: Sample Dictionary Entry

 

/redraw

% strokegray fillgray redraw -

 

{ %def

 

 

gsave

 

 

setgray myuserpath ufill

 

setgray myuserpath ustroke

 

grestore

 

 

} def

 

 

In this case, the object that is stored as the value is the procedure body

 

{ gsave setgray

myuserpath ufill setgray myuserpath ustroke

 

grestore }, and the key under which it is stored is the name redraw.

 

 

TIP

The memory used for storage of PostScript objects is allocated when the

 

object is created, not when it is stored into a dictionary. The dictionary

 

must have room for the definition in it already; only the two objects repre-

senting the key and the value are actually saved in the dictionary. In Example 10.1, the procedure body consumes about 72 bytes of memory when it is created, but no additional memory is used when it is stored into the dictionary with def.

DICTIONARIES FOR NAME SCOPING

Name scoping involves making names context-sensitive, depending on the dictionaries currently on the dictionary stack. To understand its usefulness, you must know that the most common method for retrieving data that have been stored into a dictionary is to use the name lookup mechanism. With this mechanism, an executable name encountered by the interpreter is looked up in the context of the current dictionary stack. You can use a key more than once and it can have different values associated with it in different dictionaries. When the name is looked up, the dictionary stack is searched from the top down, and the first instance of the key that is encountered is the one that is used.

This provides a simple mechanism for changing name scoping. As an example, consider the problem of underlining text. You may want to have a simple text-setting procedure that you use when you’re not underlining

120

Chapter 10: USING DICTIONARIES

(which is most of the time, usually), and a different procedure that you use when you are underlining. One way to approach that might be to have a separate dictionary with underlining information that gets pushed onto the dictionary stack when you want to underline (Example 10.2).

Example 10.2: Using Dictionary to Control Name Scoping

%these procedure turn underlining on and off by

%pushing the underlinedict dictionary on the dict stack

%or popping it off:

/underlineON { underlinedict begin } def /underlineOFF { end } def

% here is a sample regular definition for “S”: /regulardict 4 dict def

regulardict begin % (string) /Font size Xloc Yloc S /S { moveto selectfont show } bind def

end

% alternate definition for “S” that does underlining: /underlinedict 4 dict def

underlinedict begin

/S % (string) Xloc Yloc S – { %def

moveto selectfont currentpoint 3 -1 roll show 0 UnderLinePosition neg rmoveto UnderLinePosition sub lineto stroke

} bind def % (or whatever)

end

LOCAL DICTIONARIES

A local dictionary is a dictionary that is visible only under certain circumstances. If a procedure body references a particular dictionary, it is said to be local to that procedure body.

Local dictionaries are very useful. One of the most common uses of a local dictionary is to store local definitions that might be used by a procedure. This is especially important if you use the def operator, which writes into the current dictionary. It is best to make sure you know where all of the definitions are being made, to prevent errors like dictfull or invalidaccess.

Chapter 10: USING DICTIONARIES

121

Example 10.3 shows the most common technique for using local dictionaries for temporary storage for procedures. There are two things worthy of note in this example.

1.The dictionary is created (allocated) outside of the procedure itself. This keeps it from being created each time the procedure is called.

2.The same dictionary is shared among several procedures, since the data storage is only temporary. Even though the names X and Y are defined by both procedures, they do not interfere with one another as long as the use of those names does not go outside the scope of the procedure.

Example 10.3: Dictionary as Local Storage for a Procedure

/LOCAL 5 dict def

% one dictionary used by all procedures

/Text

% (string) Xloc Yloc Text -

{ %def

 

LOCAL begin

/X exch def /Y exch def /text exch def

X Y moveto text show

end } bind def

/Box % X Y Width Height Box - { %def

LOCAL begin

/Height exch def /Width exch def /Y exch def

/X exch def X Y moveto

Width 0 rlineto 0 Height rlineto

Width neg 0 rlineto closepath stroke

end } bind def

In Example 10.3, the LOCAL dictionary stores only the data, and the procedures themselves are simply written into the current dictionary.

122

Chapter 10: USING DICTIONARIES