2021-03-04

GnuCOBOL と Fedora

COBOL /ˈkoʊbɒl, -bɔːl/ (COmmon Business-Oriented Language) は、Grace Hopper 氏が開発したプログラミング言語 FLOW-MATIC を部分的にベースにして、1959 年に CODASYL によって開発されました。現在の規格は ISO/IEC 1989:2014 です。

COBOL は、事務処理で使用するために設計され、主に企業や政府の事務処理、財務、行政システムなどで使用されており、大規模なバッチ処理やトランザクション処理のジョブなど、メインフレーム上に展開されるアプリケーションでは、現在でも広く使用されています。しかし、COBOL の人気の低下と経験豊富な COBOL プログラマーのリタイアにより、プログラムは新しいプラットフォームに移行されたり、最近の言語で書き換えられたり、ソフトウェアパッケージに置き換えられたりしています。そのため COBOL のプログラミングのほとんどは、現在では純粋に既存のアプリケーションを維持するために使われています。

Wikipedia より引用、翻訳・編集

Fedora Magazine の記事

たまにしか読まない Fedora Magazine の記事ですが、GnuCOBOL の記事がありましたので少し使ってみました。

GnuCOBOL について

GnuCOBOLは、COBOL のソースコードを C 言語のソースコードに変換します。その後、C のソースコードは、コンピュータが使用する実際のバイナリ(オブジェクト・コード)にコンパイルされたり、他のプログラムが呼び出すことができるライブラリにコンパイルされたりすることができます。

UNIX や類似のオペレーティングシステム(Linux など)では、GNU C コンパイラを使用します。Windows では、Microsoft Visual Studio Express パッケージの C コンパイラを使用します。

GnuCOBOL の開発は、COBOL 2014 仕様までの COBOL 規格に沿ったものになるように努力し、既存のコンパイラに共通する機能を含むようにしていますが、開発者は規格準拠のレベルを主張していません。 それでも、2.2 Final リリースでは、NIST COBOL 85 テスト・スイートに含まれる 9,708 テストのうち、9,688 テスト (99.79%) 以上にパスしています。

Wikipedia より引用、翻訳・編集

GnuCOBOL のインストール

使用している環境は以下の通りです。

Fedora 34 (Workstation Edition Prerelease) x86_64

以下のようにインストールします。

[bitwalk@fedora-pc ~]$ sudo dnf install gnucobol
[sudo] bitwalk のパスワード:
...
依存関係が解決しました。
================================================================================
 パッケージ        Arch           バージョン               リポジトリー   サイズ
================================================================================
インストール:
 gnucobol          x86_64         3.1.2-2.fc34             fedora         770 k
依存関係のインストール:
 gmp-c++           x86_64         1:6.2.0-6.fc34           fedora          19 k
 gmp-devel         x86_64         1:6.2.0-6.fc34           fedora         174 k
 libcob            x86_64         3.1.2-2.fc34             fedora         196 k

トランザクションの概要
================================================================================
インストール  4 パッケージ

ダウンロードサイズの合計: 1.1 M
インストール後のサイズ: 3.5 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
    :
    :
インストール済み:
  gmp-c++-1:6.2.0-6.fc34.x86_64         gmp-devel-1:6.2.0-6.fc34.x86_64
  gnucobol-3.1.2-2.fc34.x86_64          libcob-3.1.2-2.fc34.x86_64

完了しました!
[bitwalk@fedora-pc ~]$

コンパイルコマンドは cobc です。

[bitwalk@fedora-pc ~]$ cobc -V
cobc (GnuCOBOL) 3.1.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch, Edward Hart
Built     Jan 26 2021 00:00:00
Packaged  Dec 23 2020 12:04:58 UTC
C version "11.0.0 20210123 (Red Hat 11.0.0-0)"
[bitwalk@fedora-pc ~]$	

COBOL のサンプル

Wikipedia より COBOL のサンプル、実例2 (Hello world) の出力文字列を一部、日本語に替えたサンプルを使います。

hello.cob
000100 IDENTIFICATION DIVISION.
000200 PROGRAM-ID. HELLO.
000300 DATA DIVISION.
000400 WORKING-STORAGE SECTION.
000500 01 HELLO1      PIC X(30).
000600 01 HELLO2.
000700     03 FILLER  PIC X(06) VALUE 'HELLO,'.
000800     03 FILLER  PIC X(01) VALUE SPACE.
000900     03 FILLER  PIC X(06) VALUE 'WORLD!'.
001000     03 FILLER  PIC X(01) VALUE SPACE.
001100     03 FILLER  PIC 9(01) VALUE 2.
001200 PROCEDURE DIVISION.
001300     MOVE 'こんにちは、世界! 1' TO HELLO1.
001400     DISPLAY HELLO1.
001500     DISPLAY HELLO2.
001600     STOP RUN.

