5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ブラウザだけで利用できるCOBOL環境(Ubuntu)を構築する

Last updated at Posted at 2022-03-05

1. はじめに

Paiza Cloud上にCOBOL環境を構築します。あわせてHerculesというホストコンピューターのエミュレータもご紹介します。Windows上でMVSを動かしてJCLからジョブを実行できます。

1.1 用意するもの

  • PaizaCloudのアカウント

1.2 構築内容

  • 対象はOpensource COBOL V1.5.1J(UTF-8) + VBISAMです
  • 画面のカーソルライブラリはncurseです(DISPLAY LINE COL での日本語は文字化けします)

1.3 参考URL

2. 環境構築

2.1 PaizaCloudの起動

いつものようにPaizaCloudを使って環境構築を行います。
image.png

2.2 サーバー作成

今回は特に他のアプリケーションをインストールする必要はありません。何も選択せずに新規サーバ作成ボタンを押して下さい。

image.png

2.3 アプリ構築

サーバが構築できたら、ターミナルを開いて下記のコマンドを投入してください

image.png

gmpの導入

数値計算ライブラリを導入します。

cd
wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.bz2
tar jxvf gmp-6.2.1.tar.bz2
cd gmp-6.2.1/
./configure
make
sudo make install

ncursesの導入

画面カーソルのライブラリを導入します。utf-8対応版のncursesもあるようですが、調べ切りませんでした。
他に検索するとワイド文字対応のncurseswというライブラリを使う方法が出てきますが、こちらは他試したところ私の手順では上手く行きませんでした。
ということで、DISPLAY LINE COL、ACCEPT LINE COLでの日本語は入出力できませんが、ファイルやコンソール出力ではキチンと日本語表示されます。

cd
wget -nc ftp://ftp.gnu.org/gnu/ncurses/ncurses-6.1.tar.gz
tar -xf ncurses-6.1.tar.*
cd ncurses-6.1/
./configure
make 
sudo make install

OpenSourceCOBOLの導入(UTF-8版)

OSSのサイトからダウンロードしたあと、まずはVBISAMをコンパイルします。次に本体のコンパイルを実施します。

cd
wget "https://www.osscons.jp/osscobol/files/?action=cabinet_action_main_download&block_id=414&room_id=21&cabinet_id=11&file_id=406&upload_id=911" -O opensource-cobol-1.5.2J.tar.gz
tar -xvf opensource-cobol-1.5.2J.tar.gz

cd
cd opensource-cobol-152J_utf8/vbisam/
./configure
make
sudo make install

cd
cd opensource-cobol-152J_utf8/
./configure --with-vbisam --enable-utf8
make
sudo make install

導入後のセルフチェック

正しく動作するか確認します

cd
cd opensource-cobol-152J_utf8/
export LD_LIBRARY_PATH=/usr/local/lib
sudo ldconfig	

cd tests
make check

cobc -V
cd

3. COBOLサンプルプログラム

3.1 HELLO WORLD

定番ということでhello worldです。
下記のファイルをhello.cobという名前で作成してください

hello.cob
000010 IDENTIFICATION                   DIVISION.
000020 PROGRAM-ID.                      HELLO.
000030 ENVIRONMENT                      DIVISION.
000040 DATA                             DIVISION.
000050 PROCEDURE                        DIVISION.
000060 MAIN.
000070     DISPLAY "HELLO WORLD".
000080     STOP RUN.

これをコンパイルして実行します。
ちなみに、このソースファイルの最終行には空行が必須です。空行はスペースやタブがあっても駄目です。この空行がないとhello.cob:7: Warning: Line not terminated by a newlineエラーになります。

cobc -x hello.cob
./hello
HELLO WORLD

3.2 ファイル入出力の例

こちらも定番だと思いますが、ファイルの入出力です。商品マスタと売上明細を突き合わせてレポートファイルを作成しています。

  1. 商品マスタを商品コードでソートする
  2. 売上明細も商品コードでソートする
  3. 両ファイルを一行ずつ読む
  4. 商品マスタの商品コードが売上明細の商品コードより大きければ、売上明細なしと判定
  5. どちらも同じ商品コードであれば、レポートを1行出力して次の売上明細を読み込む
  6. 商品マスタの商品コードより売上明細の商品コードが大きければ、次の商品マスタのレコードを読み込む
