外部呼出の「落とし穴」を埋める:PL/IにおけるENTRY宣言とLINKAGEの極意
メインフレームの現場で何十年も稼働している基幹システムを改修していると、たまに遭遇するのが「なぜか計算結果が化ける」「特定のケースでだけABENDする」といった不可解な事象だ。デバッガを叩き、メモリダンプを追った末に突き当たる原因の多くは、実は「外部PROCEDURE呼び出し時のインターフェース不一致」にある。
PL/Iは非常に強力で柔軟な言語だが、その柔軟さが仇となり、コンパイル時に型チェックを甘く設定していると、実行時に思わぬ「ゴミデータ」を掴まされることになる。今日は、保守現場で確実に生き残るための、正しいENTRY属性とLINKAGE指定の作法について解説しよう。
—
1. なぜENTRY属性の明示が「命綱」なのか
PL/Iのコンパイラは、呼び出し先のPROCEDUREが宣言されていない場合、デフォルトの引数型を推測しようとする。しかし、この「推測」こそがレガシーマイグレーションや大規模改修時のバグの温床だ。
`ENTRY`属性を明示的に記述することは、コンパイラに対して「この引数はこの型でなければならない」という契約を交わすことに他ならない。
悪い例(現場でよく見る「動くけど危険」なコード)
/i
/ 不適切な呼び出し元 /
CALL SUB_CALC(VAR_A, VAR_B);
/ コンパイラは引数の型を知らないため、デフォルトの解釈で進む /
これでは、もし`SUB_CALC`側で引数が`FIXED BIN(31)`を期待しているのに、呼び出し側が`DECIMAL`を渡していたとしても、コンパイルエラーにはならない。実行時にメモリ上のビットパターンが無理やり解釈され、数値が化ける。これが深夜のバッチ実行中に発生した時の絶望感は、経験した者にしか分からないだろう。
—
2. 実践的なENTRYインターフェース定義
確実に型チェックを行うためには、以下のように`DECLARE`文で引数の属性まで含めて定義するのが鉄則だ。
/i
/ 呼び出し元プログラムの宣言部 /
DCL SUB_CALC ENTRY (FIXED BIN(31),
CHAR(10) VAR)
OPTIONS(LINKAGE(SYSTEM));
/ 正しい呼び出し /
DCL W_VAL FIXED BIN(31) INIT(100);
DCL W_MSG CHAR(10) VAR INIT(‘TEST’);
CALL SUB_CALC(W_VAL, W_MSG);
ここで重要なのが `OPTIONS(LINKAGE(SYSTEM))` だ。これはOSの呼出規約(Standard Linkage)に従うことを明示する。特にCOBOLプログラムを呼び出す場合や、アセンブラで書かれた既存のルーチンを叩く際には、このLINKAGE指定がなければレジスタの扱いが不整合を起こし、予測不能な動作を招く。
—
3. VSAMアクセスとONユニットを絡めた実戦コード
さて、実際の業務バッチでは、外部ルーチンがVSAMファイルを操作するケースも多いだろう。エラーハンドリングと合わせて、構成例を示そう。
/i
MAIN_PROG: PROC OPTIONS(MAIN);
/ 外部ルーチンの型定義を明示 /
DCL PROC_VSAM_READ ENTRY (CHAR(8), FIXED BIN(15))
OPTIONS(LINKAGE(SYSTEM));
DCL WS_KEY CHAR(8) INIT(‘12345678’);
DCL WS_RC FIXED BIN(15);
/ ONユニットによるエラー制御(実務の基本) /
ON ENDFILE(VSAM_FILE) BEGIN;
PUT SKIP LIST(‘データ終端に到達しました’);
END;
/ 外部ルーチン呼び出し /
CALL PROC_VSAM_READ(WS_KEY, WS_RC);
/ 戻り値チェック /
IF WS_RC ^= 0 THEN DO;
PUT SKIP LIST(‘エラー発生: RC=’ || TRIM(WS_RC));
SIGNAL ERROR;
END;
END MAIN_PROG;
—
4. ベテランからのアドバイス:保守の現場で意識すべきこと
1. インクルードメンバを活用せよ:
`ENTRY`宣言をメインプログラムに直接書くのは保守性の観点から推奨しない。共通の`COPY`句(インクルードメンバ)に定義し、全ての呼び出し元でそれを参照するようにすれば、「型を変えたのに呼び出し元を修正し忘れた」というミスを物理的に排除できる。
2. BUILTIN関数の活用:
引数に渡すデータが不定の場合は、`ADDR()`や`LENGTH()`、`STG()`といった`BUILTIN`関数を積極的に活用し、渡すデータのメモリ配置を明確に意識すること。
3. リンクエラーを恐れるな:
コンパイル時に`ENTRY`属性が厳密すぎてリンクエラーになるなら、それは「隠れたバグが見つかった」と喜ぶべきだ。無理やりキャストして通すのではなく、型を合わせるのが、長寿命な基幹システムを守る唯一の道である。
最後に
PL/Iは、書き手が「システムを完全に掌握している」という前提で動く言語だ。だからこそ、インターフェース定義を疎かにする者は、いつか必ず大規模なシステム障害という高い授業料を払うことになる。
今日伝えた`ENTRY`宣言と`LINKAGE`の徹底は、一見地味なコーディング標準に思えるかもしれない。だが、これこそがバグの温床を未然に摘み取り、安定稼働というエンジニアの誇りを守るための最も有効な武器なのだ。
さあ、心当たりのあるソースコードを、今すぐ見直してみよう。君の書くその一行が、明日もメインフレームを力強く動かし続けるのだから。