COBOL ソースの編集には、vim を使いました。

vim でソースを編集

サンプルのコンパイルと実行

cobc -x でソースを実行可能なバイナリにコンパイル・ビルドしますが、さらに冗長オプション -v を付加して、ビルドの流れを出力するようにしました。

[bitwalk@fedora-pc cobol-sample]$ cobc -x -v hello.cob
cobc (GnuCOBOL) 3.1.2.0
Built     Jan 26 2021 00:00:00  Packaged  Dec 23 2020 12:04:58 UTC
C version "11.0.0 20210123 (Red Hat 11.0.0-0)"
loading standard configuration file 'default.conf'
command line:   cobc -x -v hello.cob
preprocessing:  hello.cob -> /tmp/cob4184_0.cob
return status:  0
parsing:        /tmp/cob4184_0.cob (hello.cob)
return status:  0
translating:    /tmp/cob4184_0.cob -> /tmp/cob4184_0.c (hello.cob)
executing:      gcc -c -fexceptions -grecord-gcc-switches -pipe -Wall
                -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2
                -Wp,-D_GLIBCXX_ASSERTIONS
                -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
                -fstack-protector-strong
                -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64
                -mtune=generic -fstack-clash-protection -fcf-protection
                -fstack-protector-strong -pipe -U_FORTIFY_SOURCE
                -D_FORTIFY_SOURCE=2 -I/usr/include -Wno-unused -fsigned-char
                -Wno-pointer-sign -O -o "/tmp/cob4184_0.o" "/tmp/cob4184_0.c"
return status:  0
executing:      gcc -Wl,--export-dynamic -o "hello" "/tmp/cob4184_0.o"
                -Wl,-z,relro -Wl,--as-needed -Wl,-z,now
                -specs=/usr/lib/rpm/redhat/redhat-hardened-ld
                -fstack-protector-strong -L/usr/lib64 -lcob -lm
return status:  0

ビルドの流れは以下のようになります。

[COBOL ソース]hello.cob →[前処理]/tmp/cob4184_0.cob →[C ソースへ変換]/tmp/cob4184_0.c → [コンパイルされたオブジェクト]/tmp/cob4184_0.o →[実行形式]hello

ビルドしたプログラムを実行します。

[bitwalk@fedora-pc cobol-sample]$ ls
hello  hello.cob
[bitwalk@fedora-pc cobol-sample]$ ./hello
こんにちは、世界! 1
HELLO, WORLD! 2
[bitwalk@fedora-pc cobol-sample]$

一応、日本語フォントも表示できますが、UTF-8 のエンコードでは文字のバイト数は固定ではなく、例えば日本語フォントは 3 バイトになっていているので注意が必要です。

COBOL ソースを C ソースへ変換

COBOL ソースを C ソースへ変換するだけ、ということもできます。-x の代わりに -C オプションを指定します。

[bitwalk@fedora-pc cobol-sample]$ cobc -C -v hello.cob
cobc (GnuCOBOL) 3.1.2.0
Built     Jan 26 2021 00:00:00  Packaged  Dec 23 2020 12:04:58 UTC
C version "11.0.0 20210123 (Red Hat 11.0.0-0)"
loading standard configuration file 'default.conf'
command line:   cobc -C -v hello.cob
preprocessing:  hello.cob -> /tmp/cob2258_0.cob
return status:  0
parsing:        /tmp/cob2258_0.cob (hello.cob)
return status:  0
translating:    /tmp/cob2258_0.cob -> hello.c (hello.cob)
[bitwalk@fedora-pc cobol-sample]$ ls
hello  hello.c  hello.c.h  hello.c.l.h  hello.cob

変換された hello.c は、下記のようになっています。

hello.c
/* Generated by           cobc 3.1.2.0 */
/* Generated from         hello.cob */
/* Generated at            3月 04 2021 14:09:05 */
/* GnuCOBOL build date    Jan 26 2021 00:00:00 */
/* GnuCOBOL package date  Dec 23 2020 12:04:58 UTC */
/* Compile command        cobc -C -v hello.cob */

#include <stdio.h>
#include <string.h>
#define  COB_KEYWORD_INLINE __inline
#include <libcob.h>

#define  COB_SOURCE_FILE                "hello.cob"
#define  COB_PACKAGE_VERSION            "3.1.2"
#define  COB_PATCH_LEVEL                0
#define  COB_MODULE_FORMATTED_DATE      " 3月 04 2021 19:09:05"
#define  COB_MODULE_DATE                20210304
#define  COB_MODULE_TIME                140905

