home / uni / ps / stop-err PostScript言語 / stopとエラー処理

●stop
 { ... stop ... } stoppedという構文で、stoppedはパラメータとしてスタックに積まれたプロシージャを普通に実行する。 そして、このプロシージャが終わるか、あるいはプロシージャの中でstopが実行されるとstoppedの後ろに制御が移る。 stopはどこで実行してもいい。 このとき、スタックにはstopが実行されていればtrue、実行されていなければfalseが積まれるので、直後にifなどを置けばどちらか判別できる。 これ以外のオペランドスタックの操作はしてくれない。
●エラー
 PostScriptインタープリタがやってることは、オペランドスタックを元に戻す → エラーを起こしたオブジェクトをスタックに積む → errordictでエラー種別を示す名前(ioerrorとかね)を探して実行(PLRM 3.11.1)。 だから、個々のエラーを引っ掛ける場合はerrordict内の対応するエラー名に指定されているプロシージャ(エラーハンドラ)を置き換えればいい。

 デフォルトのエラーハンドラはエラー情報を$errorという辞書に入れてstopを実行する。 もしstoppedされていなければ、インタープリタがユーザプログラム実行前に作ったstoppedの後ろに制御が移る。 最終的にここからerrordict内のhandleerrorが呼び出されて、あのメッセージが表示される(PLRM 3.11.2)。 だから、全体のエラーレポートを書き換えたいなら、errordicthandleerrorを書き換えればいい。

●stopとエラー
 したがって、stoppedされているプロシージャ内でエラーが起きるとstoppedの後ろに飛んでくる。 ここでオペランドスタックを調べても普通にstopしたのと区別がつかないが、標準のエラーハンドラは辞書$errornewerrorというキーをtrueに設定し、このキーはhandleerrorfalseに戻すことになっているので、これをチェックすればよい。 trueだったらそのままもう一度stopすれば、さらに外側のstoppedにエラーを投げることができる。
{ ... } stopped {
    $error /newerror get {
        stop    % throw error again.
    } {
        % control reaches here if stop has been executed.
    } ifelse
} if
●エラーを作り出す
 標準のエラーハンドラの動きを真似れば、自分でエラーを作り出すこともできる。
mark { ... } stopped {
    cleartomark
    $error /newerror get {
        stop
    } {
        /myerrorobject errordict /ioerror get exec
    } ifelse
} if
pop % discard the mark
ただし、配列や辞書の定義中にstopすると、cleartomarkが配列などの頭までしかクリアしてくれないので注意。 あと、$errorとかをどうすればいいのかは知らん。 より本格的には、プロシージャに入ったところでmark、エラーの場合はcleartomarkでパラメータをスタックに置いたままにしてエラーを投げ、正常に終了した場合はcleartomarkの後にパラメータを捨てて結果をスタックに置く、ということになるだろうけど(面倒く・・・んがんぐ)。

Copyright (C) 2012 You SUZUKI

$Id: stop-error.htm,v 1.2 2012/11/01 14:24:36 you Exp $