サンプルプログラムの作成 2
コーディング解説
前回同様、各部の構成に分解して、それぞれ機能を解説します。なお、前回解説した部分と重複する部分は割愛いたします。
ENVIRONMENT DIVISION
今回は入出力節のみ記述し、入力ファイル2つと出力ファイル2つを定義しています。
000500 ENVIRONMENT DIVISION. 000600 INPUT-OUTPUT SECTION. 000700 FILE-CONTROL. 000800 SELECT I-FILE1 000900 ASSIGN TO W-INPUT-FILENAME1 001000 ORGANIZATION LINE SEQUENTIAL. 001100 SELECT I-FILE2 001200 ASSIGN TO W-INPUT-FILENAME2 001300 ORGANIZATION LINE SEQUENTIAL. 001400 SELECT O-FILE1 001500 ASSIGN TO W-OUTPUT-FILENAME1 001600 ORGANIZATION LINE SEQUENTIAL. 001700 SELECT O-FILE2 001800 ASSIGN TO W-OUTPUT-FILENAME2 001900 ORGANIZATION LINE SEQUENTIAL.
すべて順編成ファイルのため、ORGANIZATION LINE SEQUENTIALの記述があります。
DATA DIVISION
今回もファイル節と作業場所節を記述しています。
ファイル節の記述
順序番号002200から002400と、002500から002700までが入力ファイルのレコード定義、002800から003100と、003200から003500までが出力ファイルのレコード定義です。いずれも1024バイトのエリアを定義していますが、1024バイトの固定長という意味でなく、入出力作業領域とでも理解しておいてください。本稿では固定長レコードを取り扱っていますが、可変長レコードも取り扱うことができます。
002000 DATA DIVISION. 002100 FILE SECTION. 002200 FD I-FILE1 002300 LABEL RECORDS ARE STANDARD. 002400 01 PIC X(1024). 002500 FD I-FILE2 002600 LABEL RECORDS ARE STANDARD. 002700 01 PIC X(1024). 002800 FD O-FILE1 002900 LABEL RECORDS ARE STANDARD. 003000 01 OUT-REC1. 003100 03 PIC X(1024). 003200 FD O-FILE2 003300 LABEL RECORDS ARE STANDARD. 003400 01 OUT-REC2. 003500 03 PIC X(1024).
作業場所節の記述
順序番号003600はコマンドライン引数の個数を格納する変数です。
順序番号003800から004100は、環境部で指定された入出力ファイルのファイル名を指定する変数です。今回はコマンドライン引数から入力するようにしています。
順序番号004200は同一商品コードでの集計に使用します。
順序番号004300から004700はマスタデータのレコードを保存しておく領域です。ファイル節でレコード定義した領域と同じサイズで定義します。順序番号004700のように、使用しない項目はFILLERで定義します。
以下、順序番号004800から005200は売上データのレコードを保存しておく領域、順序番号005300から005800は集計データ出力前データを保存しておく領域です。
003600 WORKING-STORAGE SECTION. 003700 77 ARG PIC 99. 003800 77 W-INPUT-FILENAME1 PIC X(256) VALUE "match.in1". 003900 77 W-INPUT-FILENAME2 PIC X(256) VALUE "match.in2". 004000 77 W-OUTPUT-FILENAME1 PIC X(256) VALUE "match.out". 004100 77 W-OUTPUT-FILENAME2 PIC X(256) VALUE "error.out". 004200 77 WK-CNT PIC 9(7) VALUE 0. 004300 01 INP-REC1. 004400 03 KEYC PIC X(5). 004500 03 NAME PIC X(20). 004600 03 PRICE PIC 99999v99. 004700 03 FILLER PIC X(994). 004800 01 INP-REC2. 004900 03 KEYC PIC X(5). 005000 03 SDATE PIC X(8). 005100 03 CNT PIC 9(5). 005200 03 FILLER PIC X(1006). 005300 01 OUT-REC. 005400 03 KEYC PIC X(5). 005500 03 NAME PIC X(20). 005600 03 PRICE PIC ZZZZ9.99. 005700 03 CNT PIC ZZZ,ZZ9. 005800 03 PROCEEDS PIC ZZ,ZZZ,ZZ9.99.
順序番号004400、004900、005400等で、ファイル編集項目で同一の名称が定義されています。この場合、処理部で当該項目を使用する場合は、項目が特定できるように上位の項目で修飾して使用します。
PROCEDURE DIVISION
コマンドライン引数の利用
前回はファイルの指定をハードコーディングしていましたが、今回はコマンドライン引数を利用します。
順序番号006000で引数の個数を取得しています。今回は入力ファイル2つと出力ファイル2つを引数で取得しますので、引数が4個以外の場合はエラーとしてプログラムの実行を終了します(順序番号006100~006300)。
取得した引数をそれぞれファイル名の領域に格納しています(順序番号006500~006800)。
005900 PROCEDURE DIVISION. 006000 ACCEPT ARG FROM ARGUMENT-NUMBER. 006100 IF ARG <> 4 THEN 006200 DISPLAY "PLEASE SHOW ME FILENAME" 006300 STOP RUN 006400 END-IF. 006500 ACCEPT W-INPUT-FILENAME1 FROM ARGUMENT-VALUE. 006600 ACCEPT W-INPUT-FILENAME2 FROM ARGUMENT-VALUE. 006700 ACCEPT W-OUTPUT-FILENAME1 FROM ARGUMENT-VALUE. 006800 ACCEPT W-OUTPUT-FILENAME2 FROM ARGUMENT-VALUE.
マッチング処理
2つのファイルを読み、いずれもファイル終了になるまで繰り返し処理を行います(順序番号007200、007300)。
まずは先読みをしています(順序番号007000~007100)。
繰り返し処理の内部(順序番号007200~008600)では、入力したファイルのキー(商品コード)の条件により、それぞれの処理を行っています。
- ファイル1とファイル2が同一キーの場合
- ファイル2の内容を集計する。
- 次のファイル2を読む。
- ファイル1のキーが小さい場合
- 集計ファイルを出力
- 次のファイル1を読む
- 上記以外の場合(ファイル2のキーが小さい場合)
- エラーファイルを出力する。
- 次のファイル2を読む。
なお、レコードの入出力部分の処理をPERFOREM文を使って、実際の処理を外書きにしています。1行の処理をわざわざPERFORM文で外書きにする必要は感じられないとの意見もあると思いますが、コーディングの見易さの1つの回答ということで、コーディング規約として採用するベンダは多いと思います。
006900 OPEN INPUT I-FILE1 I-FILE2 OUTPUT O-FILE1 O-FILE2. 007000 PERFORM FILE1-READ. 007100 PERFORM FILE2-READ. 007200 PERFORM UNTIL KEYC OF INP-REC1 = HIGH-VALUE 007300 AND KEYC OF INP-REC2 = HIGH-VALUE 007400 IF KEYC OF INP-REC1 = KEYC OF INP-REC2 THEN 007500 ADD CNT OF INP-REC2 TO WK-CNT 007600 PERFORM FILE2-READ 007700 ELSE 007800 IF KEYC OF INP-REC1 < KEYC OF INP-REC2 THEN 007900 PERFORM FILE1-OUT 008000 PERFORM FILE1-READ 008100 ELSE 008200 PERFORM FILE2-OUT 008300 PERFORM FILE2-READ 008400 END-IF 008500 END-IF 008600 END-PERFORM. 008700 CLOSE I-FILE1 I-FILE2 O-FILE1 O-FILE2. 008800 STOP RUN. 008900 FILE1-READ. 009000 READ I-FILE1 INTO INP-REC1 009100 AT END MOVE HIGH-VALUE TO KEYC OF INP-REC1. 009200 IF KEYC OF INP-REC1 = HIGH-VALUE THEN 009300 NEXT SENTENCE 009400 ELSE 009500 MOVE KEYC OF INP-REC1 TO KEYC OF OUT-REC 009600 MOVE NAME OF INP-REC1 TO NAME OF OUT-REC 009700 MOVE PRICE OF INP-REC1 TO PRICE OF OUT-REC 009800 END-IF. 009900 FILE2-READ. 010000 READ I-FILE2 INTO INP-REC2 010100 AT END MOVE HIGH-VALUE TO KEYC OF INP-REC2. 010200 FILE1-OUT. 010300 MULTIPLY PRICE OF INP-REC1 BY WK-CNT GIVING PROCEEDS. 010400 MOVE WK-CNT TO CNT OF OUT-REC. 010500 WRITE OUT-REC1 FROM OUT-REC. 010600 MOVE ZERO TO WK-CNT. 010700 FILE2-OUT. 010800 WRITE OUT-REC2 FROM INP-REC2.
データ部で同一の項目が定義されているので、上位の名称で修飾して使用しています(順序番号007200等)。
ここでは、"同一の項目名 OF 上位の名称"としていますが、"同一の項目名 IN 上位の名称"という記述でも問題ありません。今回はデータ名が重複していますが、ファイル名や段落名が重複していた場合も同様に上位名称で修飾し、特定が可能となるように記述する必要があります。
コンパイル
今回のサンプルコードを用意しましたので適宜ご利用ください。サンプルコードを適当なディレクトリ、ファイルに格納してコンパイルをします。今回も、単一ソース、単純なプログラムですので、直接実行ファイルを出力する方法とします。
以下は、ソースファイル名をtest-cob02.cobとした場合の例です。
/usr/local/bin/cobc -x test-cob02.cob
コンパイル後に内容を確認してください。エラーがなければ同一のディレクトリに実行ファイル"test-cob02"が作成されているはずです。
