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

Figure 5.3: Visual Chunking for Example 5.3
/Times-Roman findfont (Testing) exch 12 scalefont setfont show
/Times-Roman findfont (Testing) exch12 scalefont setfont show (Testing)
/Times-Roman findfont 12 scalefont setfont show
(Testing) /Times-Roman findfont 12 scalefont setfont show
(Testing) /Times-Roman findfont 12 scalefont setfont show
operators
exch setfont
boxed operations produce new objects bold operations rearrange their operands
bold-italic operations consume their operands empty boxes indicate values removed from stack
THINKING BACKWARD AND SIDEWAYS
A stack-based language such as PostScript makes you think differently than most programming languages. It seems, at first, as though you have to think backwards, since all the operators come after their operands. However, if you think of the entire expression at once, it is only slightly different than thinking in prefix or infix notation (see Example 5.4 through Example 5.6).
Example 5.4: Operator Prefix Notation in C
/* In a function call, the operands come in parentheses after the function name */ value = currentpoint(Y);
value = sqrt(X);
Example 5.5: Operator Infix Notation in C
/* Arithmetic operators typically come between their operands */ value = value - 12;
if ( value <= 72 ) showpage();
58 |
Chapter 5: UNDERSTANDING THE STACK |

Example 5.6: Postfix Notation in PostScript
% In PostScript, the operators always come after the operands: currentpoint exch pop 72 lt { showpage } if
Since the PostScript language allows you to write programs in a very open format, the emphasis on backward thinking is even less, and sideways thinking becomes more important, such as in Example 5.7. The language would feel much more stack-oriented if you were forced to write only one token on each line, more like assembly language. That is, in fact, almost exactly what the interpreter sees, since it reads a single token and acts on it before reading the next token.
Example 5.7: Programming One Token at a Time
/Times-Roman findfont (Testing)
exch 12
scalefont setfont show
In reality, the most common occurrence is a combination of horizontal and vertical thinking. Consider the common case of a procedure that uses local names for its arguments (Example 5.8). Its output is shown in Figure 5.4 for your reference.
Example 5.8: Procedure Arguments on the Stack
/graybox |
% gray linewidth Lx Ly Ux Uy graybox - |
{ %def |
|
/upperY exch def /upperX exch def /lowerY exch def /lowerX exch def /linewidth exch def /gray exch def
lowerX lowerY moveto lowerX upperY lineto upperX upperY lineto
upperX lowerY lineto closepath
Chapter 5: UNDERSTANDING THE STACK |
59 |

gsave
gsave gray setgray fill grestore linewidth setlinewidth stroke
grestore } bind def
0.5 2 100 200 500 400 graybox
Figure 5.4: Output of Example 5.8
output page
|
|
|
|
|
Since stacks are last-in, first-out data structures, the last object on a line is |
||
|
at the very top of the operand stack. In this example, this can be seen most |
||
|
clearly by looking at the procedure call itself; that’s why the first line in |
||
|
the procedure grabs the last argument on the line, since it is now on the |
||
|
top of the operand stack (see Figure 5.5). |
||
|
You can start to see the relationship in this example between the left-to- |
||
|
right distribution of objects in the source program and the top-to-bottom |
||
|
result on the operand stack. Notice the way the arguments to the |
||
|
procedure line up with the exch def lines in the procedure definition itself. |
||
|
|
|
|
TIP |
When reading a PostScript program, find the executable names and use |
||
|
them as reference points. If the name is a procedure call, look to the left of |
||
|
the name in the body of the program to follow along as you read down |
||
|
through the procedure definition (as in Figure 5.5). |
||
|
|
|
|
60 |
Chapter 5: UNDERSTANDING THE STACK |