- 1. Operators
- 1.1. Overview
- 1.2. Operator Characteristics
- 1.3. Operator Execution Model
- 1.4. Operator Categories
- 1.5. Stack Effects Notation
- 1.6. Operator Binding
- 1.7. Operator Performance
- 1.8. Operator Errors
- 1.9. Custom Operators (Level 2+)
- 1.10. Immediate Execution
- 1.11. Operator vs Procedure Comparison
- 1.12. Best Practices
- 1.13. Common Patterns
- 1.14. See Also
1. Operators
Operators are the executable commands that perform PostScript’s primitive operations. They manipulate objects on the operand stack, perform calculations, control program flow, and manage the graphics state.
1.1. Overview
PostScript operators are built-in primitives that execute when their names are encountered during interpretation. Unlike procedures (user-defined code), operators are implemented directly by the PostScript interpreter for efficiency.
1.2. Operator Characteristics
1.2.1. Built-in Primitives
All operators are pre-defined by the PostScript implementation and stored in systemdict.
add % Arithmetic operator
def % Dictionary operator
moveto % Graphics operator
ifelse % Control flow operator
1.3. Operator Execution Model
Understanding how operators execute is fundamental to PostScript programming.
1.3.1. Stack-Based Execution
Operators operate on objects from the operand stack and push results back:
% Before: Stack is empty
3 % Push 3: [3]
4 % Push 4: [3 4]
add % Execute add: [7]
% After: Result 7 on stack
1.4. Operator Categories
PostScript operators are organized into functional categories.
1.4.1. Stack Manipulation
Operators that reorganize the operand stack:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Remove top item |
|
|
Duplicate top item |
|
|
Exchange top two items |
|
|
Duplicate top n items |
|
|
Roll n items j times |
|
|
Copy n-th item to top |
|
|
Clear entire stack |
1 2 3 pop % Stack: [1 2]
1 2 dup % Stack: [1 2 2]
1 2 exch % Stack: [2 1]
1 2 3 2 copy % Stack: [1 2 3 2 3]
1 2 3 3 1 roll % Stack: [3 1 2]
1 2 3 2 index % Stack: [1 2 3 1]
1.4.2. Arithmetic and Math
Operators for numeric calculations:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Addition |
|
|
Subtraction |
|
|
Multiplication |
|
|
Division (real result) |
|
|
Integer division |
|
|
Modulo |
|
|
Negation |
|
|
Absolute value |
|
|
Square root |
|
|
Sine (degrees) |
|
|
Cosine (degrees) |
3 4 add % Result: 7
10 3 sub % Result: 7
5 6 mul % Result: 30
15 2 div % Result: 7.5
15 2 idiv % Result: 7
15 2 mod % Result: 1
-5 abs % Result: 5
9 sqrt % Result: 3.0
1.4.3. Array and String
Operators for composite object manipulation:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Get length |
|
|
Get element at index |
|
|
Put element at index |
|
|
Extract subrange |
|
|
Replace subrange |
|
|
Push all elements |
|
|
Pop elements into array |
|
|
Copy elements |
|
|
Execute proc for each element |
[1 2 3] length % Result: 3
[10 20 30] 1 get % Result: 20
[1 2 3] 0 99 put % Modifies array
(abc) 0 get % Result: 97 (ASCII 'a')
[1 2 3 4] 1 2 getinterval % Result: [2 3]
1.4.4. Dictionary
Operators for dictionary management:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Define in current dict |
|
|
Look up key |
|
|
Store in dict on stack |
|
|
Push dict on dict stack |
|
|
Pop dict from dict stack |
|
|
Create dictionary |
|
|
Test if key exists |
|
|
Find dict containing key |
|
|
Remove key from dict |
/x 42 def % Define x=42 in current dict
/x load % Look up x, result: 42
10 dict begin % Create dict and push on dict stack
/y 10 def % Define in new dict
currentdict /y known % Result: true
end % Pop dict stack
1.4.5. Control Flow
Operators that control program execution:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Execute object |
|
|
Conditional execution |
|
|
Conditional branch |
|
|
Counting loop |
|
|
Repeat n times |
|
|
Infinite loop |
|
|
Exit loop |
|
|
Terminate execution |
|
|
Catch stop |
% Conditional
true { (yes) } { (no) } ifelse % Executes first proc
% Loops
1 1 10 { dup mul = } for % Squares 1-10
5 { (Hello) = } repeat % Print 5 times
{ ... exit ... } loop % Exit breaks loop
1.4.6. Type and Attribute
Operators for type checking and conversion:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Get object type |
|
|
Make literal |
|
|
Make executable |
|
|
Check if executable |
|
|
Check if readable |
|
|
Check if writable |
|
|
Convert to integer |
|
|
Convert to real |
|
|
Convert to name |
|
|
Convert to string |
42 type % Result: /integertype
/name cvx % Result: name (executable)
{ } xcheck % Result: true
[1 2] rcheck % Result: true
3.14 cvi % Result: 3
(42) cvi % Result: 42
1.4.7. Graphics State
Operators that modify the graphics state:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Save graphics state |
|
|
Restore graphics state |
|
|
Set line width |
|
|
Set line cap style |
|
|
Set line join style |
|
|
Set gray color |
|
|
Set RGB color |
|
|
Get current point |
|
|
Get line width |
1.4.8. Path Construction
Operators that build paths:
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Clear current path |
|
|
Move current point |
|
|
Append line |
|
|
Append curve |
|
|
Append arc |
|
|
Close subpath |
|
|
Stroke path |
|
|
Fill path |
|
|
Clip to path |
1.5. Stack Effects Notation
Operators are documented with stack effect notation showing input and output:
| Notation | Meaning | Example |
|---|---|---|
|
Any object |
|
|
Number (int or real) |
|
|
Integer only |
|
|
Boolean |
|
|
Array object |
|
|
Stack transformation |
Before → After |
|
Nothing (empty) |
No value pushed/popped |
|
Variable number |
Multiple objects |
% add: num₁ num₂ → sum
% Pops num₂, pops num₁, pushes sum
3 4 add % num₁=3, num₂=4, sum=7
% dup: any → any any
% Copies top item
42 dup % Stack: [42 42]
% exch: any₁ any₂ → any₂ any₁
% Exchanges top two items
10 20 exch % Stack: [20 10]
1.6. Operator Binding
Operators can be bound to names in dictionaries.
1.6.1. Dictionary Lookup
When an executable name is encountered, it’s looked up in the dictionary stack:
% Built-in operators in systemdict
add % Finds /add in systemdict
% User definitions override
/add { mul } def % Redefine add as multiply
3 4 add % Now returns 12!
% Original still available
systemdict /add get exec % True add: 7
1.6.2. Binding Operators
The bind operator replaces names with operators in procedures:
% Unbound procedure
/MyProc { 3 add } def
% Redefine add
/add { mul } def
MyProc % Uses new definition (multiply)
% Bound procedure
/MyProc { 3 add } bind def
% Redefine add again
/add { sub } def
MyProc % Still uses original add
1.6.3. When to Bind
% Bind for performance and safety
/FastProc {
% ... many operators ...
} bind def
% Don't bind if you want flexibility
/FlexibleProc {
MyCustomOp % User can redefine
} def
% Selective binding (Level 2+)
/MixedProc {
add % Will be bound
//sub % Immediately looked up and bound
MyOp % Won't be bound
} bind def
1.7. Operator Performance
Different operators have different performance characteristics.
1.7.1. Fast Operators
Stack and arithmetic operators are typically very fast:
% Fast operations
dup % Stack manipulation
add % Arithmetic
eq % Comparison
1.8. Operator Errors
Operators can generate errors when misused.
1.8.1. Common Errors
| Error | Cause | Example |
|---|---|---|
|
Not enough operands |
|
|
Wrong operand type |
|
|
Value out of range |
|
|
Access violation |
|
|
Name not found |
Unknown operator name |
|
Mark mismatch |
|
% stackunderflow
add % Error: needs 2 operands
% typecheck
42 (text) add % Error: can't add string
% rangecheck
-5 array % Error: negative size
% invalidaccess
[1 2] readonly
dup 0 99 put % Error: array is readonly
% undefined
unknownop % Error: name not defined
1.9. Custom Operators (Level 2+)
Level 2 allows creating custom operators:
% Create operator (Level 2+)
/.setpagedevice /setpagedevice load def
/.setpagedevice {
% Custom pre-processing
dup /PageSize get aload pop
% Call original
/setpagedevice load exec
} bind def
% Operator can now be used
<< /PageSize [612 792] >> setpagedevice
1.10. Immediate Execution
Some operators execute immediately during token scanning:
| Token | Action |
|---|---|
|
Begin procedure mode |
|
End procedure, create array |
|
Push mark (equivalent to |
|
Create array to mark |
|
Push mark for dictionary (Level 2+) |
|
Create dictionary (Level 2+) |
% { and } execute during scanning
{ 1 2 add } % Creates executable array
% Does NOT execute add
% [ and ] execute during scanning
[ 1 2 add ] % Creates array [1 2 3]
% DOES execute add
1.11. Operator vs Procedure Comparison
| Aspect | Operator | Procedure |
|---|---|---|
Implementation |
Built-in primitive |
User-defined code |
Performance |
Fast |
Slower |
Type |
|
|
Modification |
Cannot be modified |
Can be redefined |
Execution |
Direct |
Indirect via interpreter |
Examples |
|
|
1.12. Best Practices
1.12.1. Operator Usage
-
Use built-in operators for best performance
-
Don’t redefine standard operators unnecessarily
-
Bind procedures that use operators extensively
-
Check stack depth before operations
1.12.2. Stack Discipline
% GOOD - balanced stack
/MyProc {
% in: x y
add % out: sum
} def
% BAD - unbalanced stack
/BadProc {
% in: x
dup dup % out: x x x (unexpected extras)
} def
1.13. Common Patterns
1.13.1. Stack Manipulation Idioms
% Rotate three items: a b c → b c a
exch 3 1 roll
% Duplicate second item: a b → a b a
1 index
% Swap and duplicate: a b → b a b
exch 1 index exch
% Clear n items from stack
count n sub {pop} repeat
1.14. See Also
-
Procedures - User-defined executable arrays
-
Objects - Object execution model
-
Tokens - Operator name syntax
-
Data Types - Operand types