Flow of control in SOUL
Overview
Transferring control to another point
User Language statements are normally executed in the sequence in which they are written. This topic describes special statements that can be used to transfer control to another point in the request.
These transfer control statements include:
- IF statement
- JUMP TO statement
- STOP statement
- STOP IF COUNT statement
- LOOP END statement
Index loops and repeat loops
This topic also introduces special loop types, called index loops and repeat loops, that allow a series of statements to be repeated a specified number of times.
Subroutines
User Language lets you treat a single set of statements as a simple or complex subroutine which can be called from different locations within a request.
Subroutines, common elements, and ON units are discussed in Subroutines.
IF statement
During request execution, you can direct Model 204 as to what actions it should take based on the current values of %variables or expressions. You specify a course of action in an If statement.
The If statement introduces a block. Immediately following the If statement within the block is a set of one or more SOUL statements to execute if the specified conditions are true. The block is ended by an End If or End Block statement.
Syntax
The basic format of the IF statement is:
IF expression THEN statements
where expression specifies an expression in the form described in Expressions and statements can be any User Language statements.
Ending an IF statement
You must terminate the IF statement with an END IF statement or an END BLOCK statement.
Specifying multiple conditions
You can specify a number of conditions to satisfy in the IF clause by placing them on separate lines.
You must use a hyphen to indicate line continuation; do not use parentheses. Without the hyphen, starting a new input line within the IF statement implies an AND. The precedence of the implied AND is lower than all other operators. See Operator order of precedence for a list of operators and order of precedence.
Using the THEN clause
You can place the keyword THEN at the end of the last condition or on a new line. Although the THEN keyword is not required, you should always provide it to avoid confusion and the possibility of unexpected results. The statement or statements included in the THEN clause can be any User Language statements, as shown in the following example.
IF POLICY NO EQ 100340 FULLNAME EQ 'ABBOTT, FRANKLIN G' THEN PRINT DATE OF BIRTH END IF
The THEN clause is executed only if all conditions are true. If one or more of the conditions are false, the THEN clause is not executed; execution moves to the next statement with a nesting level no deeper than that of the IF statement. In the following example, if the conditional expression is true, the FIND.RECS, PRINT.NAME, and END.PRINT statement are executed. If the expression is false, execution moves to PRINT.MSG.
. . . CHECK.VAR.A: IF NOT %A LIKE 'JACK*' THEN FIND.RECS: FIND ALL RECORDS FOR WHICH AGENT = %A END FIND PRINT.NAME: FOR EACH RECORD IN FIND.RECS PRINT AGENT WITH POLICY NO AT COLUMN 30 END FOR END.PRINT: JUMP TO PRINT.DONE END IF PRINT.MSG: PRINT 'VARIABLES NOT EQUAL' PRINT.DONE: PRINT 'ALL DONE'
Example
If a conditional expression is the last statement within a loop, a false condition continues execution of the loop with the next record or value.
In the following example, if the condition TOTAL PREMIUM > 300 is true, a second test is performed. If AGENT EQ 'CASOLA' also is true, the birth date is printed. If the first condition is not true, the second test is not performed and execution returns to the top of the FOR loop with the next record.
FIND.RECS: FIND ALL RECORDS END FIND PRINT.DOB: FOR EACH RECORD IN FIND.RECS IF TOTAL PREMIUM > 300 THEN IF AGENT EQ 'CASOLA' THEN PRINT POLICY NO - WITH DATE OF BIRTH AT COLUMN 30 END IF END IF END FOR SORT.RECS: SORT RECORDS IN FIND.RECS BY POLICY NO . . .
ELSE clause and ELSEIF clause
ELSE clause
The ELSE clause lets you specify one or more statements to execute when the condition specified in the IF statement is false. For example:
COMPUTE.A: IF %DIV LE 0 THEN %X = %X + 1 ELSE %A = %B / %DIV END IF
An ELSE clause terminates the THEN clause and must begin on a new line.
Nesting IF statements
A THEN or an ELSE clause can contain an IF statement. When IF statements are embedded, an ELSE clause without a statement label is executed when the condition of the immediately preceding IF is false.
Example 1
In the following example, the ELSE clause is executed when the conditions %W EQ '1' and %X EQ 'A' are true and the condition %Y EQ 'B' is false.
SET.Z.VAR: IF %W EQ '1' THEN IF %X EQ 'A' THEN IF %Y EQ 'B' THEN %Z = 'CASE1' ELSE %Z = 'CASE2' END IF END IF END IF
Example 2
You can specify an ELSE clause for an IF statement that does not immediately precede the ELSE. The following example illustrates how to use an ELSE clause without a statement to pair each ELSE with the correct IF. In this example, the statement %Z = 'CASE3' is executed whenever the condition %W EQ '1' is true and the condition %X EQ 'A' is false.
SET.Z.VAR: IF %W EQ '1' THEN IF %X EQ 'A' THEN IF %Y EQ 'B' THEN %Z = 'CASE1' END IF ELSE %Z = 'CASE3' END IF END IF
Using the ELSEIF clause
The ELSEIF clause provides a convenient way of specifying embedded IF statements when a series of tests are to be made, only one of which will be satisfied.
The following examples illustrate how to specify a statement using ELSEIF instead of ELSE.
Example using ELSE
IF %X EQ 'A' THEN %I = 1 ELSE IF %X EQ 'B' THEN %I = 2 ELSE IF %X EQ 'C' THEN %I = 3 END IF END IF END IF
Example using ELSEIF
IF %X EQ 'A' THEN %I = 1 ELSEIF %X EQ 'B' THEN %I = 2 ELSEIF %X EQ 'C' THEN %I = 3 END IF
Using operators with the IF statement
This section discusses how the following operators are used with IF statements:
- Comparison
- Boolean
- IS PRESENT and IS NOT PRESENT
Using variables and values in computation also discusses the use of expressions, operators, and operands.
Comparison operators
Comparison operators are used with the assignment or conditional statement to return a value of 1 if the stated relation between operands is true, and a value of 0 if false. If the operands are both numbers or are both character strings, the obvious algebraic or string comparison is made. In conditional clauses, values of non-FLOAT fields and string %variables are treated as character strings whether or not they contain numbers.
Conversion
If one operand is a character string and the other is a number, the character string is converted to a number before the comparison is made. A value of 0 results from the conversion if the string does not follow the rules for numbers used in expressions. Thus:
'+3.0' EQ 3
is true, but:
'THREE' EQ 3
is false.
Literal number operands
If one of the operands is a literal number, it should be the second operand. For example:
IF AGE > 3
is acceptable. However:
IF 3 AGE
results in an error message.
Numeric comparison of string values
If two operands that normally are strings are to be compared numerically, you must force at least one of the operands to be converted to a number. This is done by preceding the quantity with a unary plus sign.
Example 1
Suppose a request includes these statements:
SET.VAR.A: %A = 21 FOR EACH RECORD IN FIND.RECS
and the user wishes to mark those records where the AGE field is numerically less than the STRING variable %A. If the AGE field for the current record is 9, the comparison:
AGE < %A
is false because both are treated as strings and "9" is greater than "21". Either
+AGE < %A
or
AGE < +%A
produces the desired result.
Example 2
The statement:
IF AGE = 0 THEN . . .
is true if AGE is algebraically equivalent to 0 (0.00, 0, and so on) or if AGE is not a number ('FIVE', ",and so on)
IF AGE = '0' THEN . . .
is true only if AGE is equal to the character "0" (zero).
Boolean operators
The power of the IF clause can be expanded by means of the Boolean operators NOT, AND, and OR, which can be used to modify or link together comparison expressions.
Examples
IF AGE > 3 AND AGE < 15 THEN PRINT AGE
The value of the field AGE is printed if it falls between 3 and 15 inclusively. If the value of AGE is 20, it is not printed because the comparison subclauses are not both true.
In the following example, the value of the field is printed if either or both of the comparison subclauses are true. Any value greater than 45 is printed as will any value equal to 28.
IF AGE GT 45 OR AGE EQ 28 THEN PRINT AGE
Do not abbreviate conditions
When the Boolean operators AND, OR, and NOT are used in an IF statement, the conditions they connect cannot be abbreviated as can the conditions in a FIND statement. In a FIND statement, the following are equivalent:
FIND.RECS: FIND ALL RECORDS FOR WHICH AGE = 24 OR 25 OR 26 END FIND FIND.RECS: FIND ALL RECORDS FOR WHICH AGE = 24 OR AGE = 25 OR AGE = 26 END FIND
In an IF statement, the following expressions are not equivalent:
FOR EACH RECORD IN FIND.RECS IF FIELD EQ 24 OR FIELD EQ 25 - OR FIELD EQ 26 THEN - . . . FOR EACH RECORD IN FIND.RECS IF FIELD EQ 24 OR 25 OR 26 THEN . . .
The first statement is true if the value of FIELD is algebraically equivalent to 24, 25, or 26. The second statement is always true. FIELD EQ 24 is considered to be the first expression. The numbers 25 and 26 are stand-alone expressions that have no algebraic operator. Model 204 considers a literal number other than 0 a true value. Character strings are true if they contain nonzero numerical values.
ANDIF and ORIF short-circuit operators
The operators ANDIF and ORIF provide short-circuit logical operations.
The purpose of short-circuit operators is to enable the compiled code to bypass the evaluation of a second expression, depending on the result of the previous expression(s). If the result of the first expression can determine the final result of the operation, there is no need to continue evaluating subsequent expressions since they will not change the outcome.
Consider using short-circuit operators to improve performance if your code can skip evaluation of other expressions, especially if they are complex expressions. Any advantages of using short-circuit operators instead of nested IFs will depend on your code. In most cases, standard nested IF processing will provide better performance.
Using the ANDIF operator
Consider the following code that must evaluate each EQ expression before taking action:
IF LASTNAME EQ 'SMITH' AND - FIRSTNAME EQ 'SAM' AND - BIRTH.YEAR EQ 1963 THEN * do something END IF
You could rewrite the previous code to prevent evaluation of some conditions if the higher level conditions are false. For example, if LASTNAME is not equal to 'SMITH', the subsequent conditions on FIRSTNAME and BIRTH.YEAR are not evaluated:
IF LASTNAME EQ 'SMITH' THEN IF FIRSTNAME EQ 'SAM' THEN IF BIRTH.YEAR EQ 1963 THEN * do something END IF END IF END IF
You could also accomplish the same thing without nested IF statements by using ANDIF. For example, if LASTNAME is not equal to 'SMITH', the subsequent conditions are not evaluated:
IF LASTNAME EQ 'SMITH' ANDIF - FIRSTNAME EQ 'SAM' ANDIF - BIRTH.YEAR EQ 1963 THEN * do something END IF
Comparing ANDIF evaluation sequence
ANDIF and ORIF short-circuit operators illustrates how sequential expressions are evaluated when using the ANDIF operator and the result of the operations:
Expression 1 | Expression 2 | Expression 3 | Result |
---|---|---|---|
TRUE | TRUE | TRUE | TRUE |
TRUE | FALSE | (Not evaluated) | FALSE |
FALSE | (Not evaluated) | (Not evaluated) | FALSE |
Using the ORIF operator
Similarly, with the ORIF operator:
IF LASTNAME EQ 'SMITH' ORIF - LASTNAME EQ 'JONES' ORIF - FIRSTNAME EQ 'FRED' THEN * do something END IF
Comparing ORIF evaluation sequence
ANDIF and ORIF short-circuit operators illustrates how subsequent expressions are evaluated using the ORIF operator and the result of the operations:
Expression 1 | Expression 2 | Expression 3 | Result |
---|---|---|---|
TRUE | (Not evaluated) | (Not evaluated) | TRUE |
FALSE | TRUE | (Not evaluated) | TRUE |
FALSE | FALSE | TRUE | TRUE |
FALSE | FALSE | FALSE | FALSE |
Note: You can freely intersperse ANDIF evaluations and ORIF evaluations with AND evaluations and OR evaluations.
IS PRESENT and IS NOT PRESENT operators
The IS PRESENT and the IS NOT PRESENT operators can be used in expressions within record loops to determine whether or not a field is present on the current record of the loop.
The IS PRESENT operator returns a value of 1 if the specified field is present in a record, and a value of 0 if the specified field is missing. Fields with null values ('') are considered to be present. Conversely, the IS NOT PRESENT operator returns a value of 1 if the specified field is missing in a record, and a value of 0 if the field is present.
The expression:
fieldname IS NOT PRESENT
is equivalent to:
NOT fieldname IS PRESENT
Order of precedence
The IS PRESENT and IS NOT PRESENT operators have higher precedence than any other operators.
Syntax requirements
- The operand must be a field (field name); it cannot be the result of another operator.
- You must include the IS keyword as part of the IS PRESENT and IS NOT PRESENT operators.
- The IS PRESENT operator cannot be followed by a value.
True and false values
The final result of a series of comparisons has a numeric value: true equals one and false equals zero. This value can be used in assignment statements. For example:
%CONDITION1 = AGE > 3 AND AGE < 15 %CONDITION2 = NAME EQ 'SMITH' OR NAME EQ 'JONES' IF %CONDITION1 AND %CONDITION2 THEN . . .
Setting switches equal to 0 or 1, and then testing them in more than one IF statement, is an efficient comparison technique. The condition tested by IF need not contain a comparison operator.
Consider a file containing two record types. If TYPE is a field to be tested in an IF statement, the values assigned to TYPE could be 0 and 1. For example:
BEGIN FIND.RECS: FIND ALL RECORDS FOR WHICH NAME = SMITH END FIND FOR EACH RECORD IN FIND.RECS IF TYPE THEN . . .
If TYPE were equal to 1, then the expression is true and the statements following THEN are executed.
Sample request using IF statements
The following request demonstrates the use of conditionals. The request finds the average temperature during January, 1999, at each weather station. The CHECK.TEMP statement tests the value of the TEMP field in the current record. If the TEMP field is missing from the record, Model 204 assigns it the value of a zero length string (the null string) in expressions.
BEGIN NEW PAGE VARIABLES ARE FLOAT GET.VALUE: FOR EACH VALUE OF STATION %TEMP = 0 %NO = 0 FIND.RECS: FIND ALL RECORDS FOR WHICH TYPE = WEATHER DATE IS BETWEEN 990100 AND 990132 STATION = VALUE IN GET.VALUE END FIND FOR EACH RECORD IN FIND.RECS CHECK.TEMP: IF TEMP NE " THEN %NO = %NO + 1 %TEMP = %TEMP + TEMP END IF END FOR IF %NO EQ 0 THEN PRINT VALUE IN GET.VALUE TAB - 'NO TEMP OBS.-JAN 1999' JUMP TO SKIP.ONE END IF %AVTEMP = %TEMP/%NO CT.RECS: COUNT RECORDS IN FIND.RECS %MISS = COUNT IN CT.RECS - %NO PRINT VALUE IN GET.VALUE TAB %NO WITH - ' TEMP OBS., ' WITH %MISS WITH ' MISSING TEMPERATURE OBSERVATION FOR - JANUARY 1990' - TAB %AVTEMP WITH ' MEAN TEMP FOR JAN 1999' SKIP.ONE: SKIP 1 LINE END FOR END
Branching statements
The following statements can transfer control and terminate the execution of a loop or request:
- JUMP TO
- STOP
- STOP IF COUNT
- LOOP END
Although these statements typically are used in conjunction with the IF statement, they can be used in other contexts as well.
See Usage with branching statements for a discussion of branching statements with repeat loops.
JUMP TO statement
The JUMP TO statement transfers control to another statement in the request.
Syntax
The format of the JUMP TO statement is:
JUMP TO label
where label is the label of the next statement to be processed.
Example 1
. . CHECK.DATE: IF DATE OF BIRTH > 19700101 THEN JUMP TO END.REQUEST ELSE %A = TOTAL PREMIUM END IF FIND.RECS: FIND ALL RECORDS FOR WHICH DATE OF BIRTH IS > 19630618 END FIND FOR EACH RECORD IN FIND.RECS . . . END FOR END.REQUEST: PRINT 'INVALID DATE ON FILE' . . .
Computed JUMP TO
A more complex form of the JUMP TO statement, called the computed JUMP TO, selects the next statement to be processed based on the current value of some expression. The format of the computed JUMP TO is as follows:
JUMP TO (label1 [, label2] ...) expression
Where:
- label1, label2, and so on are statement labels
- expression is any valid arithmetic expression (see the discussion on expressions in Arithmetic operations).
When the JUMP TO is processed, the expression is evaluated as a number and rounded to an integer (for example, k). A jump is then performed to the kth statement label in the list.
Example 2
For example, if the user enters:
BRANCH: JUMP TO (PRINT.VIN, ACCUM.TOT, ACCUM.GRAND.TOT) - %A-3 SKIP 1 LINE
then %A-3 is evaluated and rounded to an integer. The next statement processed after BRANCH is PRINT.VIN if %A-3 = 1, ACCUM.TOT if %A-3 = 2, ACCUM.GRAND.TOT if %A-3 = 3, or the SKIP statement if %A-3 = anything else.
If k is less than one or larger than the number of entries in the list, or if the expression is not a number, no jump occurs. Processing continues with the next sequential statement.
JUMP TO branching
Both forms of the JUMP TO statement can branch outside a FOR EACH RECORD loop or refer to other statements within the same loop, but neither form can jump into a loop from outside that loop.
STOP statement
The STOP statement terminates the execution of a request. However, the STOP statement does not cancel compilation and evaluation of a continuation if the terminated request ends with END MORE.
STOP IF COUNT statement
The STOP IF COUNT statement limits the amount of output.
Syntax
The format of the STOP IF COUNT statement is:
STOP IF COUNT IN label EXCEEDS n
This statement ends a request if the number obtained by a COUNT RECORDS statement is larger than the integer n. STOP IF COUNT must be used outside a loop.
Example
BEGIN DRIVER: FIND ALL RECORDS FOR WHICH RECTYPE = DRIVER STATE = VIRGINIA END FIND NO.OF.DRIVERS: COUNT RECORDS IN DRIVER PRINT COUNT IN NO.OF.DRIVERS STOP IF COUNT IN NO.OF.DRIVERS EXCEEDS 100 FOR EACH RECORD IN DRIVER PRINT FULLNAME END FOR END
If there are 100 or fewer Virginia drivers in the file, Model 204 prints the number of drivers and then print the name of each driver. If there are more than 100 drivers in the file, Model 204 prints only the number of drivers.
LOOP END statement
The LOOP END statement transfers control to the statement immediately following the loop that contains the LOOP END statement. This, in effect, is a jump outside a loop to just beyond its end.
Example:
BEGIN FIND.RECS: FIND ALL RECORDS FOR WHICH RECTYPE = DRIVER END FIND LOOP: FOR EACH RECORD IN FIND.RECS IF DATE OF BIRTH GT 700101 THEN LOOP END END IF SET.VAR: %AGE = 900901 - DATE OF BIRTH . . . END FOR LOOP PRINT.MSG: PRINT 'MESSAGE' . . .
In the preceding request, if the date of birth is found to be greater than January 1, 1970, the LOOP statement is immediately ended and processing continues beginning with the PRINT.MSG statement.
Using branching statements to control processing
Sometimes different sets of records require identical processing. Lists can be used to eliminate the coding of duplicate sets of processing statements and branching statements can be used to control processing, as shown in the following procedure.
BEGIN MA.POL.HLDR: FIND ALL RECORDS FOR WHICH RECTYPE = POLICYHOLDER STATE = MASSACHUSETTS END FIND MAKE.LIST: PLACE RECORDS IN MA.POL.HLDR ON LIST GENERAL SORT.LIST: SORT RECORDS ON LIST GENERAL BY CITY PRINT.INFO: FOR EACH RECORD IN SORT.LIST PRINT POLICY NO AND FULLNAME - WITH CITY AT COLUMN 30 END FOR ACCUM.CT: %CT = %CT + 1 IF %CT = 2 THEN JUMP TO STOP END IF CLEAR LIST GENERAL CAL.GOODRICH: FIND ALL RECORDS FOR WHICH STATE = CALIFORNIA AGENT = GOODRICH END FIND NEW.LIST: PLACE RECORDS IN CAL.GOODRICH ON LIST GENERAL JUMP TO SORT.LIST STOP: END
In the preceding request, the MA.POL.HLDR and MAKE.LIST statements select a set of records that are processed with the SORT.LIST and PRINT.INFO statements. The CAL.GOODRICH and NEW.LIST statements select a second set of records. The request then jumps back to the SORT.LIST statement and the SORT.LIST and PRINT.INFO statements process the second set of records. The ACCUM.CT statement tests a variable and terminates the request after the second set has been processed.
Using branching statements to continue loops
Issue
It is often necessary to branch around statements in a FOR loop and continue the loop with the next record or value.
A jump to the FOR EACH RECORD statement or a jump to the first statement in the loop does not accomplish this. If a jump to the FOR EACH RECORD statement is performed within the loop, Model 204 starts again with the first record in the set being processed. If a jump to the first statement in the loop is performed, Model 204 starts processing the current record again.
Solution
A jump to a comment statement placed at the end of the loop can resolve this problem and allow Model 204 to process the next record. For example:
BEGIN FIND.RECS: FIND ALL RECORDS FOR WHICH TYPE = PAYROLL END FIND FOR EACH RECORD IN FIND.RECS IF DEPT EQ 'ACCT' THEN %TIME = %TIME + 40 JUMP TO JUMP.COMM END IF IF DEPT EQ 'PAY' THEN %TIMEP = %TIMEP + 37 END IF JUMP.COMM: *COMMENTS END FOR PRINT %TIME AND %TIMEP END
Index loops
The index loop statement executes a series of statements for each element of an array, for particular dimensions of the array, or for particular elements of the array. In addition to being used with arrays, index loops can be used any place wherever a set of statements is to be executed a number of times. If the loop is controlled by a number rather than by a value or a FOR loop, an index loop can be used.
Syntax
The format of the index loop statement is:
FOR %variable FROM exp1 TO exp2 BY exp3
Where:
- exp1 indicates the first element to be processed by the index loop. Exp1 is not allowed to change during processing.
- exp2 indicates the last element to be processed by the index loop. Exp2 is not allowed to change during processing.
- exp3 indicates the number by which the element number is to be incremented each time the loop is performed. For example,
BY 2
might be used to process every other array element.The TO and BY phrases can appear in any order. If BY is omitted, the default increment is 1.
Index loop processing
The expressions specified in the index loop are evaluated only once before the first pass through the loop. Exp1 and exp2 are evaluated before the loop, so changes will not affect the loop. However, exp3 can change within the loop.
Model 204 performs the test for index loop completion before the loop body. The increment is performed before each pass of the loop except the first. A branch is allowed out of the loop, but not into it.
For all types of variables that represent expr2 and expr3, except the FLOAT type, expr2 and expr3 are both evaluated only once. Changing the values of the variable in expr2 and/or expr3 in the body of the FOR loop will not affect the number of times that the loop is run.
FLOAT variables that represent expr2 and expr3 in a FOR loop are evaluated each time through the FOR loop. You may expand or contract the scope of the loop as well as change the BY SKIP value during the body of the FOR loop each time it is evaluated.
Example
The following example of an index loop reads inventory items from records and stores them in an array named %PRODUCT. It then reads account numbers and stores them in the array named %ACCTNO. GET.ENTRY processes the array %ACCTNO. It accesses an account number, prints it, sets corresponding items from the %PRODUCT array, and prints them. It then returns to access the next account number, and continues processing.
The following records are used as input to the index loop:
TYPE = ITEM TYPE = ITEM TYPE = ITEM ACCOUNT = 100 ACCOUNT = 200 ACCOUNT = 300 ITEM = TISSUES ITEM = CORN FLAKES ITEM = WHITE BREAD ITEM = TOOTHPOWDER ITEM = BRAN FLAKES ITEM = WHOLE WHEAT ITEM = TOOTHPASTE ITEM = PUFFED WHEAT ITEM = CORN BREAD ITEM = SOAP ITEM = PUFFED RICE ITEM = HONEY WHEAT ITEM = TOOTHBRUSH ITEM = SHREDDED WHEAT ITEM = SYRIAN BREAD
The request to process the records is as follows:
BEGIN %PRODUCT IS STRING LEN 15 ARRAY(3,5) DECLARE %ACCTNO FLOAT ARRAY(3) VARIABLES ARE FIXED %ACCT = 0 FIND.RECS: FIND ALL RECORDS FOR WHICH TYPE = ITEM END FIND GET.ENTRY: FOR EACH RECORD IN FIND.RECS %ACCT = %ACCT+1 %ACCTNO(%ACCT) = ACCOUNT FOR %INDEX FROM 1 TO 5 %PRODUCT(%ACCT,%INDEX) = ITEM(%INDEX) END FOR END FOR FOR %ACCT FROM 1 TO 3 PRINT 'CUSTOMER ACCOUNT = ' WITH - %ACCTNO(%ACCT) SKIP 1 LINE FOR %INDEX FROM 1 TO 5 PRINT 'ITEM = ' AT COLUMN 15 WITH %PRODUCT(%ACCT,%INDEX) END FOR SKIP 1 LINE END FOR END
Output appears as shown below:
CUSTOMER ACCOUNT = 100 ITEM = TISSUES ITEM = TOOTHPOWDER ITEM = TOOTHPASTE ITEM = SOAP ITEM = TOOTHBRUSH CUSTOMER ACCOUNT = 200 ITEM = CORN FLAKES ITEM = BRAN FLAKES ITEM = PUFFED WHEAT ITEM = PUFFED RICE ITEM = SHREDDED WHEAT CUSTOMER ACCOUNT = 300 ITEM = WHITE BREAD ITEM = WHOLE WHEAT ITEM = CORN BREAD ITEM = HONEY WHEAT ITEM = SYRIAN BREAD
Repeat loops
As discussed previously, you can use the index loop wherever you want to execute a set of statements a specific number of times. However, if the series of statements to be executed either does not need a number specification or if the times of execution occur in a non-uniform manner, you can use a repeat loop.
Initiating a repeat loop
A repeat loop is initiated by using one of the following REPEAT statements. A repeat loop terminates with an END REPEAT statement. You can also end a REPEAT loop with an END BLOCK statement.
REPEAT... | This statement executes a series of statements... |
---|---|
WHILE | As long as a specified condition is true. |
UNTIL | Until a specified condition is true. |
n TIMES | A specified number of times. |
FOREVER | Repeatedly until the loop is exited with a STOP, JUMP, or LOOP END statement. |
Usage with branching statements
The following rules govern branching into and out of repeat loops:
Statement | Can be used to... |
---|---|
JUMP TO | Jump out of the repeat loop. However, jumping to a statement within a repeat loop from a statement outside the repeat loop is not allowed. |
LOOP END | Transfer control to the statement immediately following the repeat loop that contains the LOOP END statement. |
STOP | Terminate processing within repeat loops; however, the STOP IF COUNT statement is not permitted. |
Refer to Branching statements for a discussion.
REPEAT WHILE statement
The REPEAT WHILE statement executes a series of statements, as long as the specified condition is true. The condition is evaluated before each execution of the body of the loop. If the condition is false when the REPEAT WHILE statement is first executed, the statements inside the loop are never executed.
Syntax
The format of the REPEAT WHILE statement is:
REPEAT WHILE condition
where condition can specify one or more conditions. The conditions must be specified on one logical line. A hyphen is used to note the continuation of the set of conditions (with a logical AND implied at each end-of-line) for a logical line.
Example 1
This statement is considered one logical line.
REPEAT WHILE POLICY NO EQ 100340 OR - (STATE EQ FLORIDA CITY EQ ORLANDO) OR INCIDENT EQ T3
Example 2
This example illustrates the use of the REPEAT WHILE statement:
. . . READ IMAGE ACCTPROC REPEAT WHILE $STATUS = 0 CALL SUB1 READ IMAGE ACCTPROC END REPEAT . . .
REPEAT UNTIL statement
The REPEAT UNTIL statement executes a series of statements until the specified condition is true. The REPEAT UNTIL statement begins executing the body of the loop before evaluating the condition.
Syntax
The format of the REPEAT UNTIL statement is:
REPEAT UNTIL condition
where condition can specify one or more conditions. The conditions must be specified on one logical line. A hyphen is used to note the continuation of the set of conditions (with a logical AND implied at each end-of-line) for a logical line.
Examples of REPEAT WHILE and REPEAT UNTIL
Example 1:
The following REPEAT WHILE program results in output of '1':
BEGIN REPEAT WHILE %I EQ 0 %I = %I + 1 PRINT %I END
Whereas the following REPEAT UNTIL program results in an endless print loop:
BEGIN REPEAT UNTIL %I EQ 0 %I = %I + 1 PRINT %I END
Example 2:
BEGIN %X IS FLOAT %TRUE IS BOOLEAN INITIAL(TRUE) REPEAT UNTIL NOT %TRUE PRINT 'INSIDE' AND %X AND %TRUE IF %X = 0 THEN %TRUE = 'TRUE' END IF %X = %X + 1 END REPEAT PRINT 'OUTSIDE' AND %X AND %TRUE END
results in:
INSIDE 0 True OUTSIDE 1 False
But changing REPEAT UNTIL to REPEAT WHILE in the Example 2 code results in:
OUTSIDE 0 True
REPEAT n TIMES statement
The REPEAT n TIMES statement executes a series of statements exactly n times.
Syntax
The format of the REPEAT n TIMES statement is:
REPEAT n TIMES
where n (the iteration count) must be either a positive integer literal, for example, 3, 100, 101, or a %variable, for example, %A, %B(%A+1). If the value of n is negative, 0, or a character string when the REPEAT statement is first executed, the statements inside the loop are not executed.
If the value of the %variable is a floating point number, it is converted to an integer before the statement is executed. For example, if REPEAT %I TIMES is specified and the value of %I is 5.9, then the statement is executed five times.
Example
. . . REPEAT 10 TIMES PRINT '***************' END REPEAT . . .
You can have a statement within the body of the loop to change the value of a %variable specified as the iteration count. However, such a change has no effect on the number of times the loop is executed because the iteration count is examined only once, prior to the first iteration.
REPEAT FOREVER statement
The REPEAT FOREVER statement executes a series of statements repeatedly until the loop is exited with a STOP, JUMP, or LOOP END statement.
Syntax
The format of the REPEAT FOREVER statement is:
REPEAT [FOREVER]
where the FOREVER keyword is optional.
Example
. . . REPEAT FOREVER READ IMAGE ACCTPROC IF $STATUS = 0 THEN CALL SUB1 ELSE LOOP END END IF END REPEAT . . .