Минимум знаний, необходимый перед чтением исходного кода на COBOL

· · COBOL, Устаревшие технологии, Бизнес-системы, Обслуживание, Mainframe

Передача проекта, реагирование на сбой, обслуживание пакетного продукта стороннего вендора. В таких ситуациях однажды на вас может внезапно свалиться исходный код на COBOL.

  • Файлы называются .cbl или .cpy
  • Все имена переменных — заглавными буквами
  • Идут подряд 01, 05, 77, 88
  • Встречаются записи вроде PIC S9(7)V99 COMP-3 — что-то среднее между заклинанием и бухгалтерской программой
  • И вдобавок сплошной COPY, так что по одному открытому файлу общей картины не увидеть

В этот момент мозг слегка превращается в порошок.

Но карта, нужная для чтения, не такая уж большая. У COBOL есть различия между процессорами и продуктами, но тот скелет, который стоит усвоить в первую очередь при чтении существующей бизнес-системы, довольно универсален. В этой статье, ориентируясь на IBM-семейство и типичный бизнес-COBOL, мы разберём минимальный набор для тех, кому внезапно пришлось читать такой исходный код.

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. Умение читать эти вещи заметно снижает вероятность заблудиться.

2. Считайте, что COBOL — прежде всего язык о «форме данных»

Если читать его с рефлексами C# или Java, сначала хочется проследить за if, for и вызовами функций. Но в COBOL быстрее сначала разобраться, «какие записи получает эта программа, какие создаёт и какими буферами располагает» — и только потом идти дальше.

Типичный бизнес-COBOL работает примерно по такой схеме.

  1. Считать запись из файла или БД
  2. Поместить её в элементы WORKING-STORAGE
  3. Разветвиться по условию
  4. Переупаковать данные в другую запись
  5. Записать результат

Иными словами, раскладка данных обычно выходит на первый план раньше алгоритма.

Например, вот такой скелет.

       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. Сначала смотрим на четыре DIVISION

Исходный код COBOL прежде всего делится на четыре крупных DIVISION.

DIVISION Что смотреть в первую очередь
IDENTIFICATION DIVISION Имя программы, старые комментарии, происхождение
ENVIRONMENT DIVISION Файлы, внешние ресурсы, предпосылки ввода-вывода
DATA DIVISION Определения записей, рабочие области, параметры
PROCEDURE DIVISION Собственно порядок обработки

Особенно важны следующие части.

  • FILE SECTION содержит определения записей входных/выходных файлов
  • WORKING-STORAGE SECTION содержит повседневные переменные, флаги, счётчики, рабочие буферы
  • LOCAL-STORAGE SECTION может содержать области, инициализируемые при каждом вызове
  • LINKAGE SECTION может содержать параметры, передаваемые извне, точку приёма для подпрограммы

Если видны LINKAGE SECTION и PROCEDURE DIVISION USING ..., велика вероятность, что эта программа не самодостаточна и работает с данными, получаемыми извне.

4. Не пугайтесь вида фиксированного формата

В старом COBOL сама позиция колонки в строке исходного кода несёт смысл. Если этого не знать, вопрос «почему слева какой-то странный отступ» так и останется без ответа.1

Если совсем грубо, в фиксированном формате это выглядит так.

  • Колонки 1–6: порядковый номер строки
  • Колонка 7: индикатор
  • Колонки 8–11: Area A
  • Колонки 12–72: Area B

Колонка 7 особенно важна.

  • * или / : строка комментария
  • - : строка продолжения
  • D : строка отладки (debugging line)
  • *> : комментарий, который можно вставить и посередине строки

Чтобы снизить визуальное давление, вот очень грубая схема.

1234567 8901 23456789012345678901234567890
      * комментарий
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAMPLE01.

Пробелы здесь — не «форматирование» в современном смысле, а отчасти синтаксис. Если преобразовать табуляцию в редакторе, сдвинуть текст влево или небрежно скопировать-вставить, код обычно ломается. Глядя на старый исходник, прежде всего усомнитесь, fixed это format или free. Если применить современный форматтер к fixed-формату, всё эффектно взрывается.

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 : верхний уровень одной записи или группы
  • 0249 : уровни под ней
  • 77 : независимый одиночный элемент
  • 88 : condition-name. Присваивает имя значению предшествующего элемента3
  • 66 : для RENAMES. Встречается нечасто, но существует

