TOC PREV NEXT INDEX

Webster Home Page



1.4 BEGIN..EXIT..EXITIF..END

HLA provides a structured GOTO via the EXIT and EXITIF statements. The EXIT and EXITIF statements let you exit a block of statements surrounded by a BEGIN..END pair. These statements behave much like the BREAK and BREAKIF statements (that let you exit from an enclosing loop) except, of course, they jump out of a BEGIN..END block rather than a loop. The EXIT and EXITIF statements are structured gotos because they do not let you jump to an arbitrary point in the code, they only let you exit from a block delimited by the BEGIN..END pair.

The EXIT and EXITIF statements take the following forms:

		exit identifier;
 
		exitif( boolean_expression) identifier;
 

 

The identifier component at the end of these two statements must match the identifier following the BEGIN and END keywords (e.g., a procedure or program name). The EXIT statement immediately transfers control to the "end identifier;" clause. The EXITIF statement evaluates the boolean expression immediately following the EXITIF reserved word and transfers control to the specified END clause only if the expression evaluates true. If the boolean expression evaluates false, the control transfers to the first statement following the EXITIF statement.

If you specify the name of a procedure as the identifier for an EXIT statement, the program will return from the procedure upon encountering the EXIT statement1. Note that the EXIT statement does not automatically restore any registers you pushed on the stack upon entry into the procedure. If you need to pop data off the stack, you must do this before executing the EXIT statement.

If you specify the name of your main program as the identifier following the EXIT (or EXITIF) statement, your program will terminate upon encountering the EXIT statement. With EXITIF, your program will only terminate if the boolean expression evaluates true. Note that your program will still terminate even if you execute the "exit MainPgmName;" statement within a procedure nested inside your main program. You do not have to execute the EXIT statement in the main program to terminate the main program.

HLA lets you place arbitrary BEGIN..END blocks within your program, they are not limited to surrounding your procedures or main program. The syntax for an arbitrary BEGIN..END block is

	begin identifier;
 

 
		<statements>
 

 
	end identifier;
 

 

The identifier following the END clause must match the identifier following the corresponding BEGIN statement. Naturally, you can nest BEGIN..END blocks, but the identifier following an END clause must match the identifier following the previous unmatched BEGIN clause.

