PERFORM: как в COBOL устроены циклы
В COBOL нет отдельных слов for и while — обе идеи циклов выражаются через одну конструкцию PERFORM с разными вариантами.
PERFORM — оператор, который повторяет блок кода заданное число раз или пока выполняется условие, объединяя в себе роли for-цикла и while-цикла из других языков.
Зачем один оператор вместо двух
В языках вроде Python или Java обычно есть отдельно for — для случая «повторить N раз» или «пройтись по списку», и отдельно while — для случая «повторять, пока верно условие». COBOL решает обе задачи одной конструкцией PERFORM, у которой есть несколько форм записи. Это не значит, что COBOL менее гибкий — просто вся логика повторения сосредоточена в одном ключевом слове, а разница выражается в дополнительных параметрах после него.
Разберём две главные формы: PERFORM VARYING (когда заранее известно, сколько раз и как меняется счётчик) и PERFORM UNTIL (когда повторяем, пока не выполнится условие, а сколько именно раз — заранее не известно).
PERFORM VARYING — аналог for
Представьте, что нужно распечатать таблицу умножения на 5, от 1 до 10. Синтаксис:
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 10
COMPUTE WS-RESULT = WS-I * 5
DISPLAY WS-I " x 5 = " WS-RESULT
END-PERFORM.Вывод (первые и последние строки):
1 x 5 = 5
2 x 5 = 10
3 x 5 = 15
...
10 x 5 = 50Читаем построчно:
WS-I— переменная-счётчик, её нужно заранее объявить как числовое поле (например,PIC 9(2)).FROM 1— начальное значение счётчика.BY 1— шаг, на который счётчик увеличивается после каждого прохода. Можно поставить иBY 2, чтобы перебирать только чётные или только нечётные числа.UNTIL WS-I > 10— условие остановки. Важный момент: это условие ОКОНЧАНИЯ цикла, а не условие продолжения. Цикл работает, покаWS-I > 10ложно, и останавливается, как только оно становится истинным.END-PERFORM— обязательная граница тела цикла, как END-IF у условия.
Обратите внимание: увеличение счётчика (BY 1) и проверка условия происходят автоматически на каждом шаге — вам не нужно вручную писать ADD 1 TO WS-I внутри тела, как пришлось бы в некоторых других языках при ручной реализации цикла.
PERFORM UNTIL — аналог while
Если заранее неизвестно, сколько раз нужно повторить действие — например, читаем строки из файла, пока не наткнёмся на его конец — используется более простая форма без счётчика:
MOVE 0 TO WS-SUM
MOVE 1 TO WS-N
PERFORM UNTIL WS-N > 5
ADD WS-N TO WS-SUM
ADD 1 TO WS-N
END-PERFORM.
DISPLAY "Сумма чисел от 1 до 5: " WS-SUM.Вывод:
Сумма чисел от 1 до 5: 15Здесь счётчик WS-N заводится и обновляется вручную двумя отдельными операторами ADD — PERFORM UNTIL сам по себе ничего не меняет, только проверяет условие перед каждым проходом. Это делает форму гибче: условие остановки может зависеть от чего угодно, а не только от простого счётчика — например, от флага, который выставляет операция чтения файла.
Как выглядит бесконечный цикл (и почему это баг)
Частая ошибка новичков — забыть обновить переменную, от которой зависит условие остановки:
MOVE 1 TO WS-N
PERFORM UNTIL WS-N > 5
DISPLAY "Итерация"
END-PERFORM.В этом коде WS-N никогда не меняется внутри цикла, условие WS-N > 5 никогда не станет истинным, и программа будет печатать "Итерация" бесконечно, пока её принудительно не остановят. Это не какая-то особая для COBOL проблема — та же логическая ошибка возможна в любом языке с while-подобным циклом, но в COBOL её особенно легко допустить, потому что счётчик в PERFORM UNTIL нужно вести полностью вручную.
Частые ошибки
- Перепутать UNTIL с условием продолжения.
UNTIL WS-I > 10значит «остановись, когда стало больше 10», а не «продолжай, пока больше 10» — это частая логическая путаница у тех, кто ожидает синтаксис вида «while условие верно». - Забыть обновить переменную в PERFORM UNTIL, что приводит к бесконечному циклу, как в примере выше.
- Забыть END-PERFORM, из-за чего тело цикла становится неоднозначным — компилятор либо выдаст ошибку, либо (в старом синтаксисе с точкой) захватит в тело больше или меньше строк, чем задумывалось.
Итоги
- PERFORM VARYING — цикл со счётчиком, аналог for: начальное значение, шаг, условие остановки задаются в одной строке.
- PERFORM UNTIL — цикл по условию, аналог while: счётчик (если он нужен) ведётся вручную внутри тела.
- Условие в UNTIL — это условие ОКОНЧАНИЯ, а не продолжения цикла.
- END-PERFORM обязателен для многострочного тела цикла.