
- •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 6
Trusting the Stack
Most beginning PostScript programmers don’t trust the operand stack. It seems like just a vehicle for transporting data to their procedures, and the sooner the data can be retrieved from the stack and put safely into a variable, the happier the programmer is.
There is a vague truth to this feeling, but it has only to do with the programmer, and not the PostScript language itself. It is a bit more difficult to think like a stack-based interpreter, so you can get confused about what is on the stack, how it got there, and what you should do with it, and this confusion can lead to bugs and lost data. However, since you cannot avoid the operand stack when writing PostScript programs, it is best just to master it, rather than to mistrust it.
67

SAFETY OF DATA ON THE STACK
In truth, the safest place for a piece of data is on the operand stack, with a few small caveats.
•If your program has bugs, you may inadvertently remove something from the operand stack that you needed, or leave something extra that will cause some later operation to trip over it. Sometimes these stack alignment programs persist for a long time, unless you consistently test all the paths through your program.
•Stack-based manipulations of more than a few operations or more than a few operands can be tricky to read and maintain, leading to the bugs just mentioned.
•If you transfer control temporarily to some other program, as you might do with an embedded illustration, for example, you should not be surprised if something you left on the operand stack is no longer there.
In general, the cleanest, fastest and best programs are those that make judicious use of the operand stack. As a rough rule of thumb, in designing a PostScript program you should spend 65 percent of your time thinking about the order of operands on the stack, whether or not you should divide all of your coordinate numbers by 1,000 before sending them to the interpreter, and whether you can get away without sending the X coordinate every time you plot a vertical line. You should spend 20 percent of your time adjusting the procedures you have defined to match the decisions you have made about operand order and use. (The remaining 15 percent is for debugging and getting distracted.)
Of course, these principles of careful use of the operand stack are derived primarily from printer drivers, which are inherently batch programs. If you are writing an interactive application in PostScript, or if you are writing a utility program that is entirely self-contained, you may have different goals—but the basic ideas still apply. The data must be on the operand stack in order for any PostScript operator to use it, so you might as well take advantage of that premise and try not to take things off the stack and put them on too many times unnecessarily.
68 |
Chapter 6: TRUSTING THE STACK |

The name of this chapter is the key: trust the operand stack. You should not simply follow a recipe that says always to use the stack or always to use variable names. Use the operand stack wisely, use it when speed is important, and use it because it is already there. Use it because you have mastered it and have learned its strengths and weaknesses and because you have to use it anyway.
Remember that the operand stack is used by every PostScript operator and procedure as the way to pass data and operands. The more cleanly your program supports this natural interface, the faster and more efficient it will be.
WHERE ARE THE DATA GOING?
One of the important things to consider when you’re designing a PostScript program is what you’re using the stack for at any given moment. Are you passing parameters to a function? Is the information on the stack raw data? Will the information be used once or many times? If you only need the data once, it is best to arrange it in such a way that you can use the data directly from the operand stack and never think about it again.
A common approach to dealing with data on the operand stack is to store the data under some name in a dictionary, rather than leaving the values on the operand stack. This has a few advantages.
•The data can be recalled onto the stack many times.
•Debugging can be easier with named data.
•Storing the data helps to minimize nasty stack manipulations.
The first few times you try to read or write PostScript programs, it may be difficult to understand what is going on in a statement like the one in Example 6.1. What is exch doing exactly where you would expect to see the value part of the definition?
As you know, the def operator requires its key and value in a particular order on the stack. If the value—the object you want to store—got put on the operand stack before you had a chance to put the key—the name under which you store that value—on the stack, then you would have them in the wrong order for def. In this case, you need to call exch to get them in
Chapter 6: TRUSTING THE STACK |
69 |

the right order. It gets just slightly more confusing when the expression is buried inside a procedure somewhere. You can’t see the value at all in that case, because it isn’t on the stack yet. It won’t be until you run the program and some operation produces the value as it executes.
If you call a procedure with many pieces of data on the operand stack as arguments, it can be a little bit tricky to get them stored into a dictionary. The typical trick is to associate keys with them and to execute def. A small amount of operand stack manipulation is required. Since the operands are in stack order, they need to be taken from the stack in the opposite order (see Example 6.1).
Example 6.1: Using exch def in a Procedure
/proc |
% A B C proc - |
{ %def |
|
/C exch def |
|
/B exch def |
|
/A exch def |
|
} def |
|
(a) (b) (c) proc |
|
Remember that the code fragment
(a) /A exch def
is equivalent to
/A (a) def
(without the exch), which is why it works. (See also Thinking Backward and Sideways in Chapter 5.)
Once you have collected the operands into the current dictionary, you simply call them by name in order to use them. Each time you supply the name in your program, it will be looked up in the current dictionary (or dictionary stack) and the value will be placed on the operand stack again.
70 |
Chapter 6: TRUSTING THE STACK |