
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 sub | 1がスタックに格納される |
1 2 | add 3 add 2 sub | 2がスタックに格納される |
3 | 3 add 2 sub | 1+2が計算され、3がスタックに格納される |
3 3 | add 2 sub | 3がスタックに格納される |
6 | 2 sub | 3+3が計算され、6がスタックに格納される |
6 2 | sub | 2がスタックに格納される |
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 add | 2がスタックに格納される |
2 3 | mul 8 2 div add | 3がスタックに格納される |
6 | 8 2 div add | 2×3が計算され、6がスタックに格納される |
6 8 | 2 div add | スタックに8が格納される |
6 8 2 | div add | スタックに2が格納される |
6 4 | add | 8÷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 mul | 3がスタックに格納される |
3 3 | dup mul mul | 3が複製されスタックに格納される |
3 3 3 | mul mul | 3が複製されスタックに格納される |
3 9 | mul | 3×3が計算さえる、9がスタックに格納される |
27 | | 3×9が計算さえる、27がスタックに格納される |
copy
オペランドスタック上の任意の個数のオペランドの複製を1つずつつくり、オペランドスタックに格納します。
例 オペランドスタックの状態が左のような場合、3 copyを実行すると、3つのオペランドが1つずつスタックにコピーされます。
オペランドスタック | プログラム | 実行された処理 |
1 2 3 4 5 | 3 copy | |
1 2 3 4 5 3 4 5 | | 3つのオペランド3、4、5が複製されスタックに格納される |
index
オペランドスタック上に任意の位置のオペランドの複製を1つ作ります。
例 オペランドスタックの状態が左のような場合、indexを実行するとオペランドが複製されます。オペランドスタック上のオペランドは0から数え始めます。
オペランドスタック | プログラム | 実行された処理 |
1 2 3 4 5 | 0 index 4 index 5 index | |
1 2 3 4 5 5 | 4 index 5 index | 先頭のオペランドが複製されスタックに格納される |
1 2 3 4 5 5 2 | 5 index | 先頭から5番目のオペランドが複製されスタックに格納される |
1 2 3 4 5 5 2 2 | | 先頭から6番目のオペランドが複製されスタックに格納される |
exch
オペランドスタック上に最後に格納された2つのオペランドのスタック上の位置を入れ替えます。
例 オペランドスタックの状態が左のような場合、exchを実行すると、2つのオペランドが入れ替わります。
オペランドスタック | プログラム | 実行された処理 |
1 2 | exch | |
2 1 | copy | 2つのオペランドが入れ替わる |
pop
オペランドスタック上に最後に格納されたオペランドを取り除きます。
例 オペランドスタックの状態が左のような場合、popを実行する度にオペランドが取り除かれます。
オペランドスタック | プログラム | 実行された処理 |
1 2 3 4 5 | pop pop pop pop | |
1 2 3 4 | pop pop pop | オペランドが取り除かれる |
1 2 3 | pop pop | オペランドが取り除かれる |
1 2 | pop | オペランドが取り除かれる |
1 | | オペランドが取り除かれる |
|