item.cob
       IDENTIFICATION    DIVISION.
       PROGRAM-ID.       ITEM.
       ENVIRONMENT       DIVISION.
       INPUT-OUTPUT      SECTION.
       FILE-CONTROL.    
           SELECT MASTER-INPT ASSIGN TO "./MASTER.TXT".
           SELECT MASTER-SORT ASSIGN TO "./MASTER-SORT.TXT".
           SELECT MASTER-TEMP ASSIGN TO "./MASTER-TEMP.TXT".
      *
           SELECT SALES-INPT  ASSIGN TO "./SALES.TXT".
           SELECT SALES-SORT  ASSIGN TO "./SALES-SORT.TXT".
           SELECT SALES-TEMP  ASSIGN TO "./SALES-TEMP.TXT".
      *
           SELECT MASTER-FILE ASSIGN TO "./MASTER-SORT.TXT".
           SELECT DETAIL-FILE ASSIGN TO "./SALES-SORT.TXT".
           SELECT REPORT-FILE ASSIGN TO "./REPORT.TXT".
      *
       DATA              DIVISION.
       FILE              SECTION.
      * 商品マスタ(ソート前)
       FD MASTER-INPT.
       01 M-INPT-RECORD.
           05 M-INPT-CODE          PIC X(07).
           05 M-INPT-COMMA1        PIC X(01).
           05 M-INPT-NAME          PIC N(09).
           05 M-INPT-COMMA2        PIC X(01).
           05 M-INPT-PRICE         PIC 9(06).
           05 M-INPT-CRLF          PIC X(02).
      * 商品マスタ(ソート後)
       FD MASTER-SORT.
       01 M-SORT-RECORD            PIC X(44).
      * 商品マスタ(処理用)
       SD MASTER-TEMP.
       01 M-TEMP-RECORD.
           05 M-TEMP-CODE          PIC X(07).
           05 M-TEMP-COMMA1        PIC X(01).
           05 M-TEMP-NAME          PIC N(09).
           05 M-TEMP-COMMA2        PIC X(01).
           05 M-TEMP-PRICE         PIC 9(06).
           05 M-TEMP-CRLF          PIC X(02).
      *
      * 売上明細(ソート前)
       FD SALES-INPT.
       01 S-INPT-RECORD.
           05 S-INPT-DATE          PIC X(08).
           05 S-INPT-COMMA1        PIC X(01).
           05 S-INPT-CODE          PIC X(07).
           05 S-INPT-COMMA2        PIC X(01).
           05 S-INPT-COUNT         PIC 9(04).
           05 S-INPT-CRLF          PIC X(02).
      * 売上明細(ソート後)
       FD SALES-SORT.
       01 S-SORT-RECORD            PIC X(23).
      * 売上明細(処理用)
       SD SALES-TEMP.
       01 S-TEMP-RECORD.
           05 S-TEMP-DATE          PIC X(08).
           05 S-TEMP-COMMA1        PIC X(01).
           05 S-TEMP-CODE          PIC X(07).
           05 S-TEMP-COMMA2        PIC X(01).
           05 S-TEMP-COUNT         PIC 9(04).
           05 S-TEMP-CRLF          PIC X(02).
      *
       FD  MASTER-FILE.
       01  MASTER-FILER.
           05  MASTER-RECORD       PIC X(44).
       FD  DETAIL-FILE.
       01  DETAIL-FILER.
           05  DETAIL-RECORD       PIC X(23).
       FD  REPORT-FILE.
       01  REPORT-FILER.
           05  REPORT-RECORD       PIC X(60).
      *
       WORKING-STORAGE       SECTION.
       01  WORK.
           05  MASTER-KEY          PIC X(07).
           05  DETAIL-KEY          PIC X(07).
      *
       01  MASTER-RECORD-WORK.
           05  MASTER-SYOHIN-CODE  PIC X(07).
           05  MASTER-COMMA1       PIC X(01).
           05  MASTER-SYOHIN-NAME  PIC N(09).
           05  MASTER-COMMA2       PIC X(01).
           05  MASTER-SYOHIN-PRICE PIC 9(06).
           05  MASTER-CRLF         PIC X(02).
      *
       01  DETAIL-RECORD-WORK.
           05  DETAIL-HANBAI-DATE  PIC X(08).
           05  DETAIL-COMMA2       PIC X(01).
           05  DETAIL-SYOHIN-CODE  PIC X(07).
           05  DETAIL-COMMA1       PIC X(01).
           05  DETAIL-HANBAI-KOSUU PIC 9(04).
           05  DETAIL-CRLF         PIC X(02).
      *
       01  REPORT-RECORD-WORK.
           05  REPORT-SYOHIN-CODE  PIC X(07).
           05  REPORT-COMMA1       PIC X(01) VALUE ','.
           05  REPORT-SYOHIN-NAME  PIC N(09).
           05  REPORT-COMMA2       PIC X(01) VALUE ','.
           05  REPORT-SYOHIN-PRICE PIC 9(06).
           05  REPORT-COMMA3       PIC X(01) VALUE ','.
           05  REPORT-HANBAI-KOSUU PIC 9(04).
           05  REPORT-COMMA4       PIC X(01) VALUE ','.
           05  REPORT-HANBAI-TOTAL PIC 9(10).
           05  REPORT-CRLF         PIC X(02) VALUE X'0D0A'.
      *
      *----------------------------------------
       PROCEDURE           DIVISION.
      *---------------------------------------- 
      * 各種処理の呼び出し
       PROGRAM-START.
           PERFORM  SORT-START THRU SORT-END.
           PERFORM  INIT-START THRU INIT-END.
           PERFORM  MAIN-START THRU MAIN-END
               UNTIL MASTER-KEY = HIGH-VALUE
               AND   DETAIL-KEY = HIGH-VALUE.
           PERFORM  CLOSE-START THRU CLOSE-END.
           STOP RUN.
       PROGRAM-END.
      *
      * 商品コードでのソート処理
       SORT-START.
           SORT MASTER-TEMP
               ASCENDING KEY M-TEMP-CODE
               USING  MASTER-INPT
               GIVING MASTER-SORT.
      *
           SORT SALES-TEMP
               ASCENDING KEY S-TEMP-CODE
               USING  SALES-INPT
               GIVING SALES-SORT.
       SORT-END.
      * 
      * 初回の読み込み
       INIT-START.
           OPEN  INPUT  MASTER-FILE.
           OPEN  INPUT  DETAIL-FILE.
           OPEN  OUTPUT REPORT-FILE.
           PERFORM MASTER-READ-START THRU MASTER-READ-END.
           PERFORM DETAIL-READ-START THRU DETAIL-READ-END.
       INIT-END.
      * 
      * 繰り返し処理
       MAIN-START.
           IF     MASTER-KEY < DETAIL-KEY
                  PERFORM ONLY-MASTER-START THRU ONLY-MASTER-END
           ELSE
               IF MASTER-KEY = DETAIL-KEY
                  PERFORM MATCHED-START     THRU MATCHED-END
               ELSE
                  PERFORM NO-MATCHED-START  THRU NO-MATCHED-END
               END-IF
           END-IF.
       MAIN-END.
      * 
      * 商品マスタ読み込み
       MASTER-READ-START.
           READ MASTER-FILE
           AT END
               MOVE HIGH-VALUE TO MASTER-KEY
               GO TO MASTER-READ-END
           END-READ.
           MOVE MASTER-RECORD      TO MASTER-RECORD-WORK.
           MOVE MASTER-SYOHIN-CODE TO MASTER-KEY.
       MASTER-READ-END.
      * 
      * 売上明細読み込み
       DETAIL-READ-START.
           READ DETAIL-FILE
           AT END
               MOVE HIGH-VALUE TO DETAIL-KEY
               GO TO DETAIL-READ-END
           END-READ.
           MOVE DETAIL-RECORD      TO DETAIL-RECORD-WORK.
           MOVE DETAIL-SYOHIN-CODE TO DETAIL-KEY.
       DETAIL-READ-END.
      * 
      * 商品マスタに対応する明細がない
       ONLY-MASTER-START.
           PERFORM MASTER-READ-START THRU MASTER-READ-END.
       ONLY-MASTER-END.
      * 
      * 商品マスタに対応する明細がある
       MATCHED-START.
           PERFORM UNTIL MASTER-KEY < DETAIL-KEY
               MOVE     MASTER-SYOHIN-CODE  TO REPORT-SYOHIN-CODE
               MOVE     MASTER-SYOHIN-NAME  TO REPORT-SYOHIN-NAME
               MOVE     MASTER-SYOHIN-PRICE TO REPORT-SYOHIN-PRICE
               MOVE     DETAIL-HANBAI-KOSUU TO REPORT-HANBAI-KOSUU
               MULTIPLY DETAIL-HANBAI-KOSUU BY MASTER-SYOHIN-PRICE
                                        GIVING REPORT-HANBAI-TOTAL
               MOVE     REPORT-RECORD-WORK  TO REPORT-FILER
               WRITE    REPORT-FILER
               PERFORM  DETAIL-READ-START THRU DETAIL-READ-END
           END-PERFORM.
           PERFORM MASTER-READ-START THRU MASTER-READ-END.
       MATCHED-END.
      * 
      * 明細に対応する商品マスタがない
       NO-MATCHED-START.
           DISPLAY 'TRAN ONLY ' MASTER-KEY DETAIL-KEY.
           PERFORM DETAIL-READ-START   THRU DETAIL-READ-END.
       NO-MATCHED-END.
      * 
      * 終了処理
       CLOSE-START.
           CLOSE  MASTER-FILE.
           CLOSE  DETAIL-FILE.
           CLOSE  REPORT-FILE.
       CLOSE-END.

