固定形式の列定義

COBOL の固定形式(Fixed Format)では1行を80文字として次のように領域が分割される。

SEQ
1〜6
シーケンス番号
IND
7
標識
Area A
8〜11
DIVISION/SECTION/段落名
Area B(命令本体)
12〜72
命令・条件・データ定義など
IDENT
73〜80
識別領域
列番号名称用途正規化での扱い
1〜6シーケンス番号旧来のカード管理用の通し番号。現代の多くのエディタが自動採番する。除去
7標識列(Indicator)*: コメント、/: ページ送りコメント、-: 継続行、空白: 通常行、D: デバッグ行判定に使い本体は除去
8〜11Area ADIVISION・SECTION・段落名・FD・01レベルなどが開始できる位置命令本体として保持
12〜72Area B命令文・条件・データ定義の本体命令本体として保持
73〜80識別領域プログラム名や連番を記入する慣習。命令とは無関係。除去

💡 80文字制限は必須ではない

現代のコンパイラの多くは80文字超の行を受け付ける設定を持つ。 しかし旧来のソースは厳密に80文字で管理されていることが多いため、本シリーズでは80文字前提で処理する。 73〜80列が全て空白の場合も識別領域として切り落とす。

標識列(列7)の詳細

列7は1文字だけだが意味は多岐にわたる。正規化で特に重要なのは次の3つだ。

意味処理方針
' '(空白)通常の命令行Area A〜B(列8〜72)を命令として処理
*コメント行行全体を削除
/ページ送りコメント行行全体を削除(* と同様に扱う)
-継続行前行に連結する(PART 04 で詳説)
Dデバッグ行通常は削除(WITH DEBUGGING MODE が宣言されている場合を除く)

Area A / Area B の使い分け

Area A(列8〜11)には DIVISION 名・SECTION 名・段落名・FD(ファイル定義)・01レベルのデータ項目などを記述する。 Area B(列12〜72)には命令文やデータ項目の下位レベルを記述する。 正規化の観点からは両者を区別する必要はなく、列8〜72を命令本体として一括して扱えばよい。

COBOL — Area A / Area B の例
* 列番号:  1234567890123456789012345678901234567890
*          |     |    |   |
*          1     7    11  12        Area B 開始
000100 PROCEDURE DIVISION.         ← Area A にある
000200     MOVE 'ABC' TO WS-VAR.   ← 命令は Area B から
000300     IF WS-VAR = 'ABC'       ← IF も Area B
000400         DISPLAY 'MATCH'     ← 継続命令は Area B
000500     END-IF.

Pythonで各領域を切り出す

Pythonのスライス(0始まり)で各領域を切り出す基本的な書き方を示す。

Python — 列領域の切り出し
def parse_cobol_line(line: str) -> dict:
    """
    COBOL固定形式の1行を各領域に分解する。
    Pythonのスライスは0始まりなので列番号から1を引く。
    """
    # 行末の改行を除去してから処理
    line = line.rstrip('\n').rstrip('\r')

    # 80文字に満たない場合でも安全に扱えるよう右パディング
    padded = line.ljust(80)

    return {
        'sequence':   padded[0:6],    # 列1〜6   シーケンス番号
        'indicator':  padded[6],      # 列7      標識
        'area_a':     padded[7:11],   # 列8〜11  Area A
        'area_b':     padded[11:72],  # 列12〜72 Area B
        'ident':      padded[72:80],  # 列73〜80 識別領域
    }

# 使用例
sample = "000100 PROCEDURE DIVISION.                                              PROG01  "
parsed = parse_cobol_line(sample)
print(f"sequence  : '{parsed['sequence']}'")   # '000100'
print(f"indicator : '{parsed['indicator']}'")  # ' '
print(f"area_a    : '{parsed['area_a']}'")     # 'PROC'
print(f"area_b    : '{parsed['area_b']}'")     # 'EDURE DIVISION.   ...'
print(f"ident     : '{parsed['ident']}'")      # 'PROG01  '

💡 ljust(80) でパディングする理由

実際のCOBOLソースには末尾の空白が省略されていたり、エディタの設定によって72文字や79文字で終わる行が混在する。 ljust(80) で常に80文字にパディングすることで、スライスの範囲外エラーや識別領域の切り出し漏れを防ぐ。

固定形式ならではの罠

⚠️ 罠①: 行ラベルのない行が混在する

古いソースを近年のエディタで保存し直した場合、一部の行でシーケンス番号が省略されていることがある。 この場合でも列7の標識は有効なので、「行長が7文字未満」でなければ列7は常に読める。 行長が6文字以下の場合は標識列なし(通常行)として扱うのが安全だ。

⚠️ 罠②: タブ文字が混入している

本来 COBOL 固定形式にタブ文字(\t)は存在しないが、 VSCode などのエディタ経由で開いて保存した場合にタブが混入することがある。 処理前に line.expandtabs(8) でタブを空白8文字に展開しておくと安全だ。

⚠️ 罠③: 自由形式(Free Format)との混同

COBOL 2002 以降では列制限のない「自由形式(Free Format)」が標準化されている。 コンパイルオプションや先頭行のディレクティブ(>>SOURCE FORMAT FREE)で判定できる場合もあるが、 本シリーズでは固定形式のみを対象とする。

次の章では…

PART 03 では固定形式の理解をもとに、最初の正規化ステップである 行ラベル除去・コメント行削除・識別領域除去 を実装する。

→ PART 03 — 行ラベル除去・コメント行削除へ