Chapter 2
Operators, Procedures, and Control Structures
How does PostScript transform simple instructions into complex graphics and automation? This chapter pulls back the curtain on PostScript's remarkable set of built-in operators, its flexible approach to procedures, and the powerful control structures that enable expressive, efficient scripting. By dissecting these building blocks, you'll discover how deliberate design choices promote both creativity and performance in graphical programming.
2.1 Operator Taxonomy and Core Primitives
PostScript is a dynamically typed, stack-oriented programming language designed for describing the appearance of printed pages. Its power and flexibility arise largely from a comprehensive set of operators categorized into distinct classes, each serving specialized roles in computation, control, and graphical rendering. Understanding these operator classes and their fundamental primitives is essential for the effective manipulation of the operand stack, execution flow, and graphical state. The following taxonomy delineates the primary operator categories, explicates their semantics, and highlights exemplary use cases.
Arithmetic Operators
Arithmetic operators perform numerical computations, predominantly on real and integer operands, directly manipulating the operand stack. Core arithmetic primitives include add, sub, mul, div, and idiv.
- add: Pops the two top operands from the stack, adds them, and pushes the sum.
- sub: Subtracts the top operand from the next, pushing the difference.
- mul: Multiplies the top two operands.
- div: Performs real division, yielding a floating-point result.
- idiv: Performs integer division, truncating toward zero.
These operators are foundational in numerical processing-scaling coordinates, manipulating dimensions, or computing analytic results within graphics and control structures. For example, add and sub are frequently used to calculate new positions or offsets when constructing paths or transforming coordinate frames.
Logical and Relational Operators
Logical operators facilitate conditional evaluation and decision-making by operating on boolean or numeric values interpreted as logical states. Principal relational operators include eq, ne, gt, lt, ge, and le, each comparing two operands and pushing a boolean result.
- eq: Tests equality.
- ne: Tests inequality.
- gt, lt: Determine greater-than or less-than relations.
- ge, le: Evaluate greater-than-or-equal and less-than-or-equal.
Logical operators such as and, or, and not apply bitwise or boolean logic. These operators are central to flow control, enabling conditional execution, loop termination, and pattern matching during procedure definitions and programmatic drawing operations.
Stack Manipulation Operators
Given PostScript's stack-centric execution model, stack manipulation operators form the backbone of operand management. They enable access to, inspection of, duplication, and reordering of stack elements.
- dup: Copies the topmost stack element.
- exch: Exchanges the top two elements.
- pop: Removes the top element.
- index: Duplicates the nth element counting from the top.
- roll: Rotates elements within the top n operands by a specified number of positions.
These primitives are critical for non-destructive operations and intermediate result management. For example, dup is extensively used to preserve operands needed for multiple subsequent computations without redundant stack pushes. roll provides low-level control for complex operand rearrangements essential in advanced algorithms and recursive procedures.
Dictionary and Name Operators
PostScript employs dictionaries as associative arrays to map names (symbols) to values. Operators in this class manage the creation, modification, and lookup of bindings within the dictionary stack.
- dict: Creates a new dictionary with a specified capacity.
- begin: Pushes a dictionary onto the dictionary stack, making its keys visible for name resolution.
- end: Pops the current dictionary from the dictionary stack.
- def: Defines a name-to-object binding in the current dictionary.
- load: Retrieves the value bound to a name.
These operators enable scoped symbol tables, permitting modularity and encapsulation within PostScript programs. They are indispensable in structuring code, parameterizing procedures, and extending language functionality through user-defined operators.
Control Flow Operators
Control flow primitives direct the sequential execution of instructions, enabling conditional branching and iteration.
- if: Executes a procedure if a boolean on the stack is true.
- ifelse: Executes one of two procedures based on a boolean condition.
- for: Iterates a procedure over a numeric range, incrementing by a specified step.
- repeat: Iterates a procedure a fixed number of times.
- exit: Terminates looping constructs prematurely.
These operators harness executable arrays (procedures) as first-class objects, enabling concise expression of complex iterative patterns and conditional logic embedded within graphics generation or data manipulations.
Graphics State Operators
PostScript's graphics model relies on a mutable graphics state encapsulating parameters such as current transformation matrix (CTM), line width, color, and clipping paths. Operators in this category interrogate and modify this state.
- gsave and grestore: Save and restore the graphics state, allowing temporary modifications without permanent side effects.
- setlinewidth: Specifies the thickness of lines in user space units.
- setrgbcolor, setgray: Assign fill and stroke colors.
- translate, scale, rotate: Manipulate the CTM to position, size, or orient subsequent graphics primitives.
- newpath, closepath: Begin and terminate path construction.
The ability to save and restore state precisely allows complex graphics operations to be nested and layered without unintended parameter spillover. Transformation operators support intricate coordinate mapping central to scalable, device-independent vector graphics.
Path Construction and Painting Operators
Path construction operators build geometric outlines composed of lines, curves, and arcs.
- moveto: Sets the current point to a specified coordinate without drawing.
- lineto: Adds a line segment from the current point to a new point.
- curveto: Adds Bézier cubic curve segments.
- arc, arcn: Add circular arc segments.
- stroke: Draws the current path with the current line style.
- fill: Fills the interior of a closed path.
These operators form the geometric basis for rendering complex shapes and text outlines. The distinction between path construction and painting primitives underscores the PostScript philosophy of describing vector graphics declaratively before rasterization.
Execution Control and Procedure Operators
...