
- •Preface
- •DESIGN FEATURES
- •STRUCTURED PROGRAMMING TECHNIQUES
- •PROGRAMMING TASKS
- •WINDOW SYSTEMS, COMMUNICATIONS, AND DISPLAYS
- •DATA STRUCTURES AND ALGORITHMS
- •CONCLUDING THOUGHTS
- •PostScript is Not Like C
- •COMPARISON OF LANGUAGE MECHANISMS
- •EXPRESSING AN ALGORITHM AS A PROGRAM
- •THE UNIX SHELL AND OPERATING SYSTEM
- •INPUT, OUTPUT, AND THROUGHPUT
- •CONCLUDING THOUGHTS
- •Foundations
- •POSTSCRIPT LANGUAGE SYNTAX
- •SIMPLE PROGRAM STRUCTURE
- •Make Definitions First
- •Indentation Style
- •SETTING UP TEMPLATES
- •DECLARING AND USING VARIABLES
- •Arithmetic with Numeric Variables
- •Using the // Notation for Constants
- •ALLOCATING MEMORY
- •GETTING MEMORY BACK
- •OPENING AND CLOSING FILES
- •COMPARISONS AND EQUALITY OF OBJECTS
- •CONCLUDING THOUGHTS
- •Some Typical Programs
- •A TYPICAL PAGE DESCRIPTION PROGRAM
- •FONT PROGRAMS
- •PROGRAMS THAT READ DATA
- •QUERY PROGRAMS
- •ENCAPSULATED POSTSCRIPT PROGRAMS
- •PERSISTENTLY RESIDENT PROGRAMS
- •CONCLUDING THOUGHTS
- •Understanding the Stack
- •A QUICK OVERVIEW OF DATA TYPES
- •NAME LOOKUP
- •HOW OPERATORS USE THE STACK
- •GROUPING AND VISUAL CHUNKING
- •THINKING BACKWARD AND SIDEWAYS
- •COMPOSITE OBJECTS
- •THE OTHER STACKS
- •The Dictionary Stack
- •The Execution Stack
- •The Graphics State Stack
- •CONCLUDING THOUGHTS
- •Trusting the Stack
- •SAFETY OF DATA ON THE STACK
- •WHERE ARE THE DATA GOING?
- •REARRANGING THE STACK
- •Using the dup and index Operators
- •Using the roll Operator
- •CONDITIONALS AND LOOPS
- •RECURSION AND LOCAL VARIABLES
- •CONCLUDING THOUGHTS
- •Building Conditional Statements
- •SIMPLE CONDITIONALS
- •SETTING UP THE CONDITION
- •CONDITIONALS ARE NOT MAGIC
- •NESTED CONDITIONALS AND ELSE CLAUSES
- •COMPOUND CONDITIONALS
- •CONCLUDING THOUGHTS
- •Using Looping Constructs
- •LOOP BASICS
- •USING THE LOOP INDEX
- •LOOPS ARE PROCEDURE BODIES
- •LOOPS OF INSTRUCTIONS
- •EXITING LOOPS PREMATURELY
- •CONCLUDING THOUGHTS
- •Procedures
- •WHAT EXACTLY IS A PROCEDURE?
- •PARAMETER PASSING
- •CONSTRUCTING GOOD PROCEDURES
- •What to Name Your Procedure
- •A Useful Naming Convention
- •SELF-MODIFYING PROCEDURES
- •CONCLUDING THOUGHTS
- •Using Dictionaries
- •DICTIONARIES FOR NAME SCOPING
- •LOCAL DICTIONARIES
- •GLOBAL DICTIONARIES OF PROCEDURES
- •MAINTAINING THE DICTIONARY STACK
- •INTO AND OUT OF DICTIONARIES
- •LOOKING INTO DICTIONARIES
- •Using the forall Operator
- •Using the where and known Operators
- •REDEFINING OPERATORS
- •Changing the Behavior of Operators
- •Debugging with Redefined Names
- •Proper Nesting of Redefinitions
- •CONCLUDING THOUGHTS
- •Creating and Manipulating Data
- •CONSTRUCTING AN ARRAY
- •CONSTRUCTING A STRING
- •MANIPULATING DATA WITH PUT AND GET
- •CONCATENATING ARRAYS AND STRINGS
- •INPUT AND OUTPUT OF STRING DATA
- •ARRAYS VERSUS DICTIONARIES
- •ADVANCED TECHNIQUES
- •CONCLUDING THOUGHTS
- •Storing and Using Data
- •Data and the Operand Stack
- •Data and Algorithms for Underlining
- •CLASSICAL DATA STRUCTURES
- •Linked Lists
- •Using Arrays to Form Lists
- •Using Dictionaries to Form Lists
- •Queues, Trees, and Other Data Structures
- •CONCLUDING THOUGHTS
- •Program Data and Instructions
- •TURNING DATA INTO INSTRUCTIONS
- •TURNING INSTRUCTIONS INTO DATA
- •DATA CONVERSIONS
- •CONCLUDING THOUGHTS
- •File Objects
- •Streams and Files
- •PostScript File Operators
- •OPENING AND CLOSING FILES
- •READING AND WRITING FILES
- •Reading from a File
- •Writing to a File
- •Copying and Renaming Files
- •WRITING FORMATTED DATA TO FILES
- •Writing Out Various Data Types
- •Spaces, Tabs, Returns, and Special Characters
- •FILE STATUS INFORMATION
- •RANDOM VERSUS SEQUENTIAL ACCESS
- •CONCLUDING THOUGHTS
- •Appendix
- •Answers to Exercises

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 |