갑자기 COBOL 소스를 읽을 처지가 되었을 때 최저한 알아두어야 할 것 - DIVISION / PIC / COMP-3 / COPY / PERFORM을 먼저 정리

· 업데이트: · · COBOL, 레거시 기술, 업무 시스템, 보수, Mainframe

수정 이력(1건, 최종 수정 2026년 09월 01일)

이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.

일본어 원문의 완역으로 다시 번역했습니다. 기존 한국어판은 원문의 일부만 옮긴 축약본이라 절, 표, Mermaid 그림, 그림 설명, FAQ가 빠져 있었습니다. 일본어 원문에 맞춰 이들을 모두 복원했고, 기술적인 주장은 일본어판과 같습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.21635181)
최초 공개
이 글을 인용하기(DOI: 10.5281/zenodo.21635180)

이 글은 Zenodo에 보관되어 있습니다. 항상 최신 버전으로 연결되는 DOI와 지금 보고 있는 버전에 고정된 DOI를 아래에 함께 제시합니다.

小村 豪 (2026). 「갑자기 COBOL 소스를 읽을 처지가 되었을 때 최저한 알아두어야 할 것 - DIVISION / PIC / COMP-3 / COPY / PERFORM을 먼저 정리」. 합동회사 코무라소프트. https://doi.org/10.5281/zenodo.21635180 https://comcomponent.com/ko/blog/2026/03/17/001-cobol-minimum-reading-guide/

DOI(최신 버전)
10.5281/zenodo.21635180
DOI(이 버전)
10.5281/zenodo.22217461

인계, 장애 대응, 벤더제 패키지의 유지보수. 그런 상황에서 어느 날 갑자기 COBOL 소스가 날아오는 일이 있습니다.

  • 파일명은 .cbl이나 .cpy
  • 변수명은 전부 대문자
  • 01, 05, 77, 88이 줄지어 있다
  • PIC S9(7)V99 COMP-3 같은, 주문과 회계 소프트웨어의 중간 같은 표기가 나온다
  • 게다가 COPY투성이라서, 열어 놓은 파일만으로는 전체가 보이지 않는다

이쯤에서 대부분의 사람은 일단 손이 멈춥니다.

다만 읽기 위한 지도는 그리 크지 않습니다. COBOL에는 처리계나 제품별 차이가 있지만, 기존 업무 시스템을 읽을 때 먼저 짚어야 할 골격은 상당히 공통됩니다. 이 글에서는 IBM 계열이나 전형적인 업무 COBOL을 염두에 두고, 갑자기 소스를 읽게 된 사람을 위한 최소 세트를 정리합니다.

손이 멈추는 이유와 지도의 크기전부 대문자인 변수명이나 레벨 번호, PIC S9(7)V99 COMP-3 같은 표기, COPY투성이라서 전체가 보이지 않는 것 때문에 손이 멈추지만, 기존 업무 시스템을 읽기 위해 먼저 짚어야 할 골격은 상당히 공통되어 지도가 그리 크지 않다는 것을 보여주는 그림.낯선 표기 앞에서 손이 멈춘다다만 골격은 처리계를 넘어 공통최소 세트의 지도만 먼저 가진다COPY투성이라 전체가 보이지 않는다

그림 1: 주문처럼 보이는 표기의 정체는 몇 개 안 되는 공통 개념으로 집약된다.

1. 먼저 결론(한마디로)

먼저 꽤 거칠지만 실무에 도움이 되는 말로 하면 이렇습니다.

  • COBOL은 로직의 언어이기 전에, 꽤 강하게 레코드 정의의 언어입니다
  • PROCEDURE DIVISION만 읽어서는 절반밖에 알 수 없습니다. 먼저 DATA DIVISION을 봅니다
  • PIC항목의 형, USAGE어떤 표현으로 가질지입니다
  • COMP-3는 packed decimal입니다. 금액이나 건수의 세계에서 자주 나옵니다
  • 88은 별도의 변수라기보다, 직전 항목의 값에 이름을 붙인 조건명입니다
  • REDEFINES같은 메모리를 다른 형태로 보는 구조입니다. 복사가 아닙니다
  • COPY가 있다면 지금 열려 있는 소스는 아직 미완성입니다. copybook을 보지 않으면 전체가 보이지 않습니다
  • PERFORM, IF, EVALUATE, READ, WRITE, CALL을 따라가면 대체적인 흐름을 잡을 수 있습니다
  • 오래된 소스는 열 위치에 의미가 있는 고정 형식입니다. 겉보기의 공백이 단순한 장식이 아닙니다1

요컨대, DIVISION, PIC, USAGE, COMP-3, REDEFINES, OCCURS, 88, COPY, PERFORM. 이 부분이 읽히면 길을 잃을 확률이 꽤 낮아집니다.

이 글의 지식 맵

COBOL은 PROCEDURE DIVISION에 의한 처리 절차의 언어이기 전에 DATA DIVISION에서 레코드의 형태를 정의하는 언어이며, 각 데이터 항목은 PICTURE로 형을, USAGE로 COMP-3 같은 내부 표현을 지정합니다. COMP-3는 10진 숫자를 2자리씩 1바이트에 채워 넣는 packed decimal로, 텍스트로 열면 의미를 알 수 없는 바이트열로 보입니다. REDEFINES는 같은 영역을 다른 형태로 보고, OCCURS는 배열을, 88 레벨은 직전 항목의 값에 이름을 붙인 조건을 나타냅니다. COPY 문은 외부의 copybook을 컴파일 시점에 include하므로, 열려 있는 소스만으로는 전체 모습이 보이지 않으며, PERFORM 문과 scope terminator로 처리의 흐름을 따라가고 FILE STATUS나 EXEC SQL, EXEC CICS로 외부 경계를 파악할 필요가 있습니다.

COBOL 읽는 법COBOL이 DATA DIVISION과 PROCEDURE DIVISION을 기둥으로 하고, PICTURE·USAGE·COMP-3·REDEFINES·OCCURS·88 레벨·COPY 문 같은 데이터 정의 요소와, PERFORM 문이나 scope terminator 같은 제어 요소, EBCDIC이나 FILE STATUS·EXEC SQL·EXEC CICS 같은 외부 경계의 요소가 어떻게 관계되는지를 보여주는 그림이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다COBOLDATA DIVISIONCOMP-3(packed decimal)PROCEDURE DIVISIONPICTURE 절(PIC)USAGE 절COMP-5REDEFINES 절OCCURS 절OCCURS DEPENDING ON88레벨(조건명)COPY문copybookPERFORM 문범위 종료자(scope terminator)MOVE 문고정 형식(참조 형식)IBM Enterprise COBOLEBCDICFILE STATUS절EXEC SQLEXEC CICS

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 21건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

2. COBOL은 먼저 “데이터의 형”의 언어라고 생각한다

C#이나 Java의 감각으로 읽으면, 처음에는 iffor나 함수 호출을 따라가고 싶어집니다. 하지만 COBOL은 그곳으로 가기 전에 “이 프로그램은 어떤 레코드를 받고, 어떤 레코드를 만들며, 어떤 버퍼를 갖고 있는가”를 짚어 두는 편이 빠릅니다.

