【実務・中級編】GOTO文のスコープ制限と非構造化プログラミングの弊害 – PL/Iの基本構文とデータ制御実践ガイド

迷宮の入り口はGOTO:PL/Iにおけるブロック制御と「負の遺産」の正体

若手のエンジニアから、「なぜ古いPL/Iプログラムはこんなにも追いかけにくいのか」と相談を受けることがある。その答えは、言語そのものの古さではなく、先人が残した「GOTOによる制御フローの蹂躙」にあることが多い。

今日は、PL/Iの基本構造である`PACKAGE`や`PROCEDURE`を振り返りつつ、特に制御フローの鬼門であるGOTO文のスコープ制限と、それが引き起こす「保守の地獄」について、現場の視点から紐解いていこう。

1. 現代PL/Iの基本構造:PACKAGEからPROCEDUREへ

かつてのPL/Iは単一のソースで巨大なモジュールを構成しがちだったが、現在の開発では`PACKAGE`文を用いたモジュール化が標準だ。これにより、外部から参照可能なエントリポイントを限定し、カプセル化を意識した設計が可能になる。

1
/

  • 現代的なPL/Iプログラムの構造例
  • PACKAGEにより内部スコープを制御する

/
MY_BATCH_PROG: PACKAGE EXPORTS(MAIN_PROC);

/ 外部から見えるのはMAIN_PROCだけ /
MAIN_PROC: PROCEDURE OPTIONS(MAIN);

DCL INPUT_REC CHAR(80);
DCL EOF_FLAG BIT(1) INIT(‘0’B);

/ VSAMファイル等の読み込みループ /
DO WHILE(^EOF_FLAG);
CALL READ_VSAM_RECORD(INPUT_REC, EOF_FLAG);
IF ^EOF_FLAG THEN
CALL PROCESS_RECORD(INPUT_REC);
END;

END MAIN_PROC;

/ 下位ルーチンは内部に隠蔽する /
PROCESS_RECORD: PROCEDURE(P_REC);
DCL P_REC CHAR(80) PARM;
/ ここにビジネスロジックを記述 /
END PROCESS_RECORD;

END MY_BATCH_PROG;

2. GOTOのスコープ制限と「スパゲッティ」の罠

PL/Iの仕様において、GOTO文は基本的に「同じブロック内、あるいは呼び出し元の親ブロックへのジャンプ」しか許されない。これだけ聞くと「安全ではないか?」と思うかもしれない。しかし、これが曲者なのだ。

非構造化の恐怖:ONユニットとGOTO

PL/Iには`ON`ユニットという強力な例外処理機構がある。これとGOTOを組み合わせると、とんでもないことが起きる。

1
/ 非推奨のコーディング例 /
ON ENDFILE(SYSIN) GOTO EXIT_LABEL;

PROC_A: PROCEDURE;
/ … 処理 … /
IF ERROR_CONDITION THEN GOTO EXIT_LABEL; / 遠くへジャンプ /
END PROC_A;

EXIT_LABEL: / ブロックを飛び越えた先で処理を再開 /

このようなコードに出くわしたことはないだろうか。ONユニット内で`GOTO`を発火させると、スタックフレームを巻き戻して(UNWINDして)ラベルへ飛ぶ。デバッガで追っていると、突然カーソルがソースの遥か彼方へワープする。これが、保守担当者が一番嫌う「制御の流れが追えないバグ」の正体だ。

3. なぜGOTOを排除すべきなのか

実務においてGOTOを多用したコードが地獄を生む理由は、大きく3つある。

1. 静的解析の無効化: コンパイラや静的解析ツールが、変数の生存期間や制御パスを正確に追えなくなる。
2. ONユニットの副作用: `SIGNAL CONDITION`などで例外を意図的に発生させ、GOTOで脱出する手法は、スタック内のメモリ解放漏れを引き起こす可能性がある。
3. 可読性の崩壊: コードの行間を読もうとしても、どこからどこへ飛ぶのかが可視化できない。

代替案:正しいフロー制御

現代のPL/I開発では、`LEAVE`文や`ITERATE`文、そして構造化された`IF-THEN-ELSE`によるフロー制御が基本だ。

1
/ 推奨:構造化されたループ制御 /
READ_LOOP: DO WHILE(NOT_EOF);
IF REC_TYPE = ‘X’ THEN DO;
/ 処理をスキップしたい場合はITERATEを使用 /
ITERATE READ_LOOP;
END;

/ 異常系はフラグ管理で制御する /
IF REC_ERR THEN DO;
CALL HANDLE_ERROR;
LEAVE READ_LOOP; / ループからの健全な脱出 /
END;
END;

4. 現場のエンジニアへ送るデバッグのコツ

もし君が、GOTOが張り巡らされた古いプログラムの改修を任されたら、以下の手順で「鎮圧」してほしい。

  • LABELの洗い出し: まずは`GOTO`文の飛び先となっている`LABEL`を全てリストアップせよ。
  • ONユニットの可視化: プログラム内で`ON`文がどこで定義され、どこで発動しているかを追い、GOTOによる脱出を排除する。可能であれば`RETURN`や`STOP`、あるいはフラグによる制御に書き換える。
  • VSAMアクセスの分離: VSAMの戻り値を判定する際、GOTOで分岐させるのではなく、`RETURN CODE`や`STATUS`を呼び出し元に戻す設計へリファクタリングせよ。

メインフレームのシステムは、我々が書く一行一行のコードの積み重ねで動いている。スパゲッティコードを解きほぐすのは骨の折れる作業だが、それは君自身のスキルを高め、次にそのコードを触る誰かの命を救うことになる。

「動けばいい」ではなく、「読みやすく、壊れにくい」コードを目指すこと。それが、真のシステムアーキテクトへの第一歩だ。

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