プログラミング言語を整える
中級COBOL を整える。
= 金融や行政の基幹システムで今も動く COBOL を、桁位置と PIC 句の道具つきで学ぶ
COBOL が初めての方は、先に そもそも COBOL とは・どんな場面で使うか をどうぞ。
COBOLとは
事務処理のために作られた言語で、英語に近い書き方と10進数の正確な計算を特徴とし、今も金融や行政の基幹システムで動いています。
| 誕生 | 1959年 |
|---|---|
| 作った人・組織 | CODASYL(米国の政府・企業が参加した委員会)。グレース・ホッパーの FLOW-MATIC の影響を受けています |
| 型の付け方 | 静的型付け(PIC 句で桁数と種類を宣言する) |
| 動かし方 | コンパイルして実行ファイルを作る(GnuCOBOL は C に変換してからコンパイルする) |
| ファイルの拡張子 | .cob / .cbl |
| 手元で動かすには | cobc -x main.cob && ./main(GnuCOBOL) |
日本での使われ方
- 銀行・保険・証券の勘定系システムで、今も COBOL のプログラムが動いています。
- 官公庁や自治体の基幹システム(税・住民記録など)にも、COBOL で作られたものがあります。
- メインフレーム(大型汎用機)の上で動くことが多く、メインフレームの保守とセットで扱われます。
- 金額を10進数の固定小数点で扱えるため、2進数の浮動小数点で起きる端数の誤差を避けやすく、お金の計算に向いています。
- 経済産業省の「DXレポート」(2018年)は、複雑化・老朽化・ブラックボックス化した既存システムが残ると2025年以降に大きな損失が出るおそれがあると指摘し(「2025年の崖」)、COBOL で書かれた古い基幹システムもこの文脈で話題になりました。
新人研修での位置づけ
金融や公共分野を担当する SIer では、既存システムの保守を担う人向けに、今も新人研修で COBOL を扱うことがあります。データ部と手続き部を分けて書く構成や、PIC 句による桁数の考え方を、実際の帳票処理やファイル処理を題材に学びます。
関わる資格・試験
- 基本情報技術者試験(かつては午後試験の選択言語の1つに COBOL がありましたが、現在の試験では出題されません)
そもそも COBOL とは
事務処理のために作られ、今も金融や行政の基幹システムを支える言語。
COBOL(コボル)は1959年に生まれた言語で、米国の政府・企業が参加した委員会 CODASYL が仕様をまとめました。英語の文章に近い書き方で、お金の計算に欠かせない10進数の正確な計算が得意です。書いたプログラムはコンパイルして実行ファイルにします。
最近の言語と比べると書く量は多くなりますが、何をしているかが読み取りやすいのが特徴です。変数の桁数や種類は PIC 句で宣言します。長く動き続けるシステムが多いため、新しく作るより、既存のプログラムを保守・改修する場面が中心です。
どこで・どんな場面で使うか
-
銀行・保険・証券の勘定系システム
お金の出入りを扱う中核のシステムで、今も COBOL のプログラムが動いています。
-
官公庁や自治体の基幹システム
税や住民記録といった、止められない業務のシステムに COBOL で作られたものがあります。
-
メインフレーム(大型汎用機)
大型の汎用機の上で動くことが多く、メインフレームの保守とセットで扱われます。
-
夜間・月末のバッチ処理
大量のデータをまとめて処理する、帳票や集計のプログラムで使われます。
-
求人での位置づけ
新規開発よりも、既存システムの保守・改修の求人で経験者が求められます。
なぜ覚えておくと得か
- 今も動くシステムを支える仕事がある。基幹システムは簡単に止められず、読める人が必要とされ続けています。
- 世代交代が課題になっている現場もある。COBOL を読める人を育てたいという会社があり、若い人が学ぶ意味があります。
- お金の計算の考え方が学べる。桁数や丸めをどう扱うかは、どの言語で業務システムを作るときにも役立ちます。
このページの桁位置の定規や PIC 句の道具で、COBOL の書き方を試してみてください。
5つのお題をCOBOLで書く
C・C++・Java・C#・COBOL・VBA の6ページで、同じ5つのお題を同じ順に並べています。言語を切り替えると、書き方の違いがそのまま比べられます。
このページではコードを実行できません。表示している出力とエラーのメッセージは、GnuCOBOL 3.1.2 で実際にコンパイル・実行して、一字一句同じになることを確かめたものです。
コード(.cob / .cbl)
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, World!".
STOP RUN.
実行すると
Hello, World!
プログラムは「部(DIVISION)」に分けて書きます。DIVISION や PROGRAM-ID は8桁目から(A領域)、DISPLAY などの文は12桁目から(B領域)書くのが固定形式の決まりです。文の終わりにはピリオドを付けます。
コード(.cob / .cbl)
IDENTIFICATION DIVISION.
PROGRAM-ID. FIZZBUZZ.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 I PIC 99.
01 I-DISP PIC Z9.
PROCEDURE DIVISION.
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 15
EVALUATE TRUE
WHEN FUNCTION MOD(I, 15) = 0
DISPLAY "FizzBuzz"
WHEN FUNCTION MOD(I, 3) = 0
DISPLAY "Fizz"
WHEN FUNCTION MOD(I, 5) = 0
DISPLAY "Buzz"
WHEN OTHER
MOVE I TO I-DISP
DISPLAY FUNCTION TRIM(I-DISP)
END-EVALUATE
END-PERFORM.
STOP RUN.
実行すると
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
繰り返しは PERFORM VARYING、条件分岐は EVALUATE で書きます。PIC 99 の変数をそのまま表示すると「01」のように0が付くため、PIC Z9(先頭の0を空白にする編集用の型)に移してから空白を取り除いています。
コード(.cob / .cbl)
IDENTIFICATION DIVISION.
PROGRAM-ID. SUMAVG.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 NUMS-INIT PIC X(8) VALUE "31415926".
01 NUMS REDEFINES NUMS-INIT.
05 NUM PIC 9 OCCURS 8 TIMES.
01 I PIC 9.
01 TOTAL PIC 9(3) VALUE 0.
01 AVG PIC 9(3)V99.
01 TOTAL-DISP PIC ZZ9.
01 AVG-DISP PIC ZZ9.99.
PROCEDURE DIVISION.
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 8
ADD NUM(I) TO TOTAL
END-PERFORM.
COMPUTE AVG ROUNDED = TOTAL / 8.
MOVE TOTAL TO TOTAL-DISP.
MOVE AVG TO AVG-DISP.
DISPLAY "Sum: " TOTAL-DISP.
DISPLAY "Avg: " AVG-DISP.
STOP RUN.
実行すると
Sum: 31 Avg: 3.88
配列は OCCURS で作り、添字は1から数えます。ここでは8桁の文字列を REDEFINES で1桁ずつの表として読み直して初期値を入れています。平均 3.875 は PIC 9(3)V99(小数2桁)に ROUNDED 付きで入れて 3.88 になり、ZZ9.99 で表示するため先頭の0が空白になります。
コード(.cob / .cbl)
IDENTIFICATION DIVISION.
PROGRAM-ID. FILEIO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT MEMO-FILE ASSIGN TO "memo.txt"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD MEMO-FILE.
01 MEMO-REC PIC X(20).
WORKING-STORAGE SECTION.
01 EOF-FLAG PIC X VALUE "N".
PROCEDURE DIVISION.
OPEN OUTPUT MEMO-FILE.
MOVE "first line" TO MEMO-REC.
WRITE MEMO-REC.
MOVE "second line" TO MEMO-REC.
WRITE MEMO-REC.
CLOSE MEMO-FILE.
OPEN INPUT MEMO-FILE.
PERFORM UNTIL EOF-FLAG = "Y"
READ MEMO-FILE
AT END
MOVE "Y" TO EOF-FLAG
NOT AT END
DISPLAY FUNCTION TRIM(MEMO-REC)
END-READ
END-PERFORM.
CLOSE MEMO-FILE.
STOP RUN.
実行すると
first line second line
ファイルは ENVIRONMENT DIVISION の SELECT で実際のファイル名と結び付け、FD でレコードの形を宣言します。LINE SEQUENTIAL は1レコード1行のテキストファイルで、GnuCOBOL などで使える拡張です。レコードは PIC X(20) の固定長なので、表示の前に TRIM で後ろの空白を取っています。
コード(.cob / .cbl)
IDENTIFICATION DIVISION.
PROGRAM-ID. DIVZERO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 A PIC 9(3) VALUE 10.
01 B PIC 9(3) VALUE 0.
01 Q PIC 9(3) VALUE 0.
PROCEDURE DIVISION.
DIVIDE A BY B GIVING Q
ON SIZE ERROR
DISPLAY "Error: division by zero"
NOT ON SIZE ERROR
DISPLAY "Result: " Q
END-DIVIDE.
DISPLAY "End of program".
STOP RUN.
実行すると
Error: division by zero End of program
COBOL には例外の仕組みの代わりに、計算文ごとに ON SIZE ERROR を付ける書き方があります。0で割ったときや、結果が受け取る変数の桁数に収まらないときに、ON SIZE ERROR の処理が動きます。
出力当てクイズ
コードを読んで、画面に出るものを選んでください。選ぶと正解と理由が出ます(答えはどこにも送られず、記録もしません)。
問1
IDENTIFICATION DIVISION.
PROGRAM-ID. Q1.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(3) VALUE 7.
PROCEDURE DIVISION.
DISPLAY N.
STOP RUN.
画面に出るのは?
PIC 9(3) は「3桁の数字」という宣言で、値は常に3桁で持ちます。そのまま DISPLAY すると、足りない上の桁が0で埋まって 007 と表示されます。
問2
IDENTIFICATION DIVISION.
PROGRAM-ID. Q2.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(3).
PROCEDURE DIVISION.
MOVE 12345 TO N.
DISPLAY N.
STOP RUN.
画面に出るのは?
数値を MOVE すると小数点の位置で桁をそろえ、入りきらない上の桁は切り捨てられます。3桁の N には下3桁の 345 だけが残り、エラーにはなりません。
問3
IDENTIFICATION DIVISION.
PROGRAM-ID. Q3.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9V99.
01 N-DISP PIC 9.99.
PROCEDURE DIVISION.
MOVE 2.71828 TO N.
MOVE N TO N-DISP.
DISPLAY N-DISP.
STOP RUN.
画面に出るのは?
PIC 9V99 は整数1桁・小数2桁の数で、V は小数点の位置だけを表します。MOVE では入りきらない小数の桁は四捨五入されずに切り捨てられるため 2.71 になり、表示用の PIC 9.99 で小数点が付きます。
問4
IDENTIFICATION DIVISION.
PROGRAM-ID. Q4.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 R PIC 99.
01 R-DISP PIC ZZ9.
PROCEDURE DIVISION.
COMPUTE R ROUNDED = 17 / 2.
MOVE R TO R-DISP.
DISPLAY "[" R-DISP "]".
STOP RUN.
画面に出るのは?
17 / 2 は 8.5 で、ROUNDED を付けると四捨五入されて 9 になります(付けなければ切り捨てで 8)。ZZ9 は先頭の0を空白に置き換える編集用の型なので、3桁の幅のまま「 9」と表示されます。
よくあるエラーと直し方
初めて書く人が出会いやすいエラーです。メッセージは英語のまま出ることが多いので、どの言葉を手がかりにすればよいかもあわせて載せています。
コンパイル時 文を書く桁がずれている
エラーになるコード
IDENTIFICATION DIVISION.
PROGRAM-ID. E1.
PROCEDURE DIVISION.
DISPLAY "Hello".
STOP RUN.
画面に出るメッセージ(抜粋)
main.cob:4: error: invalid indicator 'Y' at column 7
何が起きているか:固定形式では7桁目は標識領域で、「*」(注記)や「-」(継続)などの決まった記号しか置けません。DISPLAY を1桁目から書いたため、7桁目に来た「Y」が不正な標識として扱われました。
直し方:文は12桁目以降(B領域)から書きます。行頭に空白を7つ以上入れて、DIVISION などの見出しは8桁目、文は12桁目にそろえます。
コンパイル時 72桁目を超えて書いている
エラーになるコード
IDENTIFICATION DIVISION.
PROGRAM-ID. E2.
PROCEDURE DIVISION.
DISPLAY "This message is much too long to fit before column 72".
STOP RUN.
画面に出るメッセージ(抜粋)
main.cob:4: error: missing terminating " character
何が起きているか:固定形式では73桁目以降は無視されます。文字列の閉じる「"」が73桁目より後ろにあったため、文字列が閉じていないと判断されました。
直し方:1行を72桁目までに収めます。長い文字列は短く分けて DISPLAY に並べるか、継続行(7桁目に「-」)を使います。
コンパイル時 is not defined(定義していない名前)
エラーになるコード
IDENTIFICATION DIVISION.
PROGRAM-ID. E3.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 TOTAL PIC 9(3) VALUE 5.
PROCEDURE DIVISION.
DISPLAY TOTL.
STOP RUN.
画面に出るメッセージ(抜粋)
main.cob:7: error: 'TOTL' is not defined
何が起きているか:TOTAL のつもりで TOTL と書いたため、DATA DIVISION に宣言されていない名前として扱われました。COBOL ではすべての変数を DATA DIVISION で先に宣言する必要があります。
直し方:名前のつづりを宣言と同じ TOTAL に直します。新しい変数なら WORKING-STORAGE SECTION に宣言を足します。
実行時 ON SIZE ERROR なしで0で割る
エラーになるコード
IDENTIFICATION DIVISION.
PROGRAM-ID. E4.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 A PIC 9(3) VALUE 10.
01 B PIC 9(3) VALUE 0.
01 Q PIC 9(3) VALUE 999.
PROCEDURE DIVISION.
DIVIDE A BY B GIVING Q.
DISPLAY "Q = " Q.
STOP RUN.
画面に出るメッセージ(抜粋)
Q = 999(エラーメッセージは出ずに処理が続く)
何が起きているか:ON SIZE ERROR を付けずに0で割ると、GnuCOBOL では止まらずに処理が続き、Q は計算前の 999 のまま残りました。誤った値に気付かないまま後の処理に進むおそれがあります。
直し方:割り算や桁あふれが起こりうる計算には ON SIZE ERROR を付けて、異常時の処理を書きます。割る前に割る数が0でないかを IF で確かめる方法もあります。
桁位置の定規
昔ながらの COBOL(固定形式)は、何桁目から書くかで意味が決まります。コードを貼ると、行ごとにどの領域から書き始めているかを色で分け、決まりから外れた行を知らせます。
- 1〜6桁:一連番号(無視される)
- 7桁:標識(* はコメント)
- 8〜11桁:A領域(見出し・段落名)
- 12〜72桁:B領域(文)
- 73桁〜:無視される
桁の色分けと点検の結果
PIC 句を読む
PIC 句(項目の形)を入れると、何桁・何バイトの項目になるかを出します。値を入れると、MOVE したときに実際に入るもの(切り捨てや符号の消え方)が分かります。
MOVE の結果は GnuCOBOL 3.1.2 で DISPLAY したものと同じになることを確かめています。数字の項目(9・S・V)の表示は処理系で違うことがあり、たとえば PIC 9V99 を DISPLAY すると GnuCOBOL は小数点を入れて出しますが、IBM の処理系では数字だけが並ぶのが普通です。 + や - を並べる書き方(浮動挿入)、P、通貨記号、USAGE(COMP など)はこの道具では扱っていません。
COBOL の技術者のネットワークは、同じ運営元の KOINOBORI COBOLERS(cobolers.jp) にあります。
このツールについて
事務処理のために作られた言語で、英語に近い書き方と10進数の正確な計算を特徴とし、今も金融や行政の基幹システムで動いています。
COBOL の概要と、同じ5つのお題・出力当てクイズ・よくあるエラー。桁位置の定規と PIC 句の道具(MOVE で何が入るか)つき。
主な機能
- 概要(誕生・作った人・型・動かし方)と日本での使われ方・研修・資格
- 5つのお題のコード例(C・C++・Java・C#・VBA の同じお題へ移れる)
- 出力当てクイズ4問(PIC 句の桁あふれ・切り捨てなど)
- 桁位置の定規(A領域・B領域・7桁目・72桁超えを色分けして点検)
- PIC 句の道具(桁数・バイト数・MOVE で入る値と切り捨ての説明)
- 出力は GnuCOBOL 3.1.2 で照合済み・送信ゼロ
よくある質問
Q. 桁位置の定規は何を点検しますか?
A. 固定形式の決まり(1〜6桁目は一連番号、7桁目は標識、8〜11桁目は A領域、12〜72桁目は B領域、73桁目以降は無視)に沿って、7桁目に書けない文字が来ていないか、72桁目を越えていないか、見出しや段落名が A領域から・文が B領域から始まっているかを見ます。全角文字は1文字を1桁として数えるので、実際のコンパイラ(バイト数で数える)とはずれます。
Q. PIC 9V99 に 2.71828 を MOVE すると、なぜ 2.72 ではなく 2.71 になるのですか?
A. MOVE は小数点の位置を揃えてから、入りきらない桁を切り捨てるためです(四捨五入しません)。丸めたいときは COMPUTE … ROUNDED を使います。PIC 句の道具で値を入れると、切り捨てられた桁が分かります。
Q. 出力はどの COBOL で確かめていますか?
A. GnuCOBOL 3.1.2 です。IBM などメインフレームの COBOL とは、数字の項目を DISPLAY したときの見え方などが違うことがあります。
入力値はURLの「#」以降に入るためサーバーには送信されません。リンクを開くと同じ状態を復元します。