How to avoid stackunderflow (use variable # of arguments) in PostScript

592 Views Asked by At

I have a simple function with two variables as

/func {
/var1 exch def
/var2 exch def
... process ...
} def

(var2)(var1)func

I want to make var2 optional. However, if not providing var2, it results in stackunderflow error. How can I make a if statement to catch var2 only if the stack is not empty, and probably assign a default value if the stack is empty.

Something like

(Stack is no empty) {/var2 exch def}{/var2 (default) def} ifelse
3

There are 3 best solutions below

0
On

The count operator counts the number of operands on the stack. You might like to instead use [ to put a mark on the stack and then use counttomark instead. This saves you getting confused by operands being left over, or not yet used, when your routine is called from other routines. Of course it means you have to supply the [ as an operand on the stack.

The other usual method is to have the top operand be an integer counting the number of additional operands..

0
On

Another usual method is to use the type of the topmost operand to determine how many operands to look for.

Here's one way to implement the rotate operator that does this:

/rotate { % angle ([matrix])?  rotate  -|[matrix]
    dup type /arraytype ne 
        { true exch matrix } % no array: create array, concat later
        { false 3 1 roll } % array: do not create, do not concat later
    ifelse                    % bool angle matrix
    dup 0                     % bool angle matrix matrix 0
          3 index cos put     % bool angle matrix
    dup 1 3 index sin put     % bool angle matrix
    dup 2 3 index sin neg put % bool angle matrix
    dup 3 4 3 roll cos put    % bool matrix
    exch { concat } if % [matrix]
} def
0
On

Still another way is to pass a dictionary of named parameters. Modifying your example...

/func { %<<params>>
%begin currentdict /var2 2 copy known not {(default) put}{pop pop} ifelse
<</var2(default)>> copy begin
% ... process ...
end } def

<<
/var1 (var1)
/var2 (var2)
>> func