メインフレームの「深淵」を覗く:PL/IにおけるON ENDFILEと制御フローの極意
やあ。今日もレガシーシステムの迷宮で、ソースコードと睨めっこしている諸君。
PL/Iという言語の面白いところは、一見すると堅苦しいようでいて、実は非常に柔軟で「人間味」のある設計思想に基づいている点だ。特に、現代のJavaやPythonのような言語に慣れた若いエンジニアが最初に躓くのが、この「予約語の概念の希薄さ」と「ONユニットによる非同期的な制御フロー」だろう。
今日は、バッチ処理の心臓部である「ファイル読み込みの終了制御」について、現場の知見を交えて深掘りしていくぞ。
—
1. 「予約語がない」というPL/Iの自由度とリスク
PL/Iを初めて触るエンジニアが驚くことの一つが、`IF`や`THEN`といった構文要素が、実は「予約語ではない」という事実だ。極端な話、変数を`IF`という名前で宣言してもコンパイラは文句を言わない。(※コンテキストによって判別されるため、推奨はしないがな)。
この仕様は、長年積み上げられたレガシーコードの命名規則に独特の癖を生む。だが、逆を言えば、コーディング規約で命名規則を厳格に定義しておかないと、可読性は一気に崩壊する。保守を行う際は、まずその現場の「名前の付け方」という文化を読み解くところから始めてくれ。
—
2. ON ENDFILE:泥沼に陥らないための制御フロー
ファイル読み込みにおいて、`ENDFILE`条件は「エラー」ではなく「状態の変化」だ。これを`IF`文で逐一チェックするのではなく、`ON`ユニットという割り込みハンドラで処理するのがPL/I流のスマートな書き方だ。
しかし、現場でよく見る悲劇が「ONユニット内での無限ループ」や「制御フローの迷子」だ。まずは、現場で通用するスタンダードな構成を見てほしい。
/i
/ VSAMファイル読み込みの標準的な実装パターン /
TEST_PROG: PROC OPTIONS(MAIN);
DCL IN_FILE FILE RECORD INPUT ENV(VSAM);
DCL EOF_FLAG BIT(1) INIT(‘0’B);
DCL RECORD_AREA CHAR(80);
/ ENDFILE条件が発生した時の挙動を定義 /
ON ENDFILE(IN_FILE) BEGIN;
EOF_FLAG = ‘1’B; / フラグを立ててメインループを抜ける /
END;
OPEN FILE(IN_FILE);
DO WHILE(EOF_FLAG = ‘0’B);
READ FILE(IN_FILE) INTO(RECORD_AREA);
/ 読み込み成功時のみ処理を行う /
IF EOF_FLAG = ‘0’B THEN DO;
/ ここにビジネスロジックを記述 /
PUT SKIP LIST(‘READ DATA:’ || RECORD_AREA);
END;
END;
CLOSE FILE(IN_FILE);
END TEST_PROG;
ここがポイントだ:
- フラグ管理の徹底: `ON`ユニット内でいきなり`GO TO`でループの外へ飛ぶのは悪手だ。スタックが複雑になり、後のデバッグで地獄を見る。フラグで状態を管理し、正常なフローに戻すのが鉄則だ。
- READ後の判定: `READ`の直後に必ず`EOF_FLAG`を確認すること。これを忘れると、ファイルの最後のレコードを二重処理したり、メモリ保護違反を引き起こしたりするリスクがある。
—
3. SIGNAL ENDFILE:疑似的な終端検知というテクニック
デバッグ時や、特殊なテストケースで「意図的にファイルの終端を再現したい」ことがあるだろう。その時に役立つのが`SIGNAL`命令だ。
/i
/ 読み込み処理の途中で強制的にENDFILEを発生させる例 /
IF SOME_CRITICAL_ERROR THEN DO;
SIGNAL ENDFILE(IN_FILE);
/ これにより、あたかもファイルが空になったかのようにONユニットが発火する /
END;
この`SIGNAL`は、テスト自動化において非常に強力な武器になる。本物のVSAMデータセットを大量に用意せずとも、ロジックの末尾処理を検証できるからな。ただし、安易に業務コードで使うと後続のメンテナンス担当者が「なぜここでファイルが終わるのか?」と混乱する。使用時は必ずコメントで意図を明記しておくこと。
—
先輩エンジニアからのアドバイス
PL/Iのコードを保守する際は、「そのコードが意図した例外処理なのか、それとも場当たり的なパッチなのか」を見極める観察眼が必要だ。`ON`ユニットは強力だが、スコープを意識しないと、呼び出し元の`ON`ユニットが残ったまま次のファイル処理に移るような事故も起きる。
`REVERT`文を使って、不要になった`ON`ユニットを適宜解除する作法も忘れないでくれ。
/i
/ 特定の処理が終わったら、ONユニットの効力を解除する /
REVERT ENDFILE(IN_FILE);
メインフレームの世界は、枯れた技術の集合体に見えて、実は非常に深い論理哲学に基づいている。今日解説した「ファイル終了制御」は、バッチ処理の基礎中の基礎だ。ここを完璧にマスターすれば、どんな大規模なマイグレーション案件でも、システムを揺るがすような致命的なバグは防げるようになるはずだ。
次は、`ALLOCATE`と`POINTER`による動的メモリ管理の世界に踏み込んでみるか?……まあ、それはまた、別の機会にな。健闘を祈る。
