AIコンバートツールを使ってうろおぼえCOBOLを変換してみる

お疲れさまです、みやもとです。

先日参加したLTイベントでCOBOLの思い出話をした際、参加者の方からCOBOLのコンバートツールがあることを教えていただきました。
1日あたり最大5回まで無料で使用可能だそう。

https://www.codeconvert.ai/convert-from-cobol

IBMがAIを使ったCOBOL-Javaのコンバートツールを作っていることは聞いていましたが、Web上にもあるとは知りませんでした。
COBOLシステムの移管については長らく問題と言われながらもなかなか進んでいないと聞きます。
こういうコンバートツールが手軽に使えるようになれば希望があるのでは。

せっかく見つけたからには試してみたいということで、簡単なCOBOLのコードをコンバートしてみることにしました。

:::note warn
みやもとが最後にCOBOLやってから5年以上経過しており結構うろ覚えになっているので、間違いがあればそっと教えていただけると幸いです。
:::

## 変換元のコードを作る

今回はベースとなるコードをClaudeに作ってもらって、細かいところをちょろっと直したものを使います。
手打ちで命令文は何桁目…とかDivisionの定義はこの順番…とかやっていくのも復習としてはいいかと思いましたが、コードを書くこと自体よりコンバートツールを試してみるのがメイン目的なので楽できるところは楽することにしました。

```cobol
IDENTIFICATION DIVISION.
PROGRAM-ID. DATA-AGGREGATION.
       
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT INPUT-FILE ASSIGN TO INFILE
        ORGANIZATION IS LINE SEQUENTIAL.
    SELECT OUTPUT-FILE ASSIGN TO OUTFILE
        ORGANIZATION IS LINE SEQUENTIAL.
       
DATA DIVISION.
FILE SECTION.
FD INPUT-FILE.
01 INPUT-RECORD.
    05 INPUT-ID            PIC 9(10).
    05 INPUT-NAME          PIC G(10) USAGE DISPLAY-1.
    05 INPUT-DATE.
        07 INPUT-YEAR      PIC 9(04).
        07 INPUT-MONTH     PIC 9(02).
        07 INPUT-DAY       PIC 9(02).
    05 INPUT-AMOUNT        PIC S9(13) USAGE COMP-3.
       
FD OUTPUT-FILE.
01 OUTPUT-RECORD.
    05 OUTPUT-ID           PIC 9(10).
    05 OUTPUT-YEAR         PIC 9(4).
    05 OUTPUT-TOTAL-AMOUNT PIC S9(15) USAGE COMP-3.
       
WORKING-STORAGE SECTION.
01 WS-EOF                PIC X VALUE 'N'.
01 WS-CURRENT-ID         PIC 9(10) VALUE ZERO.
01 WS-CURRENT-YEAR       PIC 9(4) VALUE ZERO.
01 WS-TOTAL-AMOUNT       PIC S9(15) USAGE COMP-3 VALUE ZERO.
01 WS-FIRST-RECORD       PIC X VALUE 'Y'.
       
PROCEDURE DIVISION.
MAIN-PROCEDURE.
    PERFORM INITIALIZE-PROCESS
    PERFORM PROCESS-FILE
    PERFORM CLOSE-FILES
    STOP RUN.

INITIALIZE-PROCESS.
    OPEN INPUT INPUT-FILE
         OUTPUT OUTPUT-FILE.

PROCESS-FILE.
    PERFORM READ-RECORDS.
    PERFORM WRITE-FINAL-OUTPUT.

CLOSE-FILES.
    CLOSE INPUT-FILE
          OUTPUT-FILE.
       
READ-RECORDS.
    PERFORM UNTIL WS-EOF = 'Y'
        READ INPUT-FILE 
            AT END 
                MOVE 'Y' TO WS-EOF
            NOT AT END
                PERFORM PROCESS-RECORD
        END-READ
    END-PERFORM.
       
PROCESS-RECORD.
    IF WS-FIRST-RECORD = 'Y'
        MOVE 'N' TO WS-FIRST-RECORD
        MOVE INPUT-ID TO WS-CURRENT-ID
        MOVE INPUT-YEAR TO WS-CURRENT-YEAR
    END-IF.

    IF WS-CURRENT-ID NOT EQUAL INPUT-ID OR
       WS-CURRENT-YEAR NOT EQUAL INPUT-YEAR
        PERFORM WRITE-OUTPUT
        MOVE INPUT-ID TO WS-CURRENT-ID
        MOVE INPUT-YEAR TO WS-CURRENT-YEAR
        MOVE ZERO TO WS-TOTAL-AMOUNT
    END-IF.
           
    ADD INPUT-AMOUNT TO WS-TOTAL-AMOUNT.
       
WRITE-OUTPUT.
    IF WS-TOTAL-AMOUNT NOT EQUAL ZERO
        MOVE WS-CURRENT-ID TO OUTPUT-ID
        MOVE WS-CURRENT-YEAR TO OUTPUT-YEAR
        MOVE WS-TOTAL-AMOUNT TO OUTPUT-TOTAL-AMOUNT
        WRITE OUTPUT-RECORD
    END-IF.

WRITE-FINAL-OUTPUT.
    PERFORM WRITE-OUTPUT.
```

