PL/Iプリプロセッサの「闇」:コンパイル前夜のソース操作と、現代の移行プロジェクトにおける教訓
メインフレームの現場で長くPL/Iと対峙していると、言語仕様の「柔軟性」という名の魔物に出くわすことがある。特にPL/Iには「予約語」という概念が希薄だ。`IF` や `THEN` といったキーワードでさえ、コンテキストが許せば変数名として定義できてしまう。これは自由度の極みだが、同時にプリプロセッサを絡めた際の解析を困難にする要因でもある。
今回は、移行プロジェクトの技術選定やバグ解析において避けては通れない、「プリプロセッサの展開順序」という深淵に足を踏み入れよう。
—
1. プリプロセッサの展開順序:コンパイル前の「カオス」
PL/Iのコンパイラは、ソースを読み込む前にプリプロセッサフェーズという前処理を行う。この時、最も注意すべきは「`%INCLUDE` がいつ展開されるか」だ。
結論から言えば、プリプロセッサはソースを前から順に読み込み、見つけたものから逐次解決していく。
つまり、`%REPLACE` や `%IF` のロジックが `%INCLUDE` されるソースの中に含まれている場合、その展開順序によって予期せぬ挙動を引き起こす。例えば、ヘッダーファイルの中で別のマクロを定義し、それをメインソース側で条件判定に使おうとして「未定義」で落ちる、というのは新人が通る洗礼だ。
/i
/ — メインソース — /
%DCL TARGET_ENV CHAR;
%TARGET_ENV = ‘PROD’; / 環境変数をセット /
%INCLUDE MY_MACROS; / ここでマクロ定義を読み込む /
/ もしマクロ側で %REPLACE が定義されていれば、
この後のコードでその置換が有効になる /
なぜ移行時にこれが問題になるのか?
JavaやC#へのマイグレーションを行う際、PL/I特有の「コンパイル時にコードを生成する」という発想を、そのまま言語機能にマッピングできないケースが多い。ソース生成ツールがプリプロセッサの展開結果を正確に再現できず、デバッグ時に「ソース上には存在するのに、実行バイナリには反映されていない」という、現場で最も恐れられる「透明なバグ」を生むからだ。
—
2. 予約語を持たない言語仕様と、アベンドの予兆
PL/Iには予約語が存在しない。これはつまり、`DECLARE IF FIXED;` と書けば `IF` という名前の変数が生成されるということだ。この仕様は、レガシーコードの解析ツール泣かせである。
パックデシマル(FIXED DECIMAL)の罠
基幹システムで頻発するアベンドの筆頭に、パックデシマルの内部符号処理がある。COBOLの `COMP-3` と同様だが、PL/Iでは `FIXED DECIMAL` として扱われる。
/i
DCL AMNT FIXED DEC(9,2);
/
- 稀に外部インターフェースから不正な符号ビット(例:0x0F以外)が
- 混入し、演算時に S0C7 (データ例外) を引き起こすことがある。
- 移行時には、こうした「物理的な不正データ」をどうガードするか、
- 全てのDBアクセス層でバリデーションを設計する必要がある。
/
特にポインタ操作(`BASED` 変数)と組み合わせた場合、境界チェックを怠ると、メモリ上の不正な領域を数値として解釈し、計算結果が壊れる。現代のJava環境であれば `BigDecimal` で厳格に扱えるが、ポインタでメモリを直接なめるPL/Iのロジックを読み解く際は、「その変数が指し示すアドレスの先頭から何バイトが有効か」を常にダンプと照らし合わせる必要がある。
—
3. 実践的トラブルシューティング:ダンプ解析の極意
ABEND発生時、多くのエンジニアは「どこで落ちたか」だけを見て修正しようとする。しかし、真のアーキテクトは「なぜメモリレイアウトがそうなったか」を追う。
1. ベースアドレスの確認: `BASED` 変数を使用している場合、そのポインタが指すアドレスが、前の処理で解放(`FREE`)されていないか。
2. コンパイラオプションの再確認: `OPTIMIZE` オプションを上げすぎると、ループ内の変数がレジスタに保持され、ダンプ上で値が更新されていないように見えることがある。調査時は `NOOPTIMIZE` で再コンパイルし、挙動が変わるか確認せよ。
3. CICSオンライン環境: `EXEC CICS` コマンドを含むPL/Iプログラムは、タスク切り替え時にストレージがクリアされることがある。`STATIC` 変数に依存した設計は、マイグレーションにおける最大の爆弾となる。
—
結びに代えて:技術の継承という責務
PL/Iは、ハードウェアを直接叩く「低レイヤーの知恵」と、複雑なビジネスロジックを記述する「高レイヤーの表現力」を兼ね備えた、歴史の結晶だ。
もし今、あなたがPL/Iからオープン系への移行を主導しているなら、単にコードを変換するのではなく、「なぜそのプリプロセッサ命令がその順序で書かれているのか」という先人の意図を汲み取ってほしい。その「意図」こそが、移行先の新システムにおける堅牢なアーキテクチャの礎となるはずだ。
汎用機の黒い画面が吐き出すダンプの海は、時に冷酷だが、嘘はつかない。その奥にあるロジックを解き明かすことこそが、我々アーキテクトの矜持である。