Важно не считать 88 отдельной bool-переменной. Отдельной области под названием WS-OK не существует — просто когда WS-STATUS равно '0', это можно прочитать под именем WS-OK.

Ещё одна важная вещь: иерархию определяют номера уровней, а не пробелы. Визуальный отступ полезен как подсказка, но в конечном счёте доверять стоит именно 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 десятичными разрядами», но никакой точки в данных на самом деле нет. Поэтому если интерпретировать файл или дамп как «видимую строку символов», почти наверняка споткнётесь.

5.3 USAGE / DISPLAY / COMP / COMP-3

Если PIC — это форма, то USAGE — это то, в каком представлении элемент хранится. Для достаточного понимания хватит следующего минимума.45

Запись Примерное значение На что обратить внимание при чтении
DISPLAY Внешняя десятичная форма, видимая как символы На mainframe нередко предполагается EBCDIC6
COMP / BINARY Двоичное число Видимое число разрядов и внутреннее представление — разные вещи
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.

Все три — «числа», но внутреннее хранение у них разное.

На практике сильнее всего выручает рефлекс, срабатывающий при виде COMP-3.

  • Это packed decimal
  • Вероятно, сумма, налог, количество или ставка
  • Закономерно выглядит «битым», если читать его как текст
  • Разглядывание в настроении CSV или UTF-8 приводит к неприятностям

Держа в голове это понимание, вы гораздо реже будете зря паниковать при виде дампов и бинарных файлов.

И ещё одно небольшое дополнение: DISPLAY вовсе не обязательно означает ASCII-строку. В семействе z/OS по умолчанию предполагается EBCDIC, поэтому даже если цифры выглядят как символы, байтовые значения могут отличаться от ASCII '0''9'.6

5.4 REDEFINES / OCCURS / COPY / FILLER

Эти четыре конструкции — типичные места затыка при чтении.

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).

Это близко по ощущению к union в языках C-семейства. Часто встречается в написании вида «различать один и тот же 100-байтовый блок как разные типы записи».

OCCURS

OCCURS — это массив. В COBOL его чаще называют table.

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

Если далее встречается OCCURS DEPENDING ON, это таблица переменной длины. В этом случае она может влиять даже на позиции последующих элементов, поэтому если следить за ней с настроем на фиксированную длину, легко оступиться.8

COPY

COPY — это include времени компиляции. То есть открытый вами сейчас исходник вполне может быть ещё не в окончательном виде.9

       COPY CUSTOMER-REC.
       COPY ERROR-MAP.

Совершенно обычное дело, когда определения записей, общие флаги, host-переменные для SQL и внешние интерфейсы загнаны в copybook.

Если из-за обилия COPY читать становится трудно, быстрее всего проверить, нельзя ли посмотреть развёрнутый исходник или compiler listing. В IBM Enterprise COBOL для этого даже есть опция MDECK, которая выводит входной исходный код после обработки библиотек.10

FILLER

FILLER — это элемент без имени. Однако «раз на него не ссылаются, значит он бессмыслен» — неверно.

Он вполне обычно служит:

  • зарезервированной областью
  • зазором для совместимости со старой спецификацией
  • выравниванием длины записи
  • запасом для REDEFINES

У FILLER просто нет имени, но как количество байт он существует. Забудьте об этом — и при сопоставлении с внешним файлом мир будет смещаться побайтово.

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 есть два основных вида.

  • Out-of-line PERFORM, указывающий на параграф или section
  • Inline PERFORM ... END-PERFORM, где блок пишется прямо на месте

В более старом коде также обычно встречается указание диапазона вроде PERFORM A-100 THRU A-199. Это удобно, но если добавить параграф посередине, легко случайно затянуть его в диапазон, поэтому при чтении внимательно смотрите, где заканчивается диапазон.

