ゼロ除算を「許容」する設計の深淵:PL/Iにおける例外処理と信頼性の境界線
基幹システムの保守・移行現場において、`ON ZERODIVIDE` は単なる「エラー回避の便利ツール」ではない。それは、データ品質が担保しきれないレガシー環境において、バッチ処理を完遂させるための最後の防波堤だ。
しかし、この構文を安易に使うと、デバッグ地獄という名の迷宮に迷い込むことになる。今日は、PL/Iのコンパイラ挙動と、IBMメインフレームのハードウェア特性を意識した「ゼロ除算ハンドリング」の真髄について語ろう。
—
1. ONユニットのアーキテクチャと実行時の罠
まず、`ON ZERODIVIDE` はプログラムの実行制御フローを非同期的に分岐させる。重要なのは、このユニットが「どのようにスタックを巻き戻すか」という点だ。
1
/ ゼロ除算発生時のリカバリ実装例 /
MAIN_PROC: PROCEDURE OPTIONS(MAIN);
DCL DIVIDEND DEC FIXED(15,2);
DCL DIVISOR DEC FIXED(15,2);
DCL RESULT DEC FIXED(15,2);
/ ゼロ除算が発生した場合のONユニットを定義 /
ON ZERODIVIDE BEGIN;
PUT SKIP LIST(‘警告: ゼロ除算発生。計算結果をゼロとして継続します。’);
RESULT = 0;
/ GOTOで制御を戻すのが基本だが、複雑なネスト内ではスタックの整合性に注意が必要 /
GOTO CONTINUE_PROCESS;
END;
/ 演算処理 /
RESULT = DIVIDEND / DIVISOR;
CONTINUE_PROCESS:
/ ここから後続処理へ /
END MAIN_PROC;
ここで注意すべきは、`ON` ユニット内で使用する変数のスコープだ。スタックフレームが深い状態で `GOTO` を強行すると、コンパイラが生成した内部レジスタの整合性が崩れ、意図しないダンプ(S0C7やS0CB)を誘発することがある。特に、`RECURSIVE` 属性を持つプロシージャ内での使用は、アーキテクトとしては避けるべき悪手である。
—
2. パックデシマルと内部表現の不整合
マイグレーション時に最も苦しむのが、入力データに紛れ込んだ「異常なパックデシマル」だ。DB2から抽出したデータが、何らかの理由で破損しており、最下位ニブルに符号(C/D/F)以外の値が入っている場合がある。
PL/Iはこれを「算術演算時のアベンド」として検知するが、`ON ZERODIVIDE` を過信して「何でも拾える」と錯覚してはいけない。データ型が `FIXED DEC` である以上、算術演算命令(`AP` 命令や `DP` 命令)が発行される前に、入力値の正規化(`TEST DECIMAL` 命令相当のチェック)を事前に行うのが、真のプロフェッショナルの矜持だ。
—
3. Java/C#への移行を見据えた「エッジケース設計」
レガシーからオープン系言語への移行プロジェクトをリードする場合、この `ON ZERODIVIDE` の挙動をどうマッピングするかが最大の論点になる。
- PL/Iの場合: ゼロ除算が発生しても、ハンドラが適切であればプログラムは終了しない。
- Javaの場合: `ArithmeticException` がスローされる。
単純に `try-catch` で囲むだけでは、ポインタ操作(`ADDR` 関数)や、`BASED` 変数を用いた動的メモリ操作による「ポインタのオフセット計算」までを正確に再現できない。移行先で同じ信頼性を担保するためには、個別の演算箇所にガード句を入れるのではなく、演算をラップする「関数オブジェクト」を定義し、計算のたびにゼロ判定を挟むアーキテクチャを採用すべきだ。
—
4. ABEND(アベンド)発生時のダンプ解析の極意
万が一 `ON` ユニットが機能せずアベンドした場合、あなたが見るべきは `CEEDUMP` だ。特に、ゼロ除算が起きている行の直前にある「マシンコード」を確認してほしい。
もし、コンパイラオプションで `OPTIMIZE(3)` を指定している場合、コードの並び替え(命令スケジューリング)が行われ、ソースコード上の見た目とアベンド位置が微妙にズレる。この時、`OFFSET` 情報を頼りにロードモジュールのマップと突き合わせる能力が、システムアーキテクトとしての真価を問われる瞬間だ。
最後に:アーキテクトへの提言
`ON ZERODIVIDE` は、あくまで「想定外の事態」に対する救済措置だ。これに頼り切ったロジックは、コードの可読性を著しく低下させる。
「ゼロで割る」という事象は、業務ロジックの欠陥であることがほとんどだ。`ON` ユニットでリカバリして数値を 0 に書き換える前に、なぜその分母が 0 になったのか。CICSのオンライン画面で入力された値か、あるいは集計バッチでのキーブレイクのミスか。
「プログラムを止めるな」という要求に応えるのはエンジニアの務めだが、「なぜ止まるのか」を解明し、源流でデータを正すのがアーキテクトの仕事である。
PL/Iの奥深さは、こうしたハードウェアに近いレイヤーでの制御を、高級言語の文法で書ける点にある。この言語を捨てていく過程で、私たちは「機械がどう動いているか」という大切な知見を失ってはならない。
