在 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
我的期望是,通过使用 bind
,R
、G
和 B
的值将按字面意思捕获。 IE。我期望上面的代码等同于此:
/cRED { 1 0 0 setrgbcolor } def
/cGRN { 0 1 0 setrgbcolor } def
/cBLU { 0 0 1 setrgbcolor } def
遗憾的是实际结果是cRED
cGRN
和cBLU
都将颜色设置为蓝色。这是因为 cRED
cGRN
和 cBLU
仍然依赖于 R
G
和 B
对象(它们是全局变量)。所以所有颜色都是蓝色,因为 cBLU
最后定义,设置 R
G
和 B
。显然 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 }
所以,也许微效率有些轻微的损失。但它可以用于各种各样的事情。
这个问题的目的是从编程的角度更好地理解 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
.
我尝试了以下方法:
/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
我的期望是,通过使用 bind
,R
、G
和 B
的值将按字面意思捕获。 IE。我期望上面的代码等同于此:
/cRED { 1 0 0 setrgbcolor } def
/cGRN { 0 1 0 setrgbcolor } def
/cBLU { 0 0 1 setrgbcolor } def
遗憾的是实际结果是cRED
cGRN
和cBLU
都将颜色设置为蓝色。这是因为 cRED
cGRN
和 cBLU
仍然依赖于 R
G
和 B
对象(它们是全局变量)。所以所有颜色都是蓝色,因为 cBLU
最后定义,设置 R
G
和 B
。显然 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 }
所以,也许微效率有些轻微的损失。但它可以用于各种各样的事情。