COBOLのPERFORM文は、繰り返し処理(ループ)を実現するための最も重要な命令です。バッチ処理やデータ集計など、ビジネスアプリケーションのあらゆる場面で使われます。
この記事では、PERFORM文の5つのバリエーション(TIMES・VARYING・UNTIL・THRU・インライン)を基本構文から実務パターンまで、豊富なサンプルコードとともに徹底解説します。
この記事で分かること
- PERFORM TIMES:指定回数だけ繰り返す基本ループ
- PERFORM VARYING:カウンタ変数を制御するFOR文相当のループ
- PERFORM UNTIL:条件が成立するまで繰り返すWHILE文相当のループ
- PERFORM THRU:段落範囲を一括実行する方法
- インライン vs アウトオブラインPERFORMの使い分け
- EXIT PERFORMでループを途中抜けする方法
- 配列(テーブル)処理や二重ループの実装パターン
- よくあるエラーと対処法・実務での活用パターン
PERFORM TIMESの基本構文
PERFORM TIMESは、指定した回数だけ処理を繰り返す最もシンプルなループ構文です。他言語のfor (int i = 0; i < n; i++)に相当しますが、カウンタ変数は自動的には提供されません。
基本構文
COBOL – PERFORM TIMES構文
PERFORM 繰り返し回数 TIMES
処理内容
END-PERFORM
構文のポイント
- 繰り返し回数には整数リテラル(
10)またはデータ項目(変数)を指定可能
- 回数が0以下の場合、ループ内の処理は1回も実行されない
END-PERFORMでループの終端を明示する(インラインPERFORM)
固定回数のループ
まずは最も基本的な、固定回数のループの例です。
COBOL – 固定回数のPERFORM TIMES
IDENTIFICATION DIVISION.
PROGRAM-ID. TIMES-BASIC.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNT PIC 9(2) VALUE 0.
PROCEDURE DIVISION.
PERFORM 5 TIMES
ADD 1 TO WS-COUNT
DISPLAY "回数: " WS-COUNT
END-PERFORM
STOP RUN.
実行結果
回数: 01
回数: 02
回数: 03
回数: 04
回数: 05
変数で回数を指定するループ
繰り返し回数は変数(データ項目)でも指定できます。実行時にループ回数を動的に変えたい場合に便利です。
COBOL – 変数で回数を指定
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-LOOP-MAX PIC 9(3) VALUE 0.
01 WS-COUNTER PIC 9(3) VALUE 0.
PROCEDURE DIVISION.
ACCEPT WS-LOOP-MAX FROM CONSOLE
PERFORM WS-LOOP-MAX TIMES
ADD 1 TO WS-COUNTER
DISPLAY "処理中: " WS-COUNTER
" / " WS-LOOP-MAX
END-PERFORM
DISPLAY "完了"
STOP RUN.
注意:PERFORM TIMESのループ回数はループ開始時に評価されます。ループ内で回数変数の値を変更しても、繰り返し回数には影響しません。
カウンタ変数との組み合わせ
PERFORM TIMESにはカウンタ変数が自動で提供されないため、回数を数えるには自分でカウンタを管理する必要があります。
COBOL – カウンタ変数の手動管理
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-IDX PIC 9(3) VALUE 0.
01 WS-TOTAL PIC 9(5) VALUE 0.
PROCEDURE DIVISION.
*> カウンタを初期化
MOVE 0 TO WS-IDX
PERFORM 10 TIMES
ADD 1 TO WS-IDX
ADD WS-IDX TO WS-TOTAL
DISPLAY "i=" WS-IDX " 合計=" WS-TOTAL
END-PERFORM
DISPLAY "最終合計: " WS-TOTAL
STOP RUN.
実行結果
i=001 合計=00001
i=002 合計=00003
i=003 合計=00006
...
i=010 合計=00055
ポイント:カウンタの初期化忘れはよくあるバグの原因です。PERFORM TIMESの前に必ずMOVE 0 TO カウンタを書く習慣をつけましょう。カウンタ管理が面倒な場合は、次に紹介するPERFORM VARYINGが便利です。
PERFORM VARYING(カウンタ制御ループ)
PERFORM VARYINGは、カウンタ変数の初期値・増分・終了条件を一度に指定できる強力なループ構文です。他言語のfor文に最も近い形式で、COBOLのループ処理で最もよく使われます。
基本構文
COBOL – PERFORM VARYING構文
PERFORM VARYING カウンタ変数
FROM 初期値
BY 増分値
UNTIL 終了条件
処理内容
END-PERFORM
| 句 |
説明 |
例 |
VARYING | 制御するカウンタ変数 | WS-I |
FROM | カウンタの初期値 | 1 |
BY | 毎回の増分値(負数で減算も可) | 1 |
UNTIL | ループを終了する条件 | WS-I > 10 |
1から10まで処理する例
COBOL – PERFORM VARYING(1から10まで)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 9(2) VALUE 0.
01 WS-SQUARE PIC 9(4) VALUE 0.
PROCEDURE DIVISION.
PERFORM VARYING WS-I
FROM 1 BY 1
UNTIL WS-I > 10
COMPUTE WS-SQUARE = WS-I * WS-I
DISPLAY WS-I " の二乗 = " WS-SQUARE
END-PERFORM
STOP RUN.
実行結果
01 の二乗 = 0001
02 の二乗 = 0004
03 の二乗 = 0009
...
10 の二乗 = 0100
カウントダウン(逆順ループ)
BY句に負の値を指定すると、カウントダウン(逆順)のループが実現できます。
COBOL – カウントダウン
PERFORM VARYING WS-I
FROM 10 BY -1
UNTIL WS-I < 1
DISPLAY "カウント: " WS-I
END-PERFORM
実行結果
カウント: 10
カウント: 09
カウント: 08
...
カウント: 01
2ずつ増やすステップ指定
BY句に2を指定して偶数のみ処理する例です。
COBOL – ステップ2で偶数のみ処理
PERFORM VARYING WS-I
FROM 2 BY 2
UNTIL WS-I > 20
DISPLAY "偶数: " WS-I
END-PERFORM
PERFORM UNTIL(条件ループ)
PERFORM UNTILは、指定した条件が成立するまで処理を繰り返します。他言語のwhile文やdo-while文に相当し、繰り返し回数が事前にわからない場合に使います。
基本構文(前判定と後判定)
COBOL – PERFORM UNTIL(前判定:デフォルト)
*> 前判定(BEFORE):条件を先にチェック → while文相当
PERFORM UNTIL 終了条件
処理内容
END-PERFORM
*> 後判定(AFTER):処理を先に実行 → do-while文相当
PERFORM WITH TEST AFTER UNTIL 終了条件
処理内容
END-PERFORM
| 判定タイミング |
COBOL構文 |
他言語の相当 |
特徴 |
| 前判定 | PERFORM UNTIL | while | 条件次第で0回実行もあり得る |
| 後判定 | PERFORM WITH TEST AFTER UNTIL | do-while | 最低1回は必ず実行される |
前判定ループの例
COBOL – PERFORM UNTIL(合計が100を超えるまで)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUM PIC 9(3) VALUE 1.
01 WS-TOTAL PIC 9(5) VALUE 0.
PROCEDURE DIVISION.
PERFORM UNTIL WS-TOTAL > 100
ADD WS-NUM TO WS-TOTAL
DISPLAY "加算: " WS-NUM
" 合計: " WS-TOTAL
ADD 1 TO WS-NUM
END-PERFORM
DISPLAY "最終合計: " WS-TOTAL
STOP RUN.
後判定ループの例(WITH TEST AFTER)
WITH TEST AFTERを使うと、処理を最低1回は必ず実行した後で条件を判定します。ユーザー入力を受け取って検証する場面などで便利です。
COBOL – WITH TEST AFTER(入力検証ループ)
01 WS-INPUT PIC X(10) VALUE SPACES.
01 WS-VALID PIC 9(1) VALUE 0.
PROCEDURE DIVISION.
PERFORM WITH TEST AFTER
UNTIL WS-VALID = 1
DISPLAY "値を入力してください: "
ACCEPT WS-INPUT
IF WS-INPUT NOT = SPACES
MOVE 1 TO WS-VALID
ELSE
DISPLAY "空白は無効です"
END-IF
END-PERFORM
ネストしたPERFORM(二重ループ)
PERFORMはネスト(入れ子)にして二重ループを構成できます。表形式のデータ処理や、二次元配列の走査に使います。
九九表を出力する例
COBOL – 二重ループで九九表
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 9(2) VALUE 0.
01 WS-J PIC 9(2) VALUE 0.
01 WS-RESULT PIC 9(2) VALUE 0.
01 WS-LINE PIC X(80) VALUE SPACES.
PROCEDURE DIVISION.
*> 外側ループ:行(1〜9)
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 9
MOVE SPACES TO WS-LINE
*> 内側ループ:列(1〜9)
PERFORM VARYING WS-J
FROM 1 BY 1 UNTIL WS-J > 9
COMPUTE WS-RESULT = WS-I * WS-J
STRING WS-LINE DELIMITED SPACES
WS-RESULT DELIMITED SIZE
" " DELIMITED SIZE
INTO WS-LINE
END-STRING
END-PERFORM
DISPLAY WS-LINE
END-PERFORM
STOP RUN.
PERFORM VARYINGのAFTER句で二重ループ
PERFORM VARYING ... AFTER構文を使うと、ネストを使わずに二重ループを記述できます。
COBOL – AFTER句による二重ループ
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 3
AFTER WS-J
FROM 1 BY 1 UNTIL WS-J > 3
DISPLAY "I=" WS-I " J=" WS-J
END-PERFORM
実行結果
I=01 J=01
I=01 J=02
I=01 J=03
I=02 J=01
I=02 J=02
I=02 J=03
I=03 J=01
I=03 J=02
I=03 J=03
AFTER句の動作
AFTERで指定した変数(WS-J)が内側ループのカウンタになる
- WS-Jが終了条件に達するたびにWS-Iが1増加し、WS-Jが再初期化される
- ネストしたPERFORMと同じ動作だが、構文がフラットになり可読性が上がる
PERFORM THRU(段落範囲実行)
PERFORM THRU(THROUGHの略)は、開始段落から終了段落まで連続して実行する構文です。複数の段落をまとめて呼び出す場面で使います。
基本構文
COBOL – PERFORM THRU構文
PERFORM 開始段落名 THRU 終了段落名
実用例:初期化→メイン処理→終了処理の一括実行
COBOL – PERFORM THRU(段落範囲実行)
PROCEDURE DIVISION.
PERFORM INIT-PARA THRU END-PARA
STOP RUN.
INIT-PARA.
DISPLAY "初期化処理"
MOVE 0 TO WS-COUNTER.
MAIN-PARA.
DISPLAY "メイン処理"
ADD 1 TO WS-COUNTER.
END-PARA.
DISPLAY "終了処理: カウント=" WS-COUNTER.
実行結果
初期化処理
メイン処理
終了処理: カウント=001
PERFORM THRU + TIMES / UNTILの組み合わせ
PERFORM THRUはTIMESやUNTILと組み合わせて、段落範囲をループ実行することもできます。
COBOL – PERFORM THRU + TIMES
*> 段落範囲を5回繰り返す
PERFORM PROCESS-START THRU PROCESS-END
5 TIMES
*> 段落範囲を条件付きで繰り返す
PERFORM PROCESS-START THRU PROCESS-END
UNTIL WS-EOF = 'Y'
注意:PERFORM THRUで指定する段落は、ソースコード内で物理的に連続している必要があります。間に無関係な段落を挟むと、その段落も実行されてしまうため注意してください。
インラインPERFORM vs アウトオブラインPERFORM
PERFORM文にはインライン(PERFORM〜END-PERFORM)とアウトオブライン(PERFORM 段落名)の2つの書き方があります。
比較
| 項目 |
インラインPERFORM |
アウトオブラインPERFORM |
| 構文 | PERFORM ... END-PERFORM | PERFORM 段落名 |
| 処理の場所 | PERFORM文の中に直接記述 | 別の段落(パラグラフ)に記述 |
| 再利用性 | 低い(その場限り) | 高い(複数箇所から呼び出し可能) |
| 可読性 | 短い処理なら見やすい | 処理が分離されるため見通しが良い |
| 適した用途 | 簡単なループ処理 | 共通処理、複雑なロジック |
コード比較
COBOL – インラインPERFORM
PROCEDURE DIVISION.
*> インライン:処理をその場に書く
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 5
DISPLAY "処理: " WS-I
END-PERFORM
STOP RUN.
COBOL – アウトオブラインPERFORM
PROCEDURE DIVISION.
*> アウトオブライン:段落名を指定して呼び出す
PERFORM SHOW-MSG 5 TIMES
STOP RUN.
SHOW-MSG.
ADD 1 TO WS-I
DISPLAY "処理: " WS-I.
ポイント:短い処理はインラインPERFORM、複数箇所で再利用する処理や複雑なロジックはアウトオブラインPERFORM(段落に分離)が適しています。
EXIT PERFORMでループを途中抜けする
EXIT PERFORMは、ループを途中で強制的に抜けるための命令です。他言語のbreak文に相当します。条件分岐と組み合わせることで、特定の条件を満たした時点でループを終了できます。
EXIT PERFORMの使い方
COBOL – EXIT PERFORM(ループ途中抜け)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 9(3) VALUE 0.
01 WS-DATA PIC X(10).
PROCEDURE DIVISION.
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 100
*> データ取得(仮の処理)
MOVE "SAMPLE" TO WS-DATA
*> 特定条件でループを抜ける
IF WS-DATA = SPACES
DISPLAY "空データ検出 - 処理終了"
EXIT PERFORM
END-IF
DISPLAY "処理中: " WS-I
END-PERFORM
STOP RUN.
EXIT PERFORM CYCLEで次のイテレーションへ
EXIT PERFORM CYCLEは他言語のcontinue文に相当し、現在のイテレーションをスキップして次の繰り返しに進みます。
COBOL – EXIT PERFORM CYCLE(スキップ)
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 10
*> 3の倍数はスキップ
COMPUTE WS-REMAINDER =
FUNCTION MOD(WS-I, 3)
IF WS-REMAINDER = 0
EXIT PERFORM CYCLE
END-IF
DISPLAY WS-I
END-PERFORM
実行結果
01
02
04
05
07
08
10
| 命令 |
動作 |
他言語の相当 |
EXIT PERFORM | ループを完全に抜ける | break |
EXIT PERFORM CYCLE | 今回のイテレーションをスキップ | continue |
注意:EXIT PERFORMとEXIT PERFORM CYCLEはインラインPERFORM(END-PERFORMで閉じる形式)でのみ使用可能です。アウトオブラインPERFORM(段落呼び出し)では使用できません。
配列(テーブル)の処理
COBOLでは配列のことをテーブルと呼び、OCCURS句で定義します。PERFORM VARYINGを使ってテーブルの各要素を順番に処理するのが定番パターンです。
一次元テーブルの走査
COBOL – 一次元テーブルの走査
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SCORES.
05 WS-SCORE PIC 9(3)
OCCURS 5 TIMES.
01 WS-I PIC 9(2) VALUE 0.
01 WS-TOTAL PIC 9(5) VALUE 0.
01 WS-AVG PIC 9(3)V9(1) VALUE 0.
PROCEDURE DIVISION.
*> テーブルにデータを設定
MOVE 85 TO WS-SCORE(1)
MOVE 92 TO WS-SCORE(2)
MOVE 78 TO WS-SCORE(3)
MOVE 95 TO WS-SCORE(4)
MOVE 88 TO WS-SCORE(5)
*> テーブルの全要素を合計
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 5
ADD WS-SCORE(WS-I) TO WS-TOTAL
DISPLAY "SCORE(" WS-I ") = "
WS-SCORE(WS-I)
END-PERFORM
*> 平均を計算
COMPUTE WS-AVG = WS-TOTAL / 5
DISPLAY "合計: " WS-TOTAL
DISPLAY "平均: " WS-AVG
STOP RUN.
実行結果
SCORE(01) = 085
SCORE(02) = 092
SCORE(03) = 078
SCORE(04) = 095
SCORE(05) = 088
合計: 00438
平均: 087.6
二次元テーブルの処理
二次元テーブルはOCCURSをネストして定義し、二重ループで走査します。
COBOL – 二次元テーブルの処理
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SALES-TABLE.
05 WS-QUARTER OCCURS 4 TIMES.
10 WS-MONTH PIC 9(7)
OCCURS 3 TIMES.
01 WS-I PIC 9(2).
01 WS-J PIC 9(2).
01 WS-Q-TOTAL PIC 9(9) VALUE 0.
PROCEDURE DIVISION.
*> 四半期ごとの月別売上を集計
PERFORM VARYING WS-I
FROM 1 BY 1 UNTIL WS-I > 4
MOVE 0 TO WS-Q-TOTAL
PERFORM VARYING WS-J
FROM 1 BY 1 UNTIL WS-J > 3
ADD WS-MONTH(WS-I, WS-J)
TO WS-Q-TOTAL
END-PERFORM
DISPLAY "Q" WS-I " 合計: "
WS-Q-TOTAL
END-PERFORM
STOP RUN.
よくあるエラーと対処法
PERFORM文を使用する際に遭遇しやすいエラーとその対処法をまとめます。
| エラー・問題 |
原因 |
対処法 |
| 無限ループ | UNTIL条件が永遠に成立しない | 終了条件とカウンタの増分方向を確認 |
| END-PERFORM不足 | インラインPERFORMの閉じ忘れ | PERFORMとEND-PERFORMの対応を確認 |
| テーブル範囲外アクセス | 添字がOCCURS回数を超過 | UNTIL条件を> nに(>= nではなく) |
| カウンタ初期化忘れ | 前回のループの値が残っている | ループ前にMOVE 0 TO カウンタを記述 |
| PIC桁あふれ | カウンタ変数の桁数不足 | PIC桁数をループ回数に合わせて十分に確保 |
| 段落名の誤り | PERFORM先の段落名が存在しない | 段落名のスペルを正確に一致させる |
無限ループの防止策
COBOL – 無限ループの防止
01 WS-SAFETY PIC 9(5) VALUE 0.
01 WS-MAX-LOOP PIC 9(5) VALUE 10000.
PROCEDURE DIVISION.
PERFORM UNTIL WS-EOF = 'Y'
ADD 1 TO WS-SAFETY
*> 安全弁:上限回数を超えたら強制終了
IF WS-SAFETY > WS-MAX-LOOP
DISPLAY "ループ上限超過"
EXIT PERFORM
END-IF
*> 通常の処理
READ INPUT-FILE
AT END
MOVE 'Y' TO WS-EOF
END-READ
END-PERFORM
実務パターン(データ処理・帳票出力)
実際の業務プログラムでよく使われるPERFORMのパターンを紹介します。
パターン1:ファイル読み込みループ
バッチ処理で最も頻出するのが、ファイルのレコードを1件ずつ読み込んで処理するパターンです。
COBOL – ファイル読み込みループ(典型パターン)
01 WS-EOF-FLG PIC X(1) VALUE 'N'.
88 EOF-YES VALUE 'Y'.
88 EOF-NO VALUE 'N'.
01 WS-REC-CNT PIC 9(7) VALUE 0.
PROCEDURE DIVISION.
MAIN-PARA.
OPEN INPUT IN-FILE
READ IN-FILE
AT END SET EOF-YES TO TRUE
END-READ
PERFORM UNTIL EOF-YES
ADD 1 TO WS-REC-CNT
PERFORM PROCESS-RECORD
READ IN-FILE
AT END SET EOF-YES TO TRUE
END-READ
END-PERFORM
DISPLAY "処理件数: " WS-REC-CNT
CLOSE IN-FILE
STOP RUN.
ファイル読み込みのポイント
- 最初のREADをループの前に実行する(プライミングリード)
- ループ内の最後にREADを実行して次のレコードを読む
- 88レベル条件名を使うと
UNTIL EOF-YESのように自然に読める
パターン2:コントロールブレイク(グループ集計)
部署別・商品別など、キーの変わり目でグループ集計を行う「コントロールブレイク」は、COBOL実務の典型パターンです。
COBOL – コントロールブレイク処理
01 WS-PREV-DEPT PIC X(4) VALUE SPACES.
01 WS-DEPT-TOTAL PIC 9(9) VALUE 0.
01 WS-GRAND-TOTAL PIC 9(11) VALUE 0.
PROCESS-RECORD.
*> キーブレイク判定
IF IN-DEPT NOT = WS-PREV-DEPT
AND WS-PREV-DEPT NOT = SPACES
*> 前グループの小計を出力
DISPLAY "部署 " WS-PREV-DEPT
" 小計: " WS-DEPT-TOTAL
ADD WS-DEPT-TOTAL TO WS-GRAND-TOTAL
MOVE 0 TO WS-DEPT-TOTAL
END-IF
MOVE IN-DEPT TO WS-PREV-DEPT
ADD IN-AMOUNT TO WS-DEPT-TOTAL.
パターン3:帳票出力(ページ制御)
帳票を出力する際に、ページあたりの行数を管理してページヘッダーを挿入するパターンです。
COBOL – 帳票出力のページ制御
01 WS-LINE-CNT PIC 9(3) VALUE 0.
01 WS-PAGE-CNT PIC 9(3) VALUE 0.
01 WS-MAX-LINES PIC 9(3) VALUE 50.
WRITE-DETAIL.
*> ページあふれチェック
IF WS-LINE-CNT >= WS-MAX-LINES
OR WS-LINE-CNT = 0
PERFORM WRITE-PAGE-HEADER
END-IF
WRITE PRINT-REC FROM DETAIL-LINE
ADD 1 TO WS-LINE-CNT.
WRITE-PAGE-HEADER.
ADD 1 TO WS-PAGE-CNT
MOVE 0 TO WS-LINE-CNT
WRITE PRINT-REC FROM HEADER-LINE
AFTER ADVANCING PAGE
ADD 1 TO WS-LINE-CNT.
PERFORM文の全バリエーション早見表
| 構文 |
用途 |
他言語の相当 |
PERFORM n TIMES | 固定回数ループ | for (i=0; i<n; i++) |
PERFORM VARYING ... FROM ... BY ... UNTIL | カウンタ制御ループ | for (i=a; i<=b; i+=c) |
PERFORM UNTIL | 前判定条件ループ | while (condition) |
PERFORM WITH TEST AFTER UNTIL | 後判定条件ループ | do { } while (condition) |
PERFORM 段落名 | 段落の1回呼び出し | 関数呼び出し |
PERFORM A THRU B | 段落範囲を連続実行 | – |
PERFORM VARYING ... AFTER ... | 二重ループ(フラット記述) | ネストしたfor文 |
まとめ
COBOLのPERFORM文は、繰り返し処理を実現するための中核となる命令です。用途に応じて適切なバリエーションを選ぶことが、読みやすく保守しやすいプログラムを書くための鍵になります。
使い分けのガイドライン
- 繰り返し回数が決まっている → PERFORM TIMES
- カウンタ変数で制御したい → PERFORM VARYING
- 条件で終了を判断したい → PERFORM UNTIL
- 最低1回は実行したい → PERFORM WITH TEST AFTER UNTIL
- 複数段落を一括実行 → PERFORM THRU
- ループを途中で抜けたい → EXIT PERFORM
関連記事として、「PERFORM文でループ処理を行う」「OCCURS句で配列を定義する方法」「IF文を使った条件分岐の基本テクニック」「EVALUATE文で複雑な条件分岐を実装する」「COMPUTEで計算を行う」も参考にしてください。