COBOLソースを読む前に知るべき最小知識

· 更新日: · · COBOL, レガシー技術, 業務システム, 保守, Mainframe

更新履歴(3件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
COMP-3が実際にどんなバイト列になるかを、IBMの掲載例と導出付きで追加しました(ASCIIとして読むと元の数値がどこにも出ないことも示しています)。固定形式の列構造の図を80桁の目盛り付きに差し替え、読解練習を6問追加し、処理系の違い(文字コード、`COMP-4`と`COMP-5`の桁の扱いの差)を追記しました。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589684)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「COBOLソースを読む前に知るべき最小知識」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589684 https://staging.comcomponent.com/blog/2026/03/17/001-cobol-minimum-reading-guide/

DOI(最新版)
10.5281/zenodo.21589684
DOI(この版)
10.5281/zenodo.21732707

引き継ぎ、障害対応、ベンダー製パッケージの保守。そういう場面で、ある日いきなり COBOL のソースが飛んでくることがあります。

  • ファイル名は .cbl.cpy
  • 変数名は全部大文字
  • 01057788 が並ぶ
  • PIC S9(7)V99 COMP-3 みたいな、呪文と会計ソフトの中間みたいな記述が出る
  • しかも COPY だらけで、開いたファイルだけでは全体が見えない

このあたりで、たいていの人はいったん手が止まります。

ただ、読むための地図はそこまで大きくありません。COBOL には処理系や製品ごとの差がありますが、既存業務システムを読むときに先に押さえるべき骨格はかなり共通です。この記事では、IBM 系や典型的な業務 COBOL を念頭に、突然ソースを読むことになった人向けの最小セットを整理します。

1. まず結論(ひとことで)

先にかなり雑に、でも実務で役に立つ言い方をすると、こうです。

  • COBOL は ロジックの言語 である前に、かなり強く レコード定義の言語 です
  • PROCEDURE DIVISION だけ読んでも半分しか分かりません。まず DATA DIVISION を見ます
  • PIC項目の形USAGEどういう表現で持つか です
  • COMP-3 は packed decimal です。金額や件数の世界でよく出ます
  • 88 は別変数というより、直前項目の値に名前を付けた条件名 です
  • REDEFINES同じメモリを別の形で見る 仕組みです。コピーではありません
  • COPY があるなら、いま開いているソースはまだ未完成です。copybook を見ないと全体が見えません
  • PERFORMIFEVALUATEREADWRITECALL を追えれば、だいたいの流れは掴めます
  • 古いソースは 列位置に意味がある固定形式 です。見た目の空白がただの飾りではありません1

要するに、DIVISION、PIC、USAGE、COMP-3、REDEFINES、OCCURS、88、COPY、PERFORM。このへんが読めると、迷子率がかなり下がります。

この記事の知識マップ

COBOLはPROCEDURE DIVISIONによる処理手順の言語である前に、DATA DIVISIONでレコードの形を定義する言語であり、各データ項目はPICTURE句で形を、USAGE句でCOMP-3のような内部表現を指定します。COMP-3は10進数字を2桁ずつ1バイトに詰めるpacked decimalで、テキストとして開くと意味不明なバイト列に見えます。REDEFINESは同じ領域を別の形で読み替え、OCCURSは配列を、88レベルは直前項目の値に名前を付けた条件を表します。COPY文は外部のcopybookをコンパイル時に取り込むため、開いているソース単体では全体像が見えず、PERFORM文とスコープ終端子で処理の流れを追い、FILE STATUSやEXEC SQL、EXEC CICSで外部境界を押さえる必要があります。

COBOL読解の知識マップCOBOLがDATA DIVISIONとPROCEDURE DIVISIONを柱とし、PICTURE句・USAGE句・COMP-3・REDEFINES・OCCURS・88レベル・COPY文などのデータ定義要素と、PERFORM文やスコープ終端子などの制御要素、EBCDICやFILE STATUS・EXEC SQL・EXEC CICSといった外部境界の要素がどう関係するかを示す図利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用する利用するCOBOLDATA DIVISIONCOMP-3(packed decimal)PROCEDURE DIVISIONPICTURE句(PIC)USAGE句COMP-5REDEFINES句OCCURS句OCCURS DEPENDING ON88レベル(条件名)COPY文copybookPERFORM文スコープ終端子(scope terminator)MOVE文固定形式(参照形式)IBM Enterprise COBOLEBCDICFILE STATUS句EXEC SQLEXEC CICS

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全21件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. COBOL はまず「データの形」の言語だと思う

