Control Flow in PL/I
Learn conditionals, SELECT groups, and the many forms of the DO loop in PL/I with runnable, Docker-ready examples using the Iron Spring compiler
Control flow is how a program decides what to do and how many times to do it. PL/I, designed in 1964 as IBM’s “one language to rule them all,” was one of the earliest mainstream languages to embrace structured programming — block-structured conditionals and loops with explicit END terminators, rather than the tangle of GOTO statements common in its FORTRAN and assembly contemporaries.
As an imperative, procedural, and structured language, PL/I gives you a rich set of control constructs: the familiar IF/THEN/ELSE, the multi-way SELECT group (a switch/case ancestor), and a remarkably versatile DO statement that handles counted loops, conditional loops, and post-tested loops all with one keyword. PL/I’s strong, static typing means the compiler checks your comparisons and loop bounds at compile time.
In this tutorial you’ll learn how to branch with IF and SELECT, iterate with every flavor of DO, and control loops early with LEAVE. Every example is a complete, runnable program you can compile with the Iron Spring PL/I compiler inside Docker.
Conditionals: IF / THEN / ELSE
The IF statement evaluates a condition and runs the statement after THEN when it’s true. Add ELSE for the false branch, and chain ELSE IF for multi-way decisions. To run more than one statement in a branch, wrap the statements in a DO; ... END; group.
PL/I uses & for logical AND, | for logical OR, and ^= for “not equal” (the ^ is PL/I’s NOT operator).
Create a file named conditionals.pli:
CONDITIONALS: PROCEDURE OPTIONS(MAIN);
DECLARE SCORE FIXED BINARY(15);
SCORE = 85;
/* Multi-way branch with chained ELSE IF */
IF SCORE >= 90 THEN
PUT LIST('Grade: A');
ELSE IF SCORE >= 80 THEN
PUT LIST('Grade: B');
ELSE IF SCORE >= 70 THEN
PUT LIST('Grade: C');
ELSE
PUT LIST('Grade: F');
/* Compound condition runs a DO group of several statements */
IF SCORE >= 80 & SCORE < 90 THEN
DO;
PUT SKIP LIST('You passed with a solid grade.');
PUT SKIP LIST('Keep up the good work!');
END;
END CONDITIONALS;
Note that a bare IF ... THEN statement; runs only the single statement that follows THEN. The DO; ... END; group is how PL/I lets a branch control a block of statements — the same idea as { } braces in C, which PL/I predates by nearly a decade.
Multi-Way Branching: SELECT
When you need to choose among many discrete cases, the SELECT group is cleaner than a long IF/ELSE IF chain. PL/I offers two forms:
SELECT (expression);— compares the control expression against eachWHENvalue.SELECT;— evaluates eachWHENas an independent boolean condition (handy for ranges).
OTHERWISE catches anything not matched, like default in a C switch. Unlike C, PL/I’s SELECT does not fall through — exactly one WHEN (or OTHERWISE) runs.
Create a file named select.pli:
SELECTDEMO: PROCEDURE OPTIONS(MAIN);
DECLARE DAY FIXED BINARY(15);
/* Form 1: match the control expression against WHEN values */
DAY = 3;
SELECT (DAY);
WHEN (1) PUT LIST('Monday');
WHEN (2) PUT LIST('Tuesday');
WHEN (3) PUT LIST('Wednesday');
WHEN (4) PUT LIST('Thursday');
WHEN (5) PUT LIST('Friday');
OTHERWISE PUT LIST('Weekend');
END;
/* Form 2: each WHEN is a full boolean condition */
DAY = 7;
SELECT;
WHEN (DAY >= 1 & DAY <= 5) PUT SKIP LIST('It is a weekday.');
WHEN (DAY = 6 | DAY = 7) PUT SKIP LIST('It is the weekend.');
OTHERWISE PUT SKIP LIST('Invalid day.');
END;
END SELECTDEMO;
Counted Loops: The DO Statement
The DO statement is PL/I’s workhorse iterator. The counted form DO var = start TO end; runs the loop body once for each value, automatically incrementing the control variable. Add BY step to change the increment (including negative steps to count down).
Create a file named loops.pli:
LOOPS: PROCEDURE OPTIONS(MAIN);
DECLARE I FIXED BINARY(15);
DECLARE TOTAL FIXED BINARY(31);
/* Simple counted loop, 1 through 5 */
PUT LIST('Counting 1 to 5:');
DO I = 1 TO 5;
PUT SKIP EDIT(' Count = ', I) (A, F(1));
END;
/* Counted loop with a step using BY */
PUT SKIP LIST('Even numbers 2 to 10:');
DO I = 2 TO 10 BY 2;
PUT SKIP EDIT(' Even = ', I) (A, F(2));
END;
/* Accumulate a running total across iterations */
TOTAL = 0;
DO I = 1 TO 100;
TOTAL = TOTAL + I;
END;
PUT SKIP EDIT('Sum of 1 to 100 = ', TOTAL) (A, F(4));
END LOOPS;
Here we use PUT EDIT instead of PUT LIST for the numbers. The format item F(w) writes an integer right-justified in a field of width w, giving precise, predictable column alignment — F(2) prints 10 as 10 and 2 as 2.
Conditional Loops: DO WHILE and DO UNTIL
Not every loop has a known count. PL/I provides two condition-controlled forms:
DO WHILE (cond);— tests the condition before each iteration. The body may run zero times.DO UNTIL (cond);— tests the condition after each iteration. The body always runs at least once.
Create a file named whileloops.pli:
WHILELOOPS: PROCEDURE OPTIONS(MAIN);
DECLARE N FIXED BINARY(15);
/* DO WHILE tests the condition BEFORE each pass */
PUT LIST('Countdown with DO WHILE:');
N = 5;
DO WHILE (N > 0);
PUT SKIP EDIT(' N = ', N) (A, F(1));
N = N - 1;
END;
/* DO UNTIL tests the condition AFTER each pass */
PUT SKIP LIST('Doubling with DO UNTIL:');
N = 1;
DO UNTIL (N > 50);
PUT SKIP EDIT(' N = ', N) (A, F(2));
N = N * 2;
END;
END WHILELOOPS;
Early Loop Exit: LEAVE
PL/I’s LEAVE statement immediately exits the enclosing DO loop — the equivalent of break in C-family languages. To conditionally skip work within an iteration, the structured approach is to guard the work with an IF test (PL/I’s built-in MOD function returns the remainder of a division).
Create a file named loopctl.pli:
LOOPCTL: PROCEDURE OPTIONS(MAIN);
DECLARE I FIXED BINARY(15);
/* Guard with IF to act only on odd numbers */
PUT LIST('Odd numbers from 1 to 10:');
DO I = 1 TO 10;
IF MOD(I, 2) ^= 0 THEN
PUT SKIP EDIT(' Odd = ', I) (A, F(2));
END;
/* LEAVE exits the loop the moment a match is found */
PUT SKIP LIST('First multiple of 7:');
DO I = 1 TO 100;
IF MOD(I, 7) = 0 THEN
DO;
PUT SKIP EDIT(' Found ', I) (A, F(2));
LEAVE;
END;
END;
END LOOPCTL;
Running with Docker
These examples use the custom codearchaeology/pli:latest image with the Iron Spring PL/I compiler. The plicc wrapper compiles and links in one step, producing an executable named after the source file (loops.pli → ./loops). The --security-opt seccomp=unconfined flag is required for the 32-bit compiler on Docker Desktop.
| |
Expected Output
conditionals.pli (SCORE is 85, so the B branch and the compound block both run):
Grade: B
You passed with a solid grade.
Keep up the good work!
select.pli (DAY is 3, then 7):
Wednesday
It is the weekend.
loops.pli:
Counting 1 to 5:
Count = 1
Count = 2
Count = 3
Count = 4
Count = 5
Even numbers 2 to 10:
Even = 2
Even = 4
Even = 6
Even = 8
Even = 10
Sum of 1 to 100 = 5050
whileloops.pli:
Countdown with DO WHILE:
N = 5
N = 4
N = 3
N = 2
N = 1
Doubling with DO UNTIL:
N = 1
N = 2
N = 4
N = 8
N = 16
N = 32
loopctl.pli:
Odd numbers from 1 to 10:
Odd = 1
Odd = 3
Odd = 5
Odd = 7
Odd = 9
First multiple of 7:
Found 7
Key Concepts
IF/THEN/ELSEcontrols one statement by default — wrap multiple statements in aDO; ... END;group to make a branch govern a block.- Logical operators are
&(AND),|(OR), and^(NOT) — so “not equal” is written^=. These work inIFandWHENconditions alike. SELECTis PL/I’s switch/case ancestor and comes in two forms:SELECT (expr)matches values, while bareSELECTevaluates eachWHENas a boolean condition. There is no fall-through — exactly one branch runs.- One
DOkeyword, many loop shapes: counted (DO I = 1 TO 10 BY 2), pre-tested (DO WHILE), and post-tested (DO UNTIL).WHILEmay run zero times;UNTILalways runs at least once. LEAVEexits a loop early, likebreak— and the structured way to skip an iteration is a guardingIFrather than a jump.- Every block construct ends with an explicit
END, a hallmark of PL/I’s early commitment to structured programming overGOTO. PUT EDITwith anF(w)format gives precise, column-aligned numeric output, whilePUT SKIPstarts a fresh line before writing.
Running Today
All examples can be run using Docker:
docker pull codearchaeology/pli:latest
Comments
Loading comments...
Leave a Comment