ゼロ除算の深淵:PL/Iにおける例外処理とABEND回避の美学
メインフレームの世界では、コンパイラは「書かれたコードを機械語に翻訳するだけの道具」ではない。それはCPUの挙動とOSの制約を完全に掌握するための「言語インターフェース」だ。特にPL/Iは、その柔軟すぎる仕様ゆえに、現代の厳格な型付け言語に慣れたエンジニアをしばしば困惑させる。
今日は、基幹システムのバッチ処理で最も頻繁に遭遇し、かつ最も軽視されがちな「ZERODIVIDE(ゼロ除算)」について、システムアーキテクトの視点から掘り下げていこう。
予約語なき設計と、予測不能な落とし穴
PL/Iの特筆すべき仕様は、多くの言語にある「予約語」が存在しないことだ。`IF` も `THEN` も、変数名として使用できる。これは自由度の高さを示す反面、不適切なコーディングを行えば、コンパイラが「これは変数か、それともキーワードか」を判断する際に、意図せぬ解釈を招くリスクを孕んでいる。
特に、動的メモリ操作(`BASED`変数と`POINTER`)を多用するシステムでは、ポインタの指し示す先が不正な領域である場合、ゼロ除算以前にメモリ・プロテクション違反(S0C4)で即死する。例外処理を実装する際は、単なる「計算エラーの補足」ではなく、「システム全体の状態維持」を念頭に置く必要がある。
ON ZERODIVIDEによる防御的プログラミング
S0CB(ゼロ除算によるアベンド)は、バッチシステムにおける「悪の根源」だ。これが発生すると、ジョブは異常終了し、後続のリカバリ処理も止まる。これを回避するための `ON` ユニットは、単なるエラーハンドリングではなく、計算ロジックの「安全装置」として設計しなければならない。
/i
/ 例外処理の導入:ゼロ除算発生時の安全な逃げ道 /
ON ZERODIVIDE
BEGIN;
/ ゼロ除算発生時のログ出力と補正処理 /
PUT SKIP EDIT (‘警告: ゼロ除算を検知。計算をスキップして0を代入します。’) (A);
CALC_RESULT = 0;
/ 本来ならここでDB2のステータスコードを更新し、後続処理への影響を管理する /
GOTO RESUME_POINT;
END;
/ 計算実行箇所 /
DO I = 1 TO MAX_LOOP;
CALC_RESULT = DIVIDEND / DIVISOR(I);
RESUME_POINT:;
END;
実務上の注意点:パックデシマルの罠
基幹システムでは `FIXED DECIMAL` を多用するが、この内部表現(パックデシマル)は非常にデリケートだ。マイグレーションの際、Javaの `BigDecimal` へ変換すると、符号の扱い(X’0C’とX’0F’の解釈)で数値の不一致が発生することがある。PL/I側でゼロ除算をトラップする際は、同時に変数の符号ビットが正常かどうかも考慮しないと、後続の計算で「謎の数値」が伝搬し、ビジネスロジックが崩壊する。
ABEND回避とダンプ解析の極意
もし `ON` ユニットを使っても制御できないような重篤なエラー(スタックオーバーフローやシステムリソース枯渇)が発生した場合、頼りになるのは `SYSUDUMP` の解析だ。
1. レジスタの確認: ABEND発生時の命令アドレス(PSW)を確認せよ。そのアドレスがどのモジュール、どのソース行に対応しているかをロードモジュールのMAPと突き合わせる。
2. コンパイラオプションの再考: `OPTIMIZE(3)` を指定すると、コードが最適化されすぎてダンプ上の実行順序がソースと一致しなくなることがある。トラブルシューティング時は一時的に `OPTIMIZE(0)` または `TEST` オプションでデバッグ情報を付加したビルドを行え。
3. CICS環境でのエッジケース: CICSオンライン処理でゼロ除算が発生した場合、単一のタスクがアベンドするだけで済むのか、それともシステム全体に影響を及ぼすのか。`HANDLE CONDITION` を併用し、トランザクションのロールバック処理(`EXEC CICS SYNCPOINT ROLLBACK`)が正しく行われることを確認しておく必要がある。
結びに:マイグレーションを見据えたコード設計
JavaやC#への移行を控えた現場では、PL/Iのこうした「動的な挙動」を、いかに静的な言語の仕様に落とし込むかが腕の見せ所となる。ゼロ除算を `ON` ユニットで隠蔽するコードは便利だが、移行先では「例外を投げるべきか、デフォルト値を返すべきか」の判断が曖昧になりがちだ。
システムアーキテクトとして言えるのは一つ。「例外を無視するな。例外を制御可能なビジネス・ステータスに変換せよ」。
PL/Iの深い知見を持つあなたなら、今のコードが「何を守るために書かれているのか」を再定義できるはずだ。それができれば、どんな言語への移行も単なる「実装の書き換え」に過ぎない。