データファイルはこんな感じです。

MASTER.TXT
0000001,チョコ詰め合わせ ,000300
0000002,きざみショウガ煎餅,000500
0000004,ほろほろクッキー ,000010
0000003,10色豆アラカルト,000300
SALES.TXT
20220102,0000004,0012
20220103,0000002,0005
20220104,0000001,0001
20220105,0000003,0021
20220106,0000002,0008
20220107,0000001,0030
20220108,0000004,0009
20220109,0000003,0005
  • 漢字はUTF-8なので3バイト換算です
  • 入力ファイル(MASTER.TXT,SALES.TXT)の行末はCRLF(0x0A0D)の2バイトで設計されています。
  • ただし、ファイルの作成方法によっては、行の終端がLFのみとなる場合があり、その場合は結果が崩れてしまいます。
  • なので、実行結果がおかしい場合は、hexdump ファイル名 で実ファイルの行末を確認して下さい。
  • 例えばSALES.TXTの行末がCRLFではなくLFだけの場合は、item.cobの50,62,93行目のX(02)をX(01)にして、53、69行目のX(23)をX(22)に書き換えればよいと思います。

3.3 画面入出力の例

 こちらは画面入出力のサンプルです。日本語は使えません。
 プログラムの内容は入力された日付の指定月後の応当日を求めるプログラムです。

  • 入力日付が日付として成立するかチェック
  • うるう年簡略化のため入力年を1951年~2099年に限定
  • 入力日が月末であれば、応当日も末日に設定(末末対応)
  • 応当日が月の大小の関係で暦日でない場合は、応当日は月末に設定
