Removes all elements from the operand stack down to and including the topmost mark object.
1. Description
The cleartomark operator pops the operand stack repeatedly until it encounters a mark object, which it also pops and discards. All objects between the top of the stack and the mark (exclusive of the mark itself) are discarded along with the mark.
This operator is commonly used to clean up after variable-argument operations or to discard intermediate results that were accumulated after placing a mark. It’s the complement to mark for managing stack segments.
This is a Level 1 operator, available in all PostScript implementations.
3. Parameters
Requires at least one mark object on the stack. All objects above the topmost mark, plus the mark itself, will be removed.
obj1 … objn-
Any objects (of any type) between the top of the stack and the nearest mark. These will all be discarded.
mark-
A mark object (type
marktype) that delimits the stack segment to remove.
5. Examples
5.1. Basic Usage
% Simple cleartomark
mark 1 2 3 cleartomark
count % Stack: 0 (all removed)
% Preserve elements below mark
10 20 mark 1 2 3 cleartomark
count % Stack: 10 20 2
5.2. Cleaning Up After Operations
% Protect initial stack state
1 2 3 % Initial values
mark % Mark the position
10 20 30 add % Do some work (leaves 10 50)
cleartomark % Clean up work area
% Stack: 1 2 3 (restored)
5.3. Variable Argument Cleanup
% Function that processes args then cleans up
/processAndClean { % mark arg1 ... argn -> result
% Calculate sum
0 {
counttomark 0 eq { exit } if
add
} loop
% Leave result, remove mark
exch pop
} def
mark 1 2 3 4 5 processAndClean
% Stack: 15 (mark and args removed, result remains)
6. Advanced Examples
6.1. Safe Execution with Cleanup
% Execute procedure with guaranteed cleanup
/withCleanup { % mark proc -> (executes proc, cleans on exit or error)
{
exec
cleartomark
} stopped {
cleartomark % Clean up even on error
stop % Re-raise error
} if
} def
% Usage
10 20 mark
{ 2 mul add } % Some operation
withCleanup
% Stack: 50 (intermediate mark removed)
6.2. Stack State Restoration
% Save and restore stack state
/saveStack { % -> array
count array astore
} def
/restoreStack { % array -> (restores stack)
mark exch aload pop
cleartomark % Remove mark, keep elements
} def
1 2 3
saveStack % Save state
10 20 30 % Modify stack
exch % Restore state
restoreStack
% Stack: 1 2 3 (restored)
6.3. Bounded Stack Operations
[source,postscript>
% Execute with stack depth limit
/withLimit { % mark maxdepth proc -> ...
mark % Inner mark
3 -1 roll exec % Execute proc
% Check if exceeded limit
counttomark 3 -1 roll gt {
(Stack limit exceeded) print
cleartomark cleartomark
} {
pop % Remove maxdepth
cleartomark % Remove inner mark
exch pop % Remove outer mark
} ifelse
} def
6.4. Dictionary Building Pattern
% Build dictionary from marked key-value pairs
/dictFromMark { % mark /key1 val1 ... /keyn valn -> dict
counttomark 2 idiv % Count pairs
dict begin
counttomark 2 idiv {
def
} repeat
currentdict end
exch pop % Remove mark
} def
mark
/name (PostScript)
/version 3
dictFromMark
7. Edge Cases and Common Pitfalls
If no mark exists on the stack, cleartomark causes an unmatchedmark error.
|
7.1. No Mark on Stack
% BAD: No mark to clear to
clear
1 2 3
cleartomark % ERROR: unmatchedmark
% GOOD: Always ensure mark exists
mark 1 2 3
cleartomark % OK
7.2. Only Removes to First Mark
% CAUTION: Only clears to nearest mark
mark 1 2 mark 3 4 5
cleartomark
% Stack: mark 1 2 (NOT empty!)
% Only inner segment removed
% To clear both segments:
cleartomark
% Stack: (now empty)
7.3. Mark Below Current Segment
% Elements below mark are preserved
10 20 30 % Bottom elements
mark % Mark
1 2 3 % Top elements
cleartomark
% Stack: 10 20 30 (top elements and mark removed)
Always pair mark with cleartomark to avoid accumulating marks on the stack. Verify mark existence before calling cleartomark in defensive code.
|
8. Related Commands
-
mark- Push a mark object onto stack -
counttomark- Count elements to nearest mark -
clear- Remove all elements from stack -
pop- Remove single element -
]- Create array and remove mark (essentially cleartomark + array construction)
9. PostScript Level
Available in: PostScript Level 1 and higher
This is a fundamental operator available in all PostScript implementations.
10. Error Conditions
unmatchedmark-
No mark object is found on the operand stack when searching from top to bottom.
clear 1 2 3 cleartomark % ERROR: unmatchedmark
11. Performance Considerations
The cleartomark operator has O(n) time complexity where n is the number of elements between the top of the stack and the mark. This is generally very fast since most marked segments are small.
The operator must scan the stack to find the mark, so very deep marks are slightly more expensive to clear.
12. Best Practices
-
Always pair with mark: Every
markshould have a matchingcleartomarkor] -
Use for cleanup: Excellent for cleaning up intermediate results
-
Check for mark: In defensive code, verify mark exists before calling
-
Document mark usage: Make it clear when procedures use marked segments
-
Prefer over manual popping:
cleartomarkis safer than counting and popping
12.1. Good Pattern: Guaranteed Cleanup
% Always clean up, even on error
/safeOperation { % args... -> result
mark % Protect stack
{
% Do risky operations
% ... operations ...
% Leave result on stack
} stopped {
cleartomark % Clean up on error
stop % Re-raise
} {
% Success: clean up and keep result
exch cleartomark
} ifelse
} def
13. See Also
-
Operators Overview - Understanding PostScript operators
-
Stack Operations Guide - Stack manipulation tutorial
-
Error Handling - Using marks for cleanup
-
Stack Manipulation - All stack operators