【PL/I学習|実務向け】PL/IにおけるON-Unitの「ブロック単位」自動解除とスタック管理の極意

導入

メインフレームのPL/I開発において、例外処理(ON-Units)の制御は堅牢なプログラムを構築する要です。特に「ONステートメントを定義した後、いつ無効化されるのか」という寿命の管理は、予期せぬハンドラ動作を避けるために不可欠です。本記事では、ブロックの終了とともにON-Unitが自動的に解除される仕組みと、その実務的な制御手法について解説します。

基礎知識

PL/IのONステートメントは、特定の例外(エラーや割り込み)が発生した際に実行されるコードを定義する機能です。「ON-Unit」はその定義そのものを指します。
Javaなどの言語では例外ハンドラ(try-catch)が構文として固定されていますが、PL/IのON-Unitは実行時に動的に登録されます。重要なのは、BEGINブロックやPROCEDURE内で定義されたON-Unitは、そのブロックがENDで終了した瞬間に自動的にメモリから破棄(解除)されるという点です。これはPL/Iの実行時スタックと密接に連動しており、呼び出し元のON定義を上書きしたり、ブロック終了時に以前の定義へ自動的に戻ったりする「スタック管理」による恩恵を受けています。

実装/解決策

実務では、特定の処理範囲内でのみ有効な例外ハンドラを定義するために、あえてBEGINブロックを使用します。これにより、処理終了後の「ON-Unitの明示的な解除」を意識せずとも、PL/Iランタイムが自動的にスタックをポップし、安全に元の状態へ復元してくれます。

サンプルプログラム

以下のコードは、特定の処理中のみ「ゼロ除算」を個別ハンドリングし、ブロックを抜けた後に標準の動作へ戻る様子を示した例です。

/ サンプル:ブロックによるON-Unitのスコープ管理 /
TEST_PROC: PROCEDURE OPTIONS(MAIN);

/ グローバルなON-Unit定義 /
ON ZERODIVIDE BEGIN;
PUT SKIP LIST(‘全体共通:ゼロ除算が発生しました’);
END;

PUT SKIP LIST(‘— メイン処理開始 —‘);

/ 局所的な例外ハンドリングを行うBEGINブロック /
BEGIN;
/ ここで定義したON-UnitはこのBEGINブロック内でのみ有効 /
ON ZERODIVIDE BEGIN;
PUT SKIP LIST(‘局所ブロック:ゼロ除算を検知、ログ出力して継続します’);
END;

/ 意図的なゼロ除算 /
DCL A FIXED BIN(15) INIT(0);
DCL B FIXED BIN(15) INIT(10);
DCL C FIXED BIN(15);
C = B / A; / ここで局所ON-Unitが発動 /
END;
/ ここを抜けた時点で、局所ON-Unitは自動的に破棄され、元の全体共通の定義が有効に戻る /

PUT SKIP LIST(‘— 局所ブロック終了後の処理 —‘);
C = B / A; / ここでは全体共通のON-Unitが発動 /

END TEST_PROC;

応用・注意点

実務における注意点は、「動的スコープ」という性質です。Javaなどの静的スコープと異なり、ON-Unitは「プログラムの実行パス(呼び出し階層)」に依存します。つまり、ブロック内から呼び出したサブプログラムの中でエラーが発生した場合でも、呼び出し元のブロックで定義したON-Unitが有効なまま捕捉することがあります。

特に、移行ツールを用いて他言語へマイグレーションを行う際、この「実行パスに依存するスタックフレームの挙動」を正しく解析できないと、例外の捕捉漏れや、意図しないハンドラの継続が発生します。デバッグ時には、どの時点のON-Unitがスタックのどの位置にあるかを意識し、不要な場合はREVERTステートメントを併用して明示的に解除する癖をつけておくことが、安定したシステム運用の鍵となります。

コメント

タイトルとURLをコピーしました