/* Global variables */
#include "hello.c.h"

/* Function prototypes */

int             HELLO (void);
static int              HELLO_ (const int);
static void             HELLO_module_init (cob_module *module);

/* Functions */

/* PROGRAM-ID 'HELLO' */

/* ENTRY 'HELLO' */

int
HELLO ()
{
  return HELLO_ (0);
}

static int
HELLO_ (const int entry)
{
  /* Program local variables */
  #include "hello.c.l.h"

  /* Start of function code */

  /* CANCEL callback */
  if (unlikely(entry < 0)) {
        if (entry == -10)
                goto P_dump;
        if (entry == -20)
                goto P_clear_decimal;
        goto P_cancel;
  }

  /* Check initialized, check module allocated, */
  /* set global pointer, */
  /* push module stack, save call parameter count */
  if (cob_module_global_enter (&module, &cob_glob_ptr, 0, entry, 0))
        return -1;

  /* Set address of module parameter list */
  module->cob_procedure_params = cob_procedure_params;

  /* Set frame stack pointer */
  frame_ptr = frame_stack;
  frame_ptr->perform_through = 0;
  frame_ptr->return_address_ptr = &&P_cgerror;

  /* Initialize rest of program */
  if (unlikely(initialized == 0)) {
        goto P_initialize;
  }
  P_ret_initialize:

  /* Increment module active */
  module->module_active++;

  /* Entry dispatch */
  goto l_2;

  /* PROCEDURE DIVISION */

  /* Line: 12        : Entry     HELLO                   : hello.cob */
  l_2:;

  /* Line: 13        : MOVE               : hello.cob */
  memcpy (b_8, "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257\343\200\201\344\270\226\347\225\214\357\274\201 1 ", 30);

  /* Line: 14        : DISPLAY            : hello.cob */
  cob_display (0, 1, 1, &f_8);

  /* Line: 15        : DISPLAY            : hello.cob */
  cob_display (0, 1, 1, &f_9);

  /* Line: 16        : STOP RUN           : hello.cob */
  cob_stop_run (b_2);

  /* Program exit */

  /* Decrement module active count */
  if (module->module_active) {
        module->module_active--;
  }

  /* Pop module stack */
  cob_module_leave (module);

  /* Program return */
  return b_2;
  P_cgerror:
        cob_fatal_error (COB_FERROR_CODEGEN);


  /* Program initialization */
  P_initialize:

  cob_check_version (COB_SOURCE_FILE, COB_PACKAGE_VERSION, COB_PATCH_LEVEL);

  HELLO_module_init (module);

  module->crt_status = NULL;

  /* Initialize cancel callback */
  cob_set_cancel (module);

  /* Initialize WORKING-STORAGE */
  b_2 = 0;
  memset (b_8, 32, 30);
  memcpy (b_9, "HELLO,", 6);
  *(cob_u8_ptr)(b_9 + 6) = 32;
  memcpy (b_9 + 7, "WORLD!", 6);
  *(cob_u8_ptr)(b_9 + 13) = 32;
  *(b_9 + 14) = 50;

  if (0 == 1) goto P_cgerror;
  initialized = 1;
  goto P_ret_initialize;

  P_dump:
    return 0;


  /* CANCEL callback handling */
  P_cancel:

  if (!initialized)
        return 0;
  if (module && module->module_active)
        cob_fatal_error (COB_FERROR_CANCEL);

  b_2 = 0;
  cob_module_free (&module);

  initialized = 0;

  P_clear_decimal:
  return 0;

}

/* End PROGRAM-ID 'HELLO' */

/* Initialize module structure for HELLO */
static void HELLO_module_init (cob_module *module)
{
  module->module_name = "HELLO";
  module->module_formatted_date = COB_MODULE_FORMATTED_DATE;
  module->module_source = COB_SOURCE_FILE;
  module->module_entry.funcptr = (void *(*)())HELLO;
  module->module_cancel.funcptr = (void *(*)())HELLO_;
  module->module_ref_count = NULL;
  module->module_path = &cob_module_path;
  module->module_active = 0;
  module->module_date = COB_MODULE_DATE;
  module->module_time = COB_MODULE_TIME;
  module->module_type = 0;
  module->module_param_cnt = 0;
  module->ebcdic_sign = 0;
  module->decimal_point = '.';
  module->currency_symbol = '$';
  module->numeric_separator = ',';
  module->flag_filename_mapping = 1;
  module->flag_binary_truncate = 1;
  module->flag_pretty_display = 1;
  module->flag_host_sign = 0;
  module->flag_no_phys_canc = 0;
  module->flag_main = 0;
  module->flag_fold_call = 0;
  module->flag_exit_program = 0;
  module->flag_debug_trace = 0;
  module->flag_dump_ready = 0;
  module->module_stmt = 0;
  module->module_sources = NULL;
}

