【COBOL学習|初心者向け】COBOLで学ぶ!「NOT ON EXCEPTION」で呼び出し成功後の処理をスマートに記述する方法

はじめに:なぜ「NOT ON EXCEPTION」が重要なのか?

COBOLでプログラムを開発していると、他のプログラム(サブプログラム)を呼び出す機会は非常に多いです。例えば、共通で利用する計算処理や、特定の業務ロジックを切り出したモジュールなどを呼び出す場合ですね。

ここで、「呼び出しが成功した」という前提で、その後の処理をどう記述するか、というのは意外と悩ましい問題です。従来は、呼び出し元のプログラムの最後にピリオド(`.`)を打って、そのピリオドの後にサブプログラムからの復帰後の処理を記述するというのが一般的でした。しかし、この方法だと、もしサブプログラムの呼び出しでエラーが発生した場合、そのエラー処理と正常終了後の処理が混在してしまい、コードが読みにくくなりがちです。

そこで登場するのが `NOT ON EXCEPTION` です。これは、サブプログラムからの呼び出しが「正常に完了した」場合にのみ、特定の処理を実行させることができる命令です。これにより、エラーが発生しなかった場合(正常終了した場合)の処理だけを明確に分離して記述できるようになり、コードの可読性と保守性を劇的に向上させることができます。つまり、構造化されたエラーハンドリングを実現するための強力な味方なのです。

基礎知識:CALL文と例外処理の基本

COBOLで他のプログラムを呼び出すには、主に `CALL` 文を使用します。基本的な構文は以下のようになります。

CALL “サブプログラム名” USING 引数リスト.

ここで、「引数リスト」というのは、呼び出し元とサブプログラム間でデータをやり取りするための変数やデータ項目を指定する部分です。

さて、「例外処理」という言葉を聞いたことがあるでしょうか? プログラミングの世界では、プログラムの実行中に予期せぬ問題(エラー)が発生することを「例外」と呼びます。例えば、ファイルが見つからない、計算結果が不正、サブプログラムが存在しない、といった場合です。

COBOLでは、`CALL` 文でサブプログラムを呼び出した際に、もしその呼び出しが正常に行われなかった場合(例えば、サブプログラムが見つからない、実行中に致命的なエラーが発生したなど)に、そのエラー状態を検知し、特別な処理を行う仕組みがあります。この仕組みと連携するのが `NOT ON EXCEPTION` です。

`NOT ON EXCEPTION` を使うことで、「呼び出しが成功した」という条件で、その後の処理を記述できるようになるのです。

実装:NOT ON EXCEPTION の使い方

`NOT ON EXCEPTION` の構文は非常にシンプルです。`CALL` 文の直後に記述します。

CALL “サブプログラム名”
USING 引数リスト
NOT ON EXCEPTION
PERFORM 正常終了後の処理段落.
ON EXCEPTION
PERFORM エラー処理段落.
END-CALL.

この例では、`CALL` 文で “サブプログラム名” を呼び出します。

  • もし呼び出しが正常に完了した場合(例外が発生しなかった場合)、`NOT ON EXCEPTION` 句に続く `PERFORM 正常終了後の処理段落.` が実行されます。
  • もし呼び出し中に何らかの例外が発生した場合(エラーが起きた場合)、`ON EXCEPTION` 句に続く `PERFORM エラー処理段落.` が実行されます。

`ON EXCEPTION` 句は必須ではありませんが、エラー処理をしっかり行うためには記述することを強く推奨します。

参考本文で示されている例は、さらに簡潔に書くこともできます。

CALL P NOT ON EXCEPTION PERFORM NEXT-STEP.

これは、`CALL P` が正常に完了した場合に、`NEXT-STEP` という名前の段落(サブルーチン)を実行するという意味になります。 `USING` 句や `ON EXCEPTION` 句がないシンプルな形ですが、正常終了後の処理だけを記述したい場合には便利です。

サンプルプログラム:実際に動かしてみよう!

ここでは、簡単な例として、呼び出し元プログラムと、それを呼び出すサブプログラムを作成してみましょう。

まず、呼び出し元プログラム(`CALLER.cbl`)です。

IDENTIFICATION DIVISION.
PROGRAM-ID. CALLER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-MESSAGE PIC X(30) VALUE ‘呼び出し元から送信’.
01 WS-RETURN-MSG PIC X(30) VALUE SPACES.
01 WS-RETURN-CODE PIC 9(02) VALUE 0.

PROCEDURE DIVISION.
MAIN-PROCEDURE.
DISPLAY ‘— CALLER: サブプログラムを呼び出します —‘.

