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
clauses (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 9-3.
To understand how this process works, consider the program in Example 9-2.
Example 9-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 runtime 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 Example 9-3.
Example 9-3. Program equivalent to the code in Example 9-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 in this example, the #while
statement is very convenient for constructing repetitive-code sequences. This is especially invaluable for unrolling loops.
HLA provides three forms of the #for..#endfor
loop. These three loops take the following general form:
Example 9-4. HLA #for
loops
#for(valObject
:=startExpr
toendExpr
) . . #endfor #for(valObject
:=startExpr
downtoendExpr
) . . . #endfor #for(valObject
incomposite_expr
) . . . #endfor
As its name suggests, valObject
must be an object you've defined in a val
declaration.
For the first two forms of the #for
loop above, the startExpr
and endExpr
components 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 1,000:
#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 for 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 (for example, processing a fixed number of array elements, macro parameters, and so on).