PL/Iの深淵:DO-WHILEとDO-UNTILの「判定タイミング」でバグを生まないために
メインフレームの現場で長く生きていると、PL/Iという言語の「自由度の高さ」が時に慈悲深い救済となり、時にデバッグ地獄への片道切符になることを痛感する。
特に、若手エンジニアから「ループが想定した回数回らない」「意図せず1回余計に処理される」という相談を受けた際、真っ先に確認するのが`DO-WHILE`と`DO-UNTIL`の判定タイミングだ。今回は、この「たかがループ、されどループ」の挙動について、アーキテクトの視点から紐解いていく。
—
1. 判定タイミングの「決定的な違い」
PL/Iにおいて、これら2つの構文は「条件をいつ評価するか」という一点において決定的に異なる。
- DO WHILE (条件式):
ループの「入り口」で判定する。条件が偽であれば、ループ内の処理は一度も実行されない。
- DO UNTIL (条件式):
ループの「出口」で判定する。したがって、条件を満たしていようがいまいが、最低でも1回は必ず処理が実行される。
この違いを無視してVSAMの読み込み処理などを書くと、EOF(ファイルの終わり)の判定で「空のレコードを処理しようとして異常終了(S0C4やデータ例外)」という、ベテランでも肝を冷やすトラブルに直結する。
—
2. 実践コード:VSAM読み込み時の安全な実装
以下のコードは、VSAMファイルを読み込む際の典型的なパターンだ。`WHILE`を使うことで、ファイルが空だった場合や、即座に終了条件を満たした場合のガードを固めている。
/i
/ VSAMファイルからレコードを順次読み込む処理例 /
READ_LOOP: DO WHILE (EOF_FLAG = ‘0’);
READ FILE(INPUT_VSAM) INTO(REC_BUFFER);
/ EOF判定:ON ENDFILEユニットでフラグを立てる設計 /
IF EOF_FLAG = ‘1’ THEN LEAVE READ_LOOP;
/ ここにビジネスロジックを記述 /
CALL PROCESS_RECORD(REC_BUFFER);
END READ_LOOP;
ここで注目してほしいのは、`LEAVE`文と`WHILE`の組み合わせだ。`WHILE`はループ開始直前のレジスタ状態(条件フラグ)を評価する。この直前に`EOF_FLAG`を正しく更新しておくことが、メインフレームのバッチ処理において最も確実な制御フローとなる。
—
3. レジスタとコンパイラ最適化の裏側
PL/Iは「予約語」という概念が希薄だ。`IF`や`WHILE`すら、文脈によっては識別子になり得る。この柔軟性は強力だが、コンパイラにとっては最適化の難易度を上げる要因にもなる。
`DO-WHILE`や`DO-UNTIL`のループ変数(カウンタ)は、最適化レベル(`OPTIMIZE(2)`以上など)を上げると、物理レジスタに保持され、メモリアクセスを最小化するよう生成コードが最適化される。
もし、ループ内で外部から値を書き換えるようなダーティなコーディング(あるいはポインタによる領域操作)を行うと、コンパイラが「ループ変数は不変である」と誤認し、レジスタ上の古い値を使って暴走することがある。これを防ぐには、ループ変数の変更はループの最後で行うという古典的かつ堅実な作法を守る必要がある。
—
4. デバッグのコツ:ONユニットとの付き合い方
`DO`ループ内で`ON ENDFILE`のような`ONユニット`を定義するのは厳禁だ。`ONユニット`はプログラムの制御フローを大局的に監視する仕組みであり、ループのたびに再定義されるような書き方をすると、スタックを浪費し、メモリリークや意図しない動作を招く。
現場で守るべき黄金律
1. ループの入り口と出口を明確にする: `DO-WHILE`は入り口、`DO-UNTIL`は出口。この原則を逆手に取ったコーディングは後の保守担当者の悪夢になる。
2. BUILTIN関数の積極活用: `INDEX`, `SUBSTR`, `VERIFY`等は最適化されたライブラリルーチンを呼び出す。自前でループを回して文字列を解析するより、言語仕様を信じて`BUILTIN`に任せる方が、パフォーマンス的にも安全だ。
3. 変数の型を揃える: 比較演算を行う際、異なる属性の変数を比較すると、内部で暗黙の型変換(コンバージョン)が発生する。これはCPUサイクルを無駄にするだけでなく、精度の差異による論理バグを生む。`FIXED BIN(31)`同士の比較を徹底せよ。
—
最後に:コードは「自分への手紙」である
メインフレームのシステムは、数十年先も動く可能性がある。今のあなたが書いたその`DO`ループは、将来の誰か(あるいは数年後のあなた)が深夜の保守作業で読み解くことになる。
「動けばいい」ではなく、「意図が明快で、コンパイラが最適化しやすい」コードを書くこと。それこそが、IBMメインフレームエンジニアとしての真の矜持だ。現場での改修作業、健闘を祈る。