C# や Java の感覚で読むと、最初は iffor や関数呼び出しを追いたくなります。 でも COBOL は、そこに行く前に 「このプログラムはどんなレコードを受け取り、どんなレコードを作り、どんなバッファを持っているのか」 を押さえたほうが早いです。

典型的な業務 COBOL は、だいたい次の流れです。

  1. ファイルや DB からレコードを読む
  2. WORKING-STORAGE 上の項目へ入れる
  3. 条件分岐する
  4. 別のレコードへ詰め替える
  5. 書き出す

つまり、アルゴリズムよりレイアウト が先に立ちやすいです。

たとえば、こんな骨格です。

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAMPLE01.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT SALES-FILE ASSIGN TO ...

       DATA DIVISION.
       FILE SECTION.
       FD  SALES-FILE.
       01  SALES-REC.
           05  SALE-ID       PIC 9(8).
           05  SALE-AMOUNT   PIC S9(7)V99 COMP-3.

       WORKING-STORAGE SECTION.
       01  WS-EOF            PIC X VALUE 'N'.
           88  EOF           VALUE 'Y'.

       PROCEDURE DIVISION.
           PERFORM UNTIL EOF
               READ SALES-FILE
                   AT END
                       SET EOF TO TRUE
                   NOT AT END
                       PERFORM PROCESS-SALE
               END-READ
           END-PERFORM
           STOP RUN.

このコードを読むとき、最初に見るべきなのは PERFORM より先に SALE-AMOUNT の型や EOF の意味です。 COBOL は、その順番で読むと急に静かになります。

3. 4つの DIVISION を先に見る

COBOL ソースは、まず大きく 4 つの DIVISION に分かれます。

DIVISION まず見ること
IDENTIFICATION DIVISION プログラム名、古いコメント、由来
ENVIRONMENT DIVISION ファイル、外部資源、入出力の前提
DATA DIVISION レコード定義、作業領域、引数
PROCEDURE DIVISION 実際の処理手順

特に大事なのはこのあたりです。

  • FILE SECTION 入出力ファイルのレコード定義がある
  • WORKING-STORAGE SECTION 普段使う変数、フラグ、カウンタ、作業バッファがある
  • LOCAL-STORAGE SECTION 呼び出しごとに初期化される領域があることがある
  • LINKAGE SECTION 外から渡される引数や、サブプログラムの受け口があることがある

LINKAGE SECTIONPROCEDURE DIVISION USING ... が見えたら、そのプログラムは単独完結ではなく、外からデータを受けて動く 可能性が高いです。

4. 固定形式の見た目にビビらない

古い COBOL では、ソース 1 行の 列位置そのもの に意味があります。これを知らないまま見ると、「なんで左に変な余白があるのか」が永遠に分かりません。1

固定形式では、ざっくりこうです。

  • 1 - 6 列: 一連番号
  • 7 列: indicator
  • 8 - 11 列: Area A
  • 12 - 72 列: Area B

7 列目は特に大事です。

  • * または / : コメント行
  • - : 継続行
  • D : debugging line
  • *> : 途中にも書けるコメント

列と内容の対応を、目盛り付きで見るとこうなります。1 行目が 10 の位、2 行目が 1 の位の目盛りです。

         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890
SSSSSSIAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB........
  • S = 一連番号 (1 - 6 列)
  • I = indicator (7 列)
  • A = Area A (8 - 11 列)
  • B = Area B (12 - 72 列)
  • . = 73 列以降。処理系によっては識別欄として使われますが、プログラムの意味には関与しません

実際のソースに当てはめると、こうなります。

000100* この行は 7 列目が * なのでコメント
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. SAMPLE01.
000400 DATA DIVISION.
000500 WORKING-STORAGE SECTION.
000600 01  WS-ORDER.
000700     05  WS-ORDER-ID    PIC 9(8).
000800     05  WS-LONG-NAME   PIC X(30) VALUE 'ABCDEFGHIJKLMNOPQRST
000900-    'UVWXYZ0123'.

