COBOLのCALL文はプログラムを複数のモジュールに分割し、互いを呼び出す仕組みです。単純な呼び出しだけでなく、静的/動的リンク・GOBACKとSTOP RUNの使い分け・CANCEL文によるモジュール再初期化・ネストプログラムまで理解することで、保守性の高い設計ができます。
この記事ではCALL文の完全な構文オプションから、呼び出し連鎖でのGOBAK設計、バッチ処理の共通モジュール実装パターンまで解説します。引数の渡し方(BY REFERENCE/BY CONTENT/BY VALUE)については引数の使い方完全ガイドをご参照ください。
- CALL文の完全な構文(静的/動的・ON EXCEPTION・END-CALL)
- GOBACKとSTOP RUNの違い(呼び出し連鎖での誤用が多い)
- CANCEL文でモジュールをアンロードし、WORKING-STORAGEを再初期化する方法
- ネストプログラム(IDENTIFICATION DIVISION内の内部プログラム定義)
- プログラム間のデータ共有3方式の使い分け
- 共通エラーハンドラ・共通ログ出力の実践モジュール設計
CALL文の完全な構文
CALL文には静的呼び出しと動的呼び出しがあり、オプション句を組み合わせることでエラーハンドリングや引数の渡し方を細かく制御できます。
CALL {プログラム名リテラル | プログラム名変数}
[USING {[BY REFERENCE] | BY CONTENT | BY VALUE}
引数1 [引数2 ...]]
[RETURNING 戻り値変数]
[ON EXCEPTION 例外時処理]
[NOT ON EXCEPTION 正常時処理]
END-CALL.
| オプション | 説明 |
|---|---|
| プログラム名リテラル | ‘SUBPGM’のように文字列定数で指定。リンク時に結合(静的CALL) |
| プログラム名変数 | WS-PGM-NAMEのようにPIC X変数で指定。実行時にロード(動的CALL) |
| USING句 | 引数を渡す。BY REFERENCE(デフォルト)/ BY CONTENT / BY VALUE の3方式 |
| RETURNING句 | 戻り値を受け取る(COBOL 2002以降。IBM環境では使用制限あり) |
| ON EXCEPTION | CALLが失敗した場合(モジュール未存在・ロードエラー)に実行する処理 |
| NOT ON EXCEPTION | CALLが成功した場合に実行する処理(任意) |
| END-CALL | CALLブロックの明示的な終端。ON/NOT ON EXCEPTIONを使う場合は必須 |
WORKING-STORAGE SECTION.
01 WS-MODULE-NAME PIC X(8).
01 WS-AMOUNT PIC 9(9)V99.
01 WS-TAX PIC 9(7)V99.
01 WS-RATE PIC V99.
*=== 静的CALL(リテラル指定・リンク時に結合)===
PROCEDURE DIVISION.
CALL 'TAXCALC' USING WS-AMOUNT WS-RATE WS-TAX
END-CALL.
*=== 動的CALL(変数指定・実行時にロード)===
IF WS-REGION = 'JP'
MOVE 'TAXCALCJ' TO WS-MODULE-NAME
ELSE
MOVE 'TAXCALCE' TO WS-MODULE-NAME
END-IF
CALL WS-MODULE-NAME USING WS-AMOUNT WS-RATE WS-TAX
ON EXCEPTION
DISPLAY 'モジュールのロードに失敗: ' WS-MODULE-NAME
MOVE 12 TO RETURN-CODE
GOBACK
NOT ON EXCEPTION
DISPLAY 'CALLに成功しました'
END-CALL.
GOBACKとSTOP RUNの違い
COBOLにはプログラムを終了させる命令が複数ありますが、使い分けを誤るとサブプログラムがジョブ全体を終了させてしまうバグが起きます。
| 命令 | 動作 | 使いどころ |
|---|---|---|
| GOBACK | サブプログラム: 呼び元に制御を返す メインプログラム: ジョブを終了する |
サブプログラムの終了には必ずこれを使う |
| STOP RUN | どこで実行してもジョブ全体を終了する | メインプログラムの最後のみで使う |
| EXIT PROGRAM | サブプログラムからの終了(GOBACKと同じ効果) | 旧スタイル。GOBACKの方が推奨 |
| STOP literal | オペレータにメッセージを表示して一時停止 (バッチ処理では使用禁止) |
旧スタイル。現代COBOLでは非推奨 |
*=== メインプログラム ===
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN-PGM.
PROCEDURE DIVISION.
CALL 'SUBPGM-A' USING WS-DATA
END-CALL
IF RETURN-CODE NOT = 0
DISPLAY 'サブプログラムエラー'
*> メインではSTOP RUNでジョブ終了
STOP RUN
END-IF
DISPLAY '正常終了'
STOP RUN. *> メインの終了はSTOP RUN
*=== サブプログラム(STOP RUNを使ってはいけない例)===
IDENTIFICATION DIVISION.
PROGRAM-ID. SUBPGM-A.
PROCEDURE DIVISION USING LK-DATA.
IF LK-DATA = SPACES
DISPLAY 'エラー: データが空です'
MOVE 8 TO RETURN-CODE
*> NG: STOP RUNを使うとジョブ全体が終了してしまう
*STOP RUN.
*> OK: GOBACKで呼び元に戻る
GOBACK
END-IF
PERFORM PROCESS-DATA
MOVE 0 TO RETURN-CODE
GOBACK. *> サブプログラムの終了は必ずGOBACK
PROCESS-DATA.
*> 処理内容
EXIT.
サブプログラムA内でSTOP RUNを実行すると、CALLした呼び元のメインプログラムに戻らず、ジョブ全体が終了します。CLOSE漏れやロールバック漏れが発生し、ファイルが壊れたりデータが中途半端な状態になる危険があります。サブプログラムの終了は必ずGOBACKを使うことを徹底しましょう。
RETURN-CODEを使った戻りコードの連鎖
複数階層のCALL連鎖(A→B→C)でRETURN-CODEを適切に引き継がないと、エラーが呼び元に伝播しません。
*=== 最下層: SUBPGM-C ===
IDENTIFICATION DIVISION.
PROGRAM-ID. SUBPGM-C.
LINKAGE SECTION.
01 LK-DATA PIC X(100).
PROCEDURE DIVISION USING LK-DATA.
*> 処理実行
IF エラー条件
MOVE 8 TO RETURN-CODE *> エラーをRETURN-CODEにセット
GOBACK
END-IF
MOVE 0 TO RETURN-CODE
GOBACK.
*=== 中間層: SUBPGM-B ===
IDENTIFICATION DIVISION.
PROGRAM-ID. SUBPGM-B.
WORKING-STORAGE SECTION.
01 WS-RC-SAVE PIC S9(9) COMP. *> RETURN-CODEを退避
LINKAGE SECTION.
01 LK-INPUT PIC X(100).
01 LK-OUTPUT PIC X(100).
PROCEDURE DIVISION USING LK-INPUT LK-OUTPUT.
CALL 'SUBPGM-C' USING LK-INPUT
ON EXCEPTION
DISPLAY 'SUBPGM-Cのロード失敗'
MOVE 12 TO RETURN-CODE
GOBACK
END-CALL
MOVE RETURN-CODE TO WS-RC-SAVE *> すぐに退避(次のCALLで上書きされる前に)
IF WS-RC-SAVE NOT = 0
*> エラーを呼び元に伝播させる
MOVE WS-RC-SAVE TO RETURN-CODE
GOBACK
END-IF
*> Cが成功した場合の後続処理
PERFORM BUILD-OUTPUT
MOVE 0 TO RETURN-CODE
GOBACK.
*=== 呼び元: MAIN-PGM ===
PROCEDURE DIVISION.
CALL 'SUBPGM-B' USING WS-INPUT WS-OUTPUT
END-CALL
EVALUATE RETURN-CODE
WHEN 0 DISPLAY '正常終了'
WHEN 8 DISPLAY '業務エラー'
WHEN 12 DISPLAY 'システムエラー'
END-EVALUATE.
CALL直後にRETURN-CODEを確認しないまま別のCALLを実行すると、RETURN-CODEが上書きされて最初のエラーが消えます。CALL直後は必ず
MOVE RETURN-CODE TO WS-RC-SAVE で退避し、そのWS-RC-SAVEで判定するパターンを習慣にしましょう。CANCEL文でモジュールを解放・再初期化する
動的CALLでロードされたモジュールは、CANCEL文を実行するまでメモリに残ります。CANCELするとモジュールが解放され、次のCALL時に再ロード・WORKING-STORAGEが再初期化されます。
WORKING-STORAGE SECTION.
01 WS-COUNTER PIC 9(5).
PROCEDURE DIVISION.
*--- 1回目のCALL ---
CALL 'COUNTER-MOD'
MOVE RETURN-CODE TO WS-COUNTER
DISPLAY '1回目: ' WS-COUNTER *> カウンタ=1
*--- 2回目のCALL(モジュールはまだメモリに残っている)---
CALL 'COUNTER-MOD'
MOVE RETURN-CODE TO WS-COUNTER
DISPLAY '2回目: ' WS-COUNTER *> カウンタ=2(前回の状態が保持される)
*--- CANCEL: モジュールをメモリから解放 ---
CANCEL 'COUNTER-MOD'
*--- 3回目のCALL(再ロード→WORKING-STORAGEが再初期化される)---
CALL 'COUNTER-MOD'
MOVE RETURN-CODE TO WS-COUNTER
DISPLAY '3回目: ' WS-COUNTER *> カウンタ=1(初期値に戻る)
STOP RUN.
*=== COUNTER-MOD サブプログラム ===
IDENTIFICATION DIVISION.
PROGRAM-ID. COUNTER-MOD.
WORKING-STORAGE SECTION.
01 WS-CNT PIC 9(5) VALUE 0. *> 初回ロード時のみ0に初期化
PROCEDURE DIVISION.
ADD 1 TO WS-CNT
MOVE WS-CNT TO RETURN-CODE
GOBACK.
| 動作 | 説明 |
|---|---|
| CANCEL後の再CALLでWSが初期化される | バッチループで同一モジュールを毎回初期値から処理したい場合に使う |
| CANCELしない場合 | モジュールのWS値は次のCALLでも保持される。意図的に状態を持たせたい場合はCANCELしない |
| CANCEL後のON EXCEPTION | CANCELしたモジュールへの即時CALLはON EXCEPTIONにならない(再ロードされる) |
| 静的CALLへのCANCEL | リンク時に組み込まれた静的モジュールにはCANCELが効かない(コンパイラ依存) |
ネストプログラム(内部プログラム)
COBOL 85以降では、プログラムの中に別のプログラムを定義する「ネストプログラム」が使えます。別ファイルにしなくても、1つのソースファイルに複数のプログラムを収められます。
IDENTIFICATION DIVISION.
PROGRAM-ID. OUTER-PROG. *> 外部プログラム(親)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-OUTER-DATA PIC X(20) VALUE 'OUTER DATA'.
01 WS-RESULT PIC X(20).
PROCEDURE DIVISION.
CALL 'INNER-PROG' USING WS-OUTER-DATA WS-RESULT
DISPLAY '結果: ' WS-RESULT
STOP RUN.
*>>> ネストプログラムの開始 <<<
IDENTIFICATION DIVISION.
PROGRAM-ID. INNER-PROG. *> 内部プログラム(子)
DATA DIVISION.
LINKAGE SECTION.
01 LK-INPUT PIC X(20).
01 LK-OUTPUT PIC X(20).
PROCEDURE DIVISION USING LK-INPUT LK-OUTPUT.
MOVE LK-INPUT TO LK-OUTPUT
INSPECT LK-OUTPUT CONVERTING SPACES TO '-'
GOBACK.
END PROGRAM INNER-PROG. *> 内部プログラムの終端
*>>> ネストプログラムの終了 <<<
END PROGRAM OUTER-PROG. *> 外部プログラムの終端
グローバルデータを共有する(GLOBAL句)
親プログラムのWORKING-STORAGEにGLOBALを付けると、その変数をネストした子プログラムから参照できます。
IDENTIFICATION DIVISION.
PROGRAM-ID. PARENT-PROG.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-LOG-FILE PIC X(40) VALUE '/log/batch.log' GLOBAL. *> 子も参照可能
01 WS-ERROR-CODE PIC 9(4) VALUE 0 GLOBAL.
01 WS-PRIVATE-DATA PIC X(20). *> GLOBAL なし:子から見えない
PROCEDURE DIVISION.
CALL 'CHILD-PROC-A'
CALL 'CHILD-PROC-B'
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. CHILD-PROC-A.
PROCEDURE DIVISION.
*> WS-LOG-FILE は GLOBAL なので直接参照できる
DISPLAY 'ログファイル: ' WS-LOG-FILE
*> WS-PRIVATE-DATA は見えない(コンパイルエラー)
GOBACK.
END PROGRAM CHILD-PROC-A.
IDENTIFICATION DIVISION.
PROGRAM-ID. CHILD-PROC-B.
PROCEDURE DIVISION.
IF WS-ERROR-CODE NOT = 0 *> GLOBAL変数を参照
DISPLAY 'エラー検出: ' WS-ERROR-CODE
END-IF
GOBACK.
END PROGRAM CHILD-PROC-B.
END PROGRAM PARENT-PROG.
- ネストプログラム: 1つのコンパイル単位内で完結する処理・親専用のヘルパー処理。小さなユーティリティに向く
- 外部ファイル分割: 複数のメインプログラムから共有して呼ぶ共通モジュール・別チームが開発するモジュール
ネストプログラムは親からしか呼べないため、共通モジュールは外部ファイルで管理するのが原則です。
プログラム間のデータ共有3方式
CALL文で複数プログラムが協調動作するとき、データの共有方法には3つのアプローチがあります。
| 方式 | 仕組み | 特徴 | 向いている場面 |
|---|---|---|---|
| 引数(USING句) | CALLのたびに渡す。渡したいデータを明示できる | 柔軟・安全。引数が多くなるとCALL文が煩雑になる | 通常のデータ受け渡し全般 |
| EXTERNAL句 | 同一実行環境内で変数名を共有。どのプログラムからも直接参照可能 | 引数不要で便利だが、どこから変更されるか追いにくい | 全モジュール共通の設定値・エラー情報 |
| ファイル/DBを介した共有 | 一時ファイルやDBに書き出して別プログラムが読む | 完全に独立して動作可能。I/Oオーバーヘッドあり | 非同期処理・別ジョブのプログラム間 |
*=== プログラムAで定義 ===
IDENTIFICATION DIVISION.
PROGRAM-ID. PROG-A.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SHARED-CONFIG EXTERNAL. *> EXTERNAL宣言
05 CFG-DB-HOST PIC X(40).
05 CFG-DB-PORT PIC 9(5).
05 CFG-ERROR-CODE PIC 9(4).
05 CFG-LOG-LEVEL PIC X(1).
PROCEDURE DIVISION.
*> 設定値を初期化
MOVE 'db.example.com' TO CFG-DB-HOST
MOVE 5432 TO CFG-DB-PORT
MOVE 'I' TO CFG-LOG-LEVEL *> I=INFO
MOVE 0 TO CFG-ERROR-CODE
CALL 'PROG-B' *> USINGなしで呼んでも共有データを参照できる
STOP RUN.
*=== プログラムBで同名のEXTERNAL変数を定義 ===
IDENTIFICATION DIVISION.
PROGRAM-ID. PROG-B.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SHARED-CONFIG EXTERNAL. *> 同じ名前・構造でEXTERNAL宣言
05 CFG-DB-HOST PIC X(40).
05 CFG-DB-PORT PIC 9(5).
05 CFG-ERROR-CODE PIC 9(4).
05 CFG-LOG-LEVEL PIC X(1).
PROCEDURE DIVISION.
*> PROG-Aで設定した値を参照できる
DISPLAY 'DB接続先: ' CFG-DB-HOST ':' CFG-DB-PORT
GOBACK.
実践: バッチ処理の共通モジュール設計
COBOLの大規模バッチシステムでは、エラー処理・ログ出力・DB接続などを共通モジュール化することで保守性が大幅に向上します。
共通エラーハンドラモジュール
WORKING-STORAGE SECTION.
01 WS-ERR-INFO.
05 WS-ERR-CODE PIC X(4).
05 WS-ERR-MSG PIC X(80).
05 WS-ERR-PGM PIC X(8).
05 WS-ERR-SEVERITY PIC 9(2). *> 04=警告 08=エラー 12=重大
PROCEDURE DIVISION.
*> エラー発生時
MOVE 'E001' TO WS-ERR-CODE
MOVE 'ファイルOPENエラー' TO WS-ERR-MSG
MOVE 'MAIN-PGM' TO WS-ERR-PGM
MOVE 8 TO WS-ERR-SEVERITY
CALL 'ERRHANDL' USING BY REFERENCE WS-ERR-INFO
END-CALL
IF RETURN-CODE = 12
GOBACK *> 重大エラーは処理中断
END-IF.
IDENTIFICATION DIVISION.
PROGRAM-ID. ERRHANDL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TIMESTAMP PIC X(26).
01 WS-LOG-LINE PIC X(200).
01 WS-SYSDATE PIC X(8).
LINKAGE SECTION.
01 LK-ERR-INFO.
05 LK-ERR-CODE PIC X(4).
05 LK-ERR-MSG PIC X(80).
05 LK-ERR-PGM PIC X(8).
05 LK-ERR-SEVERITY PIC 9(2).
PROCEDURE DIVISION USING LK-ERR-INFO.
*> タイムスタンプ取得
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
*> ログ行を組み立て
STRING WS-TIMESTAMP(1:4) DELIMITED BY SIZE '-'
DELIMITED BY SIZE
WS-TIMESTAMP(5:2) DELIMITED BY SIZE '-'
DELIMITED BY SIZE
WS-TIMESTAMP(7:2) DELIMITED BY SIZE ' '
DELIMITED BY SIZE
WS-TIMESTAMP(9:6) DELIMITED BY SIZE ' '
DELIMITED BY SIZE
'[' DELIMITED BY SIZE
LK-ERR-PGM DELIMITED BY SPACE
'] [' DELIMITED BY SIZE
LK-ERR-CODE DELIMITED BY SIZE
'] ' DELIMITED BY SIZE
LK-ERR-MSG DELIMITED BY SPACE
INTO WS-LOG-LINE
*> 重要度に応じて出力先を分ける
EVALUATE LK-ERR-SEVERITY
WHEN 4
DISPLAY '[WARN] ' WS-LOG-LINE
WHEN 8
DISPLAY '[ERROR] ' WS-LOG-LINE
WHEN 12
DISPLAY '[FATAL] ' WS-LOG-LINE
END-EVALUATE
*> 重大エラーはRETURN-CODEに12をセット
MOVE LK-ERR-SEVERITY TO RETURN-CODE
GOBACK.
共通ログ出力モジュール(条件付きログレベル)
*=== 呼び元での使い方 ===
WORKING-STORAGE SECTION.
01 WS-LOG-MSG PIC X(120).
01 WS-LOG-LEVEL PIC X(1) VALUE 'D'. *> D=DEBUG I=INFO W=WARN E=ERROR
88 LOG-DEBUG VALUE 'D'.
88 LOG-INFO VALUE 'I'.
PROCEDURE DIVISION.
*> DEBUGログ(LOG-LEVELがDの場合のみ出力)
IF LOG-DEBUG
MOVE '処理開始: 件数チェック' TO WS-LOG-MSG
CALL 'LOGWRITE' USING BY CONTENT WS-LOG-LEVEL
BY CONTENT WS-LOG-MSG
END-CALL
END-IF
*> INFOログ(常に出力)
MOVE '処理件数: ' TO WS-LOG-MSG
STRING WS-LOG-MSG DELIMITED BY SPACE
WS-REC-COUNT DELIMITED BY SIZE
'件' DELIMITED BY SIZE
INTO WS-LOG-MSG
CALL 'LOGWRITE' USING BY CONTENT 'I'
BY CONTENT WS-LOG-MSG
END-CALL.
呼び出し連鎖の全体像(設計パターン)
*=== ジョブ制御(JCL/シェルから起動)===
*
* MAIN-PGM(ジョブ制御・全体管理)
* ├─ INITSUB (初期処理: 設定ロード・接続確立)
* ├─ OPENSUB (ファイルオープン)
* ├─ PROCSUB (主処理: データ変換・集計)←ループ呼び出し
* │ └─ VALIDSUB (入力バリデーション)
* │ └─ CALCSUB (金額計算)
* │ └─ OUTSUB (出力レコード生成)
* ├─ CLOSESUB (ファイルクローズ・統計出力)
* └─ ERRHANDL (共通エラーハンドラ)← 各サブから呼ばれる
*
*--- MAIN-PGM の PROCEDURE DIVISION ---
PROCEDURE DIVISION.
MAIN-LOGIC.
PERFORM INIT-PHASE
IF RETURN-CODE NOT = 0
PERFORM ABNORMAL-END
STOP RUN
END-IF
PERFORM OPEN-PHASE
IF RETURN-CODE NOT = 0
PERFORM ABNORMAL-END
STOP RUN
END-IF
PERFORM PROCESS-PHASE UNTIL WS-EOF
PERFORM CLOSE-PHASE
IF WS-ERROR-COUNT > 0
DISPLAY '警告: エラー件数=' WS-ERROR-COUNT
MOVE 4 TO RETURN-CODE
ELSE
MOVE 0 TO RETURN-CODE
END-IF
STOP RUN.
INIT-PHASE.
CALL 'INITSUB' USING WS-CONFIG
MOVE RETURN-CODE TO WS-RC-SAVE
IF WS-RC-SAVE NOT = 0
MOVE WS-RC-SAVE TO RETURN-CODE
END-IF.
PROCESS-PHASE.
CALL 'PROCSUB' USING WS-INPUT-REC WS-OUTPUT-REC WS-CTRL-INFO
IF RETURN-CODE = 8
ADD 1 TO WS-ERROR-COUNT
END-IF
PERFORM READ-NEXT-RECORD.
ABNORMAL-END.
DISPLAY '異常終了: RC=' RETURN-CODE
CALL 'CLOSESUB' USING WS-FILE-STATUS. *> クローズだけは確実に実行
よくある落とし穴と対策
| 落とし穴 | 症状 | 対策 |
|---|---|---|
| サブプログラムでSTOP RUNを使う | ジョブ全体が終了し、呼び元のCLOSEやロールバックが実行されない | サブプログラムの終了は必ずGOBACKを使う |
| CALL直後にRETURN-CODEを確認しない | 次のCALL文でRETURN-CODEが上書きされ、最初のエラーが消える | CALL直後にMOVE RETURN-CODE TO WS-RC-SAVEで退避してから判定 |
| 動的CALLのモジュール名の末尾スペース | PIC X(8)変数に’TAXCALC’を入れると’TAXCALC ‘(末尾スペース付き)になり、モジュールが見つからない | MOVE ‘TAXCALC’ TO WS-MOD-NAME後にINSPECT … REPLACING TRAILING SPACESするか、FUNCTION TRIM(WS-MOD-NAME)を使う |
| CANCELせずにループ内で動的CALL | ロードされたモジュールのWS値が引き継がれ、前回の残存データが混入する | ループ内で毎回初期化が必要なモジュールはCALL前にCANCELを実行する |
| ネストプログラムを外部から直接CALL | ネストプログラムは親プログラム内からしかCALLできない。別プログラムから呼ぶとエラー | 複数プログラムから共有したいモジュールは別ファイルの外部プログラムとして定義する |
よくある質問
まとめ
CALL文を使いこなすためのポイントを整理します。
| 命令/方式 | 特徴 |
|---|---|
| 静的CALL | リテラルでプログラム名指定。リンク時結合。高速・モジュール固定 |
| 動的CALL | 変数でプログラム名指定。実行時ロード。切り替え可能・ON EXCEPTIONで失敗検知 |
| GOBACK | サブプログラム終了命令。呼び元に戻る。サブでSTOP RUNは絶対禁止 |
| RETURN-CODE | 戻りコード。CALL直後にWS変数へ退避する習慣を |
| CANCEL | ロード済みモジュールを解放。次のCALLでWS再初期化 |
| ネストプログラム | 親専用の内部プログラム。GLOBAL句で変数共有可能 |
| EXTERNAL句 | プログラム間で変数を共有。設定値や共通エラー情報に使う |
CALL設計の核心は「サブプログラムの終了はGOBACK・RETURN-CODEは即座に退避・エラーは必ず呼び元に伝播」の3原則です。この原則を守るだけで、連鎖するCALLでのデバッグが格段に楽になります。
引数の渡し方(BY REFERENCE/BY CONTENT/BY VALUE)とLINKAGE SECTIONの詳細については引数の使い方完全ガイドを参照してください。サブプログラムの戻り方についてはRETURN文とGOBACKの解説も合わせてご覧ください。