1. 導入:なぜINCLUDE階層の管理が重要なのか
メインフレームのCOBOL開発において、共通定義体(COPY句や%INCLUDE)の活用は保守性向上の要です。しかし、何も考えずに階層を深くすると、プリプロセッサのスタック制限に抵触し、コンパイルエラーを引き起こすリスクがあります。また、意図しない「ダイヤモンド依存(複数のパスを経由して同じ定義が二重に取り込まれる)」は、メモリの無駄遣いだけでなく、予期せぬ再定義エラーの原因となります。本稿では、この階層制限を意識した安全なソース管理術を解説します。
2. 基礎知識:プリプロセッサと入れ子構造
プリプロセッサは、ソースコードをコンパイルする前に、%INCLUDE文で指定された外部メンバをソース内に展開します。この際、システム内部では「スタック」というメモリ領域を使用して、どのファイルを読み込み中かを記憶しています。このスタックには物理的な上限があるため、階層が深すぎると「スタックオーバーフロー」が発生します。特に、全社共通の共通基盤と、プロジェクト固有の定義が複雑に絡み合う現代のシステムでは、この階層構造の把握が不可欠です。
3. 実装・解決策:階層の平坦化とガードの実装
階層が深くなる主な原因は、各プログラムが「とりあえず必要なものを全部INCLUDEする」という設計にあります。解決策は二つあります。
一つは、「階層の平坦化」です。共通定義を細分化し、必要最小限の単位でINCLUDEさせることで、スタック消費を抑えます。
もう一つは、「ガード条件の導入」です。同じメンバが複数回読み込まれないよう、プリプロセッサ変数を利用して、二重読み込みを防ぐ仕組みを構築します。
4. サンプルプログラム:二重読み込み防止のテンプレート
以下は、%INCLUDEの二重展開を防ぐための標準的な記述例です。
/ 共通ヘッダファイル:COMMON-DEF.H /
/ 既に読み込まれている場合はスキップするガード条件 /
%IF &LOADED-COMMON-DEF = ‘YES’ %THEN %GOTO SKIP-INCLUDE;
/ ここに本来の定義を記述 /
01 WS-COMMON-AREA.
05 WS-VERSION-ID PIC X(10).
05 WS-STATUS-CODE PIC X(01).
/ 読み込み済みフラグを立てる /
%SET &LOADED-COMMON-DEF = ‘YES’;
%SKIP-INCLUDE:
/ 既に読み込まれている場合はここへジャンプして処理を終了 /
5. 応用・注意点:移行解析と依存関係の可視化
現場で最も恐ろしいのは、修正箇所がどの程度の範囲に影響するか分からない「依存関係のブラックボックス化」です。大規模な移行プロジェクトでは、プログラムやCOPYメンバの依存関係を静的解析ツールでグラフ化し、不要な階層がないかを可視化することをお勧めします。
また、ダイヤモンド依存(AがBとCを呼び、BとCが両方Dを呼ぶ構造)に陥ると、コンパイラはDが重複定義されていると判断し、エラーを返します。この場合は、Dを直接INCLUDEするのではなく、共通の親であるBまたはCのみがDを保持するよう、パッケージ設計を再考してください。
階層の深さは「設計の複雑さ」のバロメーターです。深くしすぎず、かつ依存関係を明快に保つことが、安定したメインフレーム運用への近道となります。

コメント