読み方のポイントは 4 つです。

  • 1 - 6 列は一連番号 です。上の例で 000100 のように振ってあるのがそれで、プログラムの動作には関係しません。空白のこともあります。
  • 7 列目が indicator です。* ならコメント、- なら継続行。上の例の 000900 行がそれで、前の行の文字列リテラルの続きになっています。
  • 8 - 11 列が Area A です。DIVISIONSECTION、段落名、FD、そして 0177 のレベル番号はここから始めます。上の例の IDENTIFICATION DIVISION.01 WS-ORDER. が Area A 始まりです。
  • 12 - 72 列が Area B です。普通の文と、05 などの下位レベルはここに書きます。上の例の 05 WS-ORDER-ID が Area B 始まりです。

ここでの空白は、現代的な意味での「整形」ではなく、部分的に構文です。 エディタでタブ変換したり、左に寄せたり、雑にコピペすると普通に壊れます。 古いソースを見るときは、まずそのファイルが fixed format なのか free format なのか を疑ってください。fixed 形式のソースに現代的な自動整形をかけると、Area A と Area B の境界が崩れてコンパイルが通らなくなります。

5. DATA DIVISION の最低限

5.1 レベル番号

COBOL のデータ定義は、インデントではなく レベル番号 で階層を作ります。2

       01  WS-ORDER.
           05  WS-ORDER-ID    PIC 9(8).
           05  WS-AMOUNT      PIC S9(7)V99 COMP-3.
           05  WS-STATUS      PIC X.
               88  WS-OK      VALUE '0'.
               88  WS-ERROR   VALUE '9'.

       77  WS-COUNT           PIC 9(4).

最低限これだけ覚えておけば十分です。

  • 01 : ひとまとまりの最上位レコード、グループ
  • 02 - 49 : その下の階層
  • 77 : 独立した単項目
  • 88 : condition-name。直前項目の値に名前を付ける3
  • 66 : RENAMES 用。遭遇率は高くないけれど存在はする

大事なのは、88bool の別変数 だと思わないことです。 WS-OK という領域が別にあるのではなく、WS-STATUS'0' のときに WS-OK という名前で読める、という感じです。

もう 1 つ大事なのは、階層を決めるのは空白ではなくレベル番号 だということです。 見た目の字下げは参考になりますが、最終的に信じるべきは 01 / 05 / 10 / 88 のほうです。2

5.2 PICTURE

PIC は、その項目の を表します。 いちばんよく見るのはこのへんです。

記法 ざっくり意味
X 文字
9 数字
S 符号付き
V 小数点は論理上だけ持つ
X(10) 10 文字
9(5) 5 桁数値
S9(7)V99 符号付き、整数 7 桁 + 小数 2 桁

たとえば、

  • PIC X(10) → 10 文字
  • PIC 9(5)V99 → 5 桁整数 + 2 桁小数
  • PIC S9(7)V99 → 符号付き 7 桁整数 + 2 桁小数

です。

ここで特に大事なのは V です。 V実際の . 文字を持ちませんPIC 9(5)V99 は「小数点 2 桁の数」として扱われますが、データ上にドット文字が入っているわけではありません。 なので、ファイルやダンプを「見た目の文字列」として解釈すると、だいたいこけます。

5.3 USAGE / DISPLAY / COMP / COMP-3

PIC が形だとすると、USAGEどういう表現で保持するか です。 最低限、次だけ押さえればかなり読めます。45

記法 ざっくり意味 読むときの注意
DISPLAY 文字として見える外部 10 進 mainframe では EBCDIC 前提のことがある6
COMP / BINARY 2進数 見た目の桁数と内部表現は別
COMP-3 / PACKED-DECIMAL packed decimal 文字として読むと壊れて見える

たとえば、

       01  WS-AMOUNT-DISP   PIC S9(7)V99.
       01  WS-AMOUNT-BIN    PIC S9(7) COMP.
       01  WS-AMOUNT-PACK   PIC S9(7)V99 COMP-3.

この 3 つは、全部「数値」ですが、中身の持ち方が違います

実務でいちばん効くのは COMP-3 を見た瞬間の反応です。

  • それは packed decimal
  • たぶん金額、税額、件数、レート系
  • テキストとして見ると壊れて見えて当然
  • CSV や UTF-8 の気分で眺めると事故る

という理解を持っておくと、ダンプやバイナリファイルの見え方で無駄に慌てずに済みます。

COMP-3 が実際にどんなバイト列になるか

