2017-06-01 15 views
4

私は即時実行と遅延実行を回避するつもりです。 私が理解しているところでは、インタープリターは遅延実行中かどうかを知るフラグを保持しています。PostScriptの即時実行または遅延実行

プロシージャの遅延実行は、名前検索によってプロシージャが返された可能性があります。

今、どのタイプ、アクション、または操作がこのインタープリタフラグを制御しているかを調べようとしています。

たとえば、以下のコードでは、手続きを返す最後にすぐに評価された名前があります。それは(xcheck)実行可能である一方、しかし、この手順は、プッシュされる:

/setdata 
{ 
    /a 1 def 
    /b 0 def 

/foo 
    a 0 ne 
    b 0 ne 
    and 
def 

{ foo false and } 
} def 

//setdata 

私は特別なルールがあります知っている:直接登場

手順(どちらかから を読まされているプログラムの一環として、ファイルまたはメモリ内のより大きなプロシージャの一部として)は通常、 の定義の一部または条件付きのような構文の一部であり、 がプロシージャに対して明示的に処理されます。例えば、名前を検索した結果、間接的に を取得した手続きは、通常は実行する予定の です。 PostScriptプログラムは、必要に応じてこれらの セマンティクスを無効にすることができます。

プロシージャに直接遭遇した場合(実行可能であっても)、プッシュする必要があることを理解します。 (すぐに評価される名前は直接遭遇するプロシージャを返しますので、OSにプッシュする必要があります)

私はこのロジックをインタプリタで実装するコードを考えていますが、 :

リテラル名のルックアップがある場合は、インタープリターの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:

答えて

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

私は通訳を理解しようとするときに、同じ質問と混乱の多くを持っていました。 IMO用語遅延実行はそれほど有用ではありません。また、とすぐに評価されたもあまり役に立たないと思います。 DeferredFlagは必要ありません。

ここには、インタプリタループとtokenオペレータの2つの別々の関連する部分が含まれています。

tokenは、実行可能な配列のすべてのトークンを1つのオブジェクトに集める「遅延実行」の部分を処理します。したがって、ファイルまたは文字列がプロシージャー本体で始まる場合、その上にtokenを呼び出すと、プロシージャー本体全体が生成されます。

{ execution is deferred until the closing } 

それはコメントのように見えるが、それは言葉のどれを閉じ、延期は、などが定義されていない場合でも、エラーなしで実行されますPostScriptコードの行です。しかし、execを呼び出すか、その名前を呼び出して定義すると、それが実行され、内容がよりよく定義されます。

インタープリタループは、常にexecスタックから最上位のオブジェクトを取得し、意味的に実行可能な配列、ファイル、および文字列はすべて同じように動作します。インタプリタはそれをソースとして扱い、最初の要素を取得します。名前の場合は、のソースではないため、少し異なります。 (私はそれが/作品に役立つことを期待し、私自身のこの概念を導入しています。)C-っぽい擬似コードでは:実行可能な場合は名前の場合

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); 
} 

他の3つでは、配列であるかどうかもチェックする必要があります。

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> 
+0

すぐに評価された名前について。例えば、返されるべきプロシージャの場合(imm。eval。nameの結果として)。 これは、例えば{2 3 add}のような1つのプロシージャオブジェクトを返しますか、これはトークン{、トークン2、トークン3、トークン追加、トークン}を表す5つのトークンを返しますか? – juFo

+0

1つのプロシージャー・オブジェクトを戻します。これについて考えるには2つの方法があります。 'def'は常にその値に対して単一のオブジェクトをとり、直ちに評価される名前は常に前の' def'から値を生成するので、すぐに評価される名前は単一のオブジェクトしか返せません。 OTOHのすべてのプログラム構造体は 'token'演算子を通してインタプリタに入り、' token'は常に}まで消費して単一のオブジェクトを返します。右括弧がない場合、 'token'はa/syntaxerrorを通知します。だから、 "token {"のようなものはありません。ポストスクリプトでは決して存在することはありません。 –

関連する問題