
- •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

REDEFINING OPERATORS
There are very often instances in which you want to change the behavior of your program, even just temporarily, by redefining some of the names in it before the program executes. This has many possible uses, for debugging, page accounting, distilling documents into another form, or adding to the functionality of an existing program.
As you have learned, name lookup is done in the context of the dictionary stack. There are correspondingly two basic ways to redefine a name nondestructively.
•Make a simple redefinition in the current dictionary with def.
•Push a special dictionary onto the dictionary stack into which the redefinitions are placed.
If you put the redefinitions in a separate dictionary, then it is easy to put them in place or remove them temporarily, simply by pushing or popping the dictionary from the dictionary stack. However, this method is a little bit more subject to problems, since the program may inadvertently remove your special dictionary from the dictionary stack, or try to write into it as if it were its own dictionary.
Changing the Behavior of Operators
When you redefine an operator to have some other behavior beyond or instead of its default, you must take care to preserve at least the way in which the operator interacts with the operand stack, and you probably need to simulate some of the side effects, as well. For example, the moveto operator pops two numbers off the stack and installs a current point into the graphics state. If you redefine moveto, you should at least make sure to pop exactly two numbers from the stack, and you probably ought to establish a current point while you’re at it, if you want the program to continue to execute beyond the next instruction or so (without generating a nocurrentpoint error). One very good way to accomplish this is simply to invoke the original definition of the name when you are finished with your extensions. Example 10.11 shows a redefinition of showpage that adds a “draft” notice onto the edge of the document as it is being printed. The original (or previous, to be more accurate) definition of
130 |
Chapter 10: USING DICTIONARIES |

showpage is loaded at the beginning, and is executed from within the redefined showpage procedure:
Example 10.11: Redefining showpage to Print Draft Notice
/startingCTM matrix currentmatrix def /old_showpage /showpage load def /showpage % - showpage - { %def
gsave
startingCTM setmatrix 90 rotate 30 -590 moveto
/Helvetica-Bold findfont 24 scalefont setfont (DRAFT document. Please destroy promptly.) show
grestore old_showpage
} bind def
Debugging with Redefined Names
A very good way to track the execution of your program is to redefine one of the operations in it to produce some extra tracking information as it is being called. For instance, you could redefine the show operator to echo each string back to the standard output file as it is being printed, or you could redefine the moveto operator to watch for coordinates that are off the page and to warn you. Then, once you get the program working, you can simply remove your redefinitions, and the program should work without further modification.
Example 10.12 contains a simple redefinition of the show operator that will track each string as it is being printed.
Example 10.12: Redefining show to Help Debugging
/old_show /show load def
/show % (string) show - { %def
dup == flush old_show
} bind def
Chapter 10: USING DICTIONARIES |
131 |