導入:なぜ今、COBOLで再帰呼び出しが必要なのか
業務システムでは、かつては「再帰呼び出し(自分自身を呼び出すこと)」はご法度とされてきました。しかし、組織構造のツリー探索や、複雑な計算式の評価など、階層が深くなる処理を扱う際、従来のPERFORM文だけで実装しようとすると、フラグ管理やスタックの自前実装でコードが非常に複雑化してしまいます。COBOLのRECURSIVE属性を使えば、この課題を解決し、プログラムを劇的に簡潔に保つことが可能になります。
基礎知識:再帰呼び出しとLOCAL-STORAGE SECTION
再帰呼び出しとは、プログラムが実行中に自分自身を呼び出す手法です。通常、COBOLのWORKING-STORAGE SECTIONはプログラム内で共有されるため、再帰させると値が上書きされてしまい正常に動作しません。
ここで重要になるのがLOCAL-STORAGE SECTIONです。このセクションで宣言されたデータは、プログラムが呼び出されるたびにスタック上に「インスタンス」として個別に確保されます。これにより、再帰の各階層がそれぞれ独立した変数を持つことができ、安全な再帰処理が実現するのです。
実装:RECURSIVE属性の宣言手順
実装は非常にシンプルです。PROGRAM-IDの後に「IS RECURSIVE」と記述するだけです。ただし、以下の点に注意してください。
1. 階層ごとにメモリを消費するため、再帰の深さには上限を設けること。
2. データ項目は必ずLOCAL-STORAGE SECTIONで定義すること。
サンプルプログラム:階層的な数値の総和計算
以下は、指定した数値までを再帰的に加算する簡単なサンプルです。
IDENTIFICATION DIVISION.
PROGRAM-ID. RECUR-SUM IS RECURSIVE.
DATA DIVISION.
LOCAL-STORAGE SECTION.
- 再帰の各階層で個別に確保される一時的な変数
01 WS-CURRENT-VAL PIC 9(04).
LINKAGE SECTION.
01 LK-INPUT PIC 9(04).
01 LK-RESULT PIC 9(08).
PROCEDURE DIVISION USING LK-INPUT LK-RESULT.
- 終了条件: 入力が0になったら終了
IF LK-INPUT = 0
MOVE 0 TO LK-RESULT
ELSE
- 再帰呼び出し: 自身の値を減らして呼び出す
COMPUTE WS-CURRENT-VAL = LK-INPUT – 1
CALL “RECUR-SUM” USING WS-CURRENT-VAL LK-RESULT
- 戻ってきた値に自身の値を加算
ADD LK-INPUT TO LK-RESULT
END-IF.
GOBACK.
応用・注意点:現場で陥りやすいバグの回避策
現場で再帰を使う際に最も怖いのは「無限再帰」によるスタックオーバーフローです。必ず終了条件(今回の例ではLK-INPUT = 0)が確実に到達することをテストしてください。
また、外部プログラムとの連携時には注意が必要です。RECURSIVE属性を持つプログラムを呼び出す際は、呼び出し側のスタックサイズが十分に確保されているか確認してください。大規模なデータ構造を扱う場合は、再帰ではなくスタックを明示的に保持する「動的配列」を用いた反復処理へ切り替える判断も、ベテラン技術者としての重要なスキルです。適材適所で賢く使い分けましょう。

コメント