PostScript 立即或延迟执行

PostScript immediate or deferred execution

我正在努力思考立即执行和延迟执行。 据我了解,解释器维护一个标志,知道它是否在延迟执行中。

过程的延迟执行可能是因为名称查找返回了过程。

现在我试图找出什么类型、动作或操作控制这个解释器标志。

例如,下面的这段代码在末尾有一个立即评估的名称,returns 一个过程。但是这个过程被推送了,虽然它是可执行的(xcheck):

/setdata
{
  /a 1 def
  /b 0 def

 /foo
   a 0 ne
   b 0 ne
   and
 def

 { foo false and }
} def

//setdata

我知道有一条特殊规定:

Procedures appearing directly (either as part of a program being read from a file or as part of some larger procedure in memory) are usually part of a definition or of a construct, such as a conditional, that operates on the procedure explicitly. But procedures obtained indirectly—for example, as a result of looking up a name—are usually intended to be executed. A PostScript program can override these semantics when necessary.

我明白,如果你直接遇到一个程序,你必须推送它(即使它是可执行的)。 (立即评估名称returns一个程序,这是直接遇到的,所以应该推到OS。)

现在,如果我正在考虑在解释器中实现此逻辑的代码,我可以想到这样的事情:

如果我有一个 literalname 查找,请设置解释器的 DeferredFlag = true; 现在我怎么知道延迟执行何时结束?如果遇到 "def" 名称,我可以硬编码,但可能还有其他名称。

(+ 如果过程嵌套在正在执行的过程中会发生什么。等等...)

我找不到一种方法来控制解释器中的 DeferredFlag 以了解当前的执行模式。

希望问题清楚。

更新:

一些额外的代码示例我尝试调试但没有成功。

代码 1:

/foo { 2 3 add } def
foo
% result: 5

代码 2:

/foo { 2 3 add } def
//foo
% result: { 2 3 add }

代码 3:

/foo { 2 3 add } def
/bar { foo } def
bar
% result: 5

代码 4:

/foo { 2 3 add } def
/bar { //foo } def
bar
% result: { 2 3 add }

在尝试理解解释器时,我有很多相同的问题和困惑。 IMO 术语 延迟执行 不是很有用。另外,我认为 immediately evaluated 这个词也不是很有用。您不需要 DeferredFlag。

这里涉及两个独立但相关的部分:解释器循环和 token 运算符。

token 处理 "deferred execution" 的部分,它将可执行数组的所有标记收集到单个对象中。因此,如果文件或字符串以过程主体开头,则对其调用 token 会产生整个过程主体。

{ execution is deferred until the closing }

它看起来像一条注释,但那是一行后记代码,即使 延迟 个单词的 none 也不会出现错误 运行, closingthe等定义。但是,如果您对其调用 exec,或者将其定义为一个调用,那么它将执行并且最好定义内容。

解释器循环总是从 exec 堆栈中获取顶部对象,并且在语义上,可执行数组、文件和字符串的行为都相同。解释器将其视为源并获取第一个元素。名称大小写有点不同,因为它本身不是 source。 (我正在介绍我自己的这个概念,希望它 helps/works。)在 C-ish 伪代码中:

main_loop(){
    while( ! quit ){
        eval();
    }
}

eval(){
    object = pop( exec_stack );
    if( !executable_flag( object ) )  push( op_stack, object );
    else switch( type_of( object ) ){
        case array: array_handler( object ); break;
        case string: string_handler( object ); break;
        case file: file_handler( object ); break;
        case name: name_handler( object ); break;
        default: push( op_stack, object );
    }
}

名字大小写,查找名字,如果可执行则执行。

name_handler( object ) {
    object = load( object );
    push( executable_flag( object ) ? exec_stack : op_stack, object );
}

另外三个,还必须检查是否是数组。

array_handler( object ){
    switch( length( object ){
    default:
        push( exec_stack, getinterval( object, 1, length( object ) - 1 ) );
        /* fall-thru */
    case 1:
        object = get( object, 0 );
        push( executable_flag( object ) && type_of( object ) != array ?
              exec_stack : op_stack, object );
    case 0:
        /* do nothing */
    }

}

仅当 executable_flag( object ) && type_of( object ) != array 时才推送到执行堆栈。

对于另一个问题,立即评估的名称,我更愿意称它们为立即加载 名称。 token 运算符在返回之前对其调用 load。如果在正确的地方完成,很容易处理。它与 "deferred-execution" 部分没有真正的交互。

编辑:

我运行你的样本通过我的debugger追踪。这显示了每个令牌执行后 op_stack 的 运行ning 图片。左边的元素是token返回的对象。请注意 token 已经消耗了所有 //

$ cat test.ps
(db5.ps) run currentfile cvx traceon debug

/foo { 2 3 add } def
foo
% result: 5

/foo { 2 3 add } def
//foo
% result: { 2 3 add }

/foo { 2 3 add } def
/bar { foo } def
bar
% result: 5

/foo { 2 3 add } def
/bar { //foo } def
bar
% result: { 2 3 add }

$ gsnd -DNOSAFER test.ps
GPL Ghostscript 9.19 (2016-03-23)
Copyright (C) 2016 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
 %|- 
/foo  %|- /foo 
{2 3 add}  %|- /foo {2 3 add} 
def  %|- 
foo  %|- 5 
/foo  %|- 5 /foo 
{2 3 add}  %|- 5 /foo {2 3 add} 
def  %|- 5 
{2 3 add}  %|- 5 {2 3 add} 
/foo  %|- 5 {2 3 add} /foo 
{2 3 add}  %|- 5 {2 3 add} /foo {2 3 add} 
def  %|- 5 {2 3 add} 
/bar  %|- 5 {2 3 add} /bar 
{foo}  %|- 5 {2 3 add} /bar {foo} 
def  %|- 5 {2 3 add} 
bar  %|- 5 {2 3 add} 5 
/foo  %|- 5 {2 3 add} 5 /foo 
{2 3 add}  %|- 5 {2 3 add} 5 /foo {2 3 add} 
def  %|- 5 {2 3 add} 5 
/bar  %|- 5 {2 3 add} 5 /bar 
{{2 3 add}}  %|- 5 {2 3 add} 5 /bar {{2 3 add}} 
def  %|- 5 {2 3 add} 5 
bar GS<4>
GS<4>pstack
{2 3 add}
5
{2 3 add}
5
GS<4>