継続行とは
列7(標識列)に - が記述されている行は 継続行(Continuation Line) と呼ばれ、
直前の行の続きとして結合される。継続行自体の列7は結合後に不要になる。
* 通常の命令の継続
MOVE 'THIS IS A VERY LONG STRING THAT NEEDS TO BE SPLIT ACRO
- SS MULTIPLE LINES' TO WS-MSG.
* 数値・識別子の継続(スペースで自然につながる)
MOVE WS-VERY-LONG-WORKING-STORAGE-VARIABLE-NAME
- TO WS-ANOTHER-LONG-VARIABLE.
文字列リテラル継続の引用符ルール
通常の命令継続(識別子・数値など)はそのまま前行の末尾に空白を挟んで結合すればよい。 しかし 文字列リテラル の継続には COBOL 独自のルールがある。
- 前行の末尾には開き引用符が残るが、リテラルは 途中で切れている
- 継続行の先頭(Area B の先頭 = インデックス5以降)には 閉じ引用符が再度書かれる
- 結合時はこの「前行の末尾引用符」と「継続行の先頭引用符」を除去してつなぎ合わせる
* 元ソース(シーケンス番号付き)
000100 MOVE 'HELLO WOR
000200- LD' TO WS-MSG.
* Step1後のイメージ
MOVE 'HELLO WOR ← 末尾は引用符なしで終わっている
- LD' TO WS-MSG. ← 継続行の先頭に引用符 ' がある
* 正しい結合結果
MOVE 'HELLO WORLD' TO WS-MSG.
💡 引用符の種類
COBOLでは '(シングルクォート)と "(ダブルクォート)の両方が文字列リテラルの区切りとして使われる。
実装では両方に対応する必要がある。
実装 — join_continuation_lines
def join_continuation_lines(lines: list[str]) -> list[str]:
"""
標識列が '-' の継続行を前行に結合する。
Step1〜3(シーケンス番号除去・コメント削除・識別領域除去)適用後に呼ぶ。
継続行の先頭(インデックス0)は標識 '-'。
Area B の開始はインデックス5(元の列12、Step1で6文字削除後は列7基準のインデックス5)。
文字列リテラル継続の場合:
前行末尾の引用符を除去し、継続行先頭の引用符も除去してから結合する。
通常継続の場合:
前行末尾の空白を除去し、継続行の命令部分(インデックス1以降をlstrip)をスペースで結合する。
"""
result = []
for line in lines:
if not line:
continue
indicator = line[0] # Step1後は先頭文字が標識列
if indicator == '-':
# 継続行: 前行に結合する
if not result:
# 最初の行が継続行の場合は単独行として扱う(通常はありえない)
continuation_body = line[1:].lstrip()
result.append(continuation_body)
continue
prev = result[-1]
# Area B の先頭(インデックス1からlstrip)
continuation_body = line[1:].lstrip()
# 文字列リテラル継続の判定
# 継続行の先頭文字が引用符(' または ")なら文字列リテラルの継続
if continuation_body and continuation_body[0] in ("'", '"'):
quote_char = continuation_body[0]
# 前行末尾の引用符(同種)を除去
if prev.endswith(quote_char):
prev = prev[:-1]
# 継続行の先頭引用符を除去
continuation_body = continuation_body[1:]
# 空白なしで結合(文字列は途切れなくつながる)
result[-1] = prev + continuation_body
else:
# 通常継続: スペース1文字で結合
result[-1] = prev.rstrip() + ' ' + continuation_body
else:
result.append(line)
return result
動作確認
lines = [
" MOVE 'HELLO WOR", # 文字列リテラル継続(前行)
"- LD' TO WS-MSG.", # 文字列リテラル継続(継続行)
" MOVE WS-LONG-VAR", # 通常継続(前行)
"- TO WS-DEST.", # 通常継続(継続行)
" DISPLAY 'SIMPLE'.", # 継続なし
]
result = join_continuation_lines(lines)
for line in result:
print(repr(line))
実行結果
" MOVE 'HELLO WORLD' TO WS-MSG." " MOVE WS-LONG-VAR TO WS-DEST." " DISPLAY 'SIMPLE'."
文字列リテラルが正しく 'HELLO WORLD' としてつながり、通常継続もスペース区切りで結合されていることが確認できる。
⚠️ 3行以上にまたがる継続
継続行が連続して3行以上になるケースも存在する(非常に長い文字列定数など)。
本実装では継続行を検出するたびに result[-1](最後の確定行)に結合していくため、
何行続いても正しく処理できる。
✅ 次の章では…
PART 05 ではインデントや余分なスペースを除去する スペースの正規化 を実装する。 文字列リテラル内のスペースを誤って変更しないための保護処理が重要なポイントだ。