PL/Iの「予約語なき設計」が生む美学と、ENDFILE制御の深淵
現代のJavaやC#に慣れ親しんだエンジニアが初めてPL/Iのソースコードを目にすると、十中八九その「曖昧さ」に当惑する。例えば、`IF IF = THEN THEN = ELSE;` というコードが文法的に成立してしまうという事実は、言語仕様の欠陥ではなく、むしろPL/Iという言語が持つ「極めて柔軟な構文解析」の賜物だ。
我々メインフレームアーキテクトにとって、この「予約語が存在しない」という設計思想は、ただの懐古趣味ではない。それは、何十年も前に書かれたコードを、コンパイラをアップグレードしてもなお、最小限の修正で動かし続けなければならないという、基幹システムの過酷な宿命に対する究極の解なのである。
今日は、その中でもバッチ処理の心臓部である「ストリーム入出力」と、ENDFILE条件のハンドリングについて、現場の血肉を通わせた知見を共有しよう。
—
1. ENDFILEトラップ:制御フローの罠
ストリーム入出力において、`ON ENDFILE(FILE_NAME)` を宣言するのは定石中の定石だ。しかし、このハンドラが単純な「終了処理」だと思ったら大間違いである。
/i
/ ファイル終了時のハンドラ定義 /
ON ENDFILE(SYSIN) BEGIN;
PUT SKIP LIST(‘データ読み込み完了。後続処理へ移行。’);
EOF_FLAG = ‘1’; / フラグを立ててメインループへ戻る /
END;
/ 読み込みループ /
DO WHILE(EOF_FLAG = ‘0’);
GET FILE(SYSIN) EDIT(REC_BUFFER) (A(80));
IF EOF_FLAG = ‘0’ THEN DO;
/ ここでデータ処理を行う /
END;
END;
ここで重要なのは、`ON` ユニット内で制御を戻す際、`GOTO` を使わずにフラグ制御でループを抜けるのが、現代的な再利用性を高める設計であるという点だ。かつては `GOTO` で一気にラベルへ飛ばす手法が主流だったが、DB2やCICS環境での複雑なトランザクション制御において、`GOTO` はスタックを汚染し、意図せぬアベンドを誘発する温床となる。
2. マイグレーションの最前線:パックデシマルの落とし穴
JavaやC#への移行を検討する際、最も頭を抱えるのが「パックデシマル(COMP-3)」の扱いである。PL/Iは `FIXED DECIMAL` を用いてこれを極めて効率的に処理するが、メインフレーム上の内部表現では、正の数であっても符号が `C` ではなく `F` になっていたり、あるいは意図せず `D`(負)が紛れ込むようなバグが混入することがある。
特に、`ON ENDFILE` のハンドラ内で異常終了したデータの「ダンプ」を解析する場合、この符号反転バグを即座に特定しなければならない。
- ダンプ解析の要諦: 16進ダンプで `123C` とあるべき場所が `123D` になっている時、それは単なる計算ミスではなく、ポインタ操作の誤りによるメモリ破壊(Storage Overlay)の可能性を疑え。
- ベース変数とポインタ: `BASED` ストレージを使用している際、割り当てたメモリ領域を超えてポインタを操作すると、ENDFILEが発生した瞬間に不正なアドレスを参照し、`S0C4` アベンドを叩き出す。これはスタックの破壊に直結する。
3. コンパイラ最適化とエッジケースの回避
PL/Iのコンパイラオプション(`OPTIMIZE(3)` など)は、往々にしてプログラマの「直感」を裏切る最適化を行う。特に、ループ内の演算において、`REORDER` オプションを付与すると、ループ条件が予測不能な順序で評価されることがある。
/i
/ 最適化の罠を回避するための volatile 的な工夫 /
DCL EOF_FLAG BIT(1) STATIC EXTERNAL; / 静的メモリ配置を強制し、レジスタへの過度な最適化を防ぐ /
CICSオンライン処理において、`ENDFILE` を `EXEC CICS READ` に置き換える移行を行う場合、PL/Iのネイティブな `ENDFILE` 制御から、`RESP` コードによる判定へシフトする必要がある。この際、PL/Iの `ON` ユニットの感覚で `HANDLE CONDITION` を組むと、リカバリ不能な例外ループに陥るため、必ず `RESP` を使用した逐次判定に書き換えるべきだ。
結論:レガシーは「過去の遺物」ではなく「安定の礎」
PL/Iが持つ「予約語を持たない」という柔軟性は、時にコードの可読性を下げる。しかし、その柔軟性こそが、数十年前に設計されたビジネスロジックを、最新のZシリーズのアーキテクチャ上で、コンパイラによる高度な最適化を享受しながら動かし続けるための鍵となっている。
もしあなたが今、レガシー移行の設計書を手にしているなら、言語の表面的な構文ではなく、その背後にある「メモリ管理」と「例外ハンドリングのスコープ」を注視してほしい。それこそが、メインフレームの信頼性を次世代へ繋ぐ、アーキテクトとしての唯一の道である。
何か具体的なアベンドコードや、移行先での型変換ロジックで躓いているなら、またいつでも相談してくれ。この言語には、まだ語り尽くせないほどの「職人の流儀」が眠っている。
