ゆの in PostScript その2
せっかくの PostScript なんだから、やっぱり画像で表示した方がいいかな、と思ったので、PostScript viewer などで見られるようにしてみた。あと、文字だけでは寂しいので、顔の絵もつけて華やかにしたり。
%!PS gsave 4 dict begin /GothicBBB-Medium-EUC-H findfont 16 scalefont setfont % 文字コードが EUC-JP の場合 /X{ true { (365)show currentfile 80 string readline pop 1 1 index length 1 sub getinterval show } {(ひだまり)show} count{exch}repeat ifelse } def /{ (スケッチ)show }def /_{ cvx exec }def gsave 1 dict begin /showpage {} def 0 -20 translate % 位置を調節して 0.125 0.125 scale % サイズを調節して (tiger.ps)run % お好きな PostScript 画像をお貼りください end grestore 80 30 moveto X / _ / X < 来週も見てくださいね! showpage end grestore
解説してみる
PostScript の場合に問題になるのは < です。PostScript では、< は16進数にエンコードされたバイト列の始まりを意味します。(バイト列の終わりは > です。例えば <41 42 43> は ABC という文字列になります。)なので、< と > の間に 0-9、a-f、A-F、空白以外の文字が現れるとエラーになってしまいます。
それを避けるために、currentfile という命令を使います。currentfile はインタープリタがその時実行しているファイル(この場合ソースファイル自身)のオブジェクトをスタックに置くという命令です。このファイルはインタープリタが読んだ位置まで読み終わっているので、例えば readline でファイルから 1 行読み込むと、インタープリタが読んだ次の文字から改行までが文字列として返されます。currentfile と readline を使えば < 以降行末までを文字列として扱うことができます。
ということで、X を以下のように定義すれば、"ひだまり(略) 来週も(略)" と表示されることになります。
/X { (ひだまり(略)) print % タイトルを標準出力に表示 currentfile 80 string readline pop % "/ _ / X < 来週も(略)" がスタックに置かれる。 (<) search pop pop pop % 文字列を "<" で分解して "<" 以前を捨てる。 print % 文字列を表示 } def X / _ / X < 来週も(略)
ただ、このままだと / や _ を捨ててしまっているので、もったいないです。そこで / や _ を有効活用してみたところ、こうなりました。
/X{ true { (365)show currentfile 80 string readline pop 1 1 index length 1 sub getinterval show } {(ひだまり)show} count{exch}repeat ifelse } def /{ (スケッチ)show }def /_{ cvx exec }def X / _ / X < 来週も(略)
順に動作を見ていくと、
- 最初の X : まず true と {(365) ...} と {(ひだまり)show} が スタックに置かれる。count でスタックに置かれているオブジェクトの数を数え、3 がスタックに置かれる。{exch} をスタックに置いた後、repeat でスタックから 3 と {exch} を取り出し exch(スタックの上 2 個の入れ替え)を 3 回実行する。その結果スタックは true、{(ひだまり)show}、{(365) ...} の順になる。ifelse で (ひだまり)show が実行され、"ひだまり" と表示される。
- 最初の / : PostScript では / が頭についたトークンは実行されずにスタックに置かれ、頭に / が付かないトークンは実行される。/ は長さ 0 の文字列に対応する名前オブジェクト(以下 / と書く)を、実行せずにスタックに置くことになる。
- _ : cvx でスタックトップのオブジェクトを実行可能にして exec で実行する。スタックには / があり、/ は {(スケッチ)show} と定義されているので、(スケッチ)show が実行され、"スケッチ" が表示される。
- 2番目の / : 1 回目と同様に / がスタックに置かれる。
- 2番目の X : true と {(365) ...} と {(ひだまり)show} がスタックに置かれ、スタックに /、true、{(365) ...}、{(ひだまり)show} の 4 個のオブジェクトがある状態になる。count{exch}repeat で 4 回スタックの上 2 個が入れ替えられ、元の /、true、{(365) ...}、{(ひだまり)show} に戻る。ifelse で (365)... が実行され、"365" と " 来週も(略)" が表示される。
- つまり、X の挙動をスタックにあるオブジェクトの数に従って変えています。まあそれだけなら count 0 eq{(ひだまり)show}{(365)...}ifelse でいいのですが、条件分岐が特別な構文ではなくて、スタックと命令になっていることを示したくて、やってみました。
- インタープリタは "来週も(略)" の改行まで既に読んでいるので、次の行から実行が続く。
となります。つい無駄に複雑化させようとするのは、悪い癖です。