CALL “SUBPROG”
USING WS-MESSAGE, WS-RETURN-MSG, WS-RETURN-CODE
NOT ON EXCEPTION
DISPLAY ‘— CALLER: SUBPROG は正常に完了しました —‘.
DISPLAY ‘— CALLER: SUBPROG からの戻り値: ‘ WS-RETURN-MSG.
DISPLAY ‘— CALLER: 戻りコード: ‘ WS-RETURN-CODE.
PERFORM SUBPROG-SUCCESS-PROCESS.
ON EXCEPTION
DISPLAY ‘— CALLER: SUBPROG の呼び出しでエラーが発生しました —‘.
DISPLAY ‘— CALLER: 戻りコード: ‘ WS-RETURN-CODE.
PERFORM SUBPROG-ERROR-PROCESS.
END-CALL.

DISPLAY ‘— CALLER: プログラム終了 —‘.
STOP RUN.

SUBPROG-SUCCESS-PROCESS SECTION.
DISPLAY ‘— CALLER: 正常終了後の追加処理を実行中 —‘.
DISPLAY ‘— CALLER: ここでは何か別の処理を行います —‘.
EXIT.

SUBPROG-ERROR-PROCESS SECTION.
DISPLAY ‘— CALLER: エラー発生時の追加処理を実行中 —‘.
DISPLAY ‘— CALLER: エラー内容を確認し、適切な対応を行います —‘.
EXIT.

END PROGRAM CALLER.

次に、サブプログラム(`SUBPROG.cbl`)です。このサブプログラムは、呼び出し元から受け取ったメッセージを表示し、簡単な処理をして戻り値を設定します。

IDENTIFICATION DIVISION.
PROGRAM-ID. SUBPROG.
DATA DIVISION.
LINKAGE SECTION.
01 LS-IN-MESSAGE PIC X(30).
01 LS-OUT-RETURN-MSG PIC X(30).
01 LS-OUT-RETURN-CODE PIC 9(02).

PROCEDURE DIVISION USING LS-IN-MESSAGE, LS-OUT-RETURN-MSG, LS-OUT-RETURN-CODE.
MAIN-LOGIC.
DISPLAY ‘— SUBPROG: サブプログラムが開始されました —‘.
DISPLAY ‘— SUBPROG: 受け取ったメッセージ: ‘ LS-IN-MESSAGE.

> ここで何らかの処理を行います
> 例として、戻りメッセージと戻りコードを設定します。
MOVE ‘サブプログラムからの応答’ TO LS-OUT-RETURN-MSG.
MOVE 00 TO LS-OUT-RETURN-CODE. > 正常終了を示す
DISPLAY ‘— SUBPROG: 処理を完了し、呼び出し元へ戻ります —‘.

EXIT PROGRAM. > プログラムを終了し、呼び出し元へ戻る

END PROGRAM SUBPROG.

この2つのプログラムをコンパイル・リンクし、`CALLER` を実行してみてください。
`SUBPROG` が正常に実行され、`CALLER` の `NOT ON EXCEPTION` 句内の処理が実行されるはずです。

もし、`SUBPROG` が存在しない場合や、`SUBPROG` の中で意図的にエラー(例えば、`STOP RUN` など)を発生させると、`ON EXCEPTION` 句内の処理が実行されることを確認できます。

応用・注意点:現場で役立つヒント

  • 「ピリオド」との使い分け:

前述の通り、従来はピリオドの後に正常終了後の処理を記述していましたが、`NOT ON EXCEPTION` を使うことで、呼び出しの成否と、その後の処理を明確に分離できます。特に、複数のサブプログラムを連続して呼び出す場合などは、`NOT ON EXCEPTION` を活用するとコードの流れが格段に分かりやすくなります。

  • `ON EXCEPTION` の重要性:

`NOT ON EXCEPTION` で正常系を記述したら、必ず `ON EXCEPTION` で異常系(エラー処理)も記述するようにしましょう。エラーが発生した際に、どのような処理を行うか(エラーメッセージの表示、ログへの記録、処理の中断、代替処理の実行など)を定義することは、堅牢なプログラムを作成する上で非常に重要です。

  • 戻りコードの活用:

サブプログラムから呼び出し元へ処理結果を伝える手段として、戻りコード(`PIC 9` 型などの変数)は非常に一般的です。`NOT ON EXCEPTION` や `ON EXCEPTION` と組み合わせて、戻りコードの値によってさらに詳細な条件分岐を行うこともよくあります。例えば、戻りコードが `00` なら成功、`01` なら警告、`99` なら致命的エラー、といった具合です。

  • `END-CALL` の忘れずに:

`CALL` 文で `NOT ON EXCEPTION` や `ON EXCEPTION` を使用した場合、`END-CALL` で `CALL` 文のブロックを明示的に閉じる必要があります。これを忘れると、構文エラーの原因となります。

`NOT ON EXCEPTION` は、COBOLでのプログラム連携をより安全で、読みやすいものにするための必須テクニックです。ぜひ、日々の開発で活用してみてください。

コメント

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