6.2 IF / EVALUATE / Область действия

Базовый инструмент условного ветвления — IF. Если думать про EVALUATE примерно как про switch/case, в целом это верно.

На что стоит обратить внимание — это как заканчивается область действия (scope).12

Код с явными терминаторами вроде

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

читать пока ещё легко.

Проблема — в старом коде. В COBOL . действует как неявный scope terminator и разом закрывает все ещё не закрытые операторы.12

То есть от одной-единственной точки зависит:

  • докуда простирается IF
  • докуда простирается PERFORM
  • где начинается следующий sentence

Более того, NEXT SENTENCE — не то же самое, что CONTINUE. NEXT SENTENCE переходит к месту после следующей точки, поэтому пункт назначения зависит от того, где стоит очередная ..12

При чтении старого COBOL правильный настрой — смотреть на точки, а не на концы строк.

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 SECTION и PROCEDURE DIVISION USING вызываемой стороны, форма передачи данных становится довольно наглядной.

7. Что находится за пределами COBOL

Довольно часто мир COBOL не замыкается на одном исходном коде.

Потому что снаружи остаются:

  • определения файлов
  • среда выполнения
  • подключение к БД
  • транзакционная среда
  • управление заданиями (job)

Для облегчения чтения стоит освоить хотя бы следующее.

Файлы и FILE STATUS

FILE-CONTROL в ENVIRONMENT DIVISION и FILE SECTION / FD в DATA DIVISION читаются в паре.13

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

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

Если есть FILE STATUS, туда попадает код результата после каждой операции ввода-вывода. Читая о сбоях, связанных с файлами, или о проверке EOF, без взгляда на это никуда не деться.14

EXEC SQL

Если это встречается, значит перед вами встроенный SQL.

       EXEC SQL
           SELECT ...
       END-EXEC.

В этом случае COBOL выступает «сосудом для host-переменных», а фактические условия выборки и объекты обновления находятся на стороне SQL. Поэтому кратчайший путь — читать содержимое EXEC SQL как обычный SQL.

EXEC CICS

Если это встречается, вы находитесь в транзакционном контексте CICS.15

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

В этот момент чтение перестаёт быть простым разбором batch-программы. Нужно читать с учётом внешнего контекста: экранов, транзакций, кодов ответа, COMMAREA и так далее.

JCL и определения выполнения

В mainframe-batch нередко бывает, что какой именно dataset реально будет назначен и в каком порядке пойдут job’ы, остаётся за пределами исходного кода COBOL. Если, глядя только на исходник, невозможно понять «а где вообще находится этот файл», обычно дело не в плохом коде, а просто в том, что рассматриваемая область ещё недостаточно широка.

8. Минимальный безопасный порядок чтения

Когда вам внезапно приходится читать COBOL, безопасен следующий порядок.

  1. Просмотреть все COPY Если copybook можно открыть — открыть. Если нет — поискать listing или развёрнутый исходник
  2. Собрать определения записей уровня 01 Составить список верхних уровней в FILE SECTION, WORKING-STORAGE и LINKAGE SECTION
  3. Прочитать PIC и USAGE Определить суммы, даты, количества, коды, флаги
  4. Найти READ / WRITE / REWRITE / CALL / EXEC SQL / EXEC CICS Сначала уловить ввод-вывод и внешние границы
  5. Проследить только первый основной маршрут Пройти по цепочке PERFORM от начала PROCEDURE DIVISION
  6. Посмотреть на 88 и элементы статуса После этого легче читаются значения EOF, признаков успеха/ошибки, кодов типа
  7. Отметить REDEFINES / OCCURS DEPENDING ON / COMP-3 Они обязательно скажутся позже, поэтому заранее пометьте их как опасные объекты
  8. Для файлов — посмотреть на FILE STATUS Это заметно снижает число ошибок при чтении, связанных с I/O

При таком порядке не приходится сразу же вчитываться во весь текст целиком. С COBOL гораздо легче не пытаться понять всё на 100% с самого начала, а сначала закрепить три точки — записи, внешние границы, основной маршрут — и только потом переходить к деталям.