ここは 1 回だけ手で追っておくと、以降の見え方が変わります。

packed decimal の規則は 2 つだけです。45

  1. 1 バイトに 10 進数字を 2 桁ずつ詰める
  2. ただし一番右のバイトだけは、下位 1 桁と符号で 1 バイトを使う

符号は 4 ビットの値で表され、C が正、D が負、F が符号なしです。

IBM のマニュアルに載っている例で確認します。4

定義 バイト列
PIC S9(4) PACKED-DECIMAL +1234 01 23 4C
PIC S9(4) PACKED-DECIMAL -1234 01 23 4D
PIC 9(4) PACKED-DECIMAL 1234 01 23 4F

1234 は 4 桁なので、規則 2 のぶん 1 桁ぶんの空きが先頭にできます。それが先頭の 0 です。

同じ要領で、この記事に何度も出てきた PIC S9(7)V99 COMP-3 を追ってみます。

  • S9(7)V99整数 7 桁 + 小数 2 桁 = 9 桁
  • V は小数点の位置を表すだけなので、バイトを 1 つも消費しません
  • 9 桁を 2 桁ずつ詰めると 4 バイト、残り 1 桁と符号で 1 バイト。合計 5 バイト

値が +12345.67 なら、9 桁ぶんに揃えると 001234567 なので、こうなります。

値     : +12345.67
9桁表現 : 0 0 1 2 3 4 5 6 7  と 符号
バイト  : 00 12 34 56 7C
                        ^ 符号 C = 正

負の値 -12345.67 なら、最後が 7D になるだけです。

バイト  : 00 12 34 56 7D

これをテキストとして開くとどう見えるか が本題です。00 12 34 56 7C を無理に 1 バイト 1 文字として ASCII に対応させると、

  • 00 は NUL、12 は制御文字で、そもそも文字として表示できません
  • 34456V7C|

になります。つまり画面上は「表示できない文字がいくつか並んだあとに 4V|」のように見えます。12345.67 という並びはどこにも現れません。

これが「文字化けに見えるが壊れていない」の正体です。ダンプを開いて意味不明な並びに出会ったら、まず その項目の USAGECOMP-3 ではないか を疑ってください。

ついでに、桁数からバイト数を出す早見表も置いておきます。バイト数は 「9 の数を 2 で割って小数を切り捨て、1 を足す」 で求まります。

PICTURE の 9 の数 COMP-3 のバイト数
1 1
2 - 3 2
4 - 5 3
6 - 7 4
8 - 9 5
10 - 11 6
12 - 13 7

同じバイト数に桁数が 2 つ並ぶのは、9 の数が偶数のときだけ先頭に空きの 1 桁ができる からです。S9(4)01 23 4C の 3 バイトになり、S9(5) も同じ 3 バイトで収まるのは、そのためです。

外部ファイルとのレイアウト突き合わせでは、この表がないと 1 バイトずつずれていきます。

もう 1 つだけ補足すると、DISPLAY だからといって必ず ASCII 文字列とは限りません。 z/OS 系では EBCDIC が前提になるため、数字が文字で見えていても、バイト値は ASCII の '0' - '9' とは違う ことがあります。6

5.4 REDEFINES / OCCURS / COPY / FILLER

この 4 つは、読むときの詰まりどころです。

REDEFINES

REDEFINES は、同じ領域を別の形で見る 仕組みです。コピーではありません。7

       01  REC-BUF.
           05  REC-TYPE      PIC X.
           05  REC-DATA      PIC X(99).

       01  HEADER-REC REDEFINES REC-BUF.
           05  HDR-TYPE      PIC X.
           05  HDR-DATE      PIC 9(8).
           05  FILLER        PIC X(91).

これは C 系でいう union 的な感覚に近いです。 「1 つの 100 バイトを、別レコード種別として見分ける」 みたいな書き方でよく出ます。

OCCURS

OCCURS は配列です。COBOL では table と呼ばれがちです。

       05  WS-ITEM OCCURS 12 TIMES.
           10  WS-PRICE    PIC 9(5).

さらに OCCURS DEPENDING ON が出たら、可変長テーブル です。 この場合、後続項目の位置まで影響することがあるので、固定長の気分で追うと足を踏み外します。8

COPY

COPY は compile time の include です。 つまり、いま開いているソースは まだ完成形ではない 可能性があります。9

       COPY CUSTOMER-REC.
       COPY ERROR-MAP.