One interesting use of the BEGIN..END block is that it lets you easily escape a deeply nested control structure without having to completely restructure the program. Typically, you would use this technique to exit a block of code on some special condition and the TRY..ENDTRY statement would be inappropriate (e.g., you might need to pass values in registers to the outside code, an EXCEPTION clause can't guarantee register status). The following program demonstrates the use of the BEGIN..EXIT..END sequence to bail out of some deeply nested code.


 
program beginEndDemo;
 
#include( "stdlib.hhf" );
 

 
static
 
    m:uns8;
 
    d:uns8;
 
    y:uns16;
 
    
 
readonly
 
    DaysInMonth: uns8[13] :=
 
        [
 
            0,  // No month zero.
 
            31, // Jan
 
            28, // Feb is a special case, see the code.
 
            31, // Mar 
 
            30, // Apr
 
            31, // May
 
            30, // Jun
 
            31, // Jul
 
            31, // Aug
 
            30, // Sep
 
            31, // Oct
 
            30, // Nov
 
            31  // Dec
 
        ];
 
    
 
begin beginEndDemo;
 

 
    forever
 
    
 
        try
 
        
 
            stdout.put( "Enter month, day, year: " );
 
            stdin.get( m, d, y );
 
            
 
          unprotected
 
          
 
            break;
 

 
          exception( ex.ValueOutOfRange )
 
          
 
            stdout.put( "Value out of range, please reenter", nl );
 
            
 
          exception( ex.ConversionError )
 
          
 
            stdout.put( "Illegal character in value, please reenter", nl );
 
            
 
        endtry;
 
        
 
    endfor;
 
    begin goodDate;
 
    
 
        mov( y, bx );
 
        movzx( m, eax );
 
        mov( d, dl );
 
    
 
        // Verify that the year is legal
 
        // (this program allows years 2000..2099.)
 
        
 
        if( bx in 2000..2099 ) then
 
        
 
            // Verify that the month is legal
 
            
 
            if( al in 1..12 ) then
 
            
 
                // Quick check to make sure the
 
                // day is half-way reasonable.
 
                
 
                if( dl <> 0 ) then
 
                
 
                    // To verify that the day is legal,
 
                    // we have to handle Feb specially
 
                    // since this could be a leap year.
 
                    
 
                    if( al = 2 ) then
 
                        
 
                        // If this is a leap year, subtract
 
                        // one from the day value (to convert
 
                        // Feb 29 to Feb 28) so that the 
 
                        // last day of Feb in a leap year
 
                        // will pass muster.  (This could
 
                        // set dl to zero if the date is
 
                        // Feb 1 in a leap year, but we've
 
                        // already handled dl=0 above, so
 
                        // we don't have to worry about this
 
                        // anymore.)
 
                        
 
                        date.isLeapYear( bx );
 
                        sub( al, dl );
 
                        
 
                    endif;
 
                    
 
                    // Verify that the number of days in the month
 
                    // is valid.
 
                    
 
                    exitif( dl <= DaysInMonth[ eax ] ) goodDate; 
 
                    
 
                endif;
 
                
 
            endif;
 
            
 
        endif;
 
        stdout.put( "You did not enter a valid date!", nl );
 
        
 
    end goodDate;
 
        
 
end beginEndDemo;
 

 
Program 1.8	 Demonstration of BEGIN..EXIT..END Sequence
 

In this program, the "begin goodDate;" statement surrounds a section of code that checks to see if the date entered by a user is a valid date in the 100 years from 2000..2099. If the user enters an invalid date, it prints an appropriate error message, otherwise the program quits without further user interaction. While you could restructure this code to avoid the use of the EXITIF statement, the resulting code would probably be more difficult to understand. The nice thing about the design of the code is that it uses refinement to test for a legal date. That is, it tests to see if one component is legal, then tests to see if the next component of the date is legal, and works downward in this fashion. In the middle of the tests, this code determines that the date is legal. To restructure this code to work without the EXITIF (or other GOTO type instruction) would require using negative logic at each step (asking is this component not a legal date). That logic would be quite a bit more complex and much more difficult to read, understand, and verify. Hence, this example is preferable even if it contains a structured form of the GOTO statement.

Because the BEGIN..END statement uses a label, that the EXIT and EXITIF statements specify, you can nest BEGIN..END blocks and break out of several nested blocks with a single EXIT/EXITIF statement. Figure 1.1 provides a schematic of this capability.



Figure 1.1 Nesting BEGIN..END Blocks

This ability to break out of nested BEGIN..END blocks is very powerful. Contrast this with the BREAK and BREAKIF statements that only let you exit the loop that immediately contains the BREAK or BREAKIF. Of course, if you need to exit out of multiple nested loops you won't be able to use the BREAK/BREAKIF statement to achieve this, but you can surround your loops with a BEGIN..END sequence and use the EXIT/EXITIF statement to leave those loops. The following program demonstrates how this could work, using the EXITIF statement to break out of two nested loops.


 
program brkNestedLoops;
 
#include( "stdlib.hhf" )
 

 
static
 
    i:int32;
 
    
 
begin brkNestedLoops;
 

 
    // DL contains the last value to print on each line.
 
    
 
    for( mov(0, dl ); dl <= 7; inc( dl )) do
 
    
 
        begin middleLoop;
 

 
            // DH ranges over the values to print.
 
            
 
            for( mov( 0, dh ); dh <= 7; inc( dh )) do
 
            
 
                // "i" specifies the field width
 
                // when printing DH, it also specifies
 
                // the maximum number of times to print DH.
 
                    
 
                for( mov( 2, i ); i <= 4; inc( i )) do
 
            
 
                    // Break out of both inner loops
 
                    // when DH becomes equal to DL.
 
                     
 
                    exitif( dh >= dl ) middleLoop;
 
                    
 
                    // The following statement prints
 
                    // a triangular shaped object composed
 
                    // of the values that DH goes through.
 
                    
 
                    stdout.puti8Size( dh, i, `.' );
 
                    
 
                endfor;
 
                
 
            endfor;
 
            
 
        end middleLoop;
 
        stdout.newln();
 
        
 
    endfor;
 
        
 
end brkNestedLoops;
 

 
Program 1.9	 Breaking Out of Nested Loops Using EXIT/EXITIF
 

1.5 CONTINUE..CONTINUEIF

The CONTINUE and CONTINUEIF statements are very similar to the BREAK and BREAKIF statements insofar as they affect control flow within a loop. The CONTINUE statement immediately transfers control to the point in the loop where the current iteration completes and the next iteration begins. The CONTINUEIF statement first checks a boolean expression and transfers control if the expression evaluates false.

The phrase "where the current iteration completes and the next iteration begins" has a different meaning for nearly every loop in HLA. For the WHILE..ENDWHILE loop, control transfers to the top of the loop at the start of the test for loop termination. For the FOREVER..ENDFOR loop, control transfers to the top of the loop (no test for loop termination). For the FOR..ENDFOR loop, control transfers to the bottom of the loop where the increment operation occurs (i.e., to execute the third component of the FOR loop). For the REPEAT..UNTIL loop, control transfers to the bottom of the loop, just before the test for loop termination. The following diagrams show how the CONTINUE statement behaves.



Figure 1.2 Behavior of CONTINUE in a WHILE Loop



Figure 1.3 Behavior of CONTINUE in a FOREVER Loop



Figure 1.4 Behavior of CONTINUE in a FOR Loop



Figure 1.5 Behavior of CONTINUE in a REPEAT..UNTIL Loop

It turns out that CONTINUE is rarely needed in common programs. Most of the time an IF..ENDIF statement provides the same functionality as CONTINUE (or CONTINUEIF) while being much more readable. Nevertheless, there are a few instances you will encounter where the CONTINUE or CONTINUEIF statements provide exactly what you need. However, if you find yourself using the CONTINUE or CONTINUEIF statements on a frequent basis, you should probably reconsider the logic in your programs.

1This is true for the EXITIF statement as well, though, of course, the program will only exit the procedure if the boolean expression in the EXITIF statement evaluates true.


Web Site Hits Since
Jan 1, 2000

TOC PREV NEXT INDEX