为什么内容挂在传递一个程序一个程序到另一个程序调用时使用相同的参数的名字吗? &g



我将后记过程(c)作为堆栈上的参数传递给过程(a),然后过程(a)将其作为堆栈上的参数传递给调用该过程(c)的另一个过程(b)。

当我使用字典来本地化变量并在a和b中使用相同的名称时,ghostscript挂起(在下面的代码中,这些是过程a1和a2,它们都使用proc)(. 当我给它们起不同的名字时(在下面的代码中,这些是使用approc的过程a和b)和Bproc

请注意,我知道我可以只使用堆栈传递原始参数并避免整个exch def步骤,但在我的实际代码中,我想捕获堆栈参数以在本地使用。

下面是这个问题的一个最小的工作示例:

%!PS
/c{
(C START) =
(C output) =
(C END) =
}bind def
/b{
(B START) =
1 dict begin
/Bproc exch def
Bproc
end
(B END) =
}bind def
/a{
(A START) =
1 dict begin
/Aproc exch def
{Aproc} b
end
(A END) =
}bind def
/b2{
(B2 START) =
1 dict begin
/proc exch def
proc
end
(B2 END) =
}bind def
/a2{
(A2 START) =
1 dict begin
/proc exch def
{proc} b2
end
(A2 END) =
}bind def

{c} a
% {c} a2
下面是上面代码的输出(不同的参数名称,没有问题):
$ gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=test2.pdf test2.ps
GPL Ghostscript 9.54.0 (2021-03-30)
Copyright (C) 2021 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
A START
B START
C START
C output
C END
B END
A END
$

将代码的最后两行修改如下(第一行注释掉,第二行取消注释):

...
% {c} a
{c} a2

现在ghostscript只是挂起:

$ gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite  -sOutputFile=test2.pdf test2.ps
GPL Ghostscript 9.54.0 (2021-03-30)
Copyright (C) 2021 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
C-c C-c: *** Interrupt
$

环境:OpenSuse:

$ uname -a
Linux localhost.localdomain 5.18.4-1-default #1 SMP PREEMPT_DYNAMIC Wed Jun 15 06:00:33 UTC 2022 (ed6345d) x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/os-release 
NAME="openSUSE Tumbleweed"
# VERSION="20220619"
ID="opensuse-tumbleweed"
ID_LIKE="opensuse suse"
VERSION_ID="20220619"
PRETTY_NAME="openSUSE Tumbleweed"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:tumbleweed:20220619"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"
DOCUMENTATION_URL="https://en.opensuse.org/Portal:Tumbleweed"
LOGO="distributor-logo-Tumbleweed"

我认为您被早期和晚期的名称绑定绊倒了,这是PostScript中一个微妙的点,经常使该语言的新手陷入困境。

由于后期名称绑定,您可以在执行过程中更改键/值对的定义,这可能会产生意想不到的效果。这与自修改代码大致相似。

参见第三版PostScript语言参考手册第117页的3.12早期名称绑定章节了解详细信息,但基本要点就在第一段:

"通常,当PostScript语言扫描器在被扫描的程序中遇到可执行名称时,它只是生成一个可执行名称对象;它不查找名称的值。只有当name对象被解释器执行时,它才会查找名称。查找发生在执行时位于字典策略上的字典中。">

你也不完全(我认为)做你认为你是与可执行数组令牌'{'和'}'。确切地说,这并不是把定义放在堆栈上,而是在堆栈上定义一个可执行数组。不完全是一回事。特别是,它意味着数组的内容(在{和}之间)没有被执行。

如果你想把原始函数放在堆栈上,你可以执行'/proc load'。例如,如果你想定义一个与showpage相同的函数,你可以这样做:

/my_showpage /showpage load def

:

/my_showpage {showpage} def

看看你的失败案例。

在函数a2中,首先创建并打开一个新字典。所述字典仅存在于堆栈中,因此如果您将其弹出,它将超出作用域并被垃圾收集(我确信您当然知道这一点)。

在该字典中创建一个键'/proc'与可执行数组的相关值。数组中包含{c}

然后在堆栈{proc}上创建一个新的可执行数组然后使用堆栈上的可执行数组执行函数b2。

b2再次在堆栈上启动另一个新字典,然后定义一个键/值对'/proc',其关联值为{proc}

然后执行proc,执行数组,其中唯一的东西是对'proc'的引用,因此从当前字典开始查找。

哦看!我们在当前字典中有一个定义,它是一个可执行数组。我们推入那个数组并执行它。唯一的指的是"过程",所以我们在当前字典查找一下,我们有一个,所以我们执行数组。一圈一圈地走.....

您可以通过简单地修改:

来避免这种情况
/a2{
(A2 START) =
1 dict begin
/proc exch def
{proc} b2
end
(A2 END) =
}bind def

:

/a2{
(A2 START) =
1 dict begin
/proc exch def
/proc load b2
end
(A2 END) =
}bind def

相关内容

  • 没有找到相关文章

最新更新