Let's PostScript(5) 手続きObjectと制御オペレータ
手続きオブジェクト
{.....}は実行可能の属性持つ配列のObjectです。手続きObjectと呼ばれます。 手続きObjectは今まで見てきた”dup”や"copy"といった実行可能の属性を持つオブジェクトとは大きな相違があります。 それは、インタプリタがObjectを検出した時に現れます。
属性 | 配列 | インタプリタ動作 |
---|---|---|
実行可能 | yes | Operand StackにPushされる |
実行可能 | no | インタープリタによって直ちに実行される |
Literal | Operand StackにPushされる |
手続きObjectは実行可能であるにも関わらず、即実行せずにいったんOperandStackに格納します。このような動作を遅延実行と呼びます。 一方で、"dup"や"copy"といった単一の実行可能Objectの即実行される動作を即時実行と呼びます。
OperandStackの手続きオブジェクトを直接実行するにはexecオペレータなどを使用しますが、一般的には後述する制御オペレータによって実行するのが一般的ではないかと思います。
GS>{1 2 3 4 5 exch} GS<1>exec GS<5>stack 4 5 3 2 1
制御オペレータ
論理値(true,false)から、次に実行する手続きObjectを制御するオペレータを制御オペレータと呼びます。例えば、以下のようなスクリプトです。
ex.1 GS>true {(I'm True)} if GS<1>= I'm True ex.2 GS>false {(I'm True)} if ex.3 GS>true {(I'm True)} {(I'm False)} ifelse GS<1>= I'm True ex.4 GS>false {(I'm True)} {(I'm False)} ifelse GS<1>= I'm False
ex.1では trueと{(I'm True)}}の2つのObjectがOperandStackに格納され、ifオペレータは論理値を受け取ります。今回はtrueだったため、手続きObjcet{(I'm True)}を実行しその結果(I'm True)ObjectがOperandStackに格納されます。
ex.2では falseと{(I'm True)}}の2つのObjectがOperandStackに格納され、ifオペレータは論理値を受け取ります。今回はfalseだったため、手続きObjcet{(I'm True)}は破棄されます。
ex.3では、trueと{(I'm True)}と{(I'm False)}の3つのObjectがOperandStackに格納され、ifelseオペレータは論理値を受け取ります。今回はtrueだったため、1つ目の手続きObjectである{(I'm True)}を実行しその結果(I'm True)ObjectがOperandStackに格納されます。2つ目の手続きObject{(I'm False)}は破棄されます。
ex.4では、falseと{(I'm True)}と{(I'm False)}の3つのObjectがOperandStackに格納され、ifelseオペレータは論理値を受け取ります。今回はfalseだったため、1つ目の手続きObjectである{(I'm True)}は破棄されます。2つ目の手続きObject{(I'm False)}を実行しその結果(I'm False)ObjectがOperandStackに格納されます。
これらの例では、論理値を直書きしていますが、実際には関係オペレータの結果の論理値を制御オペレータに渡すパターンが多くなります。以下のようなスクリプトになります。
ex.5 GS>1 1 eq {(Equal Object!)} if GS<1>= Equal Object! ex.6 GS>1 0 eq {(Equal Object!)} if ex.7 GS>1 1 eq {(Equal Object!)} {(Non Equal Object!)} ifelse GS<1>= Equal Object! ex.8 GS>1 0 eq {(Equal Object!)} {(Non Equal Object!)} ifelse GS<1>= Non Equal Object!
ex.4~8はex.1~4までとほぼ変わらないのですが、ようやくスクリプトっぽい動作に見えてくるのが不思議。
次回は、繰り返し処理を見ていこうと思います。