전형적인 업무 COBOL은 대체로 다음 흐름입니다.

  1. 파일이나 DB에서 레코드를 읽는다
  2. WORKING-STORAGE 상의 항목에 넣는다
  3. 조건 분기한다
  4. 다른 레코드로 다시 채운다
  5. 써낸다

즉, 알고리즘보다 레이아웃이 먼저 서기 쉽습니다.

전형적인 업무 COBOL의 흐름파일이나 DB에서 레코드를 읽고, WORKING-STORAGE 상의 항목에 넣고, 조건 분기하고, 다른 레코드로 다시 채워서 써내는, 전형적인 업무 COBOL의 흐름을 보여주는 그림.레코드를 읽는다WORKING-STORAGE에 넣는다조건 분기한다다른 레코드로 다시 채운다써낸다

그림 2: 주역은 레코드의 흐름이고, 알고리즘은 그 사이에 끼어든다.

예를 들어, 이런 골격입니다.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAMPLE01.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT SALES-FILE ASSIGN TO ...

       DATA DIVISION.
       FILE SECTION.
       FD  SALES-FILE.
       01  SALES-REC.
           05  SALE-ID       PIC 9(8).
           05  SALE-AMOUNT   PIC S9(7)V99 COMP-3.

       WORKING-STORAGE SECTION.
       01  WS-EOF            PIC X VALUE 'N'.
           88  EOF           VALUE 'Y'.

       PROCEDURE DIVISION.
           PERFORM UNTIL EOF
               READ SALES-FILE
                   AT END
                       SET EOF TO TRUE
                   NOT AT END
                       PERFORM PROCESS-SALE
               END-READ
           END-PERFORM
           STOP RUN.

이 코드를 읽을 때 먼저 봐야 하는 것은 PERFORM보다 먼저 SALE-AMOUNT의 형이나 EOF의 의미입니다. COBOL은 그 순서로 읽으면 갑자기 조용해집니다.

3. 4개의 DIVISION을 먼저 본다

COBOL 소스는 먼저 크게 4개의 DIVISION으로 나뉩니다.

DIVISION 먼저 볼 것
IDENTIFICATION DIVISION 프로그램명, 오래된 주석, 유래
ENVIRONMENT DIVISION 파일, 외부 자원, 입출력의 전제
DATA DIVISION 레코드 정의, 작업 영역, 인수
PROCEDURE DIVISION 실제 처리 절차

특히 중요한 것은 다음 부분입니다.

  • FILE SECTION 입출력 파일의 레코드 정의가 있다
  • WORKING-STORAGE SECTION 평소 쓰는 변수, 플래그, 카운터, 작업 버퍼가 있다
  • LOCAL-STORAGE SECTION 호출할 때마다 초기화되는 영역이 있을 수 있다
  • LINKAGE SECTION 외부에서 넘겨받는 인수나, 서브프로그램의 수신 창구가 있을 수 있다

LINKAGE SECTIONPROCEDURE DIVISION USING ...이 보이면, 그 프로그램은 단독으로 완결되지 않고, 외부에서 데이터를 받아 동작할 가능성이 높습니다.

LINKAGE SECTION이 보여주는 것LINKAGE SECTION과 PROCEDURE DIVISION USING이 보이면, 그 프로그램은 단독으로 완결되지 않고 외부에서 데이터를 받아 동작할 가능성이 높다는 것을 보여주는 그림.LINKAGE SECTION이 있다외부에서 데이터를 받아 동작할 가능성PROCEDURE DIVISION USING이 있다단독으로 완결되는 프로그램이 아니다

그림 3: 수신 창구의 정의가 보이면, 호출하는 쪽의 존재를 전제로 읽는다.

4. 고정 형식의 겉모습에 겁먹지 않는다

오래된 COBOL에서는 소스 한 줄의 열 위치 그 자체에 의미가 있습니다. 이것을 모른 채 보면 “왜 왼쪽에 이상한 여백이 있는지”가 영원히 알 수 없습니다.1

고정 형식에서는 대략 이렇습니다.

  • 1 - 6열: 일련번호
  • 7열: indicator
  • 8 - 11열: Area A
  • 12 - 72열: Area B

7열째가 특히 중요합니다.

  • * 또는 / : 주석 행
  • - : 계속 행
  • D : debugging line
  • *> : 도중에도 쓸 수 있는 주석

열과 내용의 대응을, 눈금이 달린 형태로 보면 이렇게 됩니다. 1행이 10의 자리, 2행이 1의 자리 눈금입니다.

         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890
SSSSSSIAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB........
  • S = 일련번호 (1 - 6열)
  • I = indicator (7열)
  • A = Area A (8 - 11열)
  • B = Area B (12 - 72열)
  • . = 73열 이후. 처리계에 따라 식별란으로 쓰이기도 하지만, 프로그램의 의미에는 관여하지 않습니다

실제 소스에 대입하면 이렇게 됩니다.

000100* 이 행은 7열째가 * 이므로 주석
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. SAMPLE01.
000400 DATA DIVISION.
000500 WORKING-STORAGE SECTION.
000600 01  WS-ORDER.
000700     05  WS-ORDER-ID    PIC 9(8).
000800     05  WS-LONG-NAME   PIC X(30) VALUE 'ABCDEFGHIJKLMNOPQRST
000900-    'UVWXYZ0123'.

읽는 방법의 포인트는 4가지입니다.

  • 1 - 6열은 일련번호입니다. 위 예에서 000100처럼 매겨져 있는 것이 그것으로, 프로그램의 동작과는 관계없습니다. 공백인 경우도 있습니다.
  • 7열째가 indicator입니다. *이면 주석, -이면 계속 행. 위 예의 000900 행이 그것으로, 앞 행의 문자열 리터럴이 이어지고 있습니다.
  • 8 - 11열이 Area A입니다. DIVISION, SECTION, 단락명, FD, 그리고 0177 레벨 번호는 여기서 시작합니다. 위 예의 IDENTIFICATION DIVISION.01 WS-ORDER.가 Area A로 시작합니다.
  • 12 - 72열이 Area B입니다. 일반 문장과, 05 같은 하위 레벨은 여기에 씁니다. 위 예의 05 WS-ORDER-ID가 Area B로 시작합니다.

여기서의 공백은 현대적인 의미의 “서식 정리”가 아니라, 부분적으로 구문입니다. 에디터에서 탭 변환하거나, 왼쪽으로 몰거나, 대충 복사 붙여넣기하면 그대로 망가집니다. 오래된 소스를 볼 때는 먼저 그 파일이 fixed format인지 free format인지를 의심하세요. fixed 형식 소스에 현대적인 자동 서식 정리를 걸면 Area A와 Area B의 경계가 무너져 컴파일이 통과하지 않게 됩니다.

