The UNTIL clause in COBOL is used with the PERFORM statement to create loops that continue executing until a specified condition becomes true. Unlike loops that run while a condition is true, UNTIL loops run while the condition is false, stopping when the condition becomes true. Understanding UNTIL is essential for creating conditional loops, processing data until a termination condition is met, and implementing iterative logic in mainframe COBOL programs.
The UNTIL clause creates a loop that executes repeatedly until a condition becomes true. Key characteristics:
UNTIL is ideal for scenarios where you want to "keep going until something happens" rather than "keep going while something is true."
The basic syntax for PERFORM UNTIL is:
12345678910PERFORM paragraph-name UNTIL condition *> Or with inline code: PERFORM statement-1 statement-2 ... UNTIL condition END-PERFORM
Components:
123456789101112131415161718192021222324WORKING-STORAGE SECTION. 01 END-OF-FILE PIC X VALUE 'N'. 01 RECORD-COUNT PIC 9(5) VALUE ZERO. PROCEDURE DIVISION. MAIN-PARA. OPEN INPUT INPUT-FILE READ INPUT-FILE AT END MOVE 'Y' TO END-OF-FILE END-READ PERFORM PROCESS-RECORD UNTIL END-OF-FILE = 'Y' DISPLAY 'Records processed: ' RECORD-COUNT CLOSE INPUT-FILE STOP RUN. PROCESS-RECORD. ADD 1 TO RECORD-COUNT *> Process the record... READ INPUT-FILE AT END MOVE 'Y' TO END-OF-FILE END-READ.
In this example:
123456789101112131415WORKING-STORAGE SECTION. 01 COUNTER PIC 9(3) VALUE 1. 01 MAX-COUNT PIC 9(3) VALUE 10. PROCEDURE DIVISION. MAIN-PARA. PERFORM DISPLAY-COUNT UNTIL COUNTER > MAX-COUNT DISPLAY 'Counting complete' STOP RUN. DISPLAY-COUNT. DISPLAY 'Count: ' COUNTER ADD 1 TO COUNTER.
This loop:
You can use UNTIL with inline statements using END-PERFORM:
1234567891011121314151617WORKING-STORAGE SECTION. 01 USER-INPUT PIC X(10). 01 VALID-INPUT PIC X VALUE 'N'. PROCEDURE DIVISION. MAIN-PARA. PERFORM DISPLAY 'Enter a value: ' ACCEPT USER-INPUT IF USER-INPUT NOT = SPACES MOVE 'Y' TO VALID-INPUT END-IF UNTIL VALID-INPUT = 'Y' END-PERFORM DISPLAY 'Valid input received: ' USER-INPUT STOP RUN.
This loop:
You can combine UNTIL with VARYING to create loops that both increment a counter and check a condition:
12345678910111213WORKING-STORAGE SECTION. 01 COUNTER PIC 9(3). 01 SUM PIC 9(5) VALUE ZERO. PROCEDURE DIVISION. MAIN-PARA. PERFORM VARYING COUNTER FROM 1 BY 1 UNTIL COUNTER > 100 COMPUTE SUM = SUM + COUNTER END-PERFORM DISPLAY 'Sum of 1 to 100: ' SUM STOP RUN.
This loop:
123456789101112WORKING-STORAGE SECTION. 01 COUNTER PIC 9(3). PROCEDURE DIVISION. MAIN-PARA. *> Count by 5s until reaching 50 PERFORM VARYING COUNTER FROM 5 BY 5 UNTIL COUNTER > 50 DISPLAY 'Count: ' COUNTER END-PERFORM STOP RUN.
This displays: 5, 10, 15, 20, 25, 30, 35, 40, 45, 50. The loop increments by 5 each iteration until COUNTER exceeds 50.
COBOL allows you to control when the condition is tested:
The condition is tested at the end of each iteration. The loop body always executes at least once:
1234567891011121314WORKING-STORAGE SECTION. 01 COUNTER PIC 9(3) VALUE 10. PROCEDURE DIVISION. MAIN-PARA. *> Default: TEST AFTER PERFORM DISPLAY-COUNT UNTIL COUNTER > 5 *> This executes once even though COUNTER (10) > 5 initially STOP RUN. DISPLAY-COUNT. DISPLAY 'Count: ' COUNTER.
Even though COUNTER (10) is already greater than 5, the loop executes once because the condition is tested after the loop body runs.
The condition is tested before each iteration. The loop body may not execute if the condition is true initially:
123456789101112131415WORKING-STORAGE SECTION. 01 COUNTER PIC 9(3) VALUE 10. PROCEDURE DIVISION. MAIN-PARA. *> TEST BEFORE: condition checked first PERFORM DISPLAY-COUNT WITH TEST BEFORE UNTIL COUNTER > 5 *> This does NOT execute because COUNTER (10) > 5 initially STOP RUN. DISPLAY-COUNT. DISPLAY 'Count: ' COUNTER.
With TEST BEFORE, the condition is checked first. Since COUNTER (10) is already greater than 5, the loop body never executes.
| Aspect | TEST AFTER (Default) | TEST BEFORE |
|---|---|---|
| When condition is tested | At the end of each iteration | Before each iteration |
| Minimum executions | At least once (if condition starts false) | Zero times (if condition starts true) |
| Use when | You want loop to always run at least once | You want to skip loop if condition is already true |
| Syntax | PERFORM ... UNTIL condition (default) | PERFORM ... WITH TEST BEFORE UNTIL condition |
UNTIL can use complex conditions with logical operators:
1234567891011121314151617WORKING-STORAGE SECTION. 01 COUNTER PIC 9(3) VALUE 1. 01 FOUND-FLAG PIC X VALUE 'N'. PROCEDURE DIVISION. MAIN-PARA. PERFORM SEARCH-LOOP UNTIL COUNTER > 100 AND FOUND-FLAG = 'Y' STOP RUN. SEARCH-LOOP. *> Continue until COUNTER exceeds 100 OR item is found *> (Loop stops when COUNTER > 100 AND FOUND-FLAG = 'Y') *> This means: stop when BOTH conditions are true ADD 1 TO COUNTER.
The loop continues while either COUNTER is not greater than 100 OR FOUND-FLAG is not 'Y'. It stops only when both conditions are true simultaneously.
12345678910111213141516WORKING-STORAGE SECTION. 01 END-OF-FILE PIC X VALUE 'N'. 01 ERROR-FLAG PIC X VALUE 'N'. PROCEDURE DIVISION. MAIN-PARA. PERFORM PROCESS-RECORD UNTIL END-OF-FILE = 'Y' OR ERROR-FLAG = 'Y' STOP RUN. PROCESS-RECORD. *> Stop if end of file OR error occurs *> Loop continues while BOTH are false *> Stops when EITHER becomes true.
The loop stops when either END-OF-FILE is 'Y' OR ERROR-FLAG is 'Y'. It continues only while both are false.
123456789101112WORKING-STORAGE SECTION. 01 CONTINUE-FLAG PIC X VALUE 'Y'. PROCEDURE DIVISION. MAIN-PARA. PERFORM PROCESS-LOOP UNTIL NOT CONTINUE-FLAG = 'Y' *> Equivalent to: UNTIL CONTINUE-FLAG NOT = 'Y' *> Loop continues while CONTINUE-FLAG = 'Y' *> Stops when CONTINUE-FLAG is not 'Y' STOP RUN.
Using NOT inverts the condition. The loop continues while CONTINUE-FLAG is 'Y' and stops when it's not 'Y'.
You can exit a PERFORM UNTIL loop before the condition becomes true:
1234567891011121314151617181920WORKING-STORAGE SECTION. 01 END-FLAG PIC X VALUE 'N'. 01 COUNTER PIC 9(3) VALUE 1. PROCEDURE DIVISION. MAIN-PARA. PERFORM PROCESS-LOOP UNTIL END-FLAG = 'Y' STOP RUN. PROCESS-LOOP. ADD 1 TO COUNTER *> Exit early if counter reaches 50 IF COUNTER > 50 MOVE 'Y' TO END-FLAG END-IF *> Continue processing...
By setting END-FLAG to 'Y' when COUNTER exceeds 50, the loop exits at the end of the current iteration, even though the original condition might have been different.
12345678910PROCEDURE DIVISION. MAIN-PARA. PERFORM *> Process item IF ERROR-CONDITION EXIT PERFORM END-IF *> More processing... UNTIL END-CONDITION END-PERFORM.
EXIT PERFORM immediately exits the current iteration and continues with the next iteration (or exits the loop if the UNTIL condition is now true).
Understanding when to use UNTIL vs WHILE:
| Aspect | UNTIL | WHILE |
|---|---|---|
| Loop continues while | Condition is FALSE | Condition is TRUE |
| Loop stops when | Condition becomes TRUE | Condition becomes FALSE |
| Natural expression | "Keep going until X happens" | "Keep going while X is true" |
| Example | UNTIL END-OF-FILE = 'Y' | WHILE NOT END-OF-FILE |
| Readability | Better for "until something happens" | Better for "while condition holds" |
Use UNTIL when:
Use WHILE when:
1234567891011PERFORM READ-AND-PROCESS UNTIL END-OF-FILE = 'Y' READ-AND-PROCESS. READ INPUT-FILE AT END MOVE 'Y' TO END-OF-FILE END-READ IF END-OF-FILE NOT = 'Y' *> Process the record END-IF.
1234567891011MOVE 'N' TO VALID-INPUT PERFORM DISPLAY 'Enter value (1-100): ' ACCEPT USER-INPUT IF USER-INPUT IS NUMERIC IF USER-INPUT >= 1 AND USER-INPUT <= 100 MOVE 'Y' TO VALID-INPUT END-IF END-IF UNTIL VALID-INPUT = 'Y' END-PERFORM.
1234567891011MOVE 1 TO SEARCH-INDEX PERFORM SEARCH-LOOP UNTIL SEARCH-INDEX > MAX-ITEMS OR ITEM-FOUND = 'Y' SEARCH-LOOP. IF SEARCH-ARRAY(SEARCH-INDEX) = TARGET-VALUE MOVE 'Y' TO ITEM-FOUND ELSE ADD 1 TO SEARCH-INDEX END-IF.
Follow these best practices when using UNTIL:
Avoid these common mistakes:
123456789*> WRONG: Condition never becomes true MOVE 1 TO COUNTER PERFORM PROCESS-LOOP UNTIL COUNTER = 0 PROCESS-LOOP. ADD 1 TO COUNTER *> COUNTER starts at 1 and only increases *> It will never equal 0 - INFINITE LOOP!
The condition COUNTER = 0 can never become true because COUNTER only increases. This creates an infinite loop.
1234567891011*> WRONG: May execute when you don't want it to MOVE 100 TO COUNTER PERFORM PROCESS-LOOP UNTIL COUNTER > 50 *> Loop executes once even though COUNTER (100) > 50 *> CORRECT: Use TEST BEFORE PERFORM PROCESS-LOOP WITH TEST BEFORE UNTIL COUNTER > 50 *> Loop does not execute because condition is true initially
12345678910*> WRONG: Using AND when you mean OR PERFORM PROCESS-LOOP UNTIL END-OF-FILE = 'Y' AND ERROR-FLAG = 'Y' *> This requires BOTH to be true to exit *> If only one is true, loop continues forever *> CORRECT: Use OR PERFORM PROCESS-LOOP UNTIL END-OF-FILE = 'Y' OR ERROR-FLAG = 'Y' *> Exits when EITHER condition is true
Think of UNTIL like playing a game:
So UNTIL is like a game where you keep taking turns until you win or reach a goal, and you always get to play at least one turn!
Complete these exercises to reinforce your understanding of UNTIL:
Create a program that uses PERFORM UNTIL to count down from 10 to 1, displaying each number. The loop should stop when the counter reaches 0.
Create a program that uses PERFORM VARYING ... UNTIL to sum numbers from 1 to 100. Display the final sum.
Create a program that uses PERFORM UNTIL to repeatedly prompt for user input until a valid number between 1 and 10 is entered. Use a flag to track valid input.
Create a program that uses PERFORM UNTIL to search through an array until either the target value is found or the end of the array is reached. Use OR in the UNTIL condition.
Create two versions of a loop: one with TEST AFTER (default) and one with TEST BEFORE. Initialize a counter to 10 and loop UNTIL counter > 5. Observe the difference in execution.
1. What does PERFORM UNTIL do?
2. When is the UNTIL condition tested?
3. What happens if the UNTIL condition is true from the start?
4. How do you create a loop that increments a counter until it reaches 10?
5. What is the difference between UNTIL and WHILE?
6. How do you exit a PERFORM UNTIL loop early?