在Thinking in Postscript(pdf),第5章,练习3(第64-65页)要求读者重构此代码以不存储任何字典条目:
36 750 moveto /Times-Roman 24 selectfont
% works like “show”, leaving current point at proper location
/ushow
% linethickness lineposition (words) ushow -
{ %def
LOCAL begin
/text exch def
/linepos exch def
/linethick exch def
gsave
0 linepos rmoveto
text stringwidth rlineto
linethick setlinewidth stroke
grestore
text show
end
} dup 0 4 dict put def
0.5 -4 (test underlined text) ushow
我的问题是LOCAL
。 Ghostscript运行此代码时没有错误,但LOCAL
不是:
在PostScript中,LOCAL
是什么?
答案 0 :(得分:3)
没有任何定义。代码有点偷偷摸摸,因为代码 dup 0 4 dict put def 将采用可执行文件并用 4 dict 的结果替换LOCAL。可复制块({}之间的东西)被复制主要是因为put没有返回任何内容。由于它是对你剩下的同一块的引用
/ushow {-dict- begin ...rest of the executable...} def
这一切都是有效的,因为LOCAL从未在任何地方使用过(它在使用之前就被销毁了)。你使用什么代替LOCAL并不重要。
答案 1 :(得分:2)
正如joojaa正确解释的那样,LOCAL
没有被定义为任何好的,因为它在执行之前被替换了。它在构造过程体(数组)期间作为可执行文件名解析,这里它的用途只是在数组中分配一个槽。它实际上可以是任何类型,我经常看到(和写){ 0 begin ...}
出于同样的目的。使用名称可以为代码的人类读者提供更多语义信息。我也看到它在我的矩阵函数中写了{ DICT begin ... }
Here,我称之为STATICDICT
。
对于像这样的任何元语法标记,有一种使用所有大写的约定。它是一个名称类型标记,但在元语法上,它指的是稍后要填充的dicttype对象。为了解释者的利益,没有必要(甚至没有任何机制)声明你正在做什么,但是通过DICT
优先于0
可以获得很多好处。再次,因为它将被完全替换,你也可以使用文字名/LOCAL
来尝试,idunno,减轻下一个菜鸟从寻找{{1}的野鹅追逐中读取你的代码} 被定义为??为此,我还简单地为令牌写了LOCAL
,以便稍后填写。我认为这些术语的选择是风格或观众或其他无形品质的问题。叹息......或者只是一个背景问题。
还有另一种样式适用于在过程体中进行动态替换。通过将字典放在dictstack上并命名它(在它自身内部,因此它是一个封闭的命名空间),我们可以用DUMMY
名称来引用它
//immediate
然后在定义之前删除字典。
4 dict begin
/mydict currentdict def
/proc {
//mydict begin
...
end
}
因此通常定义过程(在外层词典中(在此未命名,大概是end def
)),但是通过名称嵌入了词典,从该名称可用扫描程序体时。
这可以扩展到更多的程序共享相同的私有字典,方法是通过从每个定义的堆栈中提取dict。
userdict
最后的/enddefbegin { currentdict 3 1 roll end def begin } def
4 dict begin
/mydict currentdict def
/proc1 {
//mydict begin
...
end
} enddefbegin
/proc2 {
//mydict begin
...
end
} enddefbegin
end
当然可以简化为enddefbegin end
。
一个警告。以这种方式创建的字典以递归方式包含在自身中。不要尝试使用ghostscript的end def
运算符打印它!
答案 2 :(得分:1)
“蓝皮书”第133页有一个相同技术的稍微简单的例子:
/sampleproc
{ 0 begin
/localvariable 6 def
end
} def
/sampleproc load 0 1 dict put
此处的过程在修改之前定义。包裹你的想法会更容易一些。在原帖中,对我来说最棘手的部分是“dup”,因为我没有意识到堆栈上的数组不是精确的数组,它是一个数组引用(我想的是按值复制,它的功能是复制-by-reference),因此原始代码中的“put”会影响具有第一个引用的数组(因此从堆栈中消耗),第二个引用用于定义过程。这是一个新手的错误,但也许其他新手可以从中学习:
Stack Progression:
... % fast forward
1. ushow --array-- --array-- 0 4 dict | put def % dict creates a dictionary
2. ushow --array-- --array-- 0 --dict-- | put def % put arrives on stack
3. ushow --array-- --array-- 0 --dict-- put | def % put consumes the array 0 and dict
4. ushow --array-- | def % def arrives on stack
5. ushow --array-- def % def consumes the remaining tokens
6.
对于可能不正确的符号表示抱歉,我只是盯着这一段时间,并且认为我可能能够稍微盯着某个人。如果我有任何错误或误导性陈述,请告诉我。