【実務・中級編】PL/Iプリプロセッサ(%INCLUDE, %IF, %REPLACE)の展開順序 – PL/Iの基本構文とデータ制御実践ガイド

PL/Iプリプロセッサの深淵:コンパイル前夜の「静かなる戦い」を制する

メインフレームの現場で長年PL/Iを触っていると、「なぜかコンパイル結果とソースが一致しない」という怪奇現象に遭遇することがある。これは幽霊の仕業ではない。多くの場合、プリプロセッサ(コンパイラ・プリプロセッサ)が、コンパイルの直前で裏工作を行っているからだ。

PL/Iは「予約語」という概念が希薄だ。`IF` という変数名さえ許容するこの自由奔放な言語において、プリプロセッサを正しく制御することは、大規模バッチの保守性を左右する極めて重要なスキルとなる。今日は、実務でハマりやすいプリプロセッサの展開順序と、その制御フローについて深掘りしよう。

1. プリプロセッサの展開順序:何が先で、何が後か

PL/Iのコンパイルプロセスにおいて、プリプロセッサは「ソースコードを食らい、別のソースコードを吐き出す」前処理を行う。ここで重要なのは、「%INCLUDEは一番最後に処理されるわけではない」という点だ。

以下の順序を脳裏に刻んでおいてほしい。

1. %REPLACE(置換)の解決: ソース内の定数定義などを置換する。
2. %IF / %THEN / %ELSE(条件付きコンパイル)の評価: コンパイル対象とするブロックを決定する。
3. %INCLUDE(コピーブック展開): 外部メンバーを取り込み、さらにその中に含まれるプリプロセッサ指示子を再帰的に解決する。

特に厄介なのは、`%INCLUDE` されたメンバー内に `%REPLACE` が含まれている場合だ。インクルード先で定義された定数が、インクルード元のプリプロセッサ評価に影響を与えることがある。この「依存関係の連鎖」を理解していないと、デバッグ中に頭を抱えることになる。

2. 実践:条件付きコンパイルとマクロの活用

大規模バッチでは、本番環境とテスト環境で読み込むVSAMのデータセットや、論理処理を切り替える必要があるだろう。以下は、プリプロセッサを駆使してスマートに実装したコード例だ。

1
/ テスト用フラグの制御:ONならテストモード、OFFなら本番モード /
%DCL TEST_MODE CHAR;
%TEST_MODE = ‘ON’;

/ コンパイル時、TEST_MODEに応じて処理を切り替える /
%IF TEST_MODE = ‘ON’ %THEN %DO;
%PUT ‘— TEST MODE ACTIVATED —‘;
%REPLACE VSAM_DSN BY ‘PROD.VSAM.TEST.DATA’;
%END;
%ELSE %DO;
%REPLACE VSAM_DSN BY ‘PROD.VSAM.MASTER.DATA’;
%END;

TEST_PROC: PROCEDURE OPTIONS(MAIN);

DCL VSAM_FILE FILE RECORD SEQUENTIAL INPUT ENV(VSAM(DSN(VSAM_DSN)));
DCL RECORD_BUF CHAR(100);

/ ONユニットによるエラーハンドリング /
ON ENDFILE(VSAM_FILE) BEGIN;
PUT SKIP LIST(‘データ読み込み完了’);
STOP;
END;

OPEN FILE(VSAM_FILE);

DO WHILE(‘1’B);
READ FILE(VSAM_FILE) INTO(RECORD_BUF);
/ BUILTIN関数による文字列操作 /
IF SUBSTR(RECORD_BUF, 1, 4) = ‘DATA’ THEN
PUT SKIP LIST(‘処理中: ‘ || TRIM(RECORD_BUF));
END;

CLOSE FILE(VSAM_FILE);

END TEST_PROC;

3. 現場で生き残るための「鉄則」

① 「%」を忘れるな

プリプロセッサの指示子(`%INCLUDE` など)を記述する際、カラム1から書くという古典的なルールはあるが、最近のコンパイラは柔軟だ。しかし、可読性のために必ずカラム1から記述し、インデントと区別できるようにせよ。後輩がコードを追うとき、プリプロセッサ指示子と通常コードが混ざっていると、解読コストが跳ね上がる。

② %REPLACE は定数の味方

`DCL` で定義した変数で定数を管理するのも良いが、`%REPLACE` はコンパイル時に完全に置き換わるため、オブジェクトコードの最適化において有利に働く。特にVSAMのファイル名やバッファサイズなど、定数として扱うべき箇所には積極的に導入すべきだ。

③ ONユニットの落とし穴

`ON ENDFILE` や `ON ERROR` は便利だが、プリプロセッサで条件分岐させた際、そのスコープ(有効範囲)が意図通りか必ず確認せよ。プリプロセッサでコードを「削った」はずが、`ON` ユニットがグローバルに残ってしまい、予期せぬ挙動を引き起こすのはバッチ改修の「あるある」だ。

最後に:メインフレームエンジニアの矜持

PL/Iは、C言語やJavaのように「書いた通りに動く」ことだけを期待してはいけない。コンパイラがどう解釈し、プリプロセッサがどう変形し、最終的にどの機械語に翻訳されるのか。その「透過性」を意識できる者だけが、数十万行のレガシーコードを安全に改修できる。

もし、コンパイルリストの `SOURCE` ではなく `MACRO` 出力を確認する癖がついていないのなら、今すぐ確認することをお勧めする。そこにこそ、真実が書かれている。

何か不明点があれば、またいつでも相談してくれ。泥臭いトラブル解決こそが、我々メインフレームエンジニアの腕の見せ所なのだから。

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