고정 형식 소스를 건드리기 전에오래된 소스에서는 먼저 fixed format인지 free format인지 확인하고, fixed 형식 소스에 현대적인 자동 서식 정리나 탭 변환을 걸면 Area A와 Area B의 경계가 무너져 컴파일이 통과하지 않게 됨을 보여주는 그림.fixed 형식free 형식오래된 소스를 열었다fixed인가 free인가열 위치 자체가 구문자동 서식 정리나 탭 변환으로 망가진다열의 제약이 느슨하다

그림 4: 서식 정리보다 먼저, 그 파일의 형식을 확정한다.

5. DATA DIVISION의 최소한

5.1 레벨 번호

COBOL의 데이터 정의는 들여쓰기가 아니라 레벨 번호로 계층을 만듭니다.2

       01  WS-ORDER.
           05  WS-ORDER-ID    PIC 9(8).
           05  WS-AMOUNT      PIC S9(7)V99 COMP-3.
           05  WS-STATUS      PIC X.
               88  WS-OK      VALUE '0'.
               88  WS-ERROR   VALUE '9'.

       77  WS-COUNT           PIC 9(4).

최소한 이것만 기억해 두면 충분합니다.

  • 01 : 한 덩어리의 최상위 레코드, 그룹
  • 02 - 49 : 그 아래 계층
  • 77 : 독립된 단일 항목
  • 88 : condition-name. 직전 항목의 값에 이름을 붙인다3
  • 66 : RENAMES용. 마주칠 확률은 높지 않지만 존재는 한다

중요한 것은 88bool의 별도 변수라고 생각하지 않는 것입니다. WS-OK라는 영역이 별도로 있는 것이 아니라, WS-STATUS'0'일 때 WS-OK라는 이름으로 읽을 수 있다는 느낌입니다.

88 레벨의 정체88 레벨은 독립된 bool 변수가 아니라 직전 항목의 값에 이름을 붙인 조건명이며, WS-STATUS가 특정 값일 때 WS-OK라는 이름으로 읽을 수 있을 뿐임을 보여주는 그림.0일 때9일 때기저 항목 WS-STATUS값이 무엇인가WS-OK라는 이름으로 참이 된다WS-ERROR라는 이름으로 참이 된다별도의 영역은 존재하지 않는다

그림 5: 88은 변수가 아니라, 값에 붙인 읽기 쉬운 별명이다.

하나 더 중요한 것은, 계층을 결정하는 것은 공백이 아니라 레벨 번호라는 점입니다. 겉모습의 들여쓰기는 참고는 되지만, 최종적으로 믿어야 할 것은 01 / 05 / 10 / 88 쪽입니다.2

5.2 PICTURE

PIC는 그 항목의 을 나타냅니다. 가장 자주 보는 것은 다음과 같습니다.

표기 대략적인 의미
X 문자
9 숫자
S 부호 있음
V 소수점은 논리상으로만 가진다
X(10) 10문자
9(5) 5자리 수치
S9(7)V99 부호 있음, 정수 7자리 + 소수 2자리

예를 들면,

  • PIC X(10) → 10문자
  • PIC 9(5)V99 → 5자리 정수 + 2자리 소수
  • PIC S9(7)V99 → 부호 있는 7자리 정수 + 2자리 소수

입니다.

여기서 특히 중요한 것은 V입니다. V실제 . 문자를 갖지 않습니다. PIC 9(5)V99는 “소수점 2자리의 수”로 다루어지지만, 데이터 위에 점 문자가 들어 있는 것은 아닙니다. 그래서 파일이나 덤프를 “겉모습의 문자열”로 해석하면 대개 넘어집니다.

V는 논리상의 소수점PIC 9(5)V99의 V는 논리상의 소수점이며 실제 점 문자를 갖지 않고 데이터에 점이 들어가지 않으므로, 파일이나 덤프를 겉모습의 문자열로 해석하면 넘어짐을 보여주는 그림.PIC 9(5)V99소수점 2자리의 수로 다룬다데이터에 점 문자는 들어가지 않는다겉모습의 문자열로 해석하면 넘어진다

그림 6: 소수점은 정의 안에만 있고, 데이터 안에는 없다.

5.3 USAGE / DISPLAY / COMP / COMP-3

PIC가 형이라면, USAGE어떤 표현으로 보유할지입니다. 최소한 다음만 짚으면 상당히 읽을 수 있습니다.45

표기 대략적인 의미 읽을 때 주의점
DISPLAY 문자로 보이는 외부 10진 mainframe에서는 EBCDIC이 전제인 경우가 있다6
COMP / BINARY 2진수 겉보기 자릿수와 내부 표현은 다르다
COMP-3 / PACKED-DECIMAL packed decimal 문자로 읽으면 망가져 보인다

예를 들면,

       01  WS-AMOUNT-DISP   PIC S9(7)V99.
       01  WS-AMOUNT-BIN    PIC S9(7) COMP.
       01  WS-AMOUNT-PACK   PIC S9(7)V99 COMP-3.

이 3개는 전부 “수치”이지만, 내부의 보유 방식이 다릅니다.

같은 수치라도 보유 방식이 다르다같은 부호 있는 수치 항목이라도, DISPLAY는 문자로 보이는 외부 10진, COMP는 2진수, COMP-3는 packed decimal로, USAGE에 따라 내부의 보유 방식이 다름을 보여주는 그림.같은 형의 수치 항목DISPLAY(문자로 보이는 형태)COMP(2진수)COMP-3(packed decimal)문자로 읽으면 망가져 보인다

그림 7: PIC가 같아도, USAGE가 바뀌면 바이트열은 전혀 다른 것이 된다.

실무에서 가장 효과적인 것은 COMP-3를 본 순간의 반응입니다.

  • 그것은 packed decimal이다
  • 아마 금액, 세액, 건수, 레이트 계열이다
  • 텍스트로 보면 망가져 보이는 것이 당연하다
  • CSV나 UTF-8의 기분으로 들여다보면 사고가 난다

라는 이해를 갖고 있으면, 덤프나 바이너리 파일의 겉모습에서 쓸데없이 당황하지 않을 수 있습니다.

COMP-3를 본 순간의 반응COMP-3를 보면 packed decimal임을 알고, 아마 금액이나 세액이나 건수나 레이트 계열의 항목을 의심하며, 텍스트로 보면 망가져 보이는 것이 당연하므로 CSV나 UTF-8의 기분으로 들여다보지 않는다는 반응을 몸에 익히는 것을 보여주는 그림.COMP-3를 발견했다packed decimal임을 안다금액이나 건수 항목을 의심한다텍스트로 망가져 보여도 당황하지 않는다

그림 8: 이 반사만으로도, 덤프 앞에서 당황하는 횟수가 줄어든다.

COMP-3가 실제로 어떤 바이트열이 되는가

여기는 한 번만 손으로 따라가 보면 이후 보이는 방식이 달라집니다.

packed decimal의 규칙은 2개뿐입니다.45

  1. 1바이트에 10진 숫자를 2자리씩 채워 넣는다
  2. 단 가장 오른쪽 바이트만 하위 1자리와 부호로 1바이트를 쓴다

부호는 4비트 값으로 표현되며, C가 양수, D가 음수, F가 부호 없음입니다.

