ゼロ除算の深淵:PL/IにおけるON ZERODIVIDEの挙動と、移行期に潜む「死の罠」
メインフレームの現場で長く生きていると、コンパイラの最適化によって「あり得ないはずの場所」でABEND(異常終了)が発生する瞬間に立ち会うことがある。特に、古くから稼働するPL/Iのバッチ処理において、`ON ZERODIVIDE`が適切に制御されていない場合、それは単なる計算ミスではなく、システム全体の整合性を根底から揺るがす「時限爆弾」となり得る。
今日は、PL/Iの特異な言語仕様である「予約語を持たない」という哲学と、その上でいかに堅牢な例外ハンドリングを実装すべきか、そしてJavaやC#へのマイグレーション時に我々が直面する「負の遺産」について深く掘り下げていこう。
—
1. 予約語なき世界の自由と恐怖
PL/Iの最大の特長であり、同時に言語設計上の最大級の「狂気」とも言えるのが、予約語が存在しないという仕様だ。例えば、`IF`や`THEN`、あるいは`DECLARE`といったキーワードであっても、プログラマが変数名として定義できてしまう。
/i
/ 極めて危険なコードの例 /
DCL IF FIXED BIN(31);
IF = 10; / コンパイラはこれを変数と解釈する /
この仕様は柔軟性をもたらすが、レガシーコードの解析において解析ツールがしばしば迷走する原因となる。マイグレーション担当者がまずやるべきは、プリプロセッサを通した後の展開コードを注視し、識別子の衝突を徹底的に排除することだ。
—
2. ON ZERODIVIDEによる例外ハンドリングの真髄
`ON ZERODIVIDE`は、実行時にゼロ除算が発生した際、通常のプログラムフローを中断して指定したブロックへ制御を移す。ここで重要なのは、「スタックの巻き戻し」と「再開(REVERT)」の制御である。
/i
PROCEDURE MAIN;
DCL A FIXED DEC(5,0) INIT(100);
DCL B FIXED DEC(5,0) INIT(0);
DCL RESULT FIXED DEC(10,2);
/ ゼロ除算ハンドラの定義 /
ON ZERODIVIDE BEGIN;
PUT SKIP LIST(‘警告: ゼロ除算を検知しました。デフォルト値を適用します。’);
RESULT = 0; / 回復処理 /
/ ここでREVERTを指定しない限り、ONユニットは有効であり続ける /
END;
RESULT = A / B; / ここで例外発生、ONユニットへ飛ぶ /
PUT SKIP LIST(‘計算結果:’, RESULT);
END;
実務における注意点:
- ONユニットのスコープ: `ON`ユニットは、そのブロックが終了しても、スタックが戻るまで有効であり続ける。意図しない場所で古い`ON`ユニットが発火しないよう、`REVERT`ステートメントで明示的に解除する習慣を持つべきだ。
- パックデシマルの罠: DB2から抽出したデータが、予期せず`NULL`や非数値(ゴミデータ)を含んでいる場合、算術演算で`S0C7`(データ例外)ではなく、論理的な`ZERODIVIDE`を引き起こすことがある。内部表現としてのパックデシマル符号(`x’C’`や`x’D’`)が破損している場合、コンパイラオプションの`CHECK`や`SIZE`を有効にしていても、デバッグダンプを読み解くのは至難の業だ。
—
3. マイグレーションに向けたアーキテクチャ設計
JavaやC#に移行する際、多くのプロジェクトが失敗するのは「PL/Iの例外モデルをそのままtry-catchに置換しようとする」からだ。
1. 動的メモリとポインタ: PL/Iの`BASED`変数と`ADDR`関数を用いた動的メモリ操作は、C言語のポインタ操作に近く、Javaの参照管理とは本質的に異なる。これらをマイグレーションする際は、ガベージコレクションの挙動を考慮し、メモリレイアウトを再設計する必要がある。
2. CICS/DB2エッジケース: CICS環境下での`ON ZERODIVIDE`は、タスク全体のアベンドを回避するために必須だが、Java側ではスレッドローカルな例外処理として、トランザクションのロールバック基準と厳密に紐付ける必要がある。
3. ダンプ解析の教訓: メインフレームのダンプからPSW(プログラムステータスワード)を特定し、機械語レベルでどこで除算命令(`DR`や`DP`)が落ちたかを追う感覚を、現代のログ解析にどう翻訳するか。これができなければ、マイグレーション後の運用は地獄を見る。
—
結論として
PL/Iのコードを眺めていると、開発者が当時のハードウェア限界とどう戦ったかという「息遣い」が聞こえてくるようだ。`ON ZERODIVIDE`を単なる「エラー逃げ」の手段として使うのではなく、ビジネスロジックの一部として、あるいはシステムの信頼性を担保する最後の砦として設計すること。
マイグレーションは、単なるコードの書き換えではない。そのシステムが抱えてきた「計算の論理」そのものを、現代の言語仕様の上に再構築する作業である。
技術の陳腐化を嘆く前に、まずは目の前のコードが、なぜそのような構造になっているのか、その「動機」を読み解いてほしい。それができるスペシャリストこそが、レガシー移行のプロジェクトを成功に導く唯一の鍵となる。
