在 PostScript 中,定义一个过程来定义其他过程

In PostScript, define a procedure to define other procedures

这个问题的目的是从编程的角度更好地理解 PostScript。下面描述的目标只是一个用于说明的示例。

在PostScript语言中,我可以定义一个设置当前图形颜色的程序如下:

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

我想知道是否有一种方法可以定义一个可以定义其他颜色程序的程序。假设定义了这样一个名为 cdef 的过程。我可以按如下方式使用它:

/cRED 1 0 0 cdef

这应该与前面定义的 cRED 具有相同的效果。 问题是我似乎无法弄清楚如何在传递给 def.

的过程中 "capture" 堆栈上项目的字面值

我尝试了以下方法:

/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

我的期望是,通过使用 bindRGB 的值将按字面意思捕获。 IE。我期望上面的代码等同于此:

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

遗憾的是实际结果是cREDcGRNcBLU都将颜色设置为蓝色。这是因为 cRED cGRNcBLU 仍然依赖于 R GB 对象(它们是全局变量)。所以所有颜色都是蓝色,因为 cBLU 最后定义,设置 R GB。显然 bind 没有按我预期的方式工作。

有没有办法定义 cdef 来实现这个?问题的症结在于能够从堆栈中弹出一个值并使用 def 逐字存储它。例如。像这样的 伪代码:

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

其中 $ 在计算 cdef 时将被替换为堆栈顶部项目的字面值。所以 /cCYN 0 1 1 cdef 被评估为 /cCYN { 0 1 1 setrgbcolor } bind def

是否有一些运算符可以实现上述 $ 的目的?运算符 pop=index 很接近,但似乎不起作用。 此外,使用立即评估的名称(例如//name)似乎很有希望,但它们似乎甚至在执行cdef之前就已评估。

谢谢

通过 "rolling" 适当的参数而不是分配它们来完成

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

这样,里面的] cvx bind def执行的时候会在操作数栈上找到

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

然后关闭]将三个数字和setrgbcolor组成一个数组,cvx.

将其制作成一个过程

注意:然后你必须按正确的顺序传递r,g,b参数:

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

对于这种情况,Stefan 的回答可能是最好和最简单的方法。但是在 postscript 中还有很多构造过程的方法。

因为你知道元素的确切数量,你可以跳过堆栈与标记的杂耍,像这样做:

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

更复杂的方法可能对更复杂的功能有用。您可以定义参数并将定义替换为字符串模板。我认为这就是您通过立即评估的名称努力实现的目标。执行字符串会产生过程主体,但扫描和 求值 是在 运行 时执行的。

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

还有另一种方式,虽然笨拙但非常灵活。

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

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

这导致为值 1 2 3 定义此过程:

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

所以,也许微效率有些轻微的损失。但它可以用于各种各样的事情。