Chapter 8
Program Control
The statements described in this chapter direct the run-time flow of execution from statement to statement. They are the DO, BEGIN, END, IF, SELECT, GOTO, LEAVE, STOP, null, ON, SIGNAL, and REVERT statements.
The remainder of the chapter describes how to handle conditions that arise during the execution of your program.
8.1. DO Groups and Statements
A DO-group is a sequence of PL/I statements delimited by a DO statement and its corresponding END statement. The DO statement begins a sequence of statements to be executed in a group; the group ends with the nonexecutable END statement; the group contains one or more statements between the DO and END statements.
For example:
IF BIRTH_YEAR > CURRENT_YEAR THEN DO; PUT SKIP LIST ('Birth year cannot be in the future.'); GOTO GET_BIRTH_YEAR; END;
The statements in a DO-group are executed as the result of an unconditional DO statement or as the result of the successful test of a conditional DO. When the executable statements in this conditional DO-group are complete, execution continues with the next executable statement following the END statement.
You can nest DO-groups inside each other to a maximum level of 64.
Normally, all the statements contextually nested one level below the DO in the group are executed. However, control can be transferred out of a DO-group in the following ways:
By execution of a GOTO statement that transfers control to a label outside the DO-group. The GOTO statement can be present in the DO-group itself, in a procedure invoked directly or indirectly from within the DO-group, or in an ON-unit activated while the DO-group is active.
By execution of a LEAVE statement that transfers control outside the containing DO-group or to the next executable statement following the END statement that terminates the DO-group.
By execution of a RETURN or STOP statement that terminates the current procedure or program.
DO-groups have several formats. These formats are described individually under the following subheadings:
8.1.1. Simple DO
A simple DO statement is a noniterative DO. The statements nested directly between the DO statement and its corresponding END statement are executed once. PL/I treats these nested statements as if they are one statement. After all statements in the group are executed, control passes to the next executable statement in the program.
The format of a simple DO statement is:
DO; ⋮ END;
Examples
IF A < B THEN DO; PUT LIST ('more data needed'); GET LIST (VALUE); A = A + VALUE; END;
The simple DO statement is commonly used as the action of the THEN clause of an IF statement, as shown above, or of an ELSE option.
8.1.2. DO WHILE
A DO WHILE statement causes a group of statements to be repeatedly executed as long as a particular condition is satisfied. When the condition is not true, the group is not executed.
The format of the DO WHILE statement is:
DO WHILE (test-expression);
⋮
END;test-expressionAny expression that yields a scalar value. If any bit of the value is a 1, then the test expression is true; otherwise, the test expression is false. The test expression must be enclosed in parentheses. (Comparison operations yield a value with the type BIT(1).)
This expression is evaluated before each execution of the DO-group. It must have a true value in order for the DO-group to be executed. Otherwise, control passes over the DO-group to the next executable statement following the END statement that terminates the group.
Examples
DO WHILE (A < B); ⋮ END;
This DO-group is executed as long as the value of the variable A is less than the value of the variable B.
DO WHILE (LIST->NEXT ^= NULL()); ⋮ END;
This DO-group is executed until a forward pointer in a linked list has a null value.
DECLARE EOF BIT(1) INITIAL('0'B); ⋮ ON ENDFILE(INFILE) EOF = '1'B; READ FILE(INFILE) INTO(INREC); DO WHILE (^EOF); ⋮ READ FILE(INFILE) INTO(INREC); END;
This DO-group reads records from the file INFILE until the end of the file is reached. At the beginning of each iteration of the DO-group, the expression ^EOF is evaluated; the expression is '1'B until the ENDFILE ON-unit sets the value of EOF to '1'B.
A DO UNTIL statement causes a group of statements to be repeatedly executed until a particular condition is satisfied. That is, while the condition is false, the group is repeated.
The format of the DO UNTIL statement is:
DO UNTIL (test-expression);
⋮
END;test-expressionAny expression that yields a scalar value. If any bit of the value is 1, then the test expression is true; otherwise the test expression is false. The test expression must be enclosed in parentheses. (Comparison operations yield a value having the type BIT(1).)
This expression is evaluated after each execution of the DO-group. It must have a false value for the DO-group to be repeated. Otherwise, control passes to the next executable statement following the END statement that terminates the DO-group. The test expression must be enclosed in parentheses.
Note
Both the WHILE and UNTIL options check the status of test expressions, but they differ in that the WHILE option tests the value of the test expression at the beginning of the DO- group, and UNTIL tests the value of the test expression at the end of the DO-group. Therefore, a DO-group with the UNTIL option and no WHILE option will always be executed at least once, but a DO-group with the WHILE option may never be executed.
Examples
DO UNTIL (A=0); ⋮ END;
This DO-group is executed at least once and continues as long as the value of A is not equal to zero.
DO UNTIL (K < ALPHA); ⋮ END;
This DO-group is executed at least once and continues as long as the value of the variable K is greater than or equal to the value of the variable ALPHA.
8.1.4. DO REPEAT
The DO REPEAT statement executes a DO-group repetitively for different values of a control variable. The control variable is assigned a start value that is used on the first iteration of the group. The REPEAT expression is evaluated before each subsequent iteration, and its result is assigned to the control variable. A WHILE clause can also be included. If it is included, the WHILE expression is evaluated before each iteration (including the first), but after the control variable has been assigned. The format of the DO REPEAT statement is:
DOvariable=start-valueREPEATexpression[WHILE (test-expression)] [UNTIL (test-expression)]; ⋮ END;
variableA reference to a control variable. The control variable can be any scalar variable.
start-valueAn expression specifying the initial value to be given to the control variable. The evaluation of this expression must yield a value that is valid for assignment to the control variable.
expressionAn expression giving the value to be assigned to the control variable on reiterations of the DO REPEAT group. The expression is evaluated before each iteration after the first. Evaluation of this expression must yield a result that is valid for assignment to the control variable.
- WHILE (
test-expression) An option specifying a condition that controls the termination of the DO REPEAT group. The DO REPEAT group continues while the condition is true. The specified test expression must yield a scalar value. If any bit of the value is 1, then the test expression is true; otherwise, the test expression is false. The test expression must be enclosed in parentheses.
This expression is evaluated each time control reaches the DO statement; the test expression must have a true value in order for the DO-group to be executed. Otherwise, control passes to the next executable statement following the END statement that terminates the DO-group.
See Section 8.1.5, “Controlled DO” for a discussion of this option when used with the controlled DO statement.
- UNTIL (
test-expression) An option specifying a condition that further controls the termination of the DO REPEAT group. The DO REPEAT group continues until the condition is true. The specified test expression must yield a scalar value. If any bit in the value is 1, then the test expression is true; otherwise, the test expression is false. The test expression must be enclosed in parentheses.
This expression is evaluated after the first execution of the DO-group; the test expression must have a true value in order for the DO-group to be executed a second time. Otherwise, control passes to the next executable statement following the END statement that terminates the DO-group.
Note
If the WHILE and UNTIL options are omitted, the DO REPEAT statement specifies no means for terminating the group; the execution of the group must be terminated by a statement or condition occurring within the group.
A DO REPEAT group is executed by the following steps:
The following measures are taken to prevent the allocation of a new control variable during the execution of the DO-group:
If the control variable is based, its pointer qualifier is evaluated and a temporary reference of the control variable type is created. The temporary reference is used as the control variable in subsequent steps.
If the control variable is subscripted, its subscripts are evaluated and a temporary reference of the control variable type is created. The temporary reference is used as the control variable in subsequent steps.
If the control variable is neither based nor subscripted, its reference is used in subsequent steps.
The start value expression is evaluated and assigned to the control variable.
If a WHILE option is present, its test expression is evaluated. If it does not produce a true value, the execution of the DO-group terminates. If the test expression is not present, execution continues.
The body of the DO-group is executed. The execution of the DO-group may be terminated during this step by the execution of a STOP or RETURN statement or by the execution of a GOTO or LEAVE statement that transfers control outside the DO-group. Statements in the group can also modify the values of the control variable, REPEAT expression, and test expression.
If an UNTIL option is present, its test expression is evaluated. If it produces a true value, the execution of the DO-group terminates. If the test expression is not present, execution continues.
The REPEAT expression is evaluated and its value is assigned to the control variable.
Execution continues at step 3.
Examples
DO LETTER='A' REPEAT (BYTE(I));
The preceding example will repeat the group with an initial LETTER value of 'A' and with subsequent values assigned by the built-in function BYTE(I). The control variable I can be assigned new values within the group. The group will iterate endlessly unless terminated by a statement or condition within the group.
DO I = 1 REPEAT (I + 2) WHILE ( I <= 100 );
The preceding example has the same effect as the following controlled DO statement:
DO I = 1 TO 100 BY 2;
The most common use of the DO REPEAT statement is in the manipulation of lists. For example:
DO P = LIST_HEAD REPEAT (P->LIST.NEXT) WHILE ( P ^= NULL() );
In the preceding example, the pointer P is initialized with the value of the pointer control variable LIST_HEAD. The DO-group is then executed with this value of P. The REPEAT option specifies that each time control reaches the DO statement after the first execution of the DO-group, P is to be set to the value of LIST.NEXT in the structure currently pointed to by P.
8.1.5. Controlled DO
A controlled DO statement identifies a variable whose value controls the execution of the DO-group and defines the conditions under which the control variable is to be modified and repeatedly tested.
The format of the controlled DO statement is:
DOcontrol-variable=start-value[ TOend-value[BYmodify-value] ] [ BYmodify-value[TOend-value] ] [REPEATrepeat-expression] [WHILE(test-expression)] [UNTIL(test-expression)] ; END;
control-variableA reference to a variable whose current value, as compared to the end value specified in the TO option, determines whether the DO-group is executed. If none of the options are specified, the DO-group is executed a single time regardless of the value of the control variable. The control variable must be of an arithmetic data type.
start-valueAn expression specifying the initial value to be given to the control variable. Evaluation of this expression must yield an arithmetic value.
end-valueAn expression giving the value to be compared with the control variable during successive iterations. Evaluation of this expression must yield an arithmetic value. This expression is evaluated exactly once when the statement is executed for the first time. Thus if the end value changes as the loop progresses, only this initial value is used.
If you specify the BY option and do not specify the TO option, execution repeats until terminated by the WHILE or UNTIL option or until a statement in the do-group transfers control out of the do-group.
modify-valueAn expression giving a value by which the control value is to be modified. Evaluation of this expression must yield an arithmetic value. This expression is evaluated exactly once when the statement is executed for the first time. Thus if the modify value changes as the loop progresses, only this initial value is used. If you do not specify the BY option, the modify value defaults to 1.
- REPEAT
repeat-expression An option that executes a DO-group repetitively for different values of a control variable. The
repeat-expressiongives the value that is assigned to the control variable on reiterations of the DO REPEAT group. The expression is evaluated before each iteration after the first iteration. Evaluation of this expression must yield a result that is valid for assignment to the control variable. See Section 8.1.4, “DO REPEAT” for more information.- WHILE (
test-expression) An option specifying a condition that further controls the execution of the DO-group. The condition must be true at the beginning of each DO-group iteration for the DO-group to be executed. The specified test expression must yield a scalar value. If any bit in the value is a 1, then the test expression is true; otherwise, the test expression is false. The test expression must be enclosed in parentheses.
- UNTIL (
test-expression) An option specifying a condition that further controls the execution of the DO-group. This expression is evaluated at the end of each iteration of the DO-group, before the BY clause is applied to the control variable. The condition must be false at the end of a DO-group execution for the next DO-group iteration to be executed. The specified test expression must yield a scalar value. If any bit in the value is a 1, then the test expression is true; otherwise, the test expression is false. The test expression must be enclosed in parentheses.
Note
If you omit the TO, WHILE, and UNTIL options, the controlled DO statement specifies no means for terminating the group. In this case, you must include a statement or condition in the do-group to terminate execution of the group.
Example
This DO-group prompts the user for integer input values and adds each input value to the current sum. When the sum exceeds 100, the DO-group exits.
DECLARE (NEXT_VALUE,SUM) FIXED BIN; SUM = 0; DO UNTIL ( SUM > 100 ); GET LIST (NEXT_VALUE) OPTIONS PROMPT ('Next value to add? ')); SUM = SUM + NEXT_VALUE; END; PUT SKIP LIST ('The total sum is ',SUM);
The controlled DO-group is executed by the following steps:
The following measures are taken to prevent the allocation of a new control variable during the execution of the DO-group:
If the control variable is based, its pointer qualifier is evaluated and a temporary reference of the control variable type is created. The temporary reference is used as the control variable in subsequent steps.
If the control variable is subscripted, its subscripts are evaluated and a temporary reference of the control variable type is created. The temporary reference is used as the control variable in subsequent steps.
If the control variable is neither based nor subscripted, its reference is used in subsequent steps.
The start value expression is evaluated and assigned to the control variable. The expressions specified in the TO and BY options (if specified) are evaluated, and their values are stored. These expressions can contain references to the object referenced by the control variable. If they do, the original reference, not the temporary reference, is used in evaluation of the expressions.
If the TO option is present, the value of the control variable is compared with the end value specified in the TO option. Otherwise, this step is skipped. Execution of the DO-group terminates if either of the following is true:
The modify value is greater than zero and the control variable is greater than the
end-value.The modify value is less than zero and the control variable is less than the end value.
If this step terminates the DO-group on the first iteration, the control variable has a final value assigned by the start value. If the group is terminated on a subsequent iteration, the control variable has a final value assigned by step 6.
If a WHILE option is present, its test expression is evaluated. If it does not produce a true value, the execution of the DO-group terminates.
The body of the DO-group is executed. The execution of the DO-group can be terminated during this step by the execution of a STOP or RETURN statement or by the execution of a GOTO or LEAVE statement that transfers control out of the DO-group.
The body of the DO-group can also contain statements that change the values of the control variable, modify value, end value, or test expression. Changing the modify value or the end value in the body of the loop will not affect the number of times the loop is iterated. However, changing the value of the control variable or the test expression can affect the number of iterations if the control variable was not made into a temporary by step 1.
If an UNTIL option is present, its test expression is evaluated. If it produces a true value, the execution of the DO-group terminates.
Unless none of the options are specified, the value of the control variable is modified as follows:
controlvariable=controlvariable+modifyvalue;
Execution continues at step 3 unless none of the options are specified, in which case control passes to the next executable statement in the program.
Examples
DO I = 2 TO 100 BY 2;
This DO-group is executed 50 times, with values for I of 2, 4, 6, and so on.
DO I = LBOUND(ARRAY,1) TO HBOUND(ARRAY,1);
This DO-group is executed as many times as there are elements in the array variable ARRAY, using the subscript values of the array's elements for the values of I.
DO I = 1 BY 1 WHILE (X < Y);
This DO-group continues to be executed with successively higher values for I while the value of X is less than the value of Y.
DO I = 1 BY 1 WHILE (X < Y) UNTIL (X = 12);
This DO-group resembles the DO-group in the preceding example, except that the DO-group continues to be executed while the value of X is less than the value of Y or until the value of X is equal to 12.
A controlled DO statement that does not specify a TO or BY option results in a single iteration of the following DO-group. For example:
DO X = 1 WHILE (A);
Even if A is true, this DO-group executes a single time only. If A is false, it is not executed at all. Because there is no expression to change the value of X, the DO-group will not be executed again.
DO X = 1;
This DO-group executes a single time only, regardless of the value of X.
8.2. BEGIN Statement
The BEGIN statement denotes the start of a begin block.
The format of the BEGIN statement is:
BEGIN;
A begin block is a sequence of statements headed by a BEGIN statement and terminated by an END statement. A begin block can be used wherever a single executable statement is valid, for instance, in an ON-unit. The statements in a begin block can be any PL/I statements, and begin blocks can contain DO-groups, DECLARE statements, procedures, and other (nested) begin blocks.
A begin block provides a convenient way to localize variables. Variables declared as internal within a begin block are not allocated storage until the block is activated. When the block terminates, storage for internal automatic variables is released. A begin block terminates in the following situations:
When its corresponding END statement is encountered. Control continues with the next executable statement in the program.
When it executes a nonlocal GOTO to transfer control to a previous block.
When it executes a RETURN statement.
A begin block differs from a DO-group chiefly in its ability to localize variables. Variables declared within DO-groups are not localized to the group (unless the group contains a begin block or procedure that declares internal variables). Begin blocks are preferable when you want to restrict the scope of variables. Furthermore, there are some cases (such as ON-units) in which DO-groups cannot be used. Otherwise, DO-groups are often more efficient, because they do not have the overhead associated with block activation. In general, you should use a DO-group instead of a begin block unless there are declarations present or you require multiple statements in an ON-unit.
A begin block can designate a series of statements to be executed depending on the success or failure of a test in an IF statement. For example:
IF A = B THEN BEGIN ; ⋮ END;
A begin block also provides the only way to denote a series of statements to be executed when an ON condition is signaled. For example:
ON ERROR BEGIN; [statement ... ] END;
See Section 1.4, “Blocks” for more information.
8.3. END Statement
The END statement marks the end of the block or group headed by the most recent BEGIN, DO, SELECT, or PROCEDURE statement.
The format of the END statement is:
END [label-reference];label-referenceA reference to the unsubscripted label on the PROCEDURE, BEGIN, SELECT, or DO statement for which the specified END statement is the termination. A label is not required. If specified, the label reference must match only one label, which is the label of the most recent BEGIN, DO, SELECT, or PROCEDURE statement that is not already matched with an END statement. If the label reference is omitted, the most recent textual, non-terminated PROC, BEGIN, SELECT, or DO statement is matched by default.
Note that a procedure declared with the RETURNS option must execute a RETURN statement before it encounters the END statement marking the end of the procedure.
When the END statement is encountered, one of the following actions is performed, depending on the type of block or group that it terminates:
When an END statement denotes the end of a procedure, the procedure is terminated. The storage allocated for the block is released, and all automatic variables are made inaccessible. If the current procedure is the main or only procedure, the program terminates. Otherwise, control returns to the statement following the CALL statement or function invocation that invoked the procedure.
When an END statement denotes the end of a begin block, the block is terminated. Storage allocated for the block is released, and all automatic variables are made inaccessible. Control passes to the next executable statement.
When an END statement denotes the end of a DO-group, control returns either to the DO statement that heads the group or to the next executable statement following the END statement. If the DO-group is headed by a simple DO, that is, one that causes the DO-group to be executed only once, control passes to the next executable statement. Otherwise, control returns to the head of the DO-group.
When an END statement denotes the end of a SELECT-group, the SELECT-group is terminated and control passes to the next executable statement following the end statement.
8.4. IF Statement
The IF statement tests an expression and performs a specified action if the result of the test is true.
The format of the IF statement is:
IFtest-expressionTHENaction[ELSEaction];
test-expressionAny valid expression that yields a scalar bit-string value. If any bit of the value is 1, then the test expression is true; otherwise, the test expression is false.
actionAny of the following:
Any unlabeled statement except the nonexecutable statements: DECLARE, END, ENTRY, FORMAT, or PROCEDURE
An unlabeled DO-group or begin block
The IF statement evaluates the test expression. If the expression is true, the action specified following the keyword THEN is executed. Otherwise, the action, if any, specified following the ELSE keyword is executed.
Examples
IF A < B THEN BEGIN;
The begin block following this statement is executed if the value of the variable A is less than the value of the variable B.
IF ^SUCCESS THEN CALL PRINT_ERROR; ELSE CALL PRINT_SUCCESS;
The IF statement defines the action to be taken if the variable SUCCESS has a false value (the THEN clause) and the action to be taken otherwise (the ELSE clause).
8.4.1. Nested IF Statements
The action specified in a THEN or an ELSE clause can be another IF statement.
An ELSE clause is matched with the nearest preceding IF/THEN that is not itself matched with a preceding ELSE. For example:
IF ABC THEN IF XYZ THEN GOTO GBH; ELSE GOTO THESTORE; ELSE GOTO HOME;
In this example, the first ELSE clause is executed if ABC is true and XYZ is false. The second ELSE clause is executed if ABC is false.
In some cases, proper matching of IF and ELSE can require a null statement (a semicolon) as the target of an ELSE. For example:
IF ABC THEN IF XYZ THEN GOTO HOME; ELSE; ELSE GOTO THESTORE;
In this example, the ELSE GOTO THESTORE statement is executed if ABC is false.
The SELECT statement tests a series of expressions and performs a specified action depending on the result of the test. The statement has two forms: in the first form, the expressions in a WHEN clause are tested for truth; in the second form, the expressions in a WHEN clause are compared to see if any have the same value as another specified expression called the select expression. Any of the expressions can be, but need not be, constants. An optional OTHERWISE clause is available to name an action to be performed if none of the preceding expressions have satisfied the condition specified.
The two forms of the SELECT statement and the OTHERWISE clause are described in more detail below.
The general form of the SELECT statement is:
SELECT [(select-expression)]; [WHEN [ANY | ALL] (case-expression, ...) [action] ; ] ... [(OTHERWISE | OTHER) [action] ; ] END;
select-expressionAn expression that can be evaluated to any type of value.
case-expression, ...One or more expressions to be tested, evaluating to bit-string values, or, if a select expression is used, with values that will be compared to the select expression's value.
actionAny statement (including a null statement, another SELECT statement, a DO-group, or a BEGIN-END block) except a DECLARE, END, ENTRY, FORMAT, or PROCEDURE statement.
8.5.1. The Two Forms of the SELECT Statement
Depending on whether you use a select expression or not, SELECT has two different forms, which are explained in detail below.
SELECT Without a Select Expression
The first form of the SELECT statement omits the select expression. In this form, the expressions in a WHEN clause are evaluated, and a specified action is performed if the result of any test is true (or, if ALL is specified, the results of all tests are true); an expression is true if it evaluates to a bit string containing any bit with the value of '1'B. In the usual case, the test for truth results in a bit string containing one bit: '1'B for true or '0'B for false.
When the keyword ANY (the default) appears in the WHEN clause, then if any one of the expressions evaluates to true the corresponding action is performed. No further expressions in that WHEN clause or in subsequent WHEN clauses are evaluated (and thus the expressions need not have unique values), and no subsequent actions are performed.
The WHEN clauses are checked in the order listed. However, the expressions within one WHEN clause might be evaluated in any order, and not all these expressions are necessarily evaluated. As soon as any expression is found true, subsequent expressions are not evaluated.
If the keyword ALL appears in the WHEN clause, the action is performed only if all expressions in that WHEN clause evaluate to true. Once one action is performed, no subsequent WHEN clauses are evaluated and no subsequent actions are performed. If any expression in the WHEN clause does not result in a true value, no further expressions in that clause are evaluated and the action is not performed.
Following is an example of the first form of SELECT:
SELECT; WHEN ANY (A=10,A=20,A=30) B=B+1; WHEN (A=50) B=B+2; WHEN (A=60) B=B+3; WHEN (A=70) B=B+4; WHEN (A=80) B=B+5; WHEN (A=90) B=B+6; WHEN ALL (A>90,A<500) B=B+10; OTHERWISE B=B+C; END;
The SELECT statement defines the action to be taken if the variable A has any of the values specified in the WHEN clauses (or, in the case of the WHEN ALL clause, if A is both greater than 90 and less than 500). If none of the WHEN clauses is true, the action specified in the OTHERWISE clause (B=B+C) is performed.
SELECT With a Select Expression
The second form of the SELECT statement has a select expression after the keyword SELECT. This form of the SELECT statement evaluates expressions in the WHEN clauses and then compares their values to the value of the select expression (instead of testing the expressions for truth or falsity, as in the first form of SELECT). It performs a specified action if any expression has the same value as the select expression (or, if ALL is used, all expressions have the same value as the select expression). In this form of the SELECT statement, as in the previous form, the expressions in a WHEN clause might be evaluated in any order, and not all the expressions are necessarily evaluated.
Following is an example of the second form of SELECT:
SELECT(A); WHEN (50) C=C+1; WHEN ANY (60,61,62,B+C) C=C+2; WHEN ALL (70,D) C=C+3; OTHERWISE C=C+D; END;
The SELECT statement defines the action to be taken if the select expression (A in the example) evaluates to any or all of the values of the expressions following a WHEN clause. The first action (the assignment statement C=C+1) will be performed if A has a current value of 50. In that case, none of the subsequent WHEN clauses will be evaluated. The second WHEN clause includes the ANY keyword, and so the second action will be performed if A evaluates to or equals 60 or 61 or 62 or the sum of B and C. If neither the first nor the second action is performed, the third WHEN clause's expressions are tested. The third WHEN clause includes the ALL keyword, so the third action will be performed only if A equals both 70 and D. If none of the WHEN clauses causes an action to be performed, then the action in the OTHERWISE clause (the assignment statement C=C+D) will be performed.
8.5.2. OTHERWISE Clause
If none of the WHEN clauses causes the corresponding action to be performed, the action specified in the optional OTHERWISE clause is performed; but if the OTHERWISE clause is omitted, an ERROR condition is signalled. OTHERWISE can be followed by a semicolon (a null statement) to cause execution to continue and avoid an ERROR condition when you do not want to specify an action after OTHERWISE. For example:
OTHERWISE;After an action is performed following a WHEN or OTHERWISE clause, control passes to the next executable statement following the END statement that terminates the SELECT statement, unless normal flow is altered within the action.
8.5.3. Nested SELECT Statements
Note that the action specified in a WHEN or OTHERWISE clause can be another SELECT statement, resulting in nested SELECT statements with the format shown in the following example:
SELECT; WHEN (condition A) SELECT; WHEN (condition A1) statement 1; WHEN (condition A2) statement 2; END; WHEN (condition B) SELECT; WHEN (condition B1) statement 3; WHEN (condition B2) statement 4; OTHERWISE statement 5; END; OTHERWISE statement 6; END;
In this example, statement 1 is executed when both condition A and condition A1 are true. Statement 2 is executed when both condition A and condition A2 are true and A1 is false. If A is true but neither A1 nor A2 is true, an ERROR condition is reported because no OTHERWISE clause exists within this SELECT statement.
If condition A is false, condition B is checked. If B is true but B1 and B2 are both false, statement 5 (in the corresponding OTHERWISE clause) is executed. If conditions A and B are both false, statement 6 (in the outermost OTHERWISE clause) is executed.
If you want to avoid the possibility that execution could be stopped by an ERROR condition, which occurs in this example if condition A is true and A1 and A2 are false, you can put in an OTHERWISE clause with a null statement (a semicolon) as its action, which would cause control to pass to the first executable statement following the end of the outermost SELECT statement.
An END statement must terminate each SELECT statement.
8.6. GOTO Statement
The GOTO statement causes control to be transferred to a labeled statement in the current or any outer procedure.
The format of the GOTO statement is:
{ GOTO } label-reference;
{ GO TO }label-referenceA label constant or an expression that, when evaluated, yields a label value. A label value denotes a statement in the program.
The specified label cannot be the label of an ENTRY, FORMAT, or PROCEDURE statement. The label reference specified in a GOTO statement can be any of the following:
An unsubscripted label constant. For example:
GOTO ALPHA; ⋮ ALPHA:A subscripted label constant, for which the subscript is specified with an integer constant or a variable expression. For example:
GOTO PROCESS(1); ⋮ PROCESS(1):
A label variable that, when evaluated, yields a label value. For example:
DECLARE PROCESS LABEL VARIABLE; ⋮ PROCESS = BILLING; ⋮ GOTO PROCESS;
A subscripted label variable that, when evaluated, yields a label value. For example:
DECLARE X(5) LABEL; X(1) = NEXT; GOTO X(1);
In the case of a label variable, the resulting label value must designate an existing block activation. (Similarly, a label constant must designate an existing block activation.) If the designated block activation is the current block activation, the GOTO statement causes a local GOTO. No special processing occurs.
- OTHERWISE
This option can be used only when the
label-referenceis a subscripted label with a variable subscript. If present in any other case, it will be reported as an error.Make sure all the labels referenced by the GOTO statement occur after the statement. If you use potential label references for a specific GOTO statement prior to the GOTO statement, you will cause compiler errors. The following example shows a program with this illegal construct:
PROGRAM: PROCEDURE OPTIONS (MAIN); DECLARE I FIXED BINARY (31,0); PART(1): I=2; GOTO PART(I) OTHERWISE; END PROGRAM;
If the variable subscript is out of range and the OTHERWISE option is present, the statement following the GOTO will be executed next. If the OTHERWISE option is not specified and the subscript of the last label is not an asterisk (*), the subscript is reported out of range at run-time and the process will be terminated.
Nonlocal GOTO
If the specified label value is not in the current block, the GOTO statement is considered a nonlocal GOTO. The following can occur:
The current block, and any blocks intervening between it and the block containing the label value, are released. This rule applies both to procedure blocks and to begin blocks.
If a GOTO statement transfers control out of a procedure that is invoked in a function reference, the statement containing the function reference is not evaluated further.
A special case of a nonlocal GOTO occurs if a GOTO is executed in an ON-unit. The condition handling mechanism signals a system exception handler (SS$_UNWIND) to unwind the procedure call frames to the proper point before control transfers to the label. This allows programs to clean up intervening blocks before preceding.
Restriction
You can use either the OTHERWISE option or an asterisk (*) for the last label, but not both.
Examples
The following example shows the use of the GOTO statement:
RESTART:;
⋮
BEGIN;
ON ERROR GOTO RESTART;
⋮
END;The GOTO statement provides a transfer address for the current procedure when the ERROR condition is signaled.
DECLARE PROCESS(5) LABEL; ⋮ GOTO PROCESS(2);
The GOTO statement evaluates the label reference and transfers control to the label constant corresponding to the second element of the array PROCESS. PROCESS consists of label variables.
The following restrictions apply to the use of labels and label data:
No statement can have more than one label. However, an executable statement can be preceded by any number of labeled null statements, which have the same effect as would multiple labels.
Operations on label values are restricted to the operators = and ^=, for testing equality or inequality. Two values are equal if they refer to the same statement in the same block activation.
Any statement in a PL/I program can be labeled except the following:
A DECLARE statement
A statement beginning an ON-unit, THEN clause, ELSE clause, WHEN clause, or OTHERWISE clause
Labels on PROCEDURE, ENTRY, and FORMAT statements are not considered statement labels and cannot be used as the targets of GOTO statements.
An identifier occurring as a label in a block cannot be declared in that block (except as a structure member) or occur in the block's parameter list.
Any reference to a label value after its block activation terminates is an error with unpredictable results.
For more information on labels, see Section 3.7, “Label Data”.
The LEAVE statement causes control to be transferred out of the immediately containing DO-group or out of the containing DO-group whose label is specified with the statement.
The format of the LEAVE statement is:
LEAVE [label-reference];label-referenceA reference to a label on a DO statement that heads a containing DO-group. The label reference can be a label constant or a subscripted label constant for which the subscript is specified with an integer constant. The label reference cannot be a label variable, nor can it be a subscripted label constant for which the subscript is specified with a variable.
On execution, a LEAVE statement with no label reference causes control to be transferred to the first statement following the END statement that terminates the immediately containing DO-group. If the LEAVE statement has a label, control is passed to the first executable statement following the END statement for the corresponding label indicated in the LEAVE statement. Thus, the LEAVE statement provides an alternative means of terminating execution of a DO-group. In the case of a LEAVE statement with a label reference, several nested DO-groups can be terminated as control transfers outside the referenced DO-group.
Restrictions
The following restrictions apply to the use of the LEAVE statement:
A LEAVE statement must be contained within a DO-group.
A LEAVE statement must be in the same block as the DO statement to which it refers.
If a LEAVE statement has a label reference, it must refer to a label on a DO statement that heads a DO-group that contains the LEAVE statement. The LEAVE statement must be in the same block as the labeled DO statement.
The label reference specified with a LEAVE statement must be a label constant or a subscripted label constant with an integer constant subscript.
Examples
The following example shows a LEAVE statement without a label reference:
DO I = 1 TO 100; ⋮ IF COMMAND = 'QUIT' THEN LEAVE; ⋮ END; PUT LIST ('Job finished');
In this example, the LEAVE statement transfers control directly to the PUT statement if the condition in the IF statement is satisfied.
The next example shows a LEAVE statement with a label reference:
LOOP1: DO WHILE (MORE); ⋮ LOOP2: DO I = 1 TO 12; ⋮ IF QUAN(I) > 150 THEN LEAVE LOOP1; END; /* Loop 2 */ ⋮ END; /* Loop 1 */
In this example, the LEAVE statement transfers control to the first statement beyond the END statement that terminates LOOP1.
The following examples show some invalid uses of the LEAVE statement:
LEAVE; /* LEAVE statement must be in */ /* DO-group */ DO; BEGIN; LEAVE; /* LEAVE statement must be in */ END; /* same block as DO statement */ END; ON ENDFILE(SYSIN) LEAVE; /* ON-unit is separate block */ DECLARE LABVAR LABEL VARIABLE; LABVAR = LOOP; LOOP: DO I = 1 TO 10; LEAVE LABVAR; /* Label reference cannot be a variable */ END; LAB(1): DO; LAB(2): DO; I = 1; LEAVE LAB(I); /* Subscript must be a constant */ END; END;
8.8. STOP Statement
The STOP statement terminates execution of a program, regardless of the current block activation.
The format of the STOP statement is:
STOP;
The STOP statement signals the FINISH condition, and closes all open files. If the main procedure has the RETURNS attribute, no return value is obtainable.
8.9. Null Statement
The null statement performs no action. Its format is:
;
The null statement usually serves as the target statement of a THEN or ELSE clause in an IF statement, as the target of a WHEN or OTHERWISE clause in a SELECT statement, or as an action in an ON-unit. The following examples illustrate these uses.
IF A < B THEN GOTO COMPUTE; ELSE ;
In this example, no action takes place if A is greater than or equal to B; execution continues at the statement following ELSE ;. A construction of this type may be necessary when IF statements are nested (see Section 8.4.1, “Nested IF Statements”).
SELECT; WHEN (condition A,B,C) GOTO FILE_READ; WHEN (condition D,E) GOTO UPDATE; OTHERWISE; END;
In this example, control is passed to the next executable statement after END if conditions A, B, C, D, and E are not true.
ON ENDPAGE(SYSPRINT);
In this example, no action takes place upon execution of the ON-unit; the I/O operation that caused the ENDPAGE condition continues.
The null statement can also be used to declare two labels for the same executable statement, as in the following example:
LABEL1: ; LABEL2: statement ...
8.10. Condition Handling
A PL/I condition is any occurrence that causes the interruption of a program and a signal. When a condition is signaled, PL/I initiates a search for a user-written program unit called an ON-unit to handle the condition.
An ON condition is any one of several named conditions whose occurrence during the execution of a program interrupts the program. When a condition occurs or is signaled, a statement or sequence of statements, called an ON-unit, is executed. The SYSTEM option can be specified in the ON statement, causing the default system condition handling to be executed.
The following condition handling topics are discussed in subsequent sections:
The ON statement
The SIGNAL statement
The REVERT statement
Summary of ON conditions
Default PL/I ON-unit
Using Condition Prefixes (IBM Dialect Only)
Establishing ON-units
Contents of an ON-unit
Searching for ON-units
Completion of ON-units
8.10.1. ON Statement
The ON statement defines the action to be taken when a specific condition or conditions are signaled during the execution of a program. The ON statement is an executable statement. It must be executed before the statement that signals the specified condition.
The format of the ON statement is:
ONcondition-name, ... {on-unit} { SYSTEM }
condition-name, ...The name or names of the specific conditions for which an ON-unit or the SYSTEM option is specified. There is a keyword name associated with each condition. Successive keyword names must be separated by commas. The conditions are summarized in Table 8.1, “Summary of ON Conditions”; each condition is described in an individual entry in this manual.
on-unitThe action to be taken when the specified condition or conditions are signaled. An ON-unit can be:
Any single, unlabeled statement except DECLARE, DO, END, ENTRY, FORMAT, IF, ON, PROCEDURE, RETURN, or SELECT.
An unlabeled begin block.
A null statement (a semicolon alone), which causes program execution to continue as if the condition had been handled.
Only the most recent ON-unit established for a given condition can be active. If two successive ON statements are executed for the same condition, the second ON statement nullifies the first.
If no ON-unit is established for a particular condition, the condition ERROR is signaled. If no ON-unit is established for ERROR condition, the default system ON-unit is executed. See Section 8.10.5, “Default PL/I ON-Unit”.
- SYSTEM
This option invokes the default system condition handling for the specified condition, overriding any existing ON-unit for the condition. See Section 8.10.7, “Establishing ON-Units”.
8.10.2. SIGNAL Statement
The SIGNAL statement causes a specified condition to be signaled, which causes the system to search for and execute an ON-unit to handle the condition. See Section 8.10.9, “Search Path for ON-Units” for more information.
The format of the SIGNAL statement is:
SIGNAL condition-name;condition-nameThe name of the condition to be signaled. It must be one of the keywords listed in Table 8.1, “Summary of ON Conditions”. Each of these conditions is described in its own section.
Most conditions occur as a result of a hardware trap or fault, or as a result of signaling by PL/I run-time procedures. You can use the SIGNAL statement within a program as a general-purpose communication technique. In particular, the VAXCONDITION and CONDITION conditions let you signal unique user-defined condition values.
8.10.3. REVERT Statement
The REVERT statement cancels an ON-unit established for a specified condition or conditions in the current block only.
The format of the REVERT statement is as follows:
REVERT condition-name, ...;condition-name, ...The keyword name or names associated with the condition or conditions for which the ON-unit is to be reverted. Successive names must be separated by commas. The valid condition names are the same as for the ON statement.
If no ON-unit is established for a specified condition for the current block, the REVERT statement has no effect.
The REVERT statement does not cancel all ON-units that may be active at the same time it is executed (see Section 8.10.9, “Search Path for ON-Units”), only a handler in the current block.
An ON-unit can be re-established after execution of a REVERT statement by subsequently executing an ON statement.
The REVERT statement has no effect on an ON-unit established for the ANYCONDITION condition unless the statement explicitly references the ANYCONDITION condition. For example:
REVERT ANYCONDITION;
Therefore, a statement such as the following has no effect on an ON-unit established for the ANYCONDITION condition:
REVERT ZERODIVIDE;
The next example shows this more clearly:
PROGRAM: PROCEDURE OPTIONS(MAIN); DECLARE A FIXED; DECLARE B FIXED INITIAL (5); DECLARE C FIXED INITIAL (0); ON ANYCONDITION BEGIN; PUT SKIP LIST ('Handled condition = ',ONCODE()); END; REVERT ZERODIVIDE; A = B / C; /* Signal divzero */ ON ZERODIVIDE BEGIN; PUT SKIP LIST ('Handled ZERODIVIDE'); END; A = B / C; /* Signal divzero */ REVERT ZERODIVIDE; A = B / C; /* Signal divzero */ ON ZERODIVIDE BEGIN; PUT SKIP LIST ('Handled ZERODIVIDE'); END; REVERT ANYCONDITION; A = B / C; /* Signal divzero */ REVERT ZERODIVIDE; A = B / C; /* Signal divzero */ END PROGRAM;
When you run the program, the following conditions result:
Handled condition = 1156 Handled ZERODIVIDE Handled condition = 1156 Handled ZERODIVIDE PL/I ERROR condition.
8.10.4. Summary of ON Conditions
Most, but not all, ON conditions are associated with errors. The types of conditions for which you can establish ON-units are grouped in the following categories:
Conditions that occur during I/O operations:
ENDFILE, to take action when the end-of-file occurs while a file is being read.
ENDPAGE, to take action when the last line on a page is printed.
KEY, to take action when an error occurs when a record is accessed by key.
NAME (IBM dialect only), to take action when an error occurs during a data-directed GET statement with the FILE option.
RECORD (IBM dialect only), to take action when an error involving record length occurs during a READ, WRITE, or REWRITE operation.
TRANSMIT (IBM dialect only), to take action when a transmission error occurs during any I/O operation.
UNDEFINEDFILE, to respond to any file-specific errors that can occur during the opening of a file.
Conditions that indicate arithmetic conditions related to hardware violations:
FIXEDOVERFLOW, to respond when integer or fixed-point values become too large to be expressed.
OVERFLOW, to respond when floating-point values become too large to be expressed.
UNDERFLOW, to respond when floating-point values become too small to be expressed.
ZERODIVIDE, to respond when the divisor in a division operation has a value of zero.
Other conditions:
AREA, to respond when an error has been detected during an operation on an area (various subconditions can be determined through use of the ONCODE built-in function).
CHECK (IBM dialect only), valid only in a condition prefix. Used to display some or all of the names and values of data items within the scope of the prefix, when they are accessed.
CONDITION, to respond to programmer-defined conditions.
CONVERSION, to respond to data conversion errors from CHARACTER to any arithmetic data type or bit string.
SIZE (IBM dialect only), to respond to errors occurring during assignment or I/O operations involving loss of high-order bits.
STORAGE, to respond when an error has been detected during allocation of a controlled variable or a based variable other than in an area.
STRINGRANGE, to respond to substring references that are beyond the length of the string.
STRINGSIZE (IBM dialect only), to respond to errors generated when strings are assigned to targets that are not long enough.
SUBSCRIPTRANGE, to respond to array references with out-of-bound subscripts.
General classes of exception conditions:
ANYCONDITION, to respond to all conditions for which no specific ON-unit is established in the current block.
ATTENTION (IBM dialect only), to respond to user-generated attention signals.
ERROR, to respond to language-specific and run-time- specific errors.
FINISH, to respond when a STOP statement is executed.
VAXCONDITION, to respond to condition values that are specific to the operating system or to be used as user-defined conditions created by SIGNAL VAXCONDITION(n).
Table 8.1, “Summary of ON Conditions” summarizes ON conditions. Each condition is described individually in the sections that follow.
| Condition Name | Function |
|---|---|
| ANYCONDITION | Handles any condition not specifically handled by another ON-unit |
| AREA | Handles a condition that occurs during an operation on an area |
| ATTENTION | (IBM dialect only) Handles user terminal-generated attention signal |
| CHECK | (IBM dialect only) Displays names and values of specified data items |
| CONDITION | Handles programmer-defined conditions |
| CONVERSION | Handles data conversion errors |
| ENDFILE | Handles end-of-file for a specified file |
| ENDPAGE | Handles end-of-page for a specified file with PRINT attribute |
| ERROR | Handles miscellaneous error conditions and conditions for which no specific ON- unit exists |
| FINISH | Handles program exit when the main procedure executes a RETURN statement, when any block executes a STOP statement, or when the program exits due to an error that is not handled by an ON-unit |
| FIXEDOVERFLOW | Handles fixed-point decimal and integer overflow exception conditions |
| KEY | Handles any error involving the key during keyed access to a specified file |
| NAME | (IBM dialect only) Handles errors involving data-directed GET statements with the FILE option |
| OVERFLOW | Handles floating-point overflow exception conditions |
| RECORD | (IBM dialect only) Handles size errors involving records during READ, WRITE, or REWRITE operations |
| SIZE | (IBM dialect only) Handles loss of high-order bits during assignment or I/O |
| STORAGE | Handles a condition that occurs during allocation of a controlled variable or a based variable other than in an area |
| STRINGRANGE | Handles out-of-bound substring references |
| STRINGSIZE | (IBM dialect only) Handles errors involving assigning a string to a target that is too short |
| SUBSCRIPTRANGE | Handles out-of-bound array references |
| TRANSMIT | (IBM dialect only) Handles errors involving uncorrectable transmission errors during record I/O |
| UNDEFINEDFILE | Handles any errors in opening a specified file |
| VAXCONDITION | Handles operating system or programmer-specified condition values |
| ZERODIVIDE | Handles divide-by-zero exception conditions |
8.10.4.1. ANYCONDITION Condition
The ANYCONDITION keyword can be specified in an ON, REVERT, or SIGNAL statement. It designates an ON-unit established for all signaled conditions that are not handled by specific ON-units.
The ANYCONDITION keyword is not defined in the PL/I language. It is provided specifically for compatibility with the OpenVMS versions of PL/I.
8.10.4.2. AREA Condition
The AREA condition is raised when various operations fail in relation to areas. For example, it is raised if the extent of an area is not large enough to contain the variable or variables allocated to it, or if the area is incorrectly formatted.
For more information see the Endless PL/I for POSIX Systems User's Manual.
8.10.4.3. ATTENTION Condition (IBM Dialect Only)
The ATTENTION condition is raised during interactive processing when a user signals attention at the terminal or, during batch processing, by a SIGNAL ATTENTION statement.
When the ATTENTION condition is raised, an ATTENTION ON-unit is entered. PL/I ignores this condition if there is no ATTENTION ON-unit. On return from an ATTENTION ON-unit, execution resumes at a point in the program just following the point where the condition was raised.
8.10.4.4. CHECK Condition (IBM Dialect Only)
The CHECK condition is used to display names and values of data items within the scope of a condition prefix. The format of the CHECK condition is:
CHECK [ (name[,name]...) ]
nameA name of a data item, qualified or unqualified, which is one of the following:
An unsubscripted variable, either a data item or an aggregate
An entry or label constant
For example, within a condition prefix you can specify the following:
(CHECK(VAR1,VAR2,VAR3)):DO I = 1 TO 5;
You can enable the CHECK condition separately for any name in the scope of the condition prefix. If you do not specify any names, CHECK is enabled for all variables, label constants, and entry constants within the scope of the condition prefix.
The CHECK condition can be raised under the following conditions:
Statement labels—before executing the statement prefixed by the named label. Ignored if the statement is a FORMAT statement.
Entry constants—before invoking the entry point named by the entry constant.
Variables—whenever any statement in the scope of the condition prefix changes the variable or any part of the variable.
The CHECK condition does not affect the statement being executed or the flow of execution.
8.10.4.5. CONDITION Condition
The CONDITION condition name is used for ON-units to handle programmer-defined conditions. The value returned by the ONCODE built-in function is PLI$_CONDITION. There is no way to distinguish between multiple programmer-defined conditions if they are specified in the same ON statement.
The format of the CONDITION condition name is:
CONDITION (cond-name)cond-nameA name declared with the CONDITION attribute.
8.10.4.6. CONVERSION Condition
The CONVERSION condition name can be specified in an ON, SIGNAL, or REVERT statement to designate a CONVERSION condition or ON-unit.
PL/I signals the CONVERSION condition when the source character data in a conversion to bit-string or arithmetic data contains characters that are not valid in the specified context. In particular, the CONVERSION condition is raised when a character string is being converted and one of the following conditions is true:
The target of the conversion is an arithmetic type, and the source string does not contain a valid, optionally signed arithmetic constant.
The target of the conversion is a picture, and the source string does not conform to the picture specification.
The target of the conversion is a bit string, and a character other than 0 or 1 appears in the source string.
The CONVERSION condition can be raised either by a non-I/O conversion, such as an explicit conversion using a built-in function or an implicit conversion generated by the compiler, or by an I/O conversion in a GET statement. For example, A = BIT('1014') would cause the CONVERSION condition to be raised, because 4 is not a valid binary digit. Likewise, a GET statement with an arithmetic target would also cause the CONVERSION condition to be raised if the characters '12K45' appeared in the input field, because 'K' is not a valid numeric character.
You can use the ONSOURCE and ONCHAR built-in functions and pseudovariables inside an ON CONVERSION ON-unit. The ONSOURCE built-in function returns the source string that caused the CONVERSION condition to be raised. The ONCHAR built-in function returns the specific character that caused the conversion to fail. You can use the ONSOURCE pseudovariable to change the value of the conversion. Likewise, you can use the ONCHAR pseudovariable to modify only the single character in error.
If the CONVERSION condition was raised during a conversion required by the GET statement, the ONFILE built-in function returns the name of the file constant inside the CONVERSION ON-unit. If the CONVERSION condition was not raised during a conversion required by the GET statement, the ONFILE built-in function returns a null string.
ON-Unit Completion
A normal return from a CONVERSION condition will cause PL/I to attempt the conversion again if the ONSOURCE or ONCHAR pseudovariables have had values assigned to them. If the ONSOURCE value has not been modified, PL/I raises the ERROR condition instead.
For example:
/* * Sample program that displays a 'quick-fix' CONVERSION * ON-unit. At the end of this program, TARGET1 contains * the value 14015, and TARGET2 contains the value '11100'B. * Note that SOURCE1 and SOURCE2 are not modified. */ MAIN: PROCEDURE OPTIONS(MAIN); DCL SOURCE1 CHARACTER(5) VARYING INITIAL('14$15'); DCL SOURCE2 CHARACTER(5) VARYING INITIAL('11q00'); DCL TARGET1 FIXED BINARY(31); DCL TARGET2 BIT(5) ALIGNED; /* * Sample 'quick-fix' CONVERSION ON-unit that replaces * erroneous lowercase q's with 1's, and all other * erroneous characters with 0's. */ ON CONVERSION BEGIN; PUT SKIP EDIT('"',ONSOURCE(),'" "',ONCHAR(),'"')((5)A); IF ONCHAR() = 'q' THEN ONCHAR() = '1'; ELSE ONCHAR() = '0'; END; /* ON */ /* * Note that the CONVERSION condition is raised for all * 3 of the following statements. */ TARGET1 = SOURCE1; TARGET2 = SOURCE1; TARGET2 = SOURCE2; PUT SKIP(2) EDIT(SOURCE1,SOURCE2)(A,X(1),A); PUT SKIP EDIT(TARGET1,TARGET2)(F(8),X(1),B(5)); END MAIN;
The output from this program is:
"14$15" "$"
"14$15" "4"
"14$15" "$"
"14$15" "5"
"11q00" "q"
14$15 11q00
14015 11100The target of the conversion is undefined when the CONVERSION condition is raised.
The retry attempted on a normal return is for the single field that was in error. Attempts to assign a string containing, for example, a comma list of values will not be used for successive data items in a GET statement.
The actual value modified by the ONSOURCE and ONCHAR pseudovariables is a temporary value that is discarded once the conversion is complete, or the control flow cannot return to the point of the error. This means that invalid data stored in a character string variable will cause the CONVERSION condition to be raised each time the value is converted, not just the first time the conversion is attempted, regardless of modifications to the ONSOURCE and ONCHAR pseudovariables inside the CONVERSION ON-unit.
8.10.4.7. ENDFILE Condition
The ENDFILE condition name can be specified in an ON, SIGNAL, or REVERT statement to designate an end-of-file condition or ON-unit for a specific file.
PL/I signals the ENDFILE condition when a GET or READ statement attempts an input operation on a file or device after the last data item has been input.
The format of the ENDFILE condition name is:
ENDFILE (file-reference)file-referenceThe name of a file constant or file variable for which the ENDFILE ON-unit is established. If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled.
An ENDFILE ON-unit can be established for any input file. For any particular file, the meaning of the end-of-file condition depends on the type of device. For example, end-of-file is signaled for a terminal device when an End of File character is read.
For a stream file, an end-of-file condition is signaled whenever a GET statement attempts to access an empty file or attempts to access a file whose last input field has been read.
For a record file, an end-of-file condition is signaled when a READ statement is executed with the file at the end-of-file position or when a read is attempted beyond the last record in the file. For example:
ON ENDFILE (RECEIPTS) EOF = '1'B; EOF = '0'B; OPEN FILE (RECEIPTS) RECORD SEQUENTIAL; READ FILE (RECEIPTS) INTO (RECORD); DO WHILE (^EOF); ⋮ READ FILE (RECEIPTS) INTO (RECORD); END;
In this example, the ON statement establishes the default action to be taken when the last record in the input file has been processed: the flag EOF is set to '1'B.
An ON-unit established to handle end-of-file conditions can reference the ONFILE built-in function to determine the name of the file constant for which the condition was signaled.
ON-Unit Completion
If the ON-unit for the ENDFILE condition does not transfer control elsewhere in the program, control returns to the statement following the GET or READ statement that caused the condition to be signaled.
When the ENDFILE condition is signaled, it remains in effect until the file is closed. Subsequent GET or READ statements for the file cause the ENDFILE condition to be signaled repeatedly.
8.10.4.8. ENDPAGE Condition
The ENDPAGE condition name can be specified in an ON, SIGNAL, or REVERT statement to designate an end-of- page condition or ON-unit for a specific print file.
The format of the ENDPAGE condition name is:
ENDPAGE (file-reference)file-referenceThe name of the file constant or file variable for which the ENDPAGE ON-unit is to be established. If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled. The file must have the PRINT attribute.
The maximum number of lines that can be output on a single page is set by the PAGESIZE option of the OPEN statement. The maximum number of lines allowed on a single page is 32767. If not specified, PL/I uses the default page size, 60 lines.
PL/I signals the ENDPAGE condition when a PUT statement attempts to output a line beyond the last line specified for an output page. When the ENDPAGE condition is signaled, the current line number associated with the file is the page size plus 1. An ENDPAGE ON-unit allows you to provide special processing before output continues on a new page.
For example:
ON ENDPAGE (PRINTFILE) BEGIN; PUT FILE (PRINTFILE) PAGE; PUT FILE (PRINTFILE) LIST(HEADER_LINE); PUT FILE (PRINTFILE) SKIP(2); END;
The ON-unit for the ENDPAGE condition for the file PRINTFILE outputs a page eject and a header line for the new output page.
To cause PL/I to ignore the ENDPAGE condition when a large amount of output is written to a terminal, you can use the following ON-unit, that contains only the null statement:
ON ENDPAGE(SYSPRINT);
This is optional because PL/I ignores the ENDPAGE condition on SYSPRINT by default. You cannot catch the ENDPAGE(SYSPRINT) condition.
An ON-unit established to handle end-of-page conditions can reference the ONFILE built- in function to determine the name of the file constant for which the condition was signaled.
ON-Unit Completion
If the ON-unit does not transfer control elsewhere in the program, the line number is set to 1 and the program continues execution of the PUT statement. If the ENDPAGE condition was signaled during data transmission, the data is written on the new current line. If the ENDPAGE condition was caused by a LINE or a SKIP option on the PUT statement, then the action specified by these options is ignored on return.
An ENDPAGE condition can occur only once per page of output. If the ON-unit specified does not specify a new page, then execution and output continue. The current line number can increase indefinitely; PL/I does not signal the ENDPAGE condition again. However, if a LINE option on a PUT statement specifies a line number that is less than that of the current line, a new page is output and the current line is set to 1.
Default PL/I Action
If the ENDPAGE condition is signaled during file processing, PL/I starts output on a new page and continues processing. An exception is made for SYSPRINT which is to take no action. If the ENDPAGE condition is signaled as a result of a SIGNAL statement, the statement following the SIGNAL statement is executed and no page is output by default.
8.10.4.9. ERROR Condition
The ERROR condition name can be specified in an ON, SIGNAL, or REVERT statement to designate an error condition or ON-unit.
PL/I signals the ERROR condition in the following contexts:
When a condition occurs for which the default PL/I action is to signal ERROR
When the SIGNAL ERROR statement signals the condition
When there is a default PL/I ON-unit and a condition is signaled for which there is no corresponding ON-unit
PL/I signals the ERROR condition when any condition (except ENDPAGE, see preceding section) is raised and no ON-unit exists for the condition.
When any ON-unit is executed, the ON-unit can reference the built-in function ONCODE. This function returns the numeric condition value associated with the specific error that signaled the condition.
ON-Unit Completion
If an ERROR ON-unit does not handle the condition, the program is terminated.
8.10.4.10. FINISH Condition
The FINISH condition name can be specified in an ON, SIGNAL, or REVERT statement to designate a FINISH condition or a FINISH ON-unit.
PL/I signals the FINISH condition in the following contexts:
When any procedure in the program executes the STOP statement
When a procedure that specifies OPTIONS(MAIN) executes a RETURN statement, or, if the procedure does not execute a RETURN statement, when its corresponding END statement is executed
When the SIGNAL FINISH statement signals the condition
ON-Unit Completion
If a FINISH ON-unit that executes as a result of a SIGNAL FINISH statement does not execute a nonlocal GOTO statement, control returns to the statement following SIGNAL FINISH. If the FINISH ON-unit executes as a result of any of the other three causes listed above, the program terminates.
8.10.4.11. FIXEDOVERFLOW Condition
The FIXEDOVERFLOW condition name can be specified in an ON, SIGNAL, or REVERT statement to designate a fixed overflow condition or ON-unit.
PL/I signals the FIXEDOVERFLOW condition in the following circumstances:
When the result of an arithmetic operation on a fixed-point decimal or binary integer value exceeds the maximum precision of the hardware. The maximum precision allowed for a fixed-point decimal or binary value is 31.
When the source value of a fixed-point expression exceeds the precision of the target variable. For example, PL/I signals FIXEDOVERFLOW when a value that is not in the range -128 through 127 is assigned to a fixed-point binary variable with a precision of 7 bits and scale equal to zero. Similarly, the condition is signaled if a value assigned to a picture variable has more integral digits than are specified by the picture specification.
The value resulting from an operation that causes this condition is undefined.
Value of ONCODE
Two hardware exceptions exist that result in the FIXEDOVERFLOW condition. These are SS$_DECOVF (for a fixed-point decimal overflow) and SS$_INTOVF (for a fixed-point binary integer overflow). An ON-unit that receives control when FIXEDOVERFLOW is signaled can reference the ONCODE built-in function to determine which condition is actually signaled.
To define an ON-unit to respond specifically to either of these errors, use the VAXCONDITION condition name.
Example
To respond to a FIXEDOVERFLOW condition caused by either decimal or integer overflow, write an ON-unit as follows:
ON FIXEDOVERFLOW BEGIN; IF ONCODE() = SS$_DECOVF THEN DO; /* Decimal overflow handling */ END; IF ONCODE() - SS$_INTOVF THEN DO; /* Fixed binary overflow handling */ END; END; /* ON */
To respond to a decimal overflow only, write an ON-unit like the following:
ON VAXCONDITION (SS$_DECOVF) BEGIN; /* Decimal overflow handling */ END; /* ON */
ON-Unit Completion
If the ON-unit does not transfer control elsewhere in the program, control returns to the point at which the condition was signaled.
8.10.4.12. KEY Condition
The KEY condition name can be specified in an ON, SIGNAL, or REVERT statement to designate a key error condition or ON-unit for a specific file.
The format of the KEY condition name is:
KEY (file-reference)file-referenceA reference to the file constant or file variable for which the ON-unit is to be established. If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled.
PL/I signals the KEY condition during an operation on a keyed file when an error occurs in processing a key. Some examples of errors for which PL/I signals the KEY condition are:
The record indicated by the specified key cannot be found.
The key specification requires conversion from one data type to another and the conversion is not valid.
The key is not correctly specified.
The key of a relative file exceeds the maximum record number specified when the file was created. This error is shown in the Example section.
An ON-unit established to handle the KEY condition can obtain information about the condition by invoking the following built-in functions:
Example
The following example shows the key of a relative file exceeding the maximum record number specified.
%INCLUDE $RMSDEF; KEYTEST: PROCEDURE OPTIONS(MAIN); DECLARE RECBUF CHAR(80), MYFILE FILE; ON KEY(MYFILE) BEGIN; PUT SKIP LIST('Key condition raised'); IF ONCODE()=RMS$_MRN THEN PUT SKIP LIST('You have exceeded the maximum record.'); STOP; END; OPEN FILE(MYFILE) TITLE('MYFILE.DAT') OUTPUT KEYED ENVIRONMENT(FIXED_LENGTH_RECORDS, MAXIMUM_RECORD_SIZE(80), MAXIMUM_RECORD_NUMBER(20)); RECBUF = 'This record will not ever make it into the file'; WRITE FILE(MYFILE) FROM(RECBUF) KEYFROM(100); END;
ON-Unit Completion
If the ON-unit does not execute a nonlocal GOTO, control returns to the statement immediately following the statement that caused the KEY condition.
You can specify the NAME condition name in an ON, SIGNAL, or REVERT statement to handle errors that happen during execution of GET statements with the FILE option. By default, when a NAME condition is raised PL/I ignores the invalid data field, displays a message, and continues.
The format of the NAME condition name is:
NAME (file-reference)file-referenceA reference to the file constant or file variable for which the ON-unit is to be established. If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled.
Some examples of errors for which PL/I signals the NAME condition are:
The syntax of the returned data is invalid.
The name of the data item is invalid or missing. It may not be found in the data list, not be qualified, not be known in the block, be too long, or for any other reason be invalid.
A subscript may be missing or invalid in format, or may be out of range.
Use the DATAFIELD built-in function to retrieve the incorrect data field.
ON-Unit Completion
If the ON-unit does not execute a nonlocal GOTO, control returns to the statement immediately following the statement that caused the NAME condition.
8.10.4.14. OVERFLOW Condition
The OVERFLOW condition name can be specified in an ON, REVERT, or SIGNAL statement or, if you compile using the IBM dialect, in a condition prefix, to designate an ON condition or ON-unit for floating-point overflow conditions.
The exponent of a floating-point value is adjusted, if possible, to represent the value with the specified precision. That is, the precision is maximized and the exponent is minimized. The maximum precisions allowed are:
binary floating-point value—53
decimal floating-point value—15
PL/I signals the OVERFLOW condition when the result of an arithmetic operation on a floating-point value exceeds the maximum exponent size allowed by the hardware.
The value resulting from an operation that causes this condition is undefined.
ON-Unit Completion
Control returns to the point of the interruption.
You can specify the RECORD condition name in an ON, SIGNAL, or REVERT statement to handle errors that happen during execution of READ, WRITE, or REWRITE statements. By default, when a RECORD condition is raised, PL/I displays a message, and raises an ERROR condition.
The format of the RECORD condition name is:
RECORD (file-reference)file-referenceA reference to the file constant or file variable for which the ON-unit is to be established. If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled.
The ONCODE built-in function returns the specific condition codes associated with the error. Table 8.2, “Values of ONCODE Raised by RECORD” lists the RECORD condition codes and their meanings.
Table 8.2. Values of ONCODE Raised by RECORDONCODE value Raised by 20 A SIGNAL RECORD statement was executed. 21 Record variable is too small. 1. In a READ statement—the record variable is smaller than the record being read; the excess portion of the record will be lost. 2. In a WRITE or REWRITE statement to a file with fixed length records—The record variable is smaller than the record length; the excess portion of the record will be undefined. 22 Record variable is too large. 1. In a READ statement from a file with fixed-length records—the excess portion of the record variable will be undefined. 2. In a WRITE or REWRITE statement—Either the record is too large and the excess portion will be lost, or the record is of zero length and the write or rewrite will not be done. 23 Record variable is too small to contain the key. 24 The record that was just read is zero length.
ON-Unit Completion
If the ON-unit does not execute a nonlocal GOTO, control returns to the statement immediately following the statement that caused the RECORD condition.
You can specify the SIZE condition name in an ON, SIGNAL, or REVERT statement to handle errors that happen high-order (left-most) digits are lost in an assignment statement, intermediate result, or I/O operation. By default, when a SIZE condition is raised, PL/I displays a message and raises an ERROR condition.
The SIZE condition is disabled by default. To enable the SIZE condition, specify it in a condition prefix. If you signal the SIZE condition in a SIGNAL statement and SIZE is not enabled, PL/I displays an error.
The format of the SIZE condition name is:
SIZE
PL/I signals the SIZE condition when the following occurs:
The SIZE condition is enabled.
PL/I attempts to assign a value to a data item and the value exceeds the default or declared size of the target. This may occur during assignment or conversion.
Note that the size of the target is the default or declared size, not the actual amount of storage occupied by the data item. If you declare a variable as FIXED BINARY(17) and enable the SIZE condition, PL/I raises the condition if a value larger than FIXED BINARY(17) is assigned to the variable directly, by conversion, or as an intermediate value in a calculation.
The SIZE condition is not equivalent to the FIXEDOVERFLOW condition, which is raised when a fixed-point value exceeds the implementation's maximum value.
Important
Checking for size errors incurs overhead both in storage space and execution time. Therefore, it is best to use this condition prefix during program testing but not in production programs.
The ONCODE built-in function returns the specific condition codes associated with the error. Table 8.3, “Values of ONCODE Raised by SIZE” lists the SIZE condition codes and their meanings.
| ONCODE value | Raised by |
|---|---|
| 340 | 1. A SIGNAL SIZE statement was executed, or 2. SIZE was raised during assignment to a variable because high-order nonzero digits were lost, or 3. SIZE was raised during an I/O operation because significant digits were lost. |
| 341 | SIZE was raised during an I/O operation because high-order nonzero digits were lost. |
ON-Unit Completion
If the ON-unit does not execute a nonlocal GOTO, control returns to the statement immediately following the statement that caused the SIZE condition.
The STRINGRANGE condition is raised when a substring reference is beyond the length of the string. The error is detected either by compiled code or by a run-time library routine.
Note
By default, Endless PL/I for POSIX Systems does not signal the STRINGRANGE condition. Use the -k
compiler option to enable STRINGRANGE condition signalling.
STRINGRANGE can be abbreviated STRG.
Any one of several subconditions can cause the STRINGRANGE condition to be raised. You can use the ONCODE built-in function to determine which one. Table 8.4, “Values of ONCODE Raised by STRINGRANGE” shows the possible values of the ONCODE built-in function for the STRINGRANGE condition.
| ONCODE value | Raised by |
|---|---|
| PLI$_STRRANGE | SIGNAL STRINGRANGE |
| PLI$_SUBSTR2 | Out-of-range SUBSTR 2nd argument |
| PLI$_SUBSTR3 | Out-of-range SUBSTR 3rd argument |
| PLI$_BIFSTAPOS | Out-of-range starting position for an INDEX, SEARCH, or VERIFY built-in function |
Note that STRINGRANGE is always enabled in RTL code (which is currently used for more complex cases of INDEX, SEARCH,
and VERIFY), but in-line checking is only performed if the -k or --check compiler option
is used to compile the code in which the condition would be raised.
An example of the use of the STRINGRANGE condition and the ONCODE built-in function follows.
%INCLUDE $PLIDEF; ON STRINGRANGE BEGIN; /* * The THEN clause below will be executed for all * SUBSTR starting-position range errors. All other * STRINGRANGE errors will be resignaled. Note that * SUBSTR is processed in-line, so the code must be * compiled with /CHECK=BOUNDS for this ON-unit to * be effective. */ IF ONCODE() = PLI$_SUBSTR2 THEN ⋮ ELSE CALL RESIGNAL(); END;
The STRINGSIZE condition is raised when you try to assign a bit or character string to a target variable that is not long enough to hold the string. STRINGSIZE is disabled by default and must be enabled using a condition prefix.
If the STRINGSIZE condition is raised and not handled, the string is truncated from the right-hand end so that it will fit in the target variable. A message is displayed and processing continues.
The ONCODE built-in function returns the specific condition codes associated with the error. Table 8.3, “Values of ONCODE Raised by SIZE” lists the STRINGSIZE condition codes and their meanings.
| ONCODE value | Raised by |
|---|---|
| 150 | SIGNAL STRINGRANGE or assignment error in a bit or character string. |
| 151 | Assignment error in a mixed string. |
ON-Unit Completion
If the ON-unit does not execute a nonlocal GOTO, control returns to the statement immediately following the statement that caused the STRINGSIZE condition.
The SUBSCRIPTRANGE condition is raised in response to out-of-bounds subscripts in references to arrays. The value returned by the ONCODE built-in function for the SUBSCRIPTRANGE condition is PLI$_SUBRANGE or PLI$_SUBRANGEn, where n is the number of the subscript, in the range 1 through 8.
Note
By default, Endless PL/I for POSIX Systems does not signal the SUBSCRIPTRANGE condition. Use the -k
compiler option to enable SUBSCRIPTRANGE condition signalling.
8.10.4.20. STORAGE Condition
The STORAGE condition is raised when an error has been detected during allocation of a controlled variable or a based variable other than to an area. The most common cause is the exhaustion of virtual memory; another cause might be an erroneous attempt to allocate a negative amount of storage.
You can specify the TRANSMIT condition name in an ON, SIGNAL, or REVERT statement to handle errors that happen during execution of any I/O statement. By default, when a TRANSMIT condition is raised, PL/I displays a message, and raises an ERROR condition. This condition is always enabled.
The format of the TRANSMIT condition name is:
TRANSMIT (file-reference)file-referenceA reference to the file constant or file variable for which the ON-unit is to be established. If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled.
The TRANSMIT condition is raised at different points in execution of the I/O statement depending on the type of statement.
Input—after transmission of the incorrect record and, when records are blocked, after transmission of each subsequent record in the block.
Output—after transmission and, if records are blocked, after the block is complete.
Spanned record update—on the last segment of a record and not for any subsequent records in the block.
For I/O using the EVENT option—when the WAIT statement for that event is encountered.
The ONCODE built-in function returns the specific condition codes associated with the error. Table 8.2, “Values of ONCODE Raised by RECORD” lists the TRANSMIT condition codes and their meanings.
Table 8.6. Values of ONCODE Raised by TRANSMITONCODE value Raised by 40 A SIGNAL TRANSMIT statement was executed. 41 Uncorrectable output transmission error. 42 Uncorrectable input transmission error. 43 Uncorrectable output transmission error in index. 44 Uncorrectable input transmission error.inindex.45 Uncorrectable output to sequence transmission error. 46 Uncorrectable input from sequence transmission error.
ON-Unit Completion
If the ON-unit does not execute a nonlocal GOTO, processing continues as though no error had occurred. Any other errors in the statement execution, such as RECORD, will be raised.
To avoid unexpected results, if you close the file in the ON-unit, exit from the ON-unit using a nonlocal GOTO so statement execution will not continue.
8.10.4.22. UNDEFINEDFILE Condition
The UNDEFINEDFILE condition name can be specified in an ON, SIGNAL, or REVERT statement to designate an undefined file condition or ON-unit for a specific file.
The format of the UNDEFINEDFILE condition name is:
{ UNDEFINEDFILE }(file-reference)
{ UNDF }file-referenceA reference to a file constant or file variable for which the ON-unit is established.
If the name of a file variable is specified, the variable must be resolved to the name of a file constant when the on-unit is established, as well as when the condition is signaled.
PL/I signals the UNDEFINEDFILE condition when a file cannot be opened. Following are some examples of errors that cause the UNDEFINEDFILE condition:
The value specified by the TITLE option is an invalid file specification.
The file is opened for input or update and the specified file does not exist.
An existing file is accessed with PL/I file description attributes that are inconsistent with the file's actual organization.
Any system-detected file error prevents the file from being accessed.
The UNDEFINEDFILE condition lets you establish an ON-unit to provide processing when a file cannot be opened, for example, to provide a default file if no file is specified at run time.
X: PROCEDURE (FILENAME); DECLARE FILENAME CHARACTER (128) VARYING; DECLARE INPUT_FILE FILE INPUT; ON UNDEFINEDFILE (INPUT_FILE) OPEN FILE (INPUT_FILE) TITLE ('GENERIC_INPUT'); OPEN FILE (INPUT_FILE) TITLE (FILENAME);
In this example, the procedure X expects a file specification string to be passed as an argument. If no argument is passed, or if the argument is not a valid file specification, the OPEN statement fails. The UNDEFINEDFILE ON-unit provides a default OPEN statement with the file specification GENERIC_INPUT.
An ON-unit established to handle the UNDEFINEDFILE condition can obtain information about the condition by invoking the following built-in functions:
The ONFILE built-in function returns the name of the variable defined as FILE that was being processed when the condition was signaled.
The ONCODE built-in function returns the specific status value associated with the error.
ON-Unit Completion
The action taken on a normal return from the UNDEFINEDFILE condition depends on whether the file was opened explicitly or implicitly.
If the UNDEFINEDFILE condition was signaled following an explicit OPEN statement for a file, then the normal action following the ON-unit execution is for the program to continue. If the ON-unit does not transfer control elsewhere in the program, control returns to the statement following the OPEN statement that caused the condition to be signaled.
If the UNDEFINEDFILE condition was signaled during an implicit open attempt, the run- time system tests the state of the file. If the file is not open, the ERROR condition is signaled. If the file was opened by the ON-unit, execution of the I/O statement continues.
If an ON-unit receives control when an explicit OPEN results in the UNDEFINEDFILE condition, and the ON-unit does not handle the condition by opening the file or by transferring control elsewhere in the program, control returns to the statement following the OPEN. Then, if an attempt is made to access the file with an I/O statement, the UNDEFINEDFILE condition is signaled again when PL/I attempts the implicit open of the file. This time, PL/I signals the ERROR condition on completion of the ON-unit.
8.10.4.23. UNDERFLOW Condition
You can specify the UNDERFLOW condition name (which can be abbreviated UFL) in an ON, REVERT, or SIGNAL statement to designate a floating-point underflow condition or ON-unit.
PL/I signals the UNDERFLOW condition when the absolute value of the result of an arithmetic operation on a floating-point value is smaller than the minimum value that can be represented by the hardware.
ON-Unit Completion
On completion of the ON-unit, control is returned to the point of the interrupt. Continued execution is unpredictable.
This condition is signaled by PL/I only in procedures in which the UNDERFLOW option is enabled. The option is enabled when you specify UNDERFLOW in the procedure options.
The value resulting from an operation that causes the UNDERFLOW condition is undefined. (The value would be set to zero only if UNDERFLOW were not specified in the procedure options.)
8.10.4.24. VAXCONDITION Condition
The VAXCONDITION condition name can be specified in an ON, RESIGNAL, REVERT, or SIGNAL statement. The VAXCONDITION condition name provides a way to signal and handle operating-system or programmer-specified condition values. The format of the VAXCONDITION condition name is:
VAXCONDITION (expression)expressionAn expression yielding a fixed binary value. The expression is evaluated when the ON statement is executed, as well as when the condition is signaled.
The VAXCONDITION condition name is provided specifically for PL/I procedures that interact with operating system routines. For details on using the VAXCONDITION condition name and the meanings of system- and user-defined values that you can specify, see the Endless PL/I for POSIX Systems User's Manual.
8.10.4.25. ZERODIVIDE Condition
The ZERODIVIDE condition name can be specified in an ON, REVERT, or SIGNAL statement to designate a divide-by-zero condition or ON-unit.
PL/I signals the ZERODIVIDE condition when the divisor in a division operation has a value of zero. The value resulting from such an operation is undefined.
8.10.5. Default PL/I ON-Unit
PL/I defines a default ON-unit for the procedure that is designated as the main procedure. This is why there must be exactly one procedure with OPTIONS(MAIN) specified in any executable image. This default ON-unit performs the following actions depending on the condition signaled. Note that the severity of the signal is determined by the low three bits of the condition code.
If the signal is the ENDPAGE condition, the default PL/I handler executes a PUT PAGE for the file, and then continues the program at the point at which ENDPAGE was signaled. Note that ENDPAGE is ignored by default for SYSPRINT (see Section 8.10.4.8, “ENDPAGE Condition” for more information).
If the signal is the ERROR condition and the severity is fatal, the default handler signals the FINISH condition. Then, one of the following occurs:
If a FINISH ON-unit is found, it is given a chance to execute. If it executes a nonlocal GOTO or if it signals another condition, program execution continues.
If no FINISH ON-unit is found or if a FINISH ON-unit completes execution by handling the condition, then PL/I resignals the condition to the default condition handler. This handler prints a message, displays a traceback, and terminates the program.
If the signal is any condition other than ENDPAGE or ERROR with a fatal severity, the default PL/I handler signals the ERROR condition with the severity of the original condition. Then, one of the following occurs:
If an ERROR ON-unit is found, it is executed. If it completes execution by handling the condition, the program continues.
If an ERROR ON-unit is not found, the default PL/I handler resignals the condition. If this resignal results in return of control to the system, the default condition handler prints a message and a traceback. If the error is a fatal error, the default handler terminates the program; if the error is nonfatal, the program continues.
8.10.6. Using Condition Prefixes (IBM Dialect Only)
Condition prefixes let you enable or disable one or more PL/I conditions for the duration of a single statement. You can attach a condition prefix to any statement except the following: DECLARE, DEFAULT, ENTRY, or a preprocessor statement (any statement beginning with a % sign). For example:
DECLARE SOURCE CHARACTER(5) VARYING, TARGET FIXED BINARY(31); ⋮ (OVERFLOW,NOCONVERSION): TARGET = SOURCE;
Since you disabled the CONVERSION condition, PL/I does not signal it. However, if floating-point overflow occurs, PL/I signals the OVERFLOW condition.
As shown in the example, you can enable a condition by using the condition name, or disable it by using the negated condition name (for example, NOCONVERSION).
8.10.6.1. Scope of Condition Prefixes
A condition prefix affects only the statement or block to which it is attached. It does not affect procedures or ON-units invoked during execution of the statement or block.
Condition prefixes attached to DO or SELECT statements apply only to the DO or SELECT statement, not to the entire DO or SELECT group.
Condition prefixes attached to compound statements apply only to the statement to which they are attached, not to the statements contained in the compound statement.
Condition prefixes attached to PROCEDURE or BEGIN statements apply to all statements in the block, including the END statement and any other PROCEDURE or BEGIN statements nested inside the block. You can enable or disable a condition for an entire block and all the contained blocks by attaching a condition prefix to the PROCEDURE or BEGIN statement of the outermost block that you want to affect.
8.10.6.2. Default Status of Conditions
By default, some conditions are enabled unless explicitly disabled, others are disabled unless explicitly enabled, and some cannot be disabled. Table 8.7, “Conditions Enabled by Default”, Table 8.8, “Conditions Disabled by Default”, and Table 8.9, “Conditions That Cannot be Disabled” list the conditions in each of these three categories..
| CONVERSION | FIXEDOVERFLOW | OVERFLOW |
| UNDERFLOW | ZERODIVIDE |
| CHECK | SIZE | STRINGRANGE |
| STRINGSIZE | SUBSCRIPTRANGE |
| AREA | ATTENTION | CONDITION |
| ENDFILE | ENDPAGE | ERROR |
| FINISH | KEY | NAME |
| PENDING | RECORD | TRANSMIT |
| UNDEFINEDFILE |
Important
Note that the optimizer detects and diagnoses some conditions, whether or not you enable or disable them. If the optimizer detects a condition and diagnoses it, the condition is not raised when you execute the program.
8.10.7. Establishing ON-Units
An ON-unit is established for a specific ON condition or conditions following the execution of an ON statement that specifies the condition name(s). For example:
ON ENDFILE (ACCOUNTS) GOTO CLOSE_FILES;
This ON statement defines an ON-unit for an ENDFILE (end-of-file) condition in the file specified by the name ACCOUNTS. The ON-unit consists of a single statement, a GOTO statement.
After an ON-unit is established by an ON statement for a condition, it remains in effect for the activation of the current block and all its dynamically descendant blocks, unless one of the following occurs:
Another ON statement is specified for the same condition in a dynamically descendant block. The ON-unit established within the descendant block remains in effect as long as the descendant block is active.
A REVERT statement is executed for the specified condition. A REVERT statement nullifies the most recent ON-unit for the specified condition. (See Section 8.10.3, “REVERT Statement”).
Another ON statement is specified for the same condition within the current block. Within the same block, an ON statement for a specific condition cancels the previous ON-unit.
The block or procedure within which the ON-unit is established terminates. When a block exits, any ON-units it has established are reverted.
An ON-unit is established inside the ON-unit:
ON OVERFLOW BEGIN ⋮ ON OVERFLOW BEGIN ⋮ END; END;
8.10.8. Contents of an ON-Unit
An ON-unit can consist of a single simple statement, a group of statements in a begin block, or a null statement.
- Simple Statements in ON-Units
The following ON statement specifies a single simple statement in the ON-unit:
ON ERROR GOTO WRITE_ERROR_MESSAGE;
This ON statement specifies a GOTO statement that transfers control to the label WRITE_ERROR_MESSAGE in the event of the ERROR condition.
The specified statement must not be labeled and must not be any of the following:
DECLARE FORMAT RETURN DO IF SELECT END ON ENTRY PROCEDURE - Begin Blocks in ON-Units
An ON-unit can also consist of a sequence of statements in a begin block. For example:
ON ENDFILE (SYSIN) BEGIN; CLOSE FILE (TEMP); CALL PRINT_STATISTICS(TEMP); END;
This ON-unit consists of CLOSE and CALL statements that request special processing when the end-of-file condition occurs during reading of the default system input file, SYSIN.
If a BEGIN statement is specified for the ON-unit, the BEGIN statement must not be labeled. The begin block can contain any statement except a RETURN statement.
- Null Statements in ON-Units
A null statement specified for an ON-unit indicates that no processing is to occur when the condition occurs. Program execution continues as if the condition had been handled. For example:
ON ENDPAGE(SYSPRINT);
This ON-unit causes PL/I to continue output on a terminal regardless of the number of lines that have been output.
8.10.9. Search Path for ON-Units
When a condition is signaled during the execution of a PL/I procedure, PL/I searches for an ON-unit to respond to the condition. PL/I first searches the current block, that is, the block in which the condition occurred. If no ON-unit exists in this block for the specific condition, it searches the block that activated the current block (its parent), and then the block that activated that block, and so on.
PL/I executes the first ON-unit it finds, if any, that can handle the specified condition. If no ON-unit for the specific condition is found, default PL/I condition handling is performed.
8.10.10. Completion of ON-Units
The ON-unit can complete its execution in any of the following ways:
If the ON-unit executes a nonlocal GOTO statement, or if it invokes a subroutine or function that executes a nonlocal GOTO, program control is transferred to that statement and continues sequentially at that point in the program.
If the ON-unit executes a STOP statement, then the FINISH condition is signaled. If no FINISH ON-unit exists, the program is terminated.
An ON-unit can use the RESIGNAL built-in subroutine to request that PL/I continue to search for an ON-unit to handle a specific condition.
When any ON-unit (except for ERROR or FINISH) completes normally, control returns either to the statement that caused the condition or to the statement immediately following the statement that caused the condition.
Descriptions of each ON condition in this manual indicate the action that PL/I takes on completion of an ON-unit associated with the condition.