The do instruction group is a complicated set of concepts to learn. These concepts are presented as the following topics.
A do instruction group can be prone to logic pitfalls, when either the do instruction or corresponding end clause is erroneously absent. The RFLOW program that is provided with this tutorial can help you study, and correct, the control flow of your REXX programs.
do
instruction instruction ...etc end |
A do instruction without any additional clauses is used for grouping a sequence of instructions. This form of do instruction is used when more than one instruction is performed after the then keyword of an if instruction, or when clause within a select instruction group.
A name is not permitted with the end instruction, when it concludes a simple do instruction group.
An iterative Do instruction group has the following syntax variations.
do [ repetitorClause ] [ conditionalClause ]
instruction instruction ...etc end [ name ] the repetitorClause can be one of the following:
the conditionalClause can be one of the following:
|
Rexx provides a rich set of looping capabilities. An iterative do instruction can have a repetitorClause and/or a conditionalClause. When both of these clauses are absent, it is a simple do group instead.
Looping capabilities can be further refined by using leave and iterate instructions.
There are two types of simple repetitive loops. One is repeated forever, the other is repeated a finite number of times. You will rarely want to repeat a loop an infinite number of times. Instead, you will probably add a leave instruction. However, there are some Rexx programs that you will want to run indefinitely until they are cancelled.
Here are examples of simple repetitive loops.
do forever
say 'yada' if random( 15 ) = 1 then leave /* a LEAVE is a very good idea */ end do random( 3, 5 ) /* this performs the loop 3, 4, or 5 times */ say 'yada' end |
The repetition expression in a simple loop might contain an equal sign. This might be misconstrued as a counted loop, which is discussed in the next section. When you want a simple repeated loop you should enclose the expression in parentheses as follows:
say 'Enter the number of times you want to see yada, yada, yada, ...'
do ( count = linein() ) say 'yada' end |
If the parentheses around the count = linein() phrase were absent, the program would run forever. The count would begin with the number you entered, and would be incremented by 1 every loop cycle.
A counted loop has the following syntax.
do controlVariable = initialValue [ to limitValue ] [ by stepValue ] [ for repetitionValue ]
instruction instruction ...etc end [ controlVariable ] |
Note:
Expressions can be specified for the limitValue, stepValue, and repetitionValue. The result of these expressions must be numbers. The value of these expressions is computed only once -- before the controlVariable is assigned the initial value. The controlVariable may be altered within the loop. If the controlVariable is altered within the loop it can affect the number of loop iterations. Other programming languages (such as, C/C++, Java, Perl, etc.) allow the limitValue, stepValue, and repetitionValue values to be altered within the loop as well. This is not the case for Rexx. Consider for example:
limit = 1 do i=1 to limit say i if random( 1, 100 ) < 50 then limit = 2 end i |
You might think that the above loop will show 1, and then 2, 50% of the time. This does not happen ! Instead it always shows only the value 1. The following shows how to write the loop so that it sometimes shows 2 as well.
limit = 1 do i=1 to while i <= limit say i if random( 1, 100 ) < 50 then limit = 2 end i |
Counted loops are commonly used in Rexx programs. Here is a simple example that shows the powers of two, from 1 to 32.
do i=1 to 32 say '2 to the power' i 'is:' 2 ** i end |
Here is another example, that shows every 4th power of two.
do i=4 to 32 by ( 2 + 2 ) say '2 to the power' i 'is:' 2 ** i end |
Here is another example, that shows every 4th power of two, but only 4 times.
do i=4 to 32 by 4 for 4 say '2 to the power' i 'is:' 2 ** i end |
Here is another example, that shows every 4th power of two, 8 times.
do i=4 by 4 for 8 say '2 to the power' i 'is:' 2 ** i end |
In the examples above explicit numbers were used for the initial value, limit value, step value, and the repetition value. Each of these values could have been an expression instead. Furthermore, the values do not have to be whole numbers, or positive. You can even step downwards instead of upwards. Here is an example where other value types are used.
do i=-.3 to -.9 by -.3 say i end shows: -0.3 -0.6 -0.9 |
Here is another example of a counted loop with a while phrase. This loop repeats indefinitely while more lines are available from the default input stream.
say 'Enter the text to find in the input stream: pull textToFind do lineNumber = 1 while lines( ) > 0 lin = linein( ) if pos( textToFind, translate( lin ) ) > 0 then say lineNumber'.' lin end |
In the above example, the lineNumber is initially set to 1, and is incremented by 1 every loop cycle.
A conditional loop has the following syntax. As described earlier, you can also have other iterative do phrases in front of the while or until keywords.
do while booleanExpression
instruction instruction ...etc end [ name ] do until booleanExpression instruction instruction ...etc end [ name ] |
Here is a conditional loop that converts input lines to upper case.
do while lines( ) > 0 say translate( linein( ) ) end |
Here is a conditional loop that shows line numbers in front of each input line.
do lineNumber = 1 while lines( ) > 0 say lineNumber'.' linein( ) end |
A name can be specified with the end instruction, only when the associated do instruction has a named control variable.
When multiple do or select instruction groups are pending, the end instruction binds to the nearest incomplete instruction group. Consider the following example:
do i=1 to 7 select when i=1 then say 'one' when i=2 then say 'a couple' otherwise if i < 6 then say 'a few' else do say 'more than a few' end /* this binds with the do after the else */ end /* this binds with the select group */ end /* this binds with the do group */ |
When multiple iterative do groups are pending, and each of these has a named control variable, then you should specify a name after each of the corresponding end instructions. If an inaccurate control variable is referenced, error 10 (unexpected or unmatched end is raised). For example:
do i=1 to 7 do j=1 to 7 do k=1 to 7 say i '*' j '*' k 'is:' i * j * k end kk /* <-- ERROR ! this should be a k */ end j end i
|