PostScript立即执行或延迟执行

时间:2017-06-01 08:22:21

标签: postscript

我试图绕过即时和延期执行。 据我所知,解释器维护一个标志,知道它是否在延迟执行中。

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

现在我试图找出控制此解释器标志的类型,操作或操作。

例如,下面的这段代码在结尾处有一个立即计算的名称,它返回一个过程。但是这个程序被推送,而它是可执行的(xcheck):

/setdata
{
  /a 1 def
  /b 0 def

 /foo
   a 0 ne
   b 0 ne
   and
 def

 { foo false and }
} def

//setdata

我知道有一条特殊规则:

  

直接出现的程序(作为正在阅读的程序的一部分   通常是从文件中或作为内存中某些较大过程的一部分)   定义或构造的一部分,例如条件,   明确地对程序进行操作。但程序获得   间接 - 例如,通常是查找姓名的结果   打算执行。 PostScript程序可以覆盖这些   必要时的语义。

据我所知,如果你直接遇到一个程序就必须推它(即使它是可执行的)。 (立即计算的名称返回一个直接遇到的过程,因此应将其推送到操作系统。)

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

如果我有文字名查找,请设置解释器的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 }

1 个答案:

答案 0 :(得分:3)

在尝试理解翻译时,我遇到了许多相同的问题和困惑。 IMO术语延迟执行并不是很有用。另外,我认为术语立即评估也不是很有用。你不需要DeferredFlag。

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

token处理"延迟执行"它将可执行数组的所有标记收集到一个对象中。因此,如果文件或字符串以过程体开始,则在其上调用token会产生整个过程体。

{ execution is deferred until the closing }

它看起来像一个评论,但这是一行后记代码,即使没有任何单词延迟关闭 等定义。但是,如果你在它上面调用exec,或者将其定义为一个名称,那么它将被执行并且最好定义内容。

解释器循环始终从exec堆栈中获取top对象,并且在语义上,可执行数组,文件和字符串的行为都相同。解释器将其视为源并获取第一个元素。名称情况略有不同,因为它本身不是。 (我正在介绍我自己的这个概念,希望它能帮助/工作。)在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然后你推送到exec堆栈。

对于另一个问题,立即评估的名称,我更喜欢称之为立即加载的名称。 token运算符在返回之前调用load。如果在正确的地方完成,易于处理。它与"延迟执行"没有真正的互动。一部分。

编辑:

我通过我的debugger跟踪您的示例。这显示了每个令牌执行后op_stack的运行图。左侧的元素是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>