IDと年で集計して出力する処理にしています。
データ型は過去の現場で実際に見た（ような記憶がある）DISPLAY-1とかCOMP-3とかを使ってどう変換されるのかを見てみることにしました。

ではさっそく使ってみましょう。

## コンバートできる言語が多い
ここでConvert code from COBOLのサイトを見てみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/8a69c689-56e6-37fb-e517-1d24935934fb.png" width="80%">

種類が多い！

画像に収まっていませんが、ほかにもVB.NETとかありました。

とりあえず今日は私がCOBOL以外に仕事で使っている言語ということで、Javaにしてみようと思います。

Javaのアイコンをクリックしてコードを貼り付けます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/ec96808f-164d-be0d-1939-9edb463b6c37.png" width="90%">

Convertをクリックしてしばらく待つと…

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/f82230c0-d587-4eba-b726-7060fcef3f50.png" width="90%">

ちゃんと処理が出力されました。

## コンバート後のコードについて

では、実際に出力されたコードを見ていきます。
（生成されたコードについてはどこまで載せてOKなのかがちょっとよくわからなかったので、全体を見た感想と気になった点を一部抜粋して書かせていただきます。）

コンバート後のコードについては、ファイルのオープン・クローズ等の一部処理は空になっていました。
このへんは実際の環境に合わせて書いてね、ということでしょう。
一部追加で書かないといけない処理があるとはいえ、ざっくり読んだ感じ処理の流れは合っていました。
コンバートにかかる時間も体感[^1]十数秒程度で、直接COBOLを書き換える手間を考えればすごくお手軽。
[^1]:厳密に計測する方法が浮かばなかったので感覚でご容赦ください。

ただ、主に項目定義とか出力形式とかがちょこちょこ気になる…。

### コンマ区切り前提

COBOL側の項目定義部分に戻ります。

```cobol
01 INPUT-RECORD.
    05 INPUT-ID            PIC 9(10).
    05 INPUT-NAME          PIC G(10) USAGE DISPLAY-1.
    05 INPUT-DATE.
        07 INPUT-YEAR      PIC 9(04).
        07 INPUT-MONTH     PIC 9(02).
        07 INPUT-DAY       PIC 9(02).
    05 INPUT-AMOUNT        PIC S9(13) USAGE COMP-3.
```

私が現場で見たプログラムの多くは固定長データを扱うものでした。
項目も桁数（バイト数）で区切られていて、項目と項目の間に区切り文字が入っているのは稀だったと記憶しています。

しかし、コンバート後のコードではコンマで区切られている前提で変数に格納していました。

```java
    private static void readRecords(String line) {
        // Assuming line is formatted correctly
        String[] fields = line.split(",");
        int inputID = Integer.parseInt(fields[0].trim());
        int inputYear = Integer.parseInt(fields[1].trim());
        long inputAmount = Long.parseLong(fields[2].trim());

        processRecord(inputID, inputYear, inputAmount);
    }
```

処理の流れとしては同じなのですが、同じ形式のデータを処理するプログラムになっているかというと違うような…。

### パック10進数
COMP-3で定義しているのはパック10進数という形式です。
1桁1バイト（8ビット）で数字を表すゾーン10進数に対して、1桁を4ビットで数字を表すためデータ容量を少なくすることができます。
金融系等大きな金額をデータとして扱うことが多い場合に重宝したのか、金額項目はたいていCOMP-3が切られていました。

パック10進数がJavaでどういうふうに置き換えられるのかちょっと興味深かったのですが、コンバート先では単にparseLongで処理されていました。
やっぱりCOBOLと同じデータを使って処理することは想定されていないようです。

どのみち私の過去の現場は基本的にネット環境に接続されていなかったので、環境が変わっていない限りは使おうにも使えませんが…。

## 使った感想

コンバートツールと聞いて「コンバート元の処理をそのまま置き換えて同じインプットデータを処理できるコードにする」というイメージだったのですが[^2]、CodeConvertAIはあくまで同じ処理をする別言語のプログラムを作るツールのようでした。
[^2]:私のイメージが変な方に飛躍しているだけで、コードのコンバーターというのはそういうものだったりするでしょうか。

習得済み言語で書いたコードを置き換えて、勉強したい言語のイメージをつかむとかに使うと良さそうかなと思いました。