/* End functions */

他に、hello.c.hhello.c.l.h が生成されていますが、内容は割愛します。

cobc コマンドのオプション概略

cobc コマンドのオプションで主要なものをまとめました。訳に自信がない箇所は英語そのままにしました。

cobc コマンドの主要オプション
オプション説  明
-h, -helpコマンドのヘルプを表示
-V, -versionコンパイラのバージョンを表示
-i, -infoコンパイラの情報を表示
-v, -verbose冗長表示
-q, -brief表示を削減
-###-v と同じ、ただし実際にコマンドは実行しない
-x実行可能プログラムをビルド
-m動的にロードできるモジュールをビルド(デフォルト)
-j [<args>], -job[=<args>]プログラムをビルドした後に引数 <args> を渡してプログラムを実行
-std=<dialect>指定した COBOL 方言 <dialect> に対応した警告あるいは特性。指定できる方言は次の通り:
default, cobol2014, cobol2002, cobol85, xopen, ibm-strict, ibm, mvs-strict, mvs, mf-strict, mf, bs2000-strict, bs2000, acu-strict, acu, rm-strict, rm;
-F, -freeソースコードにフリーフォーマットを使用する
-fixedソースコードに固定フォーマットを使用する(デフォルト)
-O, -O2, -O3, -Osコンパイルの最適化レベル指定
-O0コンパイル最適化を無効にする
-gC コンパイルのデバッグとスタックチェックを有効にする
-d, -debug全てのランタイムれらーのチェックを有効にする。次の指定と同じ -fstack-check -fec=EC-ALL
-fec=<exception-name>例外コード <exception-name> の生成を有効にする。-fsource-location を設定する。
-fno-ec=<exception-name>例外コード <exception-name> の生成を無効にする
-o <file>出力名を <file> に設定
-b入力ファイル全てを単一の動的にロードできるモジュールにまとめる
-Eプリプロセス(前処理)のみ実行。コンパイルとリンクは実行しない
-CCOBOL ソースを C ソースへ変換(翻訳)するのみ
-Sコンパイルのみ。出力はアセンブリーファイル
-cコンパイルとアセンブル、リンクはしない
-T <file>generate and place a wide program listing into <file>
-t <file>generate and place a program listing into <file>
--tlines=<lines>specify lines per page in listing, default = 55
-P[=<dir or file>]プリプロセス(前処理)したプログラムリスト(.lst ファイル)を生成するディレクトリあるいはファイル名を指定
-Xrefgenerate cross reference through 'cobxref' (V. Coen's 'cobxref' must be in path)
-I <directory><directory> を copy/include のサーチパスに追加
-L <directory><directory> をライブラリのサーチパスに追加
-l <lib>ライブラリ <lib> をリンク
-A <options><options> オプションを C のコンパイル時に追加
-Q <options><options> オプションを C のリンク時に追加
-D <define><define> を COBOL コンパイル時に定義
-K <entry>generate CALL to <entry> as static
-conf=<file>ユーザー定義の方言を記載した設定ファイルを指定
-list-reserved予約語を表示
-list-intrinsics内部関数を表示
-list-mnemonicsニューモニックを表示
-list-systemシステムルーチンを表示
-save-temps[=<dir>]中間ファイルを保存するディレクトリを指定
-ext <extension>add file extension for resolving COPY

RHEL8 の場合

RHEL8 でも EPEL リポジトリから GnuCOBOL のパッケージをインストールすることができます。

[bitwalk@rhel-pc ~]$ dnf list gnucobol
Not root, Subscription Management repositories not updated
...
利用可能なパッケージ
gnucobol.x86_64                         3.1.2-1.el8                         epel
[bitwalk@rhel-pc ~]$

雑感

事務処理に特化したプログラミング言語 COBOL は、名前を知るのみで、自分にとっては縁の無いプログラミング言語でした。しかし、ほんの一時期、GnuCOBOL の前身である OpenCOBOL の開発で、Linux 用の RPM パッケージャとして関わっていました [1]。その縁で Coboler な方々と親しくさせていただきました。そういうことがあったので、Fedora Magazine で GnuCOBOL が紹介されているのを読んで、懐かしくなってちょっと使ってみました。

参考サイト

  1. bitWalk's: OpenCOBOL が GNU Cobol になった! [2013-10-13]
  2. 世界のプログラミング言語(28) COBOLがコロナで大注目?! 60年以上前の言語が最近話題 | TECH+ [2020-08-01]

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

0 件のコメント: