【COBOL】PERFORM文で繰り返し処理を極める|TIMES・VARYING・UNTIL・THRUを完全解説

COBOLのPERFORM文は、繰り返し処理(ループ)を実現するための最も重要な命令です。バッチ処理やデータ集計など、ビジネスアプリケーションのあらゆる場面で使われます。

この記事では、PERFORM文の5つのバリエーション(TIMESVARYINGUNTILTHRUインライン)を基本構文から実務パターンまで、豊富なサンプルコードとともに徹底解説します。

この記事で分かること
  • 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 UNTILwhile条件次第で0回実行もあり得る
後判定PERFORM WITH TEST AFTER UNTILdo-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 THRUTHROUGHの略)は、開始段落から終了段落まで連続して実行する構文です。複数の段落をまとめて呼び出す場面で使います。

基本構文

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-PERFORMPERFORM 段落名
処理の場所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 PERFORMEXIT 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で計算を行う」も参考にしてください。