レコード定義、共通フラグ、SQL 用の host variable、外部インターフェースが copybook に押し込まれているのはかなり普通です。

COPY が多くて読みにくいときは、展開後ソースや compiler listing を見られないか を確認したほうが早いです。IBM Enterprise COBOL には MDECK という、ライブラリ処理後の入力ソースを書き出すための option もあります。10

FILLER

FILLER は名前のない項目です。 ただし、「参照しないから無意味」ではありません。

  • 予約領域
  • 旧仕様との互換用の穴
  • レコード長合わせ
  • REDEFINES 用の余白

として普通に効きます。

FILLER は名前がないだけで、バイト数としては存在する。 これを忘れると、外部ファイルとのマッピングで 1 バイトずつ世界がずれていきます。

6. PROCEDURE DIVISION の最低限

DATA DIVISION が地図なら、PROCEDURE DIVISION は移動経路です。

6.1 PERFORM

PERFORM は COBOL の基本的な制御移動です。 ざっくり言うと、処理を呼んで戻る です。11

よく見る形は次です。

       PERFORM INIT-PROC
       PERFORM UNTIL EOF
           PERFORM READ-PROC
           IF NOT EOF
               PERFORM EDIT-PROC
               PERFORM WRITE-PROC
           END-IF
       END-PERFORM

PERFORM には大きく 2 系統あります。

  • 段落や節を指定する out-of-line PERFORM
  • その場にブロックを書く inline PERFORM ... END-PERFORM

さらに古いコードでは PERFORM A-100 THRU A-199 のような 範囲指定 も普通に出ます。 これは便利ですが、段落を途中で足すと巻き込み事故が起きやすいので、読むときは範囲の終端をちゃんと見ます。

6.2 IF / EVALUATE / スコープ

条件分岐は IF が基本です。 EVALUATEswitch/case 的なものだと思えばだいたい合っています。

気を付けるべきなのは スコープの終わり方 です。12

  • END-IF
  • END-PERFORM
  • END-READ

のような 明示的な終端 があるコードはまだ読みやすいです。

問題は古いコードです。COBOL では .暗黙の scope terminator として働き、まだ閉じていない文をまとめて終わらせます。12

つまり、たった 1 個のピリオドで、

  • どこまでが IF
  • どこまでが PERFORM
  • どこで次の sentence に移るか

が変わります。

さらに NEXT SENTENCECONTINUE と同じではありません。 NEXT SENTENCE次のピリオドの後ろへ進む ので、後続の . の位置次第で飛び先が変わります。12

古い COBOL を読むときは、行末ではなくピリオドを見る くらいでちょうどいいです。

6.3 READ / WRITE / CALL

業務 COBOL で頻出なのはこのへんです。

  • READ
  • WRITE
  • REWRITE
  • START
  • CALL

特に READ ... AT END ... は王道です。

       READ IN-FILE
           AT END
               SET EOF TO TRUE
           NOT AT END
               PERFORM PROCESS-REC
       END-READ

CALL 'SUBPGM' USING ... があれば、別プログラムへ飛びます。 そのときは、呼ばれ先の LINKAGE SECTIONPROCEDURE DIVISION USING を見ると、受け渡しの形がかなり見えます。

7. COBOL の外側にあるもの

COBOL は、ソースだけで世界が完結していないことがかなりあります。

  • ファイル定義
  • 実行環境
  • DB 接続
  • トランザクション環境
  • job 制御

が外側に分かれているからです。

最低限、次は押さえると読みやすくなります。

ファイルと FILE STATUS

ENVIRONMENT DIVISIONFILE-CONTROL と、DATA DIVISIONFILE SECTION / FD はセットで読みます。13

       SELECT IN-FILE ASSIGN TO ...
           FILE STATUS IS WS-FS.

       FD  IN-FILE.
       01  IN-REC.
           05 ...

FILE STATUS があれば、各 I/O 後の結果コードが入ります。 ファイル系の障害や EOF 判定を読むときは、これを見ないと始まりません。14

EXEC SQL

これが出たら、埋め込み SQL です。

       EXEC SQL
           SELECT ...
       END-EXEC.

この場合、COBOL は「ホスト変数の器」で、実際の取得条件や更新対象は SQL 側にあります。 なので、EXEC SQL の中身を普通の SQL として読む のが近道です。

