Postscript

準備体操

言語としてのPostscriptを理解するための基本要素を押さえておく。

スタックとキュー

Postscriptはスタック操作を繰り返すことで処理を進める。

ポーランド記法・逆ポーランド記法

人間が数学で用いている加減乗除算は演算子が2つの数の間に書かれる 中間記法である。

1 + 2
(1 + 2) * 3

演算子を前、または後に書く記法も存在する。

スタックマシン

演算などすべての処理対象がスタックトップ(最後に入れた方)に 施されるものの動きに触れる。まずインタプリタを起動し数値を入れ、 スタックに積まれる様子を "pstack" で確認する。

1 2 3
pstack
3
2
1
4 5 6 pstack
6
5
4
3
2
1

演算子や関数(後述)は、必要な引数をスタックから引っ張り出し、 結果をスタックトップに返す。

add
pstack
11
4
3
2
1

== 演算子はスタックトップを取り出し、出力する。

==
11
pstack
4
3
2
1

=== の違いは、= がオブジェクト形式のまま出すのに対し、== が文字列化して出す点にある。また出力後改行しない print 演算子もある。

exch は、スタック最上位の2つを交換する(exchange)。

exch
pstack
3
4
2
1

pop は、スタックトップを取り除き、 clear は、スタックをすべてクリアする。

pop
pstack
4
2
1
clear

その他スタック操作の主なものを示す。

操作意味
dupスタックトップの複製
Nindex スタックトップからN個先の要素をスタックトップに複製
Ncopy スタックトップからN個の要素をスタックトップに複製

トークンとバインド

シンボルのように扱われるのがトークンで、 任意の値(関数も)を結び付ける(バインドする)ことができる。 バインドには def を利用する。トークンがトークンとして 扱われるように / でクォートする。 バインドではスタックは変わらない。

/pi 3.14 def		% piに3.14をバインドする
pi			% piの値をスタックに積む
pstack
3.14

データタイプ

扱える基本型を列挙する。

種別書式
文字列( ) (Hello, world\n)
配列[ ] [1 2 3]
辞書<< >> << /foo 1 /bar 2>>
手続き(関数){ } { 1 add }

算術演算子

加算add
減算sub
乗算mul
除算div
整数除算idiv
剰余算mod

条件分岐とループ

論理演算子は、 eq, gt, lt, ge, le, not, and, or でいずれもスタックトップに対して作用し、true か false を スタックトップに残す。

関数のエミュレート

f というトークンに手続きをバインドする。

/f { (hello) print } def

引数はスタックトップから取って来る。 exchでスタックにある値をトークンにバインドすることで、仮引数のように 処理するのが定石である。以下の例は2つの引数を、a、bに代入し 足した結果をスタックに戻す関数的手続きである。

/tasu {
	/a exch def
	/b exch def
	a b add
} def
40 60 tasu =

練習問題

  1. 引数1つを受け取り、偶数か奇数かを出力する関数 guuki を定義せよ。

  2. 引数2つを受け取り、BMI値を出力する関数 BMI を定義せよ。






/guuki {
  /i exch def
  ( Number)
  i 2 mod 0 eq {(Even)} {(Odd)} ifelse print =
} def

ローカル変数

begin から始まり end までの部分は、begin が呼ばれたときのスタックトップにある 辞書を名前空間にしてトークンが定義される。 以下の例は、長さ1の辞書を作成し begin ブロックに入り、 変数 x, y, z 相当のトークンを利用する。ブロックから出ると x, y, z は辞書とともに消滅する。

1 dict begin
  /x 1 def
  /y 2 def
  /z 3 def
  x y z add mul ==		% ここで5が出力される
end
x
/x は既に存在せずエラー
/guuki {
 1 dict begin
  /i exch def
  ( Number)
  i 2 mod 0 eq {(Even)} {(Odd)} ifelse print =
 end
} def

リンク集