*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 |
システム・ルーチン内のプログラム例外 |
|