EXEC CICS

これが出たら、CICS のトランザクション文脈です。15

       EXEC CICS
           RECEIVE MAP(...)
       END-EXEC.

この瞬間、単なるバッチ読解ではなくなります。 画面、トランザクション、応答コード、COMMAREA など、外部文脈込みで読む必要があります。

JCL や実行定義

mainframe batch では、実際にどのデータセットが割り当てられるかどの順で job が流れるか が COBOL ソースの外にあることも珍しくありません。 ソースだけ見て「このファイルはどこにあるのか」が分からないときは、コードが悪いのではなく、見ている範囲がまだ足りていないだけ、ということが普通にあります。

処理系(コンパイラ)の違い

この記事は IBM 系を念頭に書いていますが、実務では Micro Focus や、Linux / Windows 上の COBOL に出会うこともあります。骨格は共通なので読み方は変わりませんが、「同じ書き方なのに結果が違う」 ポイントは決まっているので、先に把握しておくと事故りません。

見るところ z/OS 系(IBM Enterprise COBOL) オープン系(Micro Focus、Linux / Windows 版など)
文字コード EBCDIC が前提6 ASCII が前提6
参照形式 fixed 形式が伝統的な既定。free 形式も選べる1 fixed と free の両方を持ち、既定がどちらかはビルド設定次第1
copybook の探し方 ライブラリ指定 コンパイラ オプションでの検索パス指定
方言 「どの処理系に合わせるか」を切り替えるオプションがある

特に効くのが 文字コード です。同じ PIC X(10) でも、z/OS で書いたファイルをそのまま Windows 側で読むと、数字さえ違うバイト値になります。「移送したら全部化けた」の多くはこれで、COMP-3 の話とは別問題です。

もう 1 つ、数値の内部表現にも差が出やすい場所があります。IBM Enterprise COBOL では、BINARY / COMP-4PICTURE に書いた桁数で切り捨てが起きる のに対し、COMP-52 / 4 / 8 バイトというネイティブな 2 進数の容量まで値を持ち、切り捨てもバイナリのサイズ側で起きます16 つまり PIC S9(4) COMPPIC S9(4) COMP-5 は、同じように見えて 入る値の上限が違います。他システムと 2 進数のまま値をやり取りしているコードで COMP-5 が出てきたら、わざとそう書いてある と思って読んでください。

自分の環境と照らすときの最短手順はこうです。

  1. ビルド定義(makefile、JCL、プロジェクト設定)を先に開く。 どの処理系の、どのオプションでコンパイルされているかが、ソースより先に分かります。
  2. 参照形式(fixed / free)を確定させる。 ここを間違えたままエディタで整形すると壊れます。
  3. 文字コードを確定させる。 EBCDIC か ASCII かで、ダンプの読み方が変わります。
  4. COMP 系の項目に印を付ける。 処理系差が出るのはほぼここです。

8. 最低限の読み順

突然 COBOL を読むことになったときは、次の順番が安全です。

  1. COPY を全部洗う copybook を開けるなら開く。無理なら listing や展開後ソースを探す
  2. 01 レベルのレコード定義を拾う FILE SECTIONWORKING-STORAGELINKAGE SECTION の最上位を一覧化する
  3. PICUSAGE を読む 金額、日付、件数、コード、フラグを識別する
  4. READ / WRITE / REWRITE / CALL / EXEC SQL / EXEC CICS を検索する 入出力と外部境界を先に掴む
  5. 最初の主経路だけ追う PROCEDURE DIVISION の先頭から PERFORM 連鎖をなぞる
  6. 88 と status 項目を見る EOF、正常/異常、種別コードの意味が読みやすくなる
  7. REDEFINES / OCCURS DEPENDING ON / COMP-3 に印を付ける 後で必ず効くので、先に危険物としてマークしておく
  8. ファイルなら FILE STATUS を見る I/O エラー系の読み違いをかなり減らせる

この順番だと、いきなり全文を精読しなくて済みます。 COBOL は、最初から 100% 理解しようとするより、レコード、外部境界、主経路 の 3 点を押さえてから細部へ行くほうがずっと楽です。

8.1 練習: このレコード定義を読んでみる

