In PostScript, define a procedure to define other procedures

The goal of this question is to understand PostScript a little better from a programming perspective. The purpose described below is just an example used for illustration.

In PostScript language, I can define a routine to set the current graphic color as follows:

/cRED { 1 0 0 setrgbcolor } def  % define a procedure to set the color to red.

      

I was wondering if there is a way to define a routine that will define other color routines. Suppose that such a procedure has been defined, called cdef

. I could use it like this:

/cRED 1 0 0 cdef

      

This should have the same effect as the previous definition of cRED. The problem is that I cannot figure out how to "grab" the literal value of the items on the stack in a procedure passed to def

.

I tried the following:

/cdef { /B exch def /G exch def /R exch def { R G B setrgbcolor } bind def } def
/cRED 1 0 0  cdef
/cGRN 0 1 0  cdef 
/cBLU 0 0 1  cdef

      

I expected that using the bind

value R

G

and B

would be written literally. That is, I expected the above code to be equivalent to this:

/cRED { 1 0 0 setrgbcolor } def
/cGRN { 0 1 0 setrgbcolor } def
/cBLU { 0 0 1 setrgbcolor } def

      

Unfortunately, the actual result is that cRED

cGRN

, and cBLU

are all set color blue . This is because cRED

cGRN

and cBLU

still depends on objects R

G

and B

(which are global). And so the color is blue for everyone, because it cBLU

is determined by the latter by setting R

G

and B

. Apparently bind

didn't work as I expected.

Is there a way to define cdef

to achieve this? The crux of the problem is to pop the value off the stack and store it literally with def

. For example. something like this pseudocode:

/cdef { { $ $ $ setrgbcolor } bind def } def

      

Where $

woudl will be replaced with the literal value of the element at the top of the stack when evaluating cdef. So, it /cCYN 0 1 1 cdef

is evaluated as/cCYN { 0 1 1 setrgbcolor } bind def

Is there any statement out there that accomplishes the purpose $

as described above? Operators pop

, =

and index

are close, but don't seem to work. Also, the use of immediately evaluated names (for example //name

) seems promising, but they seem to be evaluated even before execution cdef

.

thank

+3


source to share


2 answers


Do this by rolling the parameters in place instead of assigning them

/cdef { [ 4 1 roll /setrgbcolor load ] cvx bind def } def

      

Thus, when executed ] cvx bind def

internally, it finds on the operand stack

/YourNameForTheProcedure
[ (i.e. mark)
your three parameters (the mark has been rolled below them)
the setrgbcolor operator (or procedure?)

      



Then the closure ]

will make an array of three numbers and setrgbcolor, which will be made into the procedure using cvx

.

Note: Then you must pass the parameters r, g, b in the correct order:

/CR 1 0 0 cdef
/CG 0 1 0 cdef
/CB 0 0 1 cdef

      

+4


source


Stefan's answer is probably the best and easiest way for this case. But there are several more ways to create procedures in postscript.

Since you know the exact number of elements, you can skip the stack label with the label and do it like this:

/cdef { /setrgbcolor load 4 array astore cvx def } def

      

And the more complex way can be useful for more complex functions. You can define arguments and substitute definitions for a string template. I think this is what you were aiming for with immediately appreciated names. Executing the string returns the body of the procedure, but the scan and evaluation is done at runtime.

/cdef { 
    3 dict begin
        { b g r } { exch def } forall
        ({ //r //g //b setrgbcolor }) cvx exec
    end
    def
} def

      



And one more way, which is perhaps awkward, but very flexible.

/curry {
    /exec cvx
    3 array astore cvx
} def

/cdef {
    {setrgbcolor} 3{curry}repeat
    def
} def

      

This results in this procedure being defined for values ​​1 2 3:

{ 1 { 2 { 3 { setrgbcolor } exec } exec } exec }

      

So maybe a small loss in microefficiency. But it can be used for all kinds of things.

+4


source







All Articles