9. Частые места затыка

В завершение соберём места, где новички спотыкаются с очень высокой вероятностью.

Считать REDEFINES «другой переменной»

Неверно. Это чтение одной и той же области в другой форме. Изменишь одну сторону — изменится и то, как выглядит другая.7

Считать 88 «отдельным bool»

Неверно. Это просто имя, присвоенное значению предшествующего элемента. SET WS-OK TO TRUE на самом деле записывает соответствующее значение в базовый элемент.3

Игнорировать COPY и читать только основной текст

Это всё равно что идти в горы со сложенной вдвое половиной карты. Совершенно обычное дело, когда определения полей, общие флаги и host-переменные целиком остаются снаружи.9

Считать MOVE простым присваиванием

MOVE — не просто memcpy. В зависимости от типа принимающего элемента может выполняться преобразование, выравнивание разрядов, заполнение нулями, усечение, а также редактирование и обратное редактирование (editing/de-editing).16

Недооценивать влияние .

Точка . в 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 Обработка БД
EXEC CICS Транзакционная обработка
FILE STATUS Код результата I/O

11. Итог

COBOL сложен не потому, что он старый. Просто определения данных, внешние файлы и контекст выполнения тесно переплетены между собой, из-за чего плохо видна точка входа.

Ещё раз соберём минимальный набор для чтения.

  • Ухватить карту через DIVISION
  • Сначала прочитать DATA DIVISION
  • Прочитать форму элементов через PIC и USAGE
  • Отметить COMP-3, REDEFINES, OCCURS, 88, COPY
  • Проследить за PERFORM, READ, WRITE, CALL
  • Закрепить внешние границы через FILE STATUS, EXEC SQL, EXEC CICS
  • Не недооценивать, как действует .

Когда это становится видно, COBOL превращается из «загадочной древней магии» в «язык обработки записей». Устаревшие технологии пугают не потому, что название старое, а лишь потому, что если ошибиться в масштабе, с которого начинаешь смотреть, всё внезапно перестаёт быть понятным. Если масштаб карты подобран верно, читается на удивление обычно.

12. Источники

Основные источники, упомянутые в статье.

  1. IBM, Reference format / IBM, Area A or Area B / Micro Focus, Fixed Format. О построчном фиксированном формате COBOL — нумерации колонок исходного кода, назначении Area A и Area B, а также об аналогичном описании fixed format в документации Micro Focus.  2

  2. IBM, Level-numbers. О том, что иерархию записи в COBOL задают номера уровней (01–49, 66, 77, 88), а не отступы в тексте.  2

  3. IBM, Format 2: condition-name value. О формате condition-name (уровень 88), присваивающем имя значению или диапазону значений связанного с ним элемента данных.  2

  4. IBM, Examples: numeric data and internal representation. О внутреннем представлении числовых данных COBOL в зависимости от USAGE, на конкретных примерах.  2

  5. IBM, PACKED-DECIMAL (COMP-3). Об USAGE PACKED-DECIMAL (COMP-3) — формате хранения packed decimal. 

  6. IBM, The EBCDIC character set / IBM, Handling differences in ASCII SBCS and EBCDIC SBCS characters. О наборе символов EBCDIC на mainframe-платформах и об обработке различий между однобайтовыми наборами символов ASCII и EBCDIC.  2 3

  7. IBM, Предложение REDEFINES. О предложении REDEFINES — механизме повторного описания одной и той же области памяти в другой форме.  2

  8. IBM, OCCURS DEPENDING ON clause. О предложении OCCURS DEPENDING ON, определяющем таблицы переменной длины.  2

  9. IBM, Оператор COPY. Об операторе COPY как о механизме include времени компиляции.  2

  10. IBM, Enterprise COBOL compiler options. О параметрах компилятора Enterprise COBOL, включая опцию MDECK для вывода исходного кода после обработки библиотечных COPY. 

  11. IBM, PERFORM statement / IBM, Procedure division structure. Об операторе PERFORM и об общей структуре PROCEDURE DIVISION, включая out-of-line и inline формы, а также диапазонную форму THRU. 

  12. IBM, Scope terminators / IBM, Coding a choice of actions. О явных и неявных (через точку) scope terminator’ах в COBOL и о правилах построения условных конструкций, включая поведение NEXT SENTENCE.  2 3 4

  13. IBM, Подробное описание структуры файла. О связке FILE-CONTROL в ENVIRONMENT DIVISION и FD / FILE SECTION в DATA DIVISION при описании структуры файла. 

  14. IBM, FILE STATUS clause / IBM, Using file status keys. О предложении FILE STATUS и об использовании ключей статуса файла для определения результата каждой операции ввода-вывода. 

  15. IBM, Написание программ COBOL для выполнения под управлением CICS. О написании программ COBOL, выполняющихся в транзакционной среде CICS. 

  16. IBM, Elementary move rules. О правилах элементарного MOVE — преобразовании, выравнивании разрядов, заполнении нулями, усечении и редактировании/обратном редактировании при пересылке данных между элементами разных типов. 

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу

Разбираем практический план начала эксплуатации и сопровождения бизнес-системы, у которой нет ни исходного кода, ни спецификаций. Охватыв...

Реагирование на инциденты не заканчивается восстановлением — шаблон постмортема (предотвращения повторения) для небольших команд разработки

Считать инцидент закрытым сразу после исправления и извинений — гарантированный способ повторить его снова. Адаптируем blameless-постморт...

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Технические консультации и ревью дизайна

Тема хорошо сочетается с технической консультацией и ревью архитектуры — сюда входит и то, как разбираться в существующих активах на COBOL, откуда начинать доработку, как выявлять внешние границы, и как формировать предварительную оценку перед миграцией.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

С чего лучше начинать чтение исходного кода на COBOL?
Если прочитать только PROCEDURE DIVISION, вы поймёте от силы половину. COBOL — прежде чем быть языком логики — довольно сильно является языком определения записей, поэтому сначала стоит посмотреть на DATA DIVISION. Безопасный порядок чтения такой: сначала просмотреть все COPY и открыть copybook'и, составить список определений записей уровня 01, прочитать форму элементов через PIC и USAGE, затем найти READ, WRITE, CALL, EXEC SQL и EXEC CICS, чтобы понять ввод-вывод и внешние границы, и только после этого проследить цепочку PERFORM от начала PROCEDURE DIVISION, ограничившись основным маршрутом.
Что означает PIC S9(7)V99 COMP-3?
PIC описывает форму элемента, а USAGE — в каком представлении он хранится. S9(7)V99 означает число со знаком: 7 разрядов целой части и 2 разряда дробной, но V — это лишь логическая десятичная точка, и никакого символа точки в данных фактически нет. COMP-3 — это packed decimal, и такое USAGE часто встречается у сумм, налогов, количеств и ставок. Если смотреть на такие данные как на текст, они закономерно выглядят «битыми», поэтому разглядывать дамп в настроении CSV или UTF-8 — верный способ получить неприятности.
Как правильно понимать уровень 88 и REDEFINES в COBOL?
88 — это не отдельная bool-переменная, а условное имя (condition-name), присвоенное значению предшествующего элемента. SET WS-OK TO TRUE на самом деле записывает соответствующее значение в базовый элемент. REDEFINES — это механизм просмотра одной и той же области памяти в другой форме; это не копирование, а нечто близкое к union в C-подобных языках. Изменение одной стороны меняет и то, как выглядит другая, поэтому такая конструкция часто применяется, чтобы различать типы записей в пределах одной области памяти.
Что делать, если из-за обилия COPY не видно общей картины?
COPY — это include времени компиляции, поэтому открытый вами исходник вполне может оказаться ещё не в окончательном виде. Определения записей, общие флаги, host-переменные для SQL и внешние интерфейсы вполне обычно оказываются загнаны в copybook. Если из-за этого читать становится трудно, быстрее всего проверить, можно ли посмотреть развёрнутый исходник или compiler listing; в IBM Enterprise COBOL для этого даже есть опция MDECK, которая выводит входной исходный код после обработки библиотек.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог