|
HLA's #while..#endwhile and #for..#endfor statements provide compile time loop constructs. The #while statement tells HLA to process the same sequence of statements repetitively during compilation. This is very handy for constructing data tables as well as providing a traditional looping structure for compile time programs. Although you will not employ the #while statement anywhere near as often as the #if statement, this compile time control structure is very important when you write advanced HLA programs.
The #while statement uses the following syntax:
#while( constant_boolean_expression ) << text >> #endwhile
When HLA encounters the #while statement during compilation, it will evaluate the constant boolean expression. If the expression evaluates false, HLA will skip over the text between the #while and the #endwhile clause (the behavior is similar to the #if statement if the expression evaluates false). If the expression evaluates true, then HLA will process the statements between the #while and #endwhile clauses and then "jump back" to the start of the #while statement in the source file and repeat this process, as shown in Figure 10-3.
#while(constant_boolean_expression) HLA repetitively compiles this code as long as the expression is true. It effectively inserts multiple copies of this statement sequence into your source file (the exact number of copies depends on the value of the loop control expression). endwhile
To understand how this process works, consider the program in Listing 10-2.
Listing 10-2: #WHILE..#ENDWHILE Demonstration.
program ctWhile; #include( "stdlib.hhf" ) static ary: uns32[5] := [ 2, 3, 5, 8, 13 ]; begin ctWhile; ?i := 0; #while( i < 5 ) stdout.put( "array[ ", i, " ] = ", ary[i*4], nl ); ?i := i + 1; #endwhile end ctWhile;
As you can probably surmise, the output from this program is the following:
array[ 0 ] = 2 array[ 1 ] = 3 array[ 2 ] = 4 array[ 3 ] = 5 array[ 4 ] = 13
What is not quite obvious is how this program generates this output. Remember, the #while..#endwhile construct is a compile time language feature, not a run-time control construct. Therefore, the previous #while loop repeats five times during compilation. On each repetition of the loop, the HLA compiler processes the statements between the #while and #endwhile clauses. Therefore, the preceding program is really equivalent to the code that is shown in Listing 10-3.
Listing 10-3: Program Equivalent to the Code in Listing 10-2.
program ctWhile; #include( "stdlib.hhf" ) static ary: uns32[5] := [ 2, 3, 5, 8, 13 ]; begin ctWhile; stdout.put( "array[ ", 0, " ] = ", ary[0*4], nl ); stdout.put( "array[ ", 1, " ] = ", ary[1*4], nl ); stdout.put( "array[ ", 2, " ] = ", ary[2*4], nl ); stdout.put( "array[ ", 3, " ] = ", ary[3*4], nl ); stdout.put( "array[ ", 4, " ] = ", ary[4*4], nl ); end ctWhile;
As you can see, the #while statement is very convenient for constructing repetitivecode sequences. This is especially invaluable for unrolling loops. Additional uses of the #while loop appear in later sections of this text.
HLA provides three forms of the #for..#endfor loop. These three loops take the following general form:
#for( valObject := startExpr to endExpr ) . . . #endfor #for( valObject := startExpr downto endExpr ) . . . #endfor #for( valObject in composite_expr ) . . . #endfor
As its name suggests, valObject must be an object you've defined in a val declaration (or must be currently undefined; these #for loops will define the symbol locally for you if the loop control variable is undefined).
For the first two forms of the #for loop above, the startExpr and endExprcomponents can be any HLA constant expression that yields an integer value. The first of these #for loops is semantically equivalent to the following #while code:
?valObject := startExpr; #while( valObject <= endExpr ) . . . ?valObject := valObject + 1; #endwhile
The second of these #for loops is semantically equivalent to the #while loop:
?valObject := startExpr; #while( valObject >= endExpr ) . . . ?valObject := valObject - 1; #endwhile
The third of these #for loops (the one using the in keyword) is especially useful for processing individual items from some composite data type. This loop repeats once for each element, field, character, and so on, of the composite value you specify for composite_expr. This can be an array, string, record, or character set expression. For arrays, this #for loop repeats once for each element of the array and on each iteration of the loop; the loop control variable contains the current element's value. For example, the following compile time loop displays the values ‘1,’ ‘10,’ ‘100,’ and ‘1000’:
#for( i in [1, 10, 100, 1000]) #print( i ) #endfor
If the composite_expr constant is a string constant, the #for loop repeats once for each character in the string and sets the value of the loop control variable to the current character. If the composite_expr constant expression is a record constant, then the loop will repeat once for each field of the record and on each iteration the loop control variable will take on the type and value of the current field. If the composite_expr expression is a character set, the loop will repeat once for each character in the set, and the loop control variable will be assigned that character.
The #for loop actually turns out to be more useful than the #while loop because the larger number of compile time loops you encounter repeat a fixed number of times (e.g., processing a fixed number of array elements, macro parameters, and so on). However, because #for was added relatively late in HLA's design, you'll still see a large number of #while loops in existing source code (most of those are simulating a #for loop).
|