COBOLのお勉強(1)

先の宣言 に基づき、COBOLを勉強している。 テキストは『 入門COBOL 』を使用。 処理系には OpenCOBOL を使用。

お勉強の成果をレポートしてみる。

今のところの印象としては、はっきり言ってこれは素晴らしい言語だ。激しく興奮しながらテキストを読んでいる。

確かに汎用言語としてはかなり貧弱だし、これしか知らないCOBOLerがそのままの感覚でネットワークプログラムなんかを設計した日には悲惨なことになるのは目に見えている。私なんか、過去に単価や日付が文字列で格納されているRDBを見ただけでのけぞってしまったし。

でも、なるほどCOBOLは会計処理DSLとして素晴らしい。DSL厨としては興奮せずにはいられない。 これを超える金融DSLは今のところない というのも頷ける。

大規模なソフトウェアを書こうと思ったときに落とし穴になりそうな仕様はどっさりあるけれども、そんなことは触る前から分かってるわけで。それよりも、原簿を読んで集計して打ち出すとか、帳票を読んでラインプリンタに打ち出すのに特化したDSLとしての完成度に感動する。

COBOLを知らないでDSLとか言ってた私みたいな人は、是非一度勉強してみるべきだと思った。

OpenCOBOLのインストール

Ubuntu Linuxのaptには入ってた。MacPortsには無かったのでsourceforgeから0.32のソースを落としてきて野良ビルド

GNU MPに依存してるらしい。多倍長整数/小数の処理に使ってるな。これは当然MacPortsに入ってるので port install gmp

で、

$ ./configure --prefix=/opt/local --with-lfs64 --with-gnu-ld

してみたら、"checking for gmp.h... no"と言われるのは何故だー。さては/opt/local/include見てないだろ。実は。--includedir指定も無視してくれるので、仕方がない。

$ env CFLAGS='-I /opt/local/include' -LDFLAGS='-L/opt/local/lib' \
 ./configure --prefix=/opt/local --with-lfs64 --with-gnu-ld

すると、GNU MPのバージョンが3以降でないとか言われて失敗。4.2.1なんだけど……。よく分からないので、configure.acの112行目の

AC_CHECK_LIB([gmp], [__gmp_rand], , AC_MSG_ERROR(GMP 3 or later is required))

コメントアウトしてから

$ autoconf
$ env CFLAGS='-I /opt/local/include' -LDFLAGS='-L/opt/local/lib' \
 ./configure --prefix=/opt/local --with-lfs64 --with-gnu-ld

で、makeしようと思ったら、今度は

ar cru libsupport.a  
ar: no archive members specified

とか言われる。なんか、生成されたlib/Makefileがよろしくないらしい。126行目のam_libsupport_a_OBJECTSを

am_libsupport_a_OBJECTS = getopt.o getopt1.o

に設定。これであとはmake && make installで通った。

$ cobc --version
>cobc (OpenCOBOL) 0.32
>Copyright (C) 2001-2004 Keisuke Nishida

COBOLの文法。

いよいよCOBOLの文法を学んでいくわけだ。本を読むと、なんかいろいろ書いてある。むー。COBOLの文法はCOBOL一般形式とかいう書式で定義されているらしい(?) が、そういう難しいことは現代っ子には分からないので、もっと直感的に把握できるように、疑似(E)BNFで書いてみる。

program : identification_division
            environment_division?
            data_division?
            procedure_division?
            end_proram_header?

むー。簡単だな。で、正確には任意にコメント行を書いてもよく、ただし、プログラムの始まりはidentification_divisionでないといけないらしい。

program : identification_division
            comment_line*
            environment_division?
            comment_line*
            data_division?
            comment_line*
            procedure_division?
            comment_line*
            end_proram_header?
            comment_line*

identification_divisionは、というと

identification_division : 'IDENTIFICATION' 'DIVISION' '.'
                           'PROGRAM-ID' '.' program_name '.'
program_name : user_defined_word

user_defined_word(利用者語)は終端記号かな。利用者語は予約語を除く、'A-Za-z0-9-'の30文字以内の組み合わせ、大文字と小文字は区別しない、とある。最近の処理系はもっと長くてもOkとも。

むー。"IDENTIFICATION DIVISION"のあととか、あちこちに、「終止符のあとに空白を書く」っていう指示があるけれども、この空白は無くてもコンパイル通るみたいなんだよね。改行でもいいってことかね。トークンを読むときの区切り文字ってことなんだろうか。"PROGRAM-ID.HOGE."と繋げちゃいけないよ、と。最初からBNFで書いてくれればわかりやすいんだけど、んー、なんか、COBOLができた当時ってBNFが無かったような気がする。

最初のプログラム

COBOLの場合、各行の最初の6桁は行番号、次の1桁は標識領域といってその行の種別を書くらしい。空白文字だと普通のプログラム行で、'*'や'/'だとコメント行と。

で、8桁目からプログラムを書く。なんというか、なるほどパンチカードに便利な仕様ですな。

でも行番号書くのは嫌だよね。と、かつてBASICからCに移ったときの経験から思う。最近の処理系は自由書式とか言って行番号や標識領域を書かなくてもいい書式を認識してくれる、らしい。OpenCOBOLでは--freeオプションを渡せばよい。

で、identification_divisionがあればいいんだな。

identification division.
program-id. nop-program.

と。それで、コンパイルする。

$ cobc --free nop.cob    
i686-apple-darwin8-gcc-4.0.1: /tmp/cobe6mgXE.c: No such file or directory
i686-apple-darwin8-gcc-4.0.1: no input files

テキストの嘘つきー。どうでもいいけど、OpenCOBOLはCへのトランスレータなのね。procedure_divisionが無いからCソースコードが生成されてないんだろうと推測して、procedure_divisionも書いてみる。

identification division.
program-id. nop-program.

procedure division.

こんどはコンパイルが通った。カレントディレクトリに実行ファイルnopができてる。

小文字で書いてみたけど、どうだろう。COBOLerを筆頭とする古代語の使い手はよく大文字がいいと言っているけれども、そもそも大文字が書きづらいし認識しづらいっていうんで派生してできたのが小文字なんだけどなぁ。

Hello world

今度はHello, worldを書いてみた。むぅ。やっぱり全部小文字は見づらいかもしれない。C言語族に見られるようなプログラム構造に合わせた構文のメリハリに乏しいんだもの。デフォルトのままではvimがあんまりちゃんとシンタックスハイライトしてくれないのもあるけれども。

利用者語だけ小文字っていうスタイルにしてみた。これは私がSQLを書くときと同じ。

IDENTIFICATION DIVISION.
PROGRAM-ID. hello-world.

PROCEDURE DIVISION.
    DIPLAY 'Hello, World!'.

END PROGRAM hello-world.

まぁ、こんなものか。あと、サブプログラムなんかを使う必然性から、現代COBOLではend_program_headerは書いておくのが正しいお作法らしい。文法は、

end_program_header : 'END' 'PROGRAM' program_name '.'

あと、1行に書いてもコンパイル通った。やっぱり、空白が必要なのはトークン切り出しの話なのかね。

identification division. program-id. hello-world. procedure division. display 'Hello, world!'. end program hello-world.

今日のまとめ

program : identification_division
            comment_line*
            environment_division?
            comment_line*
            data_division?
            comment_line*
            procedure_division?
            comment_line*
            end_proram_header?
            comment_line*

identification_division : 'IDENTIFICATION' 'DIVISION' '.'
                           'PROGRAM-ID' '.' program_name '.'
end_program_header : 'END' 'PROGRAM' program_name '.'

program_name : user_defined_word(終端)
=end