更新履歴(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 - 変数名は全部大文字
01、05、77、88が並ぶ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 を見ないと全体が見えませんPERFORM、IF、EVALUATE、READ、WRITE、CALLを追えれば、だいたいの流れは掴めます- 古いソースは 列位置に意味がある固定形式 です。見た目の空白がただの飾りではありません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で外部境界を押さえる必要があります。
flowchart LR
accTitle: COBOL読解の知識マップ
accDescr: COBOLがDATA DIVISIONとPROCEDURE DIVISIONを柱とし、PICTURE句・USAGE句・COMP-3・REDEFINES・OCCURS・88レベル・COPY文などのデータ定義要素と、PERFORM文やスコープ終端子などの制御要素、EBCDICやFILE STATUS・EXEC SQL・EXEC CICSといった外部境界の要素がどう関係するかを示す図
cobol["COBOL"]
cobol_data_division["DATA DIVISION"]
comp_3["COMP-3(packed decimal)"]
cobol_procedure_division["PROCEDURE DIVISION"]
cobol_picture_clause["PICTURE句(PIC)"]
cobol_usage_clause["USAGE句"]
comp_5["COMP-5"]
cobol_redefines["REDEFINES句"]
cobol_occurs["OCCURS句"]
cobol_occurs_depending_on["OCCURS DEPENDING ON"]
cobol_88_level["88レベル(条件名)"]
cobol_copy["COPY文"]
copybook["copybook"]
cobol_perform["PERFORM文"]
cobol_scope_terminator["スコープ終端子(scope terminator)"]
cobol_move["MOVE文"]
cobol_fixed_format["固定形式(参照形式)"]
ibm_enterprise_cobol["IBM Enterprise COBOL"]
ebcdic["EBCDIC"]
cobol_file_status["FILE STATUS句"]
exec_sql["EXEC SQL"]
exec_cics["EXEC CICS"]
cobol -->|"利用する"| cobol_data_division
cobol -->|"利用する"| cobol_procedure_division
cobol_data_division -->|"利用する"| cobol_picture_clause
cobol_data_division -->|"利用する"| cobol_usage_clause
cobol_usage_clause -->|"利用する"| comp_3
cobol_usage_clause -->|"利用する"| comp_5
cobol_data_division -->|"利用する"| cobol_redefines
cobol_data_division -->|"利用する"| cobol_occurs
cobol_occurs_depending_on -->|"利用する"| cobol_occurs
cobol_data_division -->|"利用する"| cobol_88_level
cobol -.->|"利用する"| cobol_copy
cobol_copy -->|"利用する"| copybook
cobol_procedure_division -->|"利用する"| cobol_perform
cobol_procedure_division -->|"利用する"| cobol_scope_terminator
cobol_procedure_division -->|"利用する"| cobol_move
cobol -.->|"利用する"| cobol_fixed_format
ibm_enterprise_cobol -->|"利用する"| ebcdic
ibm_enterprise_cobol -.->|"利用する"| cobol_fixed_format
cobol -.->|"利用する"| cobol_file_status
cobol -.->|"利用する"| exec_sql
cobol -.->|"利用する"| exec_cics
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全21件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. COBOL はまず「データの形」の言語だと思う
C# や Java の感覚で読むと、最初は if や for や関数呼び出しを追いたくなります。
でも COBOL は、そこに行く前に 「このプログラムはどんなレコードを受け取り、どんなレコードを作り、どんなバッファを持っているのか」 を押さえたほうが早いです。
典型的な業務 COBOL は、だいたい次の流れです。
- ファイルや DB からレコードを読む
WORKING-STORAGE上の項目へ入れる- 条件分岐する
- 別のレコードへ詰め替える
- 書き出す
つまり、アルゴリズムよりレイアウト が先に立ちやすいです。
たとえば、こんな骨格です。
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 SECTION と PROCEDURE 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 です。
DIVISION、SECTION、段落名、FD、そして01と77のレベル番号はここから始めます。上の例の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。直前項目の値に名前を付ける366:RENAMES用。遭遇率は高くないけれど存在はする
大事なのは、88 を bool の別変数 だと思わないことです。
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 バイトに 10 進数字を 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は制御文字で、そもそも文字として表示できません34は4、56はV、7Cは|
になります。つまり画面上は「表示できない文字がいくつか並んだあとに 4V|」のように見えます。12345.67 という並びはどこにも現れません。
これが「文字化けに見えるが壊れていない」の正体です。ダンプを開いて意味不明な並びに出会ったら、まず その項目の USAGE が COMP-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 が基本です。
EVALUATE は switch/case 的なものだと思えばだいたい合っています。
気を付けるべきなのは スコープの終わり方 です。12
END-IFEND-PERFORMEND-READ
のような 明示的な終端 があるコードはまだ読みやすいです。
問題は古いコードです。COBOL では . が 暗黙の scope terminator として働き、まだ閉じていない文をまとめて終わらせます。12
つまり、たった 1 個のピリオドで、
- どこまでが
IFか - どこまでが
PERFORMか - どこで次の sentence に移るか
が変わります。
さらに NEXT SENTENCE は CONTINUE と同じではありません。
NEXT SENTENCE は 次のピリオドの後ろへ進む ので、後続の . の位置次第で飛び先が変わります。12
古い COBOL を読むときは、行末ではなくピリオドを見る くらいでちょうどいいです。
6.3 READ / WRITE / CALL
業務 COBOL で頻出なのはこのへんです。
READWRITEREWRITESTARTCALL
特に READ ... AT END ... は王道です。
READ IN-FILE
AT END
SET EOF TO TRUE
NOT AT END
PERFORM PROCESS-REC
END-READ
CALL 'SUBPGM' USING ... があれば、別プログラムへ飛びます。
そのときは、呼ばれ先の LINKAGE SECTION と PROCEDURE DIVISION USING を見ると、受け渡しの形がかなり見えます。
7. COBOL の外側にあるもの
COBOL は、ソースだけで世界が完結していないことがかなりあります。
- ファイル定義
- 実行環境
- DB 接続
- トランザクション環境
- job 制御
が外側に分かれているからです。
最低限、次は押さえると読みやすくなります。
ファイルと FILE STATUS
ENVIRONMENT DIVISION の FILE-CONTROL と、DATA DIVISION の FILE 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-4 は PICTURE に書いた桁数で切り捨てが起きる のに対し、COMP-5 は 2 / 4 / 8 バイトというネイティブな 2 進数の容量まで値を持ち、切り捨てもバイナリのサイズ側で起きます。16 つまり PIC S9(4) COMP と PIC S9(4) COMP-5 は、同じように見えて 入る値の上限が違います。他システムと 2 進数のまま値をやり取りしているコードで COMP-5 が出てきたら、わざとそう書いてある と思って読んでください。
自分の環境と照らすときの最短手順はこうです。
- ビルド定義(makefile、JCL、プロジェクト設定)を先に開く。 どの処理系の、どのオプションでコンパイルされているかが、ソースより先に分かります。
- 参照形式(fixed / free)を確定させる。 ここを間違えたままエディタで整形すると壊れます。
- 文字コードを確定させる。 EBCDIC か ASCII かで、ダンプの読み方が変わります。
COMP系の項目に印を付ける。 処理系差が出るのはほぼここです。
8. 最低限の読み順
突然 COBOL を読むことになったときは、次の順番が安全です。
COPYを全部洗う copybook を開けるなら開く。無理なら listing や展開後ソースを探す01レベルのレコード定義を拾うFILE SECTION、WORKING-STORAGE、LINKAGE SECTIONの最上位を一覧化するPICとUSAGEを読む 金額、日付、件数、コード、フラグを識別するREAD/WRITE/REWRITE/CALL/EXEC SQL/EXEC CICSを検索する 入出力と外部境界を先に掴む- 最初の主経路だけ追う
PROCEDURE DIVISIONの先頭からPERFORM連鎖をなぞる 88と status 項目を見る EOF、正常/異常、種別コードの意味が読みやすくなるREDEFINES/OCCURS DEPENDING ON/COMP-3に印を付ける 後で必ず効くので、先に危険物としてマークしておく- ファイルなら
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).
設問
CUST-RECは全体で何バイトですか。CUST-BALANCEは、レコードの先頭から数えて何バイト目から始まりますか。- 2 件目の
HIST-AMOUNTは、先頭から何バイト目から始まりますか。 CUST-KBNに'1'が入っているとき、真になる条件名はどれですか。- このファイルをテキストエディタで開いたとき、壊れて見えるのはどの項目 ですか。
- この定義だけでは分からないことを 2 つ挙げてください。
解答
-
74 バイトです。内訳はこうです。
項目 計算 バイト数 CUST-IDX(8)8 CUST-NAMEX(20)20 CUST-KBNX1 CUST-BALANCE9 桁の COMP-3 5 CUST-HIST(8 + 4)× 3 回36 FILLERX(4)4 合計 74 88レベルは条件名なので バイトを消費しません。ここを数えてしまうのがよくある間違いです。FILLERは名前がないだけで、4 バイトはしっかり存在します。 -
30 バイト目からです。手前に
8 + 20 + 1 = 29バイトあるので、その次から始まります。 -
55 バイト目からです。
CUST-HISTが始まるのは 35 バイト目で、1 件が 12 バイトなので、1 件目は 35 - 46 バイト、2 件目は 47 - 58 バイト。そのうち先頭 8 バイトがHIST-DATEなので、HIST-AMOUNTは 55 バイト目からです。 -
CUST-VIPです。CUST-VIPという領域が別にあるのではなく、CUST-KBNが'1'のときにその名前で読める、というだけです。 -
CUST-BALANCEとHIST-AMOUNTです。どちらもCOMP-3なので、文字として読むと意味のない並びになります。HIST-DATEはPIC 9(8)のDISPLAYなので、ASCII 環境なら20260317のように数字として読めます。ただし EBCDIC 環境では、数字に見えてもバイト値は ASCII と違います。 -
たとえば、次のようなことです。
- この定義自体が
COPYで持ち込まれているのか。 copybook 側を見ないと、実際に使われている版かどうか分かりません。 - ファイルの文字コードが EBCDIC か ASCII か。
PIC XとPIC 9 DISPLAYの見え方が変わります。 CUST-KBNに'0'と'1'以外が入る運用があるか。 条件名は 2 つしか定義されていませんが、それ以外の値が来ないという保証にはなりません。- ファイル自体の属性(レコード長、可変長かどうか、
FILE STATUS)。 これはENVIRONMENT DIVISIONとFDを見ないと分かりません。
- この定義自体が
設問 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を先に読むPICとUSAGEで項目の形を読むCOMP-3、REDEFINES、OCCURS、88、COPYに印を付けるPERFORM、READ、WRITE、CALLを追うFILE STATUS、EXEC SQL、EXEC CICSで外部境界を押さえる.の効き方を甘く見ない
ここが見えると、COBOL は「謎の古代魔法」から「レコード処理の言語」へ変わります。 レガシー技術は、名前が古いから怖いのではなく、最初に見る縮尺を間違えると急に分かりにくい だけです。地図の縮尺が合えば、意外と普通に読めます。
12. 参考資料
本文中の主な参照先です。本文の上付き番号がそのままこの一覧へのリンクになっていて、各項目の末尾の矢印から元の位置へ戻れます。
-
IBM, “Reference format” / IBM, “Area A or Area B” / Micro Focus, “Fixed Format” ↩ ↩2 ↩3 ↩4
-
IBM, “Level-numbers” ↩ ↩2
-
IBM, “Format 2: condition-name value” ↩ ↩2
-
IBM, “Examples: numeric data and internal representation” ↩ ↩2 ↩3 ↩4
-
IBM, “PACKED-DECIMAL (COMP-3)” ↩ ↩2
-
IBM, “The EBCDIC character set” / IBM, “Handling differences in ASCII SBCS and EBCDIC SBCS characters” ↩ ↩2 ↩3 ↩4 ↩5
-
IBM, “REDEFINES 節” ↩ ↩2
-
IBM, “OCCURS DEPENDING ON clause” ↩ ↩2
-
IBM, “COPY ステートメント” ↩ ↩2
-
IBM, “PERFORM statement” / IBM, “Procedure division structure” ↩
-
IBM, “Scope terminators” / IBM, “Coding a choice of actions” ↩ ↩2 ↩3 ↩4
-
IBM, “ファイル構造の詳細記述” ↩
-
IBM, “FILE STATUS clause” / IBM, “Using file status keys” ↩
-
IBM, “Computational items” ↩
-
IBM, “Elementary move rules” ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
テストのないレガシー業務アプリに安全に手を入れる ── 特性化テストとリファクタリングの実践
テストのない業務アプリに安全に手を入れるために、現在の挙動を固定する特性化テスト(ゴールデンマスター法)の手順、継ぎ目(seam)の作り方、リファクタリングと機能追加を混ぜない運用ルールをC#の例で解説します。
ソースコードも仕様書もないシステムを引き継いだら ── 止めずに運用・保守するための実務手順
ソースコードも仕様書もない業務システムの運用・保守を始める実務手順を整理します。動いている環境の保全とバックアップ、実行ファイル・DBの棚卸し、挙動からの仕様復元、延命・ラップ・再構築の判断まで解説します。
MSMQはいつまで使えるのか ── 「非推奨ですらない」レガシーキューの移行判断
MSMQは公式の非推奨リストに載っていない一方、System.Messagingは.NET Frameworkにしか存在せず、.NETへの移行を妨げます。廃止の噂と実際の現在地を事実で整理し、使い続ける・移行するの判断基準と移行先の選び方をまとめます。
QRコードの読み取り値をそのまま使ってはいけない ── 誤り訂正が通っても値は保証されない
QRコードの誤り訂正は、訂正が通れば値が正しいと保証する仕組みではありません。サンプル画像と2種類のデコーダによる実測から、汚れの当たり方しだいで別の値として読めてしまう理由と、業務システム側に必要な検証を解説します。
PowerShellでREST APIと連携する ── Invoke-RestMethodの実務
PowerShellから社内APIやSaaSのREST APIを呼ぶ実務をまとめます。認証ヘッダーの渡し方、日本語JSONの文字化け対策、4xx/5xxのエラー処理、429のリトライ、ページング、プロキシとTLSの落とし穴まで解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
ActiveX / 移行テーマ
COM / ActiveX / OCX を残すか、包むか、置き換えるかを整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
技術相談・設計レビュー
既存 COBOL 資産の読み解き方、改修の入り口、外部境界の把握、移行前の見立て整理まで含めて、技術相談・設計レビューと相性がよいテーマです。
不具合調査・原因解析
引き継ぎ直後の障害対応や、COBOL 資産のどこで不整合が起きているかを追う作業は、不具合調査・原因解析として進めやすいです。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- 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というオプションもあります。