終わりの流儀:PL/IのON ENDFILEと、制御の深淵を歩く
メインフレームのバッチ処理において、「ファイルが終わる」という現象は、単なるEOF(End of File)ではない。それはプログラムの生存期間における一つの「変調」であり、システムアーキテクトとしては、この変調をいかに優雅に、かつ堅牢にハンドリングするかが腕の見せ所だ。
今日のテーマは `ON ENDFILE`。一見すると単純なファイル終了制御だが、その裏にはスタック管理や条件伝播という、コンパイラが隠蔽している「死と再生」のメカニズムが潜んでいる。
1. ON ENDFILEの基本と「トラップの作法」
PL/Iの `ON ENDFILE` は、単なる条件分岐ではない。これは「条件ハンドラ(Condition Handler)」としての割込み処理だ。まずは、基本構造を再確認しよう。
/i
/ ファイル終了時のハンドリング例 /
MAIN_PROC: PROCEDURE OPTIONS(MAIN);
DCL SYSIN FILE RECORD INPUT;
DCL EOF_FLAG BIT(1) INIT(‘0’B);
/ 終了条件の定義:
REVERTで元に戻せるよう、スタックの管理を意識すること /
ON ENDFILE(SYSIN) BEGIN;
EOF_FLAG = ‘1’B;
PUT SKIP LIST (‘— ファイルの末尾に到達しました —‘);
END;
OPEN FILE(SYSIN);
DO WHILE (EOF_FLAG = ‘0’B);
READ FILE(SYSIN) INTO(WORK_AREA);
IF EOF_FLAG THEN LEAVE;
/ ここでメイン処理を記述 /
END;
CLOSE FILE(SYSIN);
END MAIN_PROC;
ここで重要なのは、`ON` ユニット内で発生した例外が、呼び出し元のスコープへどう伝播するかという点だ。特に、複雑なサブルーチンを呼び出している場合、`ON` ユニットが「どこで定義されたか」によって挙動が変わる。動的スコープ(Dynamic Scope)の影響を理解していないと、アベンド解析時に迷宮入りすることになる。
2. ネストされたONユニットと優先順位の罠
複数のプロシージャが連鎖する環境では、`ON` ユニットは「現在実行中のプロシージャから遡って」最も近い定義が有効になる。
- 自動変数とスタック: `ON` ユニットはスタック上に積まれる。
- REVERTの重要性: 特定の処理ブロックだけで有効にしたい場合は、必ず `REVERT` 文を使ってスタックを破棄せよ。これを怠ると、意図しない場所で古い終了処理が発火する。
移行プロジェクトにおいて、この「スタックの巻き戻し」の挙動をJavaの `try-catch` やC#の `finally` と一対一で対応させようとすると、高い確率で設計が破綻する。PL/IのONユニットは、例外処理というよりは「信号(シグナル)受信機」に近いのだ。
3. 基幹システムにおけるエッジケースと最適化の知見
パックデシマル(COMP-3)の内部表現とON条件
ファイル読み込み時に、予期せぬ16進数(`0C`や`0D`以外のゴミデータ)が混入し、`CONVERSION` 条件が発火することがある。`ON ENDFILE` と `ON CONVERSION` を組み合わせてエッジケースを処理する際、ポインタを用いて領域を直接覗き込み、バイナリレベルで異常値を検証するコードを書いておくと、後々のデータ不整合調査で命拾いをする。
ポインタと動的メモリ操作
`BASED` 変数を用いた動的割り当てを行っている場合、ファイル終了処理でメモリを解放(`FREE`)し忘れると、巨大なバッチ処理ではあっという間に仮想記憶を食いつぶす。`ENDFILE` を検知した瞬間に、現在保持しているポインタリストを順次辿ってメモリを解放する「クリーンアップ・ルーチン」を別プロシージャとして持たせておくのが、熟練のアーキテクトの流儀だ。
4. マイグレーションに向けた「ダンプ解析」の視点
Javaへの移行を検討している読者へ。現在のメインフレームで発生しているダンプを眺める時、`ON` ユニットがどこでスタックされているかは、`CEEHDLR`(言語環境プログラムの条件ハンドラ)の情報を追うことで特定できる。
- アベンド時: `ON` ユニット内で異常が発生すると、ハンドラが無限ループに陥ることがある。これを防ぐには、`ON` ユニット内でのエラー発生を厳重に封じ込め、`STOP` ではなく `SIGNAL FINISH` を適切に呼ぶ設計が求められる。
- 最適化の影響: コンパイラオプションで `OPTIMIZE(3)` を指定している場合、変数の生存範囲が最適化によって変更され、ダンプ上の変数が「最適化により参照不可」となることがある。これに対処するには、開発環境では `TEST` オプションを付与し、本番環境との差異を事前にドキュメント化しておくことが重要だ。
まとめ:システムアーキテクトとして
PL/Iの `ON ENDFILE` は、単なるレガシーな構文ではない。それは、計算機資源が極めて貴重だった時代に、OSとプログラムが「異常」をいかにスマートに共有するかを追求した、言語設計の結晶である。
モダンな言語へ移行する際、この「条件駆動型の制御フロー」を、単なる例外処理へ置き換えるのではなく、システムの「状態管理プロトコル」として再定義できるか。それが、移行を成功させるための最後のピースとなる。
もし、貴方の移行先コードが単なる `try-catch` の羅列で埋め尽くされているなら、それはまだ本当の意味での「PL/Iからの脱却」には至っていないのかもしれない。技術の本質を見極め、次世代のシステムを堅牢なものに磨き上げてほしい。
