Уровни записей: 01, 05, 88
Разбираемся, как из простых PIC-полей строится иерархическая структура — «карточка» с вложенными данными — и что за особый уровень 88 умеет заменять сравнение на понятное имя.
Уровень записи — число в начале объявления COBOL-переменной, которое показывает её место в иерархии: является ли она самостоятельной записью или частью более крупной структуры.
Зачем данным иерархия
До сих пор мы объявляли переменные по одной: имя, возраст, зарплата — каждая сама по себе. Но в реальной программе часто нужно сгруппировать связанные данные вместе — например, «адрес» логично состоит из города, улицы и дома, а «сотрудник» — из имени, должности и зарплаты. В Python для этого используют словари или классы: sotrudnik = {"imya": "Ivanov", "dolzhnost": "Buhgalter"}. В COBOL для той же цели служат уровни записей — числа вроде 01, 05, 10, которые показывают, что одно поле «вложено» в другое, подобно папкам и файлам на компьютере.
Уровень 01 всегда обозначает вершину структуры — самостоятельную запись целиком. Всё, что вложено внутрь неё, получает более крупные числа уровня — обычно с шагом 05: 05, 10, 15 и так далее. Чем больше число уровня, тем глубже вложенность, примерно как заголовки h2 и h3 на веб-странице показывают структуру статьи.
Пример: карточка сотрудника
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SOTRUDNIK.
05 IMYA PIC X(20) VALUE "Ivanov".
05 DOLZHNOST PIC X(15) VALUE "Buhgalter".
05 ZARPLATA PIC 9(6) VALUE 45000.
PROCEDURE DIVISION.
DISPLAY "Zapis celikom: " SOTRUDNIK.
DISPLAY "Tolko imya: " IMYA.
STOP RUN.Вывод:
Zapis celikom: Ivanov Buhgalter 045000
Tolko imya: IvanovРазбираем построчно
Строка 01 SOTRUDNIK. объявляет запись верхнего уровня — обратите внимание, у неё нет PIC-клаузы, потому что сама по себе она не хранит данные напрямую, а просто «называет» группу. Дальше идут три поля уровня 05: IMYA, DOLZHNOST и ZARPLATA — каждое со своей PIC-клаузой, как мы разбирали в предыдущем уроке. Эти три поля физически и составляют содержимое записи SOTRUDNIK — если сложить их длины (20 + 15 + 6 = 41 байт), это и будет полный размер записи целиком.
В программе можно обратиться и к записи целиком по имени SOTRUDNIK — тогда COBOL напечатает все вложенные поля подряд, как единую строку — и к отдельному вложенному полю по имени IMYA, если нужно только оно. Это удобно: иногда нужно обработать запись как единый блок (например, записать в файл), а иногда — работать только с одним конкретным полем внутри неё.
Уровень 88 — не поле, а именованное условие
Особый и очень практичный случай — уровень 88. Он не описывает отдельные данные, а даёт имя условию, связанному со значением поля уровнем выше. Представьте, что у вас есть поле «статус заказа», которое может быть 1 (новый), 2 (в обработке) или 3 (завершён). Вместо того чтобы в каждом месте кода писать громоздкое сравнение IF STATUS = 3, можно один раз объявить понятное имя для этого условия.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 STATUS-ZAKAZA PIC 9 VALUE 1.
88 ZAKAZ-NOVYY VALUE 1.
88 ZAKAZ-V-RABOTE VALUE 2.
88 ZAKAZ-ZAVERSHEN VALUE 3.
PROCEDURE DIVISION.
IF ZAKAZ-NOVYY
DISPLAY "Zakaz tolko sozdan"
END-IF.
STOP RUN.Вывод:
Zakaz tolko sozdanРазбираем условное имя подробно
Строка 01 STATUS-ZAKAZA PIC 9 VALUE 1. — это обычное числовое поле из одной цифры с начальным значением 1. А дальше идут три строки уровня 88: каждая не создаёт новую переменную, а просто говорит «условие ZAKAZ-NOVYY истинно тогда, когда STATUS-ZAKAZA равен 1». Дальше в PROCEDURE DIVISION вместо явного сравнения IF STATUS-ZAKAZA = 1 мы пишем просто IF ZAKAZ-NOVYY — код становится читаемым почти как обычное предложение на английском, что и было исторической целью языка COBOL (COmmon Business-Oriented Language дословно и означает «общий бизнес-ориентированный язык» — его специально придумывали так, чтобы менеджеры, не программисты, могли хотя бы читать код).
Это отдалённо похоже на именованные константы или enum в современных языках (например, OrderStatus.NEW в Java), но работает даже более прямолинейно — уровень 88 буквально привязывается к конкретному значению конкретного поля, а не создаёт отдельный самостоятельный тип.
Мини-пример: карточка ученика с условием
Соберём три идеи раздела вместе: группировку через уровни 01/05 и условное имя через уровень 88.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 UCHENIK-ZAPIS.
05 IMYA-UCH PIC X(15) VALUE "Sidorova".
05 OTSENKA PIC 9 VALUE 5.
88 OTLICHNO VALUE 5.
PROCEDURE DIVISION.
IF OTLICHNO
DISPLAY IMYA-UCH " uchitsya na otlichno"
END-IF.
STOP RUN.Вывод:
Sidorova uchitsya na otlichnoЗдесь UCHENIK-ZAPIS уровня 01 — вся запись целиком, IMYA-UCH и OTSENKA уровня 05 — два вложенных поля, а OTLICHNO уровня 88 — условное имя, привязанное к конкретному значению оценки. Заметьте, что уровень 88 в этом примере вложен ещё глубже — он идёт сразу после поля OTSENKA, к которому относится, а не после всей записи.
Частые ошибки новичков
Первая ошибка — пытаться дать записи уровня 01 собственную PIC-клаузу, если у неё есть вложенные поля. Запись-группа (та, что содержит другие поля) PIC не имеет — её «форма» целиком определяется суммой вложенных полей.
Вторая ошибка — перепутать порядок вложенности уровней. Числа уровней не обязаны идти строго по единице, но должны логично возрастать сверху вниз: нельзя, чтобы поле уровня 05 шло раньше уровня 01, или чтобы поле с меньшим числом уровня оказалось «внутри» поля с большим — иерархия должна быть последовательной, как вложенные списки.
Третья ошибка — забыть, что уровень 88 не создаёт переменную, которую можно менять напрямую. Нельзя написать MOVE 5 TO ZAKAZ-NOVYY — вместо этого значение меняют у поля-родителя (STATUS-ZAKAZA), а условие 88 лишь проверяет результат. Начинающие иногда путают условное имя с обычным полем и удивляются ошибке компиляции.
Итоги
- Уровни записей (числа вроде 01, 05, 10) строят иерархию данных: запись верхнего уровня 01 объединяет вложенные поля с бо́льшими числами уровня.
- Запись-группа без вложенных PIC-полей не хранит данные напрямую — её размер определяется суммой всех вложенных полей.
- Уровень 88 — особый случай: он не поле, а именованное условие, привязанное к конкретному значению поля-родителя, что делает код читаемым почти как обычный текст.
- Такая структура данных — предшественник современных вложенных объектов и enum-типов, только оформленная под язык, придуманный для мейнфреймов 1960-х годов.