IBM 매뉴얼에 실려 있는 예로 확인해 봅니다.4

정의 바이트열
PIC S9(4) PACKED-DECIMAL +1234 01 23 4C
PIC S9(4) PACKED-DECIMAL -1234 01 23 4D
PIC 9(4) PACKED-DECIMAL 1234 01 23 4F

1234는 4자리이므로, 규칙 2 때문에 선두에 1자리만큼의 빈자리가 생깁니다. 그것이 선두의 0입니다.

같은 요령으로, 이 글에 여러 번 나온 PIC S9(7)V99 COMP-3를 따라가 봅니다.

  • S9(7)V99정수 7자리 + 소수 2자리 = 9자리
  • V는 소수점 위치를 나타낼 뿐이므로, 바이트를 하나도 소비하지 않습니다
  • 9자리를 2자리씩 채우면 4바이트, 나머지 1자리와 부호로 1바이트. 합계 5바이트

값이 +12345.67이라면, 9자리로 맞추면 001234567이므로 이렇게 됩니다.

값      : +12345.67
9자리 표현 : 0 0 1 2 3 4 5 6 7  와 부호
바이트   : 00 12 34 56 7C
                        ^ 부호 C = 양수

음수 -12345.67이라면, 마지막이 7D가 될 뿐입니다.

바이트   : 00 12 34 56 7D

이것을 텍스트로 열면 어떻게 보이는가가 본론입니다. 00 12 34 56 7C를 억지로 1바이트 1문자로 ASCII에 대응시키면,

  • 00은 NUL, 12는 제어 문자라서 애초에 문자로 표시할 수 없습니다
  • 344, 56V, 7C|

가 됩니다. 즉 화면에는 “표시할 수 없는 문자가 몇 개 이어진 뒤 4V|“처럼 보입니다. 12345.67이라는 나열은 어디에도 나타나지 않습니다.

이것이 “글자가 깨진 것처럼 보이지만 실제로는 망가지지 않은” 상태의 정체입니다. 덤프를 열었을 때 알 수 없는 나열을 만나면, 먼저 그 항목의 USAGECOMP-3는 아닌지를 의심하세요.

COMP-3의 바이트열이 만들어지는 방식packed decimal은 10진 숫자를 1바이트에 2자리씩 채워 넣고 가장 오른쪽 바이트만 하위 1자리와 부호로 쓰기 때문에 9자리 수치는 5바이트가 되고, 이를 ASCII로 열어도 원래 수치의 나열은 어디에도 나타나지 않음을 보여주는 그림.10진 숫자를 2자리씩 1바이트로마지막 바이트는 하위 1자리와 부호9자리면 합계 5바이트ASCII로 열면 원래 수치가 나타나지 않는다글자가 깨진 것처럼 보이지만 망가지지 않았다

그림 9: 채워 넣는 규칙 2가지를 알면, 알 수 없던 덤프가 읽을 수 있는 나열로 바뀐다.

덧붙여, 자릿수에서 바이트 수를 구하는 조견표도 함께 둡니다. 바이트 수는 “9의 개수를 2로 나눠 소수를 버리고, 1을 더한다”로 구할 수 있습니다.

PICTURE의 9 개수 COMP-3의 바이트 수
1 1
2 - 3 2
4 - 5 3
6 - 7 4
8 - 9 5
10 - 11 6
12 - 13 7

같은 바이트 수에 자릿수가 2개씩 늘어서는 것은, 9의 개수가 짝수일 때만 선두에 1자리 분의 빈자리가 생기기 때문입니다. S9(4)01 23 4C의 3바이트가 되고, S9(5)도 같은 3바이트로 들어가는 것은 그 때문입니다.

외부 파일과의 레이아웃 대조에서는, 이 표가 없으면 1바이트씩 어긋나 갑니다.

하나 더 보충하면, DISPLAY라고 해서 반드시 ASCII 문자열이라고는 할 수 없습니다. z/OS 계열에서는 EBCDIC이 전제가 되므로, 숫자가 문자로 보이더라도, 바이트값은 ASCII의 '0' - '9'와는 다른 경우가 있습니다.6

5.4 REDEFINES / OCCURS / COPY / FILLER

이 4가지는 읽을 때 막히는 지점입니다.

REDEFINES

REDEFINES같은 영역을 다른 형태로 보는 구조입니다. 복사가 아닙니다.7

       01  REC-BUF.
           05  REC-TYPE      PIC X.
           05  REC-DATA      PIC X(99).

       01  HEADER-REC REDEFINES REC-BUF.
           05  HDR-TYPE      PIC X.
           05  HDR-DATE      PIC 9(8).
           05  FILLER        PIC X(91).

이것은 C 계열로 말하면 union적인 감각에 가깝습니다. “1개의 100바이트를, 별도의 레코드 종류로 구별한다”는 식의 쓰임에서 자주 나옵니다.

REDEFINES는 같은 영역의 다른 해석REDEFINES는 복사가 아니라 같은 메모리 영역을 다른 형태로 보는 구조로, 하나의 버퍼를 범용 레코드로도 헤더 레코드로도 읽을 수 있고, 한쪽을 고쳐 쓰면 다른 한쪽의 보이는 방식도 바뀜을 보여주는 그림.하나의 메모리 영역REC-BUF로 본다HEADER-REC로 본다한쪽을 쓰면 양쪽의 보이는 방식이 바뀐다

그림 10: 정의가 2개 있어도, 실체의 바이트열은 하나뿐이다.

OCCURS

OCCURS는 배열입니다. COBOL에서는 table이라고 불리기 쉽습니다.

       05  WS-ITEM OCCURS 12 TIMES.
           10  WS-PRICE    PIC 9(5).

게다가 OCCURS DEPENDING ON이 나오면, 가변 길이 테이블입니다. 이 경우, 후속 항목의 위치까지 영향을 받는 일이 있으므로, 고정 길이라는 기분으로 따라가면 발을 헛디딥니다.8

OCCURS DEPENDING ON의 주의점OCCURS는 배열이며, OCCURS DEPENDING ON이 붙으면 가변 길이 테이블이 되어 후속 항목의 위치까지 값에 따라 움직일 수 있으므로, 고정 길이라는 기분으로 오프셋을 따라가면 발을 헛디딤을 보여주는 그림.붙어 있지 않다붙어 있다OCCURS를 발견했다DEPENDING ON이 붙어 있는가고정 횟수의 테이블가변 길이 테이블후속 항목의 위치도 움직일 수 있다

그림 11: DEPENDING ON이라는 세 단어로, 오프셋 계산의 전제가 바뀐다.

COPY

COPY는 compile time의 include입니다. 즉, 지금 열려 있는 소스는 아직 완성형이 아닐 가능성이 있습니다.9

       COPY CUSTOMER-REC.
       COPY ERROR-MAP.

레코드 정의, 공통 플래그, SQL용 host variable, 외부 인터페이스가 copybook에 밀어넣어져 있는 것은 꽤 흔합니다.

COPY가 많아서 읽기 어려울 때는, 전개 후 소스나 compiler listing을 볼 수 없는지를 확인하는 편이 빠릅니다. IBM Enterprise COBOL에는 MDECK라는, 라이브러리 처리 후의 입력 소스를 출력하기 위한 option도 있습니다.10

COPY가 있는 소스의 읽는 법COPY는 컴파일 시점의 include이며 열려 있는 소스가 완성형이 아닐 가능성이 있으므로, copybook을 확인하거나 읽기 어려울 때는 전개 후 소스나 compiler listing, MDECK 옵션의 출력을 찾아본다는 것을 보여주는 그림.읽기 어려울 때COPY를 발견했다열려 있는 소스가 미완성일지 모른다copybook을 열어 확인전개 후 소스나 listing을 찾는다

그림 12: 지금 보이는 줄 수가, 그 프로그램의 전부라고는 할 수 없다.

FILLER

FILLER는 이름이 없는 항목입니다. 다만, “참조하지 않으니 의미가 없다”는 것은 아닙니다.

  • 예약 영역
  • 구 사양과의 호환용 구멍
  • 레코드 길이 맞춤
  • REDEFINES용 여백

으로서 평범하게 쓰입니다.

FILLER는 이름이 없을 뿐이고, 바이트 수로서는 존재합니다. 이것을 잊으면, 외부 파일과의 매핑에서 1바이트씩 세계가 어긋나 갑니다.

FILLER를 세지 않으면 일어나는 일FILLER는 이름이 없을 뿐 바이트 수로서는 존재하며 예약 영역이나 레코드 길이 맞춤으로 쓰이므로, 세는 것을 잊으면 외부 파일과의 매핑이 1바이트씩 어긋나 감을 보여주는 그림.포함했다잊었다FILLER는 이름이 없는 항목바이트 수로서는 존재한다레이아웃 계산에 포함했는가외부 파일과 일치한다1바이트씩 어긋나 간다

그림 13: 참조되지 않는 항목에도, 길이라는 역할이 있다.

6. PROCEDURE DIVISION의 최소한

DATA DIVISION이 지도라면, PROCEDURE DIVISION은 이동 경로입니다.

6.1 PERFORM

PERFORM은 COBOL의 기본적인 제어 이동입니다. 대략 말하면 처리를 불러서 돌아온다입니다.11

자주 보는 형태는 다음입니다.

       PERFORM INIT-PROC
       PERFORM UNTIL EOF
           PERFORM READ-PROC
           IF NOT EOF
               PERFORM EDIT-PROC
               PERFORM WRITE-PROC
           END-IF
       END-PERFORM

PERFORM에는 크게 2계통이 있습니다.

  • 단락이나 절을 지정하는 out-of-line PERFORM
  • 그 자리에 블록을 쓰는 inline PERFORM ... END-PERFORM

게다가 더 오래된 코드에서는 PERFORM A-100 THRU A-199 같은 범위 지정도 흔히 나옵니다. 이것은 편리하지만, 단락을 도중에 추가하면 말려드는 사고가 일어나기 쉬우므로, 읽을 때는 범위의 끝을 제대로 봅니다.

PERFORM의 3가지 형태PERFORM에는 단락이나 절을 지정해서 불러서 돌아오는 out-of-line과, 그 자리에 블록을 쓰는 inline이 있고, 오래된 코드에는 THRU에 의한 범위 지정도 있어서, 범위 지정은 단락을 도중에 추가하면 말려드는 사고가 일어나기 쉬움을 보여주는 그림.PERFORM을 발견했다단락을 부르는 out-of-line그 자리에 쓰는 inlineTHRU의 범위 지정범위의 끝을 반드시 확인한다

그림 14: 어떤 형태의 PERFORM인지에 따라, 따라가야 할 복귀 지점과 범위가 달라진다.

6.2 IF / EVALUATE / 스코프

조건 분기는 IF가 기본입니다. EVALUATEswitch/case적인 것이라고 생각하면 대체로 맞습니다.

주의해야 하는 것은 스코프가 끝나는 방식입니다.12

  • END-IF
  • END-PERFORM
  • END-READ

같은 명시적인 종단이 있는 코드는 아직 읽기 쉽습니다.

문제는 오래된 코드입니다. COBOL에서는 .암묵의 scope terminator로 작동하여, 아직 닫히지 않은 문장을 한꺼번에 끝내 버립니다.12

즉, 단 하나의 마침표로,

  • 어디까지가 IF인가
  • 어디까지가 PERFORM인가
  • 어디서 다음 sentence로 넘어가는가

가 바뀝니다.

게다가 NEXT SENTENCECONTINUE와 같지 않습니다. NEXT SENTENCE다음 마침표 뒤로 진행하므로, 후속 .의 위치에 따라 도착지가 달라집니다.12

오래된 COBOL을 읽을 때는 줄 끝이 아니라 마침표를 본다 정도로 딱 좋습니다.

마침표의 무게END-IF 같은 명시적인 종단이 있는 코드는 읽기 쉽지만, 오래된 코드에서는 마침표가 암묵의 scope terminator로 작동해서 아직 닫히지 않은 문장을 한꺼번에 끝내 버리기 때문에, 마침표 하나의 위치로 IF나 PERFORM의 범위가 바뀜을 보여주는 그림.END-IF 등이 있다없는 오래된 코드명시적인 종단이 있는가범위가 읽기 쉽다마침표가 암묵의 종단하나의 위치로 범위가 바뀐다줄 끝이 아니라 마침표를 본다

그림 15: 오래된 코드의 제어 흐름은, 마침표의 위치가 쥐고 있다.

6.3 READ / WRITE / CALL

업무 COBOL에서 빈출인 것은 이 부근입니다.

  • READ
  • WRITE
  • REWRITE
  • START
  • CALL

특히 READ ... AT END ...는 정석입니다.

       READ IN-FILE
           AT END
               SET EOF TO TRUE
           NOT AT END
               PERFORM PROCESS-REC
       END-READ

CALL 'SUBPGM' USING ...이 있으면, 다른 프로그램으로 넘어갑니다. 그때는 호출받는 쪽의 LINKAGE SECTIONPROCEDURE DIVISION USING을 보면, 주고받는 형태가 상당히 보입니다.

CALL을 발견했을 때 따라가는 법CALL이 있으면 다른 프로그램으로 넘어가므로, 호출받는 쪽의 LINKAGE SECTION과 PROCEDURE DIVISION USING을 보면 인수를 주고받는 형태가 보임을 보여주는 그림.CALL을 발견했다다른 프로그램으로 넘어간다호출받는 쪽의 LINKAGE SECTION을 본다USING으로 주고받는 형태를 파악한다

그림 16: 호출의 의미는, 호출받는 쪽의 수신 창구와 세트로 읽는다.

7. COBOL의 바깥에 있는 것

COBOL은 소스만으로 세계가 완결되지 않는 경우가 꽤 있습니다.

  • 파일 정의
  • 실행 환경
  • DB 접속
  • 트랜잭션 환경
  • job 제어

가 바깥쪽에 나뉘어 있기 때문입니다.

최소한 다음을 짚으면 읽기 쉬워집니다.

파일과 FILE STATUS

ENVIRONMENT DIVISIONFILE-CONTROL과, DATA DIVISIONFILE SECTION / FD는 세트로 읽습니다.13

       SELECT IN-FILE ASSIGN TO ...
           FILE STATUS IS WS-FS.

       FD  IN-FILE.
       01  IN-REC.
           05 ...

FILE STATUS가 있으면, 각 I/O 후의 결과 코드가 들어갑니다. 파일 계열 장애나 EOF 판정을 읽을 때는, 이것을 보지 않으면 시작조차 안 됩니다.14

파일 정의는 세트로 읽는다ENVIRONMENT DIVISION의 FILE-CONTROL에 있는 SELECT와, DATA DIVISION의 FD는 세트로 하나의 파일 정의이며, FILE STATUS가 있으면 각 입출력 후의 결과 코드가 들어가므로, 파일 계열 장애와 EOF 판정은 여기서부터 읽는다는 것을 보여주는 그림.FILE-CONTROL의 SELECT세트로 하나의 파일 정의FILE SECTION의 FDFILE STATUS에 결과 코드가 들어간다장애와 EOF 판정 해독의 시작점

그림 17: 파일의 모습은, 2개의 DIVISION에 나뉘어 쓰여 있다.

EXEC SQL

이것이 나오면 embedded SQL입니다.

       EXEC SQL
           SELECT ...
       END-EXEC.

이 경우, COBOL은 “host 변수의 그릇”이고, 실제 취득 조건이나 갱신 대상은 SQL 쪽에 있습니다. 그래서 EXEC SQL의 내용을 보통의 SQL로 읽는 것이 지름길입니다.

EXEC CICS

이것이 나오면 CICS의 트랜잭션 문맥입니다.15

       EXEC CICS
           RECEIVE MAP(...)
       END-EXEC.

이 순간, 단순한 배치 해독이 아니게 됩니다. 화면, 트랜잭션, 응답 코드, COMMAREA 등, 외부 문맥까지 포함해서 읽을 필요가 있습니다.

JCL이나 실행 정의

mainframe batch에서는 실제로 어느 데이터셋이 할당되는지어떤 순서로 job이 흐르는지가 COBOL 소스 바깥에 있는 경우도 드물지 않습니다. 소스만 봐서는 “이 파일은 어디에 있는가”를 알 수 없을 때는, 코드가 나쁜 것이 아니라 보고 있는 범위가 아직 부족할 뿐인 경우가 흔히 있습니다.

소스 바깥에 있는 세계EXEC SQL이 나오면 실제 취득 조건은 SQL 쪽에, EXEC CICS가 나오면 화면이나 트랜잭션 같은 외부 문맥에, mainframe batch에서는 데이터셋 할당이나 job의 흐름이 JCL에 있다는 식으로, COBOL 소스의 바깥쪽에 세계가 나뉘어 있음을 보여주는 그림.EXEC SQL소스 바깥도 본다EXEC CICSJCL이나 실행 정의SQL의 조건 · 화면 문맥 · job의 흐름

그림 18: 알 수 없는 것은 코드 탓이 아니라, 보고 있는 범위가 좁을 뿐인 경우가 있다.

처리계(컴파일러)의 차이

이 글은 IBM 계열을 염두에 두고 썼지만, 실무에서는 Micro Focus나, Linux / Windows 위의 COBOL을 만나는 경우도 있습니다. 골격은 공통이므로 읽는 법은 달라지지 않지만, “같은 작성법인데 결과가 다르다”는 포인트는 정해져 있으므로, 먼저 파악해 두면 사고를 피할 수 있습니다.

보는 곳 z/OS 계열(IBM Enterprise COBOL) 오픈 계열(Micro Focus, Linux / Windows판 등)
문자 코드 EBCDIC이 전제6 ASCII가 전제6
참조 형식 fixed 형식이 전통적인 기본값. free 형식도 선택 가능1 fixed와 free를 모두 가지며, 기본값이 어느 쪽인지는 빌드 설정에 따라 다르다1
copybook을 찾는 법 라이브러리 지정 컴파일러 옵션에서의 검색 경로 지정
방언 “어느 처리계에 맞출지”를 전환하는 옵션이 있다

특히 효과가 큰 것이 문자 코드입니다. 같은 PIC X(10)이라도, z/OS에서 작성한 파일을 그대로 Windows 쪽에서 읽으면, 숫자조차 다른 바이트값이 됩니다. “이관했더니 전부 깨졌다”의 많은 경우가 이것이며, COMP-3의 이야기와는 별개 문제입니다.

하나 더, 수치의 내부 표현에도 차이가 나기 쉬운 부분이 있습니다. IBM Enterprise COBOL에서는, BINARY / COMP-4PICTURE에 적은 자릿수에서 잘림이 발생하는 데 비해, COMP-52 / 4 / 8바이트라는 네이티브한 2진수 용량까지 값을 가지며, 잘림도 바이너리 크기 쪽에서 일어납니다.16PIC S9(4) COMPPIC S9(4) COMP-5는 비슷해 보여도 들어갈 수 있는 값의 상한이 다릅니다. 다른 시스템과 2진수 그대로 값을 주고받는 코드에서 COMP-5가 나온다면, 일부러 그렇게 쓴 것이라고 생각하고 읽으세요.

자신의 환경과 비교할 때의 가장 빠른 절차는 다음과 같습니다.

  1. 빌드 정의(makefile, JCL, 프로젝트 설정)를 먼저 연다. 어느 처리계의, 어느 옵션으로 컴파일되는지가, 소스보다 먼저 파악됩니다.
  2. 참조 형식(fixed / free)을 확정한다. 여기를 틀린 채로 에디터에서 정리하면 망가집니다.
  3. 문자 코드를 확정한다. EBCDIC인지 ASCII인지에 따라, 덤프를 읽는 법이 달라집니다.
  4. COMP 계열 항목에 표시를 해둔다. 처리계 차이가 나오는 것은 거의 여기입니다.
자신의 환경과 비교하는 가장 빠른 절차빌드 정의를 먼저 열어 어느 처리계와 옵션인지 확인하고, 참조 형식이 fixed인지 free인지 확정하고, 문자 코드가 EBCDIC인지 ASCII인지 확정하고, 처리계 차이가 나기 쉬운 COMP 계열 항목에 표시를 해두는 절차를 보여주는 그림.빌드 정의를 먼저 연다참조 형식을 확정한다문자 코드를 확정한다COMP 계열 항목에 표시를 해둔다

그림 19: 소스를 읽어 들이기 전의 4단계로, 처리계 차이로 인한 사고를 막을 수 있다.

8. 최소한의 읽는 순서

