「なぜ差分がこんなにノイズだらけなんだ」と思ったら、原因は行ラベルの通し番号がずれていただけだった——そんな経験がCOBOL正規化に手を付けた理由です。完全なパーサーを書かなくても、文字列操作の積み重ねで十分戦えることが分かりました。
なぜ正規化が必要か
図1: COBOL正規化の処理ステップ — 固定フォーマット入力から正規化済みテキスト出力まで
COBOLソースコードはメインフレーム全盛期の慣習を色濃く残しており、現代のツールでそのまま扱おうとすると様々な困難が生じる。
代表的な問題を挙げると、差分比較ツールが行ラベルの変化に反応してノイズを大量に出力したり、
簡易的な静的解析スクリプトがコメント行を命令と誤認識したりする。
継続行が別行に分断されているためコマンドラインの grep では完全な文字列がヒットしないケースも多い。
こうした問題に対して 正規化(Normalization) を一段挟むことで、後続の解析・移行・差分比較の品質が大幅に向上する。 正規化は「完全なCOBOLパーサーを書く」という重い作業ではなく、 文字列操作と状態機械(ステートマシン)を組み合わせた実用的なアプローチで実現できる。
before / after — 何が変わるか
以下に典型的な変換例を示す。
000100 IDENTIFICATION DIVISION. 000200* このプログラムはサンプルです 000300 PROGRAM-ID. SAMPLE. 000400 PROCEDURE DIVISION. 000500 MOVE 'HELLO WOR- 000600- LD' TO WS-MSG. 000700 DISPLAY WS-MSG. STOP RUN.
IDENTIFICATION DIVISION. PROGRAM-ID. SAMPLE. PROCEDURE DIVISION. MOVE 'HELLO WORLD' TO WS-MSG. DISPLAY WS-MSG. STOP RUN.
変換の内訳は次のとおり。
- 列1〜6の 行ラベル(シーケンス番号) を除去
- 列7が
*の コメント行 を削除 - 列7が
-の 継続行 を前行に結合(文字列リテラルも正しく連結) - 連続スペース を間詰め
- ピリオドを区切りとして 1行1命令 に分割(
DISPLAY WS-MSG. STOP RUN.→ 2行に分解)
正規化の対象を整理する
* または / の行。静的解析・差分比較では不要なため削除する。- の行は前行の続き。文字列リテラル継続の場合は引用符の扱いに注意が必要。END-xxx スコープ終端を区切りに分割。文字列中・PIC句・数値リテラルのピリオドを誤検出しないようステートマシンで処理する。⚠️ 完全なCOBOLパーサーではない
本シリーズの実装はすべての方言・拡張に対応する完全パーサーを目指すものではない。 主要な固定形式COBOLを対象とした実用的な正規化ツールとして設計する。 本番適用前には対象プロジェクト固有の特殊記法を必ず確認すること。
シリーズ構成
全8回で段階的に実装を積み上げる。
✅ 次の章では…
PART 02 では正規化の前提知識として COBOL 固定形式フォーマットの列定義を詳解する。 列番号を知らずに文字列操作を行うと行ラベルを命令と誤認するなど深刻なバグにつながるため、必ず読んでほしい。
COBOLソース正規化でよくある誤り
COBOLソースの正規化処理は固定形式の特殊ルールを無視すると誤処理につながります。最初の段階でよく陥る誤りを整理します。
| 誤り/失敗パターン | 何が起きるか | 正しい対処/防止策 |
|---|---|---|
| COBOLを自由形式(フリーフォーマット)として処理する | 行番号・コメント標識・継続記号が内容として誤解析され、正規化結果が正しくない | 固定形式(列1〜72が有効)を前提にして、各列の役割を把握してから処理ロジックを設計する |
| 正規化の目的を明確にせずに実装を始める | 不要なステップを実装したり、必要なステップを省いたりして効果が出ない | 「何のために正規化するか(grep・パーサー接続・差分比較等)」を定め、必要な正規化ステップだけを選択して実装する |
| 元のソースを直接変更して正規化する | 元のソースが失われ、正規化後との比較や元に戻す作業ができなくなる | 元ファイルは変更せず、正規化済みコピーを別ディレクトリに出力する設計にする |