|
*PSSRは、RPG38からあるのですが、利用するチャンスは余りないかもしれません。ツールなどを作っていると、使うことがあります。最近iSUCに参加したら、*PSSRを知らない人がいました。「エラーが起きると*PSSRにうつって、そこから終わりにすることも出来るし、続けることも出来ます」と説明すると、「じゃあ、0除算エラーにIFNEは要らなかったんだ」といいます。変な事言うナー、と思っていたのですが、後で、彼が勘違いをしていることに、気づきました。
*PSSRは、例外エラーが起きた場合、定義してある場合、*PSSRに制御権が移ります。有る程度そこで、エラーハンドリングが出来ますが、以下のことに注意して下さい。
H DEBUG DATEDIT(*YMD/)
C**************************************************************************
C* M A I N - R O U T I N E
C**************************************************************************
C Z-ADD 0 S 2 0
C*
C EVAL S=100
C EVAL S=10
C EVAL S=1.005
C*
C MOVE *ON *INLR
C RETURN
C*-------------------------------------------------------------------------
C *PSSR BEGSR
C*-------------------------------------------------------------------------
C*
C ENDSR '*DETL'
|
このプログラムは永久ループします。理由は、*PSSRの戻り点は、自由に決めることは出来無いからです。上のソースでは、EVAL
S=100でエラーが起きます(00103)。そこで、*PSSRに進みますが、なにもしていません。そして戻り点、*DETLは、早い話、C仕様書の最初です。すると、再び、Z-ADD
0 S に戻ります。そして、エラーをおこし、を繰り返します。*PSSRを指定しただけだと、このようになるのです。
マニュアルを見てみましょう。
ENDSR
命令はファイル例外/エラー・サブルーチン中の最後の指定でなければならず、次のように指定することが必要です。
| 位置 |
記入項目 |
| 6 |
C |
| 7〜11 |
ブランク |
| 12〜25 |
サブルーチン内の GOTO
指定で使用するラベルを入れることができます。 |
| 26〜35 |
ENDSR |
| 36〜49 |
任意指定の記入項目で、サブルーチンの処理後に制御が戻される地点を指定します。この記入項目は6桁の文字フィールド、リテラル、または配列要素でなければならず、その値によって以下の戻り点の1つが指定されます。 注:
戻り点をリテラルとして指定する場合には、アポストロフィで囲む必要があります。名前付き固定情報として指定する場合には、その固定情報は文字でなければならず、先行ブランクのない戻り点だけが含まれていることが必要です。フィールドまたは配列要素の中に指定する場合には、フィールドまたは配列要素の中で値を左寄せしなければなりません。 |
|
*DETL |
明細行の先頭に続きます。 |
| *GETIN |
入力レコードの入手ルーチンに続きます。 |
| *TOTC |
合計演算の先頭に続きます。 |
| *TOTL |
合計行の先頭に続きます。 |
| *OFL |
オーバーフロー行の先頭に続きます。 |
| *DETC |
明細演算の先頭に続きます。 |
| *CANCL |
プログラムの処理を取り消します。(註「プログラムメッセージを出します。」) |
| ブランク |
RPG IV
の省略時のエラー処理プログラムへ制御を戻します。演算項目2がブランクの値および演算項目2が指定されていない場合でも、これが適用されます。サブルーチンがEXSR
命令によって呼び出され、演算項目2がブランクであった場合には、次の順次命令に制御が戻されます。ブランクは実行時にのみ有効です。 |
| 50〜76 |
ブランク |
さて、このループを止めるのは簡単です。W1ERRがそれを制御します。2度目に*PSSRが出たら、*CANCL(プログラムメッセージを出す)にしています。あるいは、H1等をオンにして、プログラム終了も良く行う方法です。あとでデバッグに役立つように、DUMP(デバッグオプションをH仕様書に指定)するのも役立つでしょう。
H DEBUG DATEDIT(*YMD/)
D SDS
D ##STSC 11 15
C**************************************************************************
C* M A I N - R O U T I N E
C**************************************************************************
C Z-ADD 0 S 2 0
C*
C EVAL S=100
C EVAL S=10
C EVAL S=1.005
C*
C MOVE *ON *INLR
C RETURN
C*-------------------------------------------------------------------------
C *PSSR BEGSR
C*-------------------------------------------------------------------------
C W1ERR IFEQ *ON
C MOVE *OFF W1ERR 1
C MOVE '*CANCL' RTNPNT
C ELSE
B001 C ##STSC IFEQ '00103'
001 C MOVE '*DETL ' RTNPNT 6
C MOVE *ON W1ERR
+001 C ELSE
001 C MOVE '*CANCL' RTNPNT
E001 C END
E001 C END
C*
C ENDSR RTNPNT
|
しかし、ここで、RTNPNTをなにに変えても、EVAL S=10に進むことは出来ません。つまり、次の行へ、RESUMEする事は無いのです。どのようにしたら、S=100のエラーを無視して、次の行に進めるのでしょうか?S=100をエラーにならないようにする(桁を増やす)、か、その行を、Z-ADDに変更する、しか手は無いのでしょうか?ふーむ。ロチェスタの人は、出来ると言い張っていたのですが...。
マニュアルの記載によれば、「サブルーチンがEXSR
命令によって呼び出され、演算項目2がブランクであった場合には、次の順次命令に制御が戻されます。」とあります。これを利用したらどうでしょうか?
H DEBUG DATEDIT(*YMD/)
C**************************************************************************
C* M A I N - R O U T I N E
C**************************************************************************
C Z-ADD 0 S 2 0
C*
C EVAL S=100
C EXSR *PSSR
C*
C EVAL S=10
C EVAL S=1.005
C*
C MOVE *ON *INLR
C RETURN
C*-------------------------------------------------------------------------
C *PSSR BEGSR
C*-------------------------------------------------------------------------
C*
C ENDSR
|
結局、だめです。EVAL S=100の直後、*PSSRに進みますが、なにもせず、戻りますので、*PSSRのENDSRの後で、エラーになります。そこで、ENDSRの演算項目2に、何かを入れて、スキップしたいところですが、*DETL他では、結局、後続の、EVAL=10に進みません。つまり、いったんエラーが起きたら、その明細サイクルはスキップしてしまい、次へ進むのです。BASICのON
ERROR GOSUBとは、動きが違います。
EVALの桁あふれエラーは、どうにもなりません。何とかして欲しいです。
参考:プログラム状況コード(RPGiv)
| 通常のコード |
| コード |
条件 |
| 00000 |
例外/エラーは起こっていない。 |
| 00001 |
呼び出されたプログラムから LR
標識がオンになって戻った。 |
| 例外/エラーのコード |
| コード |
条件 |
| 00100 |
ストリング操作の範囲外の値 |
| 00101 |
負の平方根 |
| 00102 |
ゼロによる除算 |
| 00103 |
中間結果が結果を入れるだけ大きくない。 |
| 00112 |
日付/時刻、または時刻スタンプの値が正しくない。 |
| 00113 |
日付オーバーフローまたは下位桁あふれ。(たとえば、日付演算の結果が*HIVAL
より大きいかまたは *LOVAL より小さい数になる場合。) |
| 00114 |
日付が4文字の年から2文字の年にマップされ、日付の範囲が
1940〜2039にない日付マッピング・エラー。 |
| 00120 |
テーブルまたは配列の順序が違っている。 |
| 00121 |
配列指標が正しくない。 |
| 00122 |
OCCUR が範囲外 |
| 00123 |
プログラムの初期設定ステップでリセットしようとした。 |
| 00202 |
呼び出されたプログラムまたはプロシージャーが正常に実行されず、停止標識
(H1〜H9) はオンでない。 |
| 00211 |
呼出しプログラムまたはプロシージャーのエラー |
| 00222 |
ポインターまたはパラメーター・エラー |
| 00231 |
呼び出されたプログラムまたはプロシージャーから停止標識がオンになって戻った。 |
| 00232 |
このプログラムで停止標識がオンになった。 |
| 00233 |
RETURN 命令の実行時に停止標識がオンになった。 |
| 00299 |
RPG IV 定様式ダンプが正常に実行されなかった。 |
| 00333 |
DSPLY 命令のエラー |
| 00401 |
IN/OUT で指定されたデータ域が見つからない。 |
| 00402 |
事前開始でないジョブに対しては *PDA は無効 |
| 00411 |
データ域のタイプまたは長さが一致しない。 |
| 00412 |
データ域が出力用にロックされていない。 |
| 00413 |
IN/OUT 命令のエラー |
| 00414 |
ユーザーにデータ域を使用する権限がない。 |
| 00415 |
ユーザーにデータ域を変更する権限がない。 |
| 00421 |
UNLOCK 命令のエラー |
| 00431 |
データ域は別のプログラムによってすでにロック済みである。 |
| 00432 |
データ域は同じ処理内のプログラムによってロック済みである。 |
| 00450 |
文字フィールド全体がシフト・アウトおよびシフト・イン文字で囲まれていない。 |
| 00501 |
分類順序検索の障害 |
| 00502 |
分類順序変換の障害 |
| 00802 |
コミットメント制御は活動状態になっていない。 |
| 00803 |
ロールバック操作が正常に実行されなかった。 |
| 00804 |
COMMIT 命令でエラーが起こった。 |
| 00805 |
ROLBK 命令でエラーが起こった。 |
| 00907 |
10 進数データ・エラー(数字または符号が無効) |
| 00970 |
プログラムの生成に使用されたコンパイラーのレベル番号が、RPG
IVの実行時サブルーチンのレベル番号と一致しない。 |
| 09998 |
ILE RPG OS/400
用コンパイラーまたは実行時サブルーチンの内部障害 |
| 09999 |
システム・ルーチン内のプログラム例外 |
|