갑자기 COBOL을 읽게 되었을 때는 다음 순서가 안전합니다.

  1. COPY를 전부 훑는다 copybook을 열 수 있으면 연다. 무리라면 listing이나 전개 후 소스를 찾는다
  2. 01 레벨의 레코드 정의를 줍는다 FILE SECTION, WORKING-STORAGE, LINKAGE SECTION의 최상위를 목록화한다
  3. PICUSAGE를 읽는다 금액, 날짜, 건수, 코드, 플래그를 식별한다
  4. READ / WRITE / REWRITE / CALL / EXEC SQL / EXEC CICS를 검색한다 입출력과 외부 경계를 먼저 파악한다
  5. 최초의 주 경로만 따라간다 PROCEDURE DIVISION의 선두부터 PERFORM 연쇄를 짚어 간다
  6. 88과 status 항목을 본다 EOF, 정상/이상, 종별 코드의 의미가 읽기 쉬워진다
  7. REDEFINES / OCCURS DEPENDING ON / COMP-3에 표시를 해둔다 나중에 반드시 영향을 미치므로, 먼저 위험물로서 표시해 둔다
  8. 파일이라면 FILE STATUS를 본다 I/O 오류 계열의 오독을 상당히 줄일 수 있다

이 순서라면, 갑자기 전문을 정독하지 않아도 됩니다. COBOL은 처음부터 100% 이해하려 하기보다, 레코드, 외부 경계, 주 경로의 3가지를 짚은 다음 세부로 가는 편이 훨씬 편합니다.

안전한 읽는 순서COPY를 훑어서 copybook을 확인하고, 01 레벨의 레코드 정의를 목록화하고, PIC와 USAGE로 항목의 형을 읽고, 입출력과 외부 경계를 검색으로 파악한 뒤, PROCEDURE DIVISION 선두의 PERFORM 연쇄로 주 경로를 따라가고, 위험물에 표시를 해두는 읽는 순서를 보여주는 그림.COPY를 전부 훑는다01 레벨을 목록화한다PIC와 USAGE로 형을 읽는다입출력과 외부 경계를 검색한다주 경로의 PERFORM 연쇄를 따라간다위험물에 표시를 해둔다

그림 20: 전문 정독이 아니라, 이 순서로 바깥부터 채워 나간다.

8.1 연습: 이 레코드 정의를 읽어 보자

읽는 법 설명만으로는 몸에 익지 않으므로, 작은 레코드를 하나 놓아 둡니다. 먼저 스스로 답을 낸 뒤에 아래 해답을 보세요.

       01  CUST-REC.
           05  CUST-ID          PIC X(8).
           05  CUST-NAME        PIC X(20).
           05  CUST-KBN         PIC X.
               88  CUST-NORMAL  VALUE '0'.
               88  CUST-VIP     VALUE '1'.
           05  CUST-BALANCE     PIC S9(7)V99 COMP-3.
           05  CUST-HIST OCCURS 3 TIMES.
               10  HIST-DATE    PIC 9(8).
               10  HIST-AMOUNT  PIC S9(5)V99 COMP-3.
           05  FILLER           PIC X(4).

문제

  1. CUST-REC는 전체 몇 바이트입니까.
  2. CUST-BALANCE는, 레코드 선두에서 세어 몇 바이트째부터 시작합니까.
  3. 2번째 HIST-AMOUNT는, 선두에서 몇 바이트째부터 시작합니까.
  4. CUST-KBN'1'이 들어 있을 때, 참이 되는 조건명은 무엇입니까.
  5. 이 파일을 텍스트 에디터로 열었을 때, 망가져 보이는 것은 어느 항목입니까.
  6. 이 정의만으로는 알 수 없는 것을 2가지 드십시오.

해답

  1. 74바이트입니다. 내역은 이렇습니다.

    항목 계산 바이트 수
    CUST-ID X(8) 8
    CUST-NAME X(20) 20
    CUST-KBN X 1
    CUST-BALANCE 9자리 COMP-3 5
    CUST-HIST (8 + 4) × 3회 36
    FILLER X(4) 4
    합계   74

    88 레벨은 조건명이므로 바이트를 소비하지 않습니다. 이것을 세어 버리는 것이 흔한 실수입니다. FILLER는 이름이 없을 뿐, 4바이트는 분명히 존재합니다.

  2. 30바이트째부터입니다. 앞에 8 + 20 + 1 = 29바이트 있으므로, 그다음부터 시작합니다.

  3. 55바이트째부터입니다. CUST-HIST가 시작되는 것은 35바이트째이고, 1건이 12바이트이므로, 1번째는 35 - 46바이트, 2번째는 47 - 58바이트. 그중 선두 8바이트가 HIST-DATE이므로, HIST-AMOUNT는 55바이트째부터입니다.

  4. CUST-VIP입니다. CUST-VIP라는 영역이 별도로 있는 것이 아니라, CUST-KBN'1'일 때 그 이름으로 읽을 수 있다는 것뿐입니다.

  5. CUST-BALANCEHIST-AMOUNT입니다. 둘 다 COMP-3이므로, 문자로 읽으면 의미 없는 나열이 됩니다. HIST-DATEPIC 9(8)DISPLAY이므로, ASCII 환경이라면 20260317처럼 숫자로 읽을 수 있습니다. 다만 EBCDIC 환경에서는, 숫자로 보이더라도 바이트값은 ASCII와 다릅니다.

  6. 예를 들면 다음과 같은 것입니다.

    • 이 정의 자체가 COPY로 들여온 것인지. copybook 쪽을 보지 않으면, 실제로 쓰이고 있는 버전인지 알 수 없습니다.
    • 파일의 문자 코드가 EBCDIC인지 ASCII인지. PIC XPIC 9 DISPLAY의 보이는 방식이 달라집니다.
    • CUST-KBN'0''1' 이외가 들어가는 운용이 있는지. 조건명은 2개만 정의되어 있지만, 그 외의 값이 오지 않는다는 보장은 되지 않습니다.
    • 파일 자체의 속성(레코드 길이, 가변 길이 여부, FILE STATUS). 이것은 ENVIRONMENT DIVISIONFD를 보지 않으면 알 수 없습니다.

문제 1과 3을 틀렸다면, 5.3의 자릿수와 바이트 수 표로 돌아가세요. COBOL 오독은, 대개 여기서부터 시작됩니다.

9. 흔히 막히는 지점

마지막으로, 초보자가 꽤 높은 확률로 걸리는 지점을 정리합니다.

REDEFINES를 “별도 변수”라고 생각한다

다릅니다. 같은 영역을 다른 형태로 읽고 있습니다. 한쪽을 고쳐 쓰면, 다른 한쪽의 보이는 방식도 바뀝니다.7

88을 “독립된 bool”이라고 생각한다

다릅니다. 직전 항목의 값에 이름이 붙어 있을 뿐입니다. SET WS-OK TO TRUE는 뒤에서 기저 항목에 대응값을 넣습니다.3

COPY를 무시하고 본문만 읽는다

열려 있는 파일은, 아직 전체의 절반입니다. 필드 정의, 공통 플래그, host variable이 통째로 바깥에 있는 것은 흔합니다.9

MOVE를 단순 대입이라고 생각한다

