【テクニカル・上級編】ON ENDFILEユニットによるファイル終了制御 – PL/Iの基本構文とデータ制御実践ガイド

孤高のPL/I:ON ENDFILEの深淵と「予約語なき世界」の落とし穴

PL/Iという言語は、しばしば「何でも書けるが、何もかもが複雑怪奇になる」と揶揄されます。しかし、メインフレームの心臓部で30年以上稼働し続けるミッションクリティカルなバッチ処理において、これほど堅牢かつ柔軟な言語は他にありません。

今日は、多くのマイグレーションプロジェクトで「なぜかバグの温床になりやすい」と言われる `ON ENDFILE` の制御フローと、その背景にあるPL/Iの特異な言語仕様について、アーキテクトの視点から紐解いていきましょう。

1. 予約語なき世界と「識別子の罠」

JavaやC#に慣れた現代のエンジニアが最も驚くのは、PL/Iには厳密な「予約語」が存在しないという点です。例えば、`IF` という変数名を定義することも、文法上は許されてしまいます。

1
/ 狂気の沙汰だが、文法的には正しい /
DCL IF BIN FIXED(15);
IF = 10;

この仕様は、コンパイラが「文脈」を解釈してコードを生成していることに起因します。しかし、移行の現場ではこれが仇となります。`ENDFILE` もまた、予約語ではありません。そのため、誤って同じ名前の変数やプロシージャを定義すると、コンパイラは警告すら出さずに「意図しないコード」を生成します。

マイグレーション時に静的解析を行う際は、これら「予約語っぽい名前」の変数にフラグを立てるのが、トラブルを未然に防ぐ鉄則です。

2. ON ENDFILE:制御フローの「出口戦略」

さて、本題の `ON ENDFILE` です。ファイルの終了を検知して終了処理へジャンプする際、多くのエンジニアが `GOTO` を多用しますが、ここに罠があります。

1
ON ENDFILE(SYSIN) BEGIN;
/ ファイル終了時のクリーンアップ処理 /
PUT SKIP LIST(‘処理完了。集計を開始します。’);
GOTO PROCESS_SUMMARY; / ここでメインループを脱出 /
END;

/ メイン読み込みループ /
DO WHILE(‘1’B);
READ FILE(SYSIN) INTO(RECORD_AREA);
/ データの加工ロジック /
END;

PROCESS_SUMMARY:
/ 集計ロジック /

この実装の何が問題か。それは、「ONユニット内でのGOTOは、スタックを適切に解放しない場合がある」という点です。特にCICS環境下や、複雑な `BEGIN-END` ブロックがネストされた環境では、不正な終了処理が原因で、メモリリークや最悪の場合はABEND(U4038など)を引き起こします。

推奨されるアーキテクチャ:シグナルと終了フラグ

現代的なアプローチとしては、`GOTO` による制御権の強制移動を避け、フラグ制御に切り替えることを強く推奨します。

1
DCL EOF_FLG BIT(1) INIT(‘0’B);

ON ENDFILE(SYSIN) EOF_FLG = ‘1’B;

DO WHILE(EOF_FLG = ‘0’B);
READ FILE(SYSIN) INTO(RECORD_AREA);
IF EOF_FLG THEN LEAVE; / LEAVEでループを安全に脱出 /
/ メインロジック /
END;

`LEAVE` を使うことで、PL/Iのランタイム管理下で正しくブロックを終了させることができます。これはJavaの `break` に近い挙動ですが、スタックフレームの整合性を保つ意味で、レガシー移行においては遥かに安全な設計です。

3. マイグレーションを成功させる「深層」の知見

パックデシマルと内部表現の不整合

マイグレーション先がJava等の場合、`PIC S9(7) COMP-3` のようなパックデシマル型の扱いに苦労します。特に、符号ビット(`F`や`C`など)を正しくハンドリングしないと、負数の扱いで計算結果が反転するバグが頻発します。ダンプ解析を行う際は、必ずEBCDICの16進数ダンプを確認し、符号ビットが期待通りの値になっているか検証してください。

ポインタ操作とアベンド

`BASED` 変数を用いた動的メモリ操作を行っている場合、ポインタが `NULL` を指していないかのチェックは必須です。PL/Iはポインタの不正アクセスに対して極めて寛容ですが、結果として後続の処理で `S0C4` (Protection Exception) を引き起こします。
移行設計時には、`CHECK(SIZE, SUBSCRIPTRANGE)` オプションをコンパイル時に必ず付与してください。これはパフォーマンスを多少犠牲にしますが、デバッグコストを劇的に削減します。

埋め込みSQL (DB2) との親和性

CICS + DB2でPL/Iを動かす場合、`ON ENDFILE` と `SQLCODE` のチェックタイミングが競合することがあります。DB2のカーソルループ内でファイル読み込みを行うような設計の場合、割り込みが重複し、カーソルがクローズされないままハングアップするケースが散見されます。
「ファイル処理」と「DB処理」のONユニットは、必ずスコープを分離し、`SIGNAL` を用いて例外をハンドリングする設計にすべきです。

最後に:守りの技術を極める

PL/Iという言語は、枯れているようでいて、その仕様の深淵には現代の高級言語が捨ててしまった「ハードウェアとの対話」が残されています。

「なぜこの挙動なのか」をコンパイラの出力リスト(LIST/MAPオプション)から読み解くスキルこそが、システムアーキテクトとしての真価を問われます。これからマイグレーションを控えている皆様、どうか安易なリライトに逃げず、まずはそのコードが持つ「設計思想」をダンプの向こう側から見抜いてください。

それが、何百万行もの基幹コードを安全に新天地へと導く唯一の道です。

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