Duplicates the nth element from the top of the operand stack, where n is counted from 0.
1. Description
The index operator removes a non-negative integer n from the operand stack, counts down to the nth element from the top (where the top is position 0), and pushes a copy of that element onto the stack.
This operator is particularly useful for accessing elements deep in the stack without disturbing the intervening elements. It’s essentially a generalized form of dup, where 0 index is equivalent to dup.
This is a Level 1 operator, available in all PostScript implementations.
2. Syntax
anyn ... any0 n index anyn ... any0 anyn
2.1. Stack Effect
| Position | Content |
|---|---|
Top |
|
Top-1 |
|
Top-2 |
|
… |
… |
Top-(n+1) |
|
| Position | Content |
|---|---|
Top |
|
Top-1 |
|
Top-2 |
|
… |
… |
Top-(n+1) |
|
3. Parameters
n-
Non-negative integer specifying which element to duplicate. 0 indicates the top element, 1 the second element, etc.
anyn … any0-
At least n+1 elements must be present on the stack below the n operand.
4. Return Values
A copy of the element at position n from the top of the stack (before the n was removed).
5. Examples
5.1. Basic Usage
% Stack positions are 0-based from top
(a)(b)(c)(d) 0 index -> (a)(b)(c)(d)(d) % Top element
(a)(b)(c)(d) 1 index -> (a)(b)(c)(d)(c) % Second element
(a)(b)(c)(d) 2 index -> (a)(b)(c)(d)(b) % Third element
(a)(b)(c)(d) 3 index -> (a)(b)(c)(d)(a) % Fourth element
5.3. Accessing Buried Values
% Access value deep in stack
1 2 3 4 5 % Stack: 1 2 3 4 5
2 index % Stack: 1 2 3 4 5 3
% Retrieved third element (3) without disturbing stack
5.4. Using in Calculations
% Calculate: (a + b) * a
% where a and b are already on stack
10 20 % Stack: 10 20 (a=10, b=20)
add % Stack: 30
10 % Need original 'a' again - but it's gone!
% Better approach:
10 20 % Stack: 10 20
1 index % Stack: 10 20 10 (duplicate a)
3 1 roll % Stack: 10 10 20
add % Stack: 10 30
mul % Stack: 300
6. Advanced Examples
6.1. Implementing pick Operation
% Some PostScript dialects have 'pick' which is same as 'index'
/pick { % ... n -> ... elem
index
} def
1 2 3 4 5
2 pick % Stack: 1 2 3 4 5 3
6.2. Safe Index with Bounds Check
% Index with safety check
/safeIndex { % ... n -> ... elem (or error)
dup count 1 sub gt {
pop
(Error: index out of bounds) print
0
} {
index
} ifelse
} def
1 2 3
5 safeIndex % Prints error, returns 0
6.3. Copying Multiple Deep Elements
% Copy elements at specific indices
/multiIndex { % ... idx1 idx2 idx3 ... idxn n -> ... elem1 elem2 ... elemn
dup 1 sub -1 0 {
% For each index
1 add index
exch
} for
pop
} def
10 20 30 40 50
3 1 0 % Indices to copy
3 multiIndex % Copies elements at positions 0, 1, 3
7. Edge Cases and Common Pitfalls
Using index with n greater than or equal to the stack depth causes a rangecheck error.
|
7.1. Index Out of Range
% BAD: Index too large
1 2 3
5 index % ERROR: rangecheck
% Only 3 elements, can't access index 5
7.3. Stack Underflow
% BAD: Not enough elements
clear
0 index % ERROR: stackunderflow
% Need at least 1 element plus the index
7.4. Off-by-One Errors
% CAUTION: Remember indexing is 0-based
(a)(b)(c)
2 index % Returns (a), not (c)!
% Position 0 = (c), Position 1 = (b), Position 2 = (a)
Remember that stack positions are counted from 0, where 0 is the topmost element. The index operand itself is removed before counting, so you’re indexing into the stack as it was before calling index.
|
9. PostScript Level
Available in: PostScript Level 1 and higher
This is a fundamental operator available in all PostScript implementations.
10. Error Conditions
stackunderflow-
The operand stack has fewer than n+2 elements (n+1 elements plus the n operand itself).
clear 1 2 3 % 3 elements 3 index % ERROR: stackunderflow % Need 4 elements for index 3 rangecheck-
The value of n is negative, or n is greater than or equal to the number of elements on the stack (excluding n itself).
1 2 3 5 index % ERROR: rangecheck (only 3 elements) 1 2 3 -1 index % ERROR: rangecheck (negative) typecheck-
The top operand is not an integer.
1 2 3 (not a number) index % ERROR: typecheck
11. Performance Considerations
The index operator has O(1) constant time complexity. It’s very fast regardless of the index value, as it doesn’t need to traverse the stack.
However, frequently using large index values may indicate poor stack management. Consider restructuring your code to keep frequently accessed values near the top of the stack.
12. Best Practices
-
Use for deep access:
indexis ideal when you need an element buried in the stack -
Prefer dup for top element: Use
duprather than0 indexfor clarity -
Check bounds: Use
countto verify sufficient stack depth before large indices -
Document stack layout: When using
index, clearly document which stack position contains what -
Consider roll instead: For repeated access to deep elements,
rollmight be more efficient
12.1. Clear Documentation
% Always document stack layout when using index
/drawLine { % x1 y1 x2 y2 -> -
% Stack: x1 y1 x2 y2
3 index % Stack: x1 y1 x2 y2 x1
3 index % Stack: x1 y1 x2 y2 x1 y1
moveto
lineto
stroke
} def
% Or better yet, use named values:
/drawLine { % x1 y1 x2 y2 -> -
4 dict begin
/y2 exch def /x2 exch def
/y1 exch def /x1 exch def
x1 y1 moveto
x2 y2 lineto
stroke
end
} def
13. See Also
-
Operators Overview - Understanding PostScript operators
-
Stack Operations Guide - Stack manipulation tutorial
-
Stack Manipulation - All stack operators