MOVE는 단순한 memcpy가 아닙니다. 받는 쪽의 형에 따라, 변환, 자릿수 맞춤, 0 채움, 잘라내기, 편집·역편집이 들어갈 수 있습니다.17

.의 영향을 가볍게 본다

COBOL의 .은 생각보다 무겁습니다. 명시 종단이 없는 오래된 코드에서는, 이 마침표가 어디까지를 닫고 있는지를 잘못 보면 제어 흐름을 잘못 읽습니다.12

packed decimal이나 EBCDIC을 “글자 깨짐”이라고 생각한다

망가졌다고는 할 수 없습니다. 애초에 문자열이 아니거나, ASCII가 아닐 뿐인 경우가 꽤 있습니다.46

OCCURS DEPENDING ON의 뒤쪽을 고정 위치라고 생각한다

가변 길이 테이블의 후속 항목은, 값에 따라 위치가 움직일 수 있습니다. 고정 길이라는 머리로 읽으면, 오프셋 계산이 전부 어긋납니다.8

10. 먼저 보는 조견표

발견한 단어 먼저 생각할 것
01 레코드나 그룹의 최상위. 여기서 전체상을 잡는다
88 플래그나 상태 코드의 의미명. 분기를 읽는 열쇠
PIC X(...) 문자 항목
PIC 9(...) / S9(...)V... 수치 항목. 자릿수와 소수 위치를 확인
COMP binary
COMP-3 packed decimal. 금액·건수일 가능성이 높다
REDEFINES 같은 영역을 다르게 해석하고 있다
OCCURS 배열·table
OCCURS DEPENDING ON 가변 길이. 후속 위치에도 주의
FILLER 이름은 없지만 길이는 있다
COPY copybook을 보지 않으면 완성형이 보이지 않는다
PERFORM 주 경로의 골격
READ / WRITE / REWRITE 파일 I/O
EXEC SQL DB 처리
EXEC CICS 트랜잭션 처리
FILE STATUS I/O의 결과 코드

11. 정리

COBOL은 오래되었기 때문에 어려운 것이 아닙니다. 데이터 정의, 외부 파일, 실행 문맥이 밀접하게 결합되어 있기 때문에 최초의 입구가 보이기 어려울 뿐입니다.

읽기 위한 최소 세트를 다시 한번 정리하면 이렇습니다.

  • DIVISION으로 지도를 잡는다
  • DATA DIVISION을 먼저 읽는다
  • PICUSAGE로 항목의 형을 읽는다
  • COMP-3, REDEFINES, OCCURS, 88, COPY에 표시를 해둔다
  • PERFORM, READ, WRITE, CALL을 따라간다
  • FILE STATUS, EXEC SQL, EXEC CICS로 외부 경계를 짚는다
  • .이 작용하는 방식을 가볍게 보지 않는다

여기가 보이면, COBOL은 “수수께끼의 고대 마법”에서 “레코드 처리의 언어”로 바뀝니다. 레거시 기술은, 이름이 오래되었기 때문에 무서운 것이 아니라, 처음에 보는 축척을 틀리면 갑자기 알기 어려워질 뿐입니다. 지도의 축척이 맞으면, 의외로 평범하게 읽을 수 있습니다.

축척을 맞춰서 읽는다DIVISION으로 지도를 잡고, DATA DIVISION을 먼저 읽어서 항목의 형을 짚고, PERFORM이나 READ 등으로 흐름을 따라가고, FILE STATUS나 EXEC SQL이나 EXEC CICS로 외부 경계를 짚는 순서로 축척을 맞추면, COBOL은 레코드 처리의 언어로서 평범하게 읽힌다는 것을 보여주는 그림.DIVISION으로 지도를 잡는다DATA DIVISION으로 형을 읽는다PERFORM과 입출력으로 흐름을 따라간다외부 경계를 짚는다수수께끼의 고대 마법이 레코드 처리의 언어가 된다

그림 21: 어려움의 정체는 언어가 오래되어서가 아니라, 처음 축척을 고르는 방식이다.

12. 참고 자료

본문 중의 주요 참조처입니다. 본문의 위 첨자 번호가 그대로 이 목록으로의 링크가 되며, 각 항목 끝의 화살표에서 원래 위치로 돌아갈 수 있습니다.

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

ActiveX 이관

COM / ActiveX / OCX 자산을 유지할지, 감쌀지, 교체할지의 단계적 판단을 정리한 토픽 페이지입니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

COBOL 소스는 어디부터 읽기 시작하면 좋을까요?
PROCEDURE DIVISION만 읽어서는 절반밖에 알 수 없습니다. COBOL은 로직의 언어이기 전에 꽤 강하게 레코드 정의의 언어이므로, 먼저 DATA DIVISION을 봅니다. 안전한 읽기 순서는, COPY를 전부 훑어서 copybook을 확인하고, 01 레벨의 레코드 정의를 목록화하고, PIC와 USAGE로 항목의 형을 읽고, READ·WRITE·CALL·EXEC SQL·EXEC CICS를 검색해서 입출력과 외부 경계를 파악한 뒤, PROCEDURE DIVISION 선두의 PERFORM 연쇄로 주 경로만 따라가는 흐름입니다.
PIC S9(7)V99 COMP-3란 무슨 뜻인가요?
PIC는 항목의 형을, USAGE는 어떤 표현으로 보유할지를 나타냅니다. S9(7)V99는 부호 있는 정수 7자리 + 소수 2자리의 수치이지만, V는 논리상의 소수점이며 데이터 위에 점 문자가 들어 있는 것은 아닙니다. COMP-3는 packed decimal로, 금액·세액·건수·레이트 계열의 항목에서 자주 나옵니다. 텍스트로 보면 망가져 보이는 것이 당연하므로, CSV나 UTF-8의 기분으로 덤프를 들여다보면 사고가 납니다.
COBOL의 88 레벨과 REDEFINES는 어떻게 이해하면 될까요?
88은 독립된 bool 변수가 아니라, 직전 항목의 값에 이름을 붙인 조건명(condition-name)입니다. SET WS-OK TO TRUE는 뒤에서 기저 항목에 대응하는 값을 넣습니다. REDEFINES는 같은 메모리 영역을 다른 형태로 보는 구조로, 복사가 아니라 C 계열의 union에 가까운 감각입니다. 한쪽을 고쳐 쓰면 다른 한쪽의 보이는 방식도 바뀌기 때문에, 하나의 영역을 레코드 종류별로 구별하는 작성법에서 자주 나옵니다.
COPY 문이 많아서 전체가 보이지 않을 때는 어떻게 하면 될까요?
COPY는 컴파일 시점의 include이므로, 지금 열려 있는 소스는 아직 완성형이 아닐 가능성이 있습니다. 레코드 정의, 공통 플래그, SQL용 host variable, 외부 인터페이스가 copybook에 밀어넣어져 있는 것은 꽤 흔합니다. 읽기 어려울 때는 전개 후 소스나 compiler listing을 볼 수 없는지 확인하는 편이 빠르며, IBM Enterprise COBOL에는 라이브러리 처리 후의 입력 소스를 출력하는 MDECK라는 옵션도 있습니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기