コンピュータ基礎II 通信授業課題2C 参考ページ



3. PostScriptの特徴、計算方法

PostScriptの言語の特徴や、四則演算の方法、以降のサンプルで使用するオペレータの説明をしておきます。

○後置記法

PostScriptでは計算に使われる値(オペランド)が、命令(オペレータ)の前に置かれます。

例えば、addは2つの値を足すオペレータですが、10と20の値を足す時は、
10 20 add
とオペランドを先に、オペレータを後に書きます。
これを演算子が後ろにくるので「後置記法」と言います。対して、10 + 20という書き方は、演算子が真ん中に来るので「中置記法」と言います。

基本的な図形の描き方でもそうでしたが、オペランドがオペレータの前に来るのがPostScriptの特徴です(100 0 lineto など)。

○スタック

オペランドは実行時にオペランドスタックと呼ばれる場所に格納されます。オペランドスタックはその名の通り、スタックというデータ構造です(スタックがどんなデータ構造かは「通信授業課題1B」の課題でもあるので調べて欲しいと思います)。

例えば、
10 20 add
を実行するとします。まずオペランドスタックに10が、その次にオペランドスタックに20が格納されます。
addを正確にいうと、オペランドスタックから2つの値を取りだし、合計を計算してオペランドスタックに格納するオペレータです。
したがって、オペランドスタックから10と20が取り出され(オペランドスタックからなくなります)、合計が計算され、オペランドスタックには30が格納されます。

○計算を実行するオペレータ

PostScriptで四則演算をするオペレータには以下のようなものがあります。計算の実行結果をオペランドスタックの状態と併せて見てみます。

a b add
オペランドスタックから2つのオペランドa、bを取り出し、a + b を計算しオペランドスタックに格納します。

a b sub
オペランドスタックから2つのオペランドa、bを取り出し、a − b を計算しオペランドスタックに格納します。

a b mul
オペランドスタックから2つのオペランドa、bを取り出し、a × b を計算しオペランドスタックに格納します。

a b div
オペランドスタックから2つのオペランドa、bを取り出し、a ÷ b を計算しオペランドスタックに格納します。

差と商の計算では、オペランドスタックに格納されているオペランドの順番が関係します。

スタックは最後に格納した値が最初に取り出されるようなデータ構造です。いくつか計算の例を以下に示します。
以下の表の上から順番に真ん中のプログラムが実行され、オペランドスタックの内容は左側のように移り変わります。

例 1 2 add 3 add 2 sub (1+2+3−2)

オペランドスタックプログラム実行された処理
 1 2 add 3 add 2 sub実行前、スタックは空
1 2 add 3 add 2 sub1がスタックに格納される
1 2 add 3 add 2 sub2がスタックに格納される
33 add 2 sub1+2が計算され、3がスタックに格納される
3 3 add 2 sub3がスタックに格納される
62 sub3+3が計算され、6がスタックに格納される
6 2sub2がスタックに格納される
4 6−2が計算され、4がスタックに格納される


例 2 3 mul 8 2 div add (2 × 3 + 8 ÷ 2)

オペランドスタックプログラム実行された処理
 2 3 mul 8 2 div add実行前、スタックは空
2 3 mul 8 2 div add2がスタックに格納される
2 3 mul 8 2 div add3がスタックに格納される
68 2 div add2×3が計算され、6がスタックに格納される
6 8 2 div addスタックに8が格納される
6 8 2div addスタックに2が格納される
6 4add8÷2が計算され、4がスタックに格納される
10 6+4が計算され、10がスタックに格納される


一見複雑ですが、スタックの構造を理解し、計算に慣れれば、順次計算を行い結果をスタックに格納し、またその格納されたオペランドに計算をするだけなので非常に楽です。
以降のグラフィック描画のサンプルを見る際は、オペランドスタックの状態を思い浮かべながら処理を追うと理解しやすいと思います。

四則演算以外に、以下のようなオペレータがあります。

a b idiv
整数aを整数bで割った時の整数の商を返します。

a b mod
整数aを整数bで割った時の余りを返します。

○オペランドスタックを操作するオペレータ

dup
オペランドに最後に格納されたオペランド(最初に取り出されるオペランド)を複製してオペランドスタックに格納します。

例 3 dup dup mul mul

オペランドスタックプログラム実行された処理
 3 dup dup mul mul実行前、スタックは空
3 dup dup mul mul3がスタックに格納される
3 3 dup mul mul3が複製されスタックに格納される
3 3 3mul mul3が複製されスタックに格納される
3 9 mul3×3が計算さえる、9がスタックに格納される
27 3×9が計算さえる、27がスタックに格納される


copy
オペランドスタック上の任意の個数のオペランドの複製を1つずつつくり、オペランドスタックに格納します。

例 オペランドスタックの状態が左のような場合、3 copyを実行すると、3つのオペランドが1つずつスタックにコピーされます。

オペランドスタックプログラム実行された処理
1 2 3 4 53 copy 
1 2 3 4 5 3 4 5 3つのオペランド3、4、5が複製されスタックに格納される


index
オペランドスタック上に任意の位置のオペランドの複製を1つ作ります。

例 オペランドスタックの状態が左のような場合、indexを実行するとオペランドが複製されます。オペランドスタック上のオペランドは0から数え始めます。

オペランドスタックプログラム実行された処理
1 2 3 4 50 index 4 index 5 index 
1 2 3 4 5 54 index 5 index先頭のオペランドが複製されスタックに格納される
1 2 3 4 5 5 25 index先頭から5番目のオペランドが複製されスタックに格納される
1 2 3 4 5 5 2 2 先頭から6番目のオペランドが複製されスタックに格納される


exch
オペランドスタック上に最後に格納された2つのオペランドのスタック上の位置を入れ替えます。

例 オペランドスタックの状態が左のような場合、exchを実行すると、2つのオペランドが入れ替わります。

オペランドスタックプログラム実行された処理
1 2exch 
2 1copy2つのオペランドが入れ替わる


pop
オペランドスタック上に最後に格納されたオペランドを取り除きます。

例 オペランドスタックの状態が左のような場合、popを実行する度にオペランドが取り除かれます。

オペランドスタックプログラム実行された処理
1 2 3 4 5pop pop pop pop 
1 2 3 4pop pop popオペランドが取り除かれる
1 2 3pop popオペランドが取り除かれる
1 2popオペランドが取り除かれる
1 オペランドが取り除かれる