読み方の説明だけでは定着しないので、小さいレコードを 1 本置いておきます。先に自分で答えを出してから 下の解答を見てください。

       01  CUST-REC.
           05  CUST-ID          PIC X(8).
           05  CUST-NAME        PIC X(20).
           05  CUST-KBN         PIC X.
               88  CUST-NORMAL  VALUE '0'.
               88  CUST-VIP     VALUE '1'.
           05  CUST-BALANCE     PIC S9(7)V99 COMP-3.
           05  CUST-HIST OCCURS 3 TIMES.
               10  HIST-DATE    PIC 9(8).
               10  HIST-AMOUNT  PIC S9(5)V99 COMP-3.
           05  FILLER           PIC X(4).

設問

  1. CUST-REC は全体で何バイトですか。
  2. CUST-BALANCE は、レコードの先頭から数えて何バイト目から始まりますか。
  3. 2 件目の HIST-AMOUNT は、先頭から何バイト目から始まりますか。
  4. CUST-KBN'1' が入っているとき、真になる条件名はどれですか。
  5. このファイルをテキストエディタで開いたとき、壊れて見えるのはどの項目 ですか。
  6. この定義だけでは分からないことを 2 つ挙げてください。

解答

  1. 74 バイトです。内訳はこうです。

    項目 計算 バイト数
    CUST-ID X(8) 8
    CUST-NAME X(20) 20
    CUST-KBN X 1
    CUST-BALANCE 9 桁の COMP-3 5
    CUST-HIST (8 + 4) × 3 回 36
    FILLER X(4) 4
    合計   74

    88 レベルは条件名なので バイトを消費しません。ここを数えてしまうのがよくある間違いです。FILLER は名前がないだけで、4 バイトはしっかり存在します

  2. 30 バイト目からです。手前に 8 + 20 + 1 = 29 バイトあるので、その次から始まります。

  3. 55 バイト目からです。CUST-HIST が始まるのは 35 バイト目で、1 件が 12 バイトなので、1 件目は 35 - 46 バイト、2 件目は 47 - 58 バイト。そのうち先頭 8 バイトが HIST-DATE なので、HIST-AMOUNT は 55 バイト目からです。

  4. CUST-VIP です。CUST-VIP という領域が別にあるのではなく、CUST-KBN'1' のときにその名前で読める、というだけです。

  5. CUST-BALANCEHIST-AMOUNT です。どちらも COMP-3 なので、文字として読むと意味のない並びになります。HIST-DATEPIC 9(8)DISPLAY なので、ASCII 環境なら 20260317 のように数字として読めます。ただし EBCDIC 環境では、数字に見えてもバイト値は ASCII と違います。

  6. たとえば、次のようなことです。

    • この定義自体が COPY で持ち込まれているのか。 copybook 側を見ないと、実際に使われている版かどうか分かりません。
    • ファイルの文字コードが EBCDIC か ASCII か。 PIC XPIC 9 DISPLAY の見え方が変わります。
    • CUST-KBN'0''1' 以外が入る運用があるか。 条件名は 2 つしか定義されていませんが、それ以外の値が来ないという保証にはなりません。
    • ファイル自体の属性(レコード長、可変長かどうか、FILE STATUS)。 これは ENVIRONMENT DIVISIONFD を見ないと分かりません。

設問 1 と 3 を間違えたなら、5.3 の桁数とバイト数の表へ戻ってください。COBOL の読み違いは、たいていここから始まります。

9. よくある詰まりどころ

最後に、初心者がかなり高確率で引っかかる場所をまとめます。

REDEFINES を「別の変数」だと思う

違います。 同じ領域を別の形で読んでいます。片方を書き換えると、もう片方の見え方も変わります。7

88 を「独立した bool」だと思う

違います。 直前項目の値に名前が付いているだけです。SET WS-OK TO TRUE は、裏では基底項目へ対応値を入れます。3

COPY を無視して本文だけ読む

開いているファイルは、まだ全体の半分です。 フィールド定義、共通フラグ、host variable がごっそり外にあることは普通です。9

MOVE を単純代入だと思う

MOVE は単なる memcpy ではありません。 受け側の型に応じて、変換、桁合わせ、ゼロ埋め、切り詰め、編集・逆編集が入ることがあります。17

. の影響を軽く見る

COBOL の . は想像より重いです。 明示終端がない古いコードでは、このピリオドがどこまで閉じているか を見誤ると制御フローを読み違えます。12