period.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID.             MAIN.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WORK.
           05  Y1        PIC 9(1).
           05  Y2        PIC 9(1) VALUE 4.
           05  Y3        PIC 9(4).
       01  INPUTS.
           05  INPUT-DATE.
               10 INPUT-YEAR   PIC 9(4).
               10 INPUT-MONTH  PIC 9(2).
               10 INPUT-DAY    PIC 9(2).
           05  INPUT-PERIOD  PIC 99.
           05  INPUT-CMD     PIC 9.
       01  OUTPUTS.
           05  OUTPUT-DATE.
               10 OUTPUT-YEAR   PIC 9(4).
               10 OUTPUT-MONTH  PIC 9(2).
               10 OUTPUT-DAY    PIC 9(2).
       01  INDICATORS.
           05  MSG         PIC X(40)      VALUE "***".
           05  TMP        PIC 9(1).
       SCREEN SECTION.
       01  DATA-ENTRY-SCREEN.
           05  VALUE "Period Date Calculator" BLANK SCREEN  
                                                    LINE 1 COL 10.
           05  VALUE "Start(date)"                  LINE 3 COL 5.
           05  DATE-INPUT                           LINE 3 COL 25
               PIC  9(8)  TO INPUT-DATE.
           05  VALUE "Period(month)"                LINE 4 COL 5.
           05  PERIOD-INPUT                         LINE 4 COL 25
               PIC 99     TO INPUT-PERIOD.
           05  VALUE "1:Go  9:Exit"                 LINE 6 COL 5.
           05  RESPONSE-INPUT                       LINE 6 COL 25
               PIC 9      TO INPUT-CMD.
           05  SYSTEM-MSG                           LINE 8 COL 5
               PIC X(40)      FROM MSG.
      *
      *----------------------------------------
       PROCEDURE DIVISION.
      *----------------------------------------
      * 各種処理の呼び出し
       PROGRAM-START.
         PERFORM LOOP-START THRU LOOP-END
 	         UNTIL INPUT-CMD = 9.
         STOP RUN.
       PROGRAM-END.
      *
      * ループ処理
       LOOP-START.
         DISPLAY DATA-ENTRY-SCREEN.
         ACCEPT DATA-ENTRY-SCREEN.
      *  -------------------------------
      *  STEP1 入力年月の検査
         IF INPUT-YEAR > 1950 AND INPUT-YEAR < 2100
           THEN 
             IF INPUT-MONTH > 0 AND INPUT-MONTH < 13
               THEN
                 IF INPUT-DAY > 0 AND INPUT-DAY < 32
                   THEN
                     MOVE "STEP1" TO MSG;
                   ELSE 
                     MOVE "DAY ERROR!" TO MSG;
                 END-IF
               ELSE 
                 MOVE "MONTH ERROR!" TO MSG;
             END-IF
           ELSE
             MOVE "YEAR ERROR! (1951 - 2099)" TO MSG;
         END-IF.
      *  -------------------------------
      *  STEP2 入力日の検査(末日ならSETEP3へ)
         IF MSG = "STEP1"
           THEN
             MOVE "STEP2" TO MSG;
      *      2月の場合
             IF INPUT-MONTH = 2
               THEN
                 DIVIDE Y2 INTO INPUT-YEAR GIVING Y3 REMAINDER Y1;
                 IF Y1 = 0
                   THEN
                     IF INPUT-DAY > 29
                       THEN
                         MOVE "DAY ERROR!! -29" TO MSG;
                     END-IF
                     IF INPUT-DAY = 29
                       THEN
                         MOVE "STEP3" TO MSG;
                     END-IF
                   ELSE
                     IF INPUT-DAY > 28
                       THEN
                         MOVE "DAY ERROR!! -28" TO MSG;
                     END-IF
                     IF INPUT-DAY = 28
                       THEN
                         MOVE "STEP3" TO MSG;
                     END-IF
                 END-IF
             END-IF
      *      小の月、大の月
             IF    INPUT-MONTH = 4
                OR INPUT-MONTH = 6
                OR INPUT-MONTH = 9
                OR INPUT-MONTH = 11
               THEN
                 IF INPUT-DAY > 30
                   THEN
                     MOVE "DAY ERROR!! -30" TO MSG;
                 END-IF
                 IF INPUT-DAY = 30
                   THEN
                     MOVE "STEP3" TO MSG;
                 END-IF
               ELSE
                 IF INPUT-DAY > 31
                   THEN
                     MOVE "DAY ERROR!! -31" TO MSG;
                 END-IF
                 IF INPUT-DAY = 31
                   THEN
                     MOVE "STEP3" TO MSG;
                 END-IF
             END-IF
         END-IF.
      *  -------------------------------
      *  STEP2 入力日の検査(末日ならSETEP3へ)
         IF MSG = "STEP2"
           THEN
             IF INPUT-PERIOD > 0 AND INPUT-PERIOD < 24
               THEN 
      *          応答する年月を算出
                 MOVE INPUT-YEAR TO OUTPUT-YEAR;
                 MOVE INPUT-DAY TO OUTPUT-DAY;
                 ADD INPUT-MONTH INPUT-PERIOD GIVING OUTPUT-MONTH;
                 IF OUTPUT-MONTH > 12
                   THEN
                     SUBTRACT 12 FROM OUTPUT-MONTH;
                     ADD 1 TO OUTPUT-YEAR;
                 END-IF
      *          応答月が2月の場合
                 IF OUTPUT-MONTH = 2
                   THEN
                     DIVIDE Y2 INTO OUTPUT-YEAR 
                                      GIVING Y3 REMAINDER Y1;
                     IF Y1 = 0
                       THEN
                         IF OUTPUT-DAY > 29
                           THEN
                             MOVE 29 TO OUTPUT-DAY;
                         END-IF
                       ELSE
                         IF OUTPUT-DAY > 28
                           THEN
                             MOVE 28 TO OUTPUT-DAY;
                         END-IF
                     END-IF
                 END-IF
                 IF    OUTPUT-MONTH = 4
                    OR OUTPUT-MONTH = 6
                    OR OUTPUT-MONTH = 9
                    OR OUTPUT-MONTH = 11
                   THEN
      *              応答月が小の月の場合
                     IF OUTPUT-DAY > 30
                       THEN
                         MOVE 30 TO OUTPUT-DAY;
                     END-IF
                   ELSE
      *              応答月が大の月の場合
                     IF INPUT-DAY > 31
                       THEN
                         MOVE 31 TO OUTPUT-DAY;
                     END-IF
                 END-IF
      *          応答日を回答として設定
                 MOVE OUTPUT-DATE TO MSG;
               ELSE
                 MOVE "PERIOD ERROR!! 1-23" TO MSG;
             END-IF
         END-IF.
      *
      *  STEP3 末末応当日
         IF MSG = "STEP3"
           THEN
      *      応答する年月を算出
             MOVE INPUT-YEAR TO OUTPUT-YEAR;
             MOVE INPUT-DAY TO OUTPUT-DAY;
             ADD INPUT-MONTH INPUT-PERIOD GIVING OUTPUT-MONTH;
      *      応答月が2月の場合
             IF OUTPUT-MONTH = 2
               THEN
                 DIVIDE Y2 INTO OUTPUT-YEAR 
                                  GIVING Y3 REMAINDER Y1;
                 IF Y1 = 0
                   THEN
                     MOVE 29 TO OUTPUT-DAY;
                   ELSE
                     MOVE 28 TO OUTPUT-DAY;
                 END-IF
             END-IF
             IF    OUTPUT-MONTH = 4
                OR OUTPUT-MONTH = 6
                OR OUTPUT-MONTH = 9
                OR OUTPUT-MONTH = 11
               THEN
      *          応答月が小の月の場合
                 MOVE 30 TO OUTPUT-DAY;
               ELSE
      *          応答月が大の月の場合
                 MOVE 31 TO OUTPUT-DAY;
             END-IF
      *          応答日を回答として設定
             MOVE OUTPUT-DATE TO MSG;
         END-IF.
       LOOP-END.

 まぁなんて保守性のないソースでしょうか・・・。やっつけ感が満載ですが、とりあえず動いたのでサンプルとして載せました。

付録 Herculesのご紹介

こちらは記事のご紹介です。手順通り実施するとWindows上で仮想MVSが動作します。JCLが動きますので、そういった部分の自宅学習にはよいのではないでしょうか。

最後に

いかがだったでしょうか。恥ずかしながら初めてCOBOLのプログラムを書いてみました。なので書き方がイマイチなのだとは思うのですが、プログラムをシンプルに書けるのは良いなと思いました。
 
 DISPLAY LINE COL で日本語が使えないとか、REPORT SECTIONがサポートされていないとか、構築環境がイマイチなのかもしれません。OpenSourceさんからはDocker版が提供されているので、Dockerを利用できる人はそちらを使って学習するのが最も良い気がします。

次回こそ・・・

 IPFSを使ったNFTに挑戦したいと思います。

記事一覧

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?