Dictionary LOCAL在Postscript中做什么?

Dictionary LOCAL在Postscript中做什么?,dictionary,postscript,Dictionary,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 /linepo

在(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语言参考第三版中
  • 记录在PostScript语言教程和食谱中

在PostScript中,什么是本地的?

没有定义。代码有点狡猾,因为代码dup 0 4 dict put def将获取可执行文件并用4 dict的结果替换本地文件。复制可执行块(在{}之间填充)的主要原因是put不返回任何内容。因为它指的是你留下的同一个街区

/ushow {-dict- begin ...rest of the executable...} def

这一切都是有效的,因为LOCAL从未在任何地方使用过(它在使用之前被销毁)。用什么代替本地并不重要。

正如joojaa正确解释的那样,
LOCAL
没有定义为任何可以的东西,因为它在执行之前被替换了。它在过程体(数组)的构造过程中解析为一个可执行名称,这里它的用途只是在数组中分配一个插槽。它实际上可以是任何类型,我经常看到(并编写)
{0 begin…}
也是出于同样的目的。使用名称可以向代码的人类读者提供更多语义信息。我还看到它在我的矩阵函数中写了
{DICT begin…}
,显然我称之为
STATICDICT

对于这样的元语法标记,有一种使用所有大写字母的惯例。它是一个nametype标记,但在元语法上,它指的是一个dictype对象,将在以后填充。为了解释器的利益,不需要(甚至不需要任何机制)声明您正在做什么,但是通过选择
DICT
而不是
0
可以获得很多好处。同样,由于它将被完全替换,您也可以使用一个字面名称
/LOCAL
,来尝试,idunno,从寻找
LOCAL
定义的地方的大雁追逐中释放下一个阅读代码的noob??为此,我还简单地编写了
DUMMY
,以便稍后填充令牌。我想这些术语的选择是风格、受众或其他无形的品质。叹息。。。或者只是上下文的问题

还有另一种样式可以很好地用于在过程体中进行动态替换。通过将字典放在dictstack上并对其命名(在其内部,因此它是一个封闭的名称空间),我们可以使用
//immediate
名称来引用它

4 dict begin
/mydict currentdict def
/proc {
    //mydict begin
    ...
    end
}
然后在定义之前删除字典

end def
因此,通常定义过程(在外部级别字典中(此处未命名,推测为
userdict
),但通过名称嵌入字典,以避免在扫描过程主体时使用该名称

这可以扩展到更多共享同一个私有字典的过程,方法是为每个定义将dict从堆栈中去掉

/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
当然可以简化为
end def

一个警告。以这种方式创建的字典本身是递归包含的。不要尝试使用ghostscript的
==
操作符打印它

《蓝皮书》第133页有一个同样技术的简单例子:

/sampleproc 
{ 0 begin 
  /localvariable 6 def 
  end 
} def 
/sampleproc load 0 1 dict put 
在这里,在修改程序之前先对其进行定义。这更容易让你集中注意力。在最初的文章中,对我来说最棘手的部分是“dup”,因为我没有意识到堆栈上的数组不是一个精确的数组,它是一个数组引用(我认为是按值复制,它的函数是按引用复制),所以原始代码中的“put”会影响具有第一个引用的数组(这是从堆栈中消耗的),第二个用于定义过程。这是一个新手的错误,但也许其他新手可以从中学习:

堆栈进程:

...                                               % 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. 

很抱歉,可能是不正确的符号,我只是盯着这个看了一会儿,我想我可能可以为某人节省一点盯着的时间。请告诉我是否有任何错误或误导性的陈述需要修复。

我不知道PS程序可以或会修改可执行数组。这很狡猾。回答很好,thanks!嘿,等等。这意味着PostScript就像LISP:代码只是您执行的数据。如果您愿意,可以进行操作。@WayneConrad查看另一个在PS中修改过程数组的示例。这是一个非常灵活且强大的功能。我已经开始使用-777作为这种伪标记,因为它太难看了,只会发出尖叫声在屏幕上看到一些奇怪的事情。