packed decimal や EBCDIC を「文字化け」だと思う

壊れているとは限りません。 最初から文字列ではない、または ASCII ではないだけ、ということがかなりあります。46

OCCURS DEPENDING ON の後ろを固定位置だと思う

可変長テーブルの後続項目は、値によって位置が動くことがあります。 固定長の頭で読むと、オフセット計算が全部ずれます。8

10. まず見る早見表

見つけた語 まず考えること
01 レコードやグループの最上位。ここから全体像を掴む
88 フラグや状態コードの意味名。分岐を読む鍵
PIC X(...) 文字項目
PIC 9(...) / S9(...)V... 数値項目。桁数と小数位置を確認
COMP binary
COMP-3 packed decimal。金額・件数の可能性が高い
REDEFINES 同じ領域を別解釈している
OCCURS 配列・table
OCCURS DEPENDING ON 可変長。後続位置にも注意
FILLER 名前はないが長さはある
COPY copybook を見ないと完成形が見えない
PERFORM 主経路の骨格
READ / WRITE / REWRITE ファイル I/O
EXEC SQL DB 処理
EXEC CICS トランザクション処理
FILE STATUS I/O の結果コード

11. まとめ

COBOL は、古いから難しいのではありません。 データ定義、外部ファイル、実行文脈が密に結び付いている ので、最初の入口が見えにくいだけです。

読むための最小セットをもう一度まとめると、こうです。

  • DIVISION で地図を掴む
  • DATA DIVISION を先に読む
  • PICUSAGE で項目の形を読む
  • COMP-3REDEFINESOCCURS88COPY に印を付ける
  • PERFORMREADWRITECALL を追う
  • FILE STATUSEXEC SQLEXEC CICS で外部境界を押さえる
  • . の効き方を甘く見ない

ここが見えると、COBOL は「謎の古代魔法」から「レコード処理の言語」へ変わります。 レガシー技術は、名前が古いから怖いのではなく、最初に見る縮尺を間違えると急に分かりにくい だけです。地図の縮尺が合えば、意外と普通に読めます。

12. 参考資料

本文中の主な参照先です。本文の上付き番号がそのままこの一覧へのリンクになっていて、各項目の末尾の矢印から元の位置へ戻れます。

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

COBOLのソースはどこから読み始めればよいですか?
PROCEDURE DIVISIONだけ読んでも半分しか分かりません。COBOLはロジックの言語である前にかなり強くレコード定義の言語なので、まずDATA DIVISIONを見ます。安全な読み順は、COPYを全部洗ってcopybookを確認し、01レベルのレコード定義を一覧化し、PICとUSAGEで項目の形を読み、READ・WRITE・CALL・EXEC SQL・EXEC CICSを検索して入出力と外部境界を掴んでから、PROCEDURE DIVISION先頭のPERFORM連鎖で主経路だけを追う、という流れです。
PIC S9(7)V99 COMP-3とはどういう意味ですか?
PICは項目の形、USAGEはどういう表現で保持するかを表します。S9(7)V99は符号付きで整数7桁+小数2桁の数値ですが、Vは論理上の小数点であり、データ上にドット文字が入っているわけではありません。COMP-3はpacked decimalで、金額・税額・件数・レート系の項目でよく出ます。テキストとして見ると壊れて見えて当然なので、CSVやUTF-8の気分でダンプを眺めると事故ります。
COBOLの88レベルやREDEFINESはどう理解すればよいですか?
88は独立したbool変数ではなく、直前項目の値に名前を付けた条件名(condition-name)です。SET WS-OK TO TRUEは裏では基底項目へ対応する値を入れます。REDEFINESは同じメモリ領域を別の形で見る仕組みで、コピーではなくC系のunionに近い感覚です。片方を書き換えるともう片方の見え方も変わるため、1つの領域をレコード種別ごとに見分ける書き方でよく出ます。
COPY文が多くて全体が見えないときはどうすればよいですか?
COPYはコンパイル時のincludeなので、いま開いているソースはまだ完成形ではない可能性があります。レコード定義、共通フラグ、SQL用のhost variable、外部インターフェースがcopybookに押し込まれているのはかなり普通です。読みにくいときは展開後ソースやcompiler listingを見られないか確認するのが早く、IBM Enterprise COBOLにはライブラリ処理後の入力ソースを書き出すMDECKというオプションもあります。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る