Whenever BBC BASIC (Z80) comes across a FOR, REPEAT, WHILE, GOSUB, FN or PROC statement, it needs to remember where it is in the program so that it can loop back or return there when it encounters a line with NEXT, UNTIL, ENDWHILE or RETURN statement or when it reaches the end of a function or procedure. These 'return addresses' tell BBC BASIC (Z80) where it is in the structure of your program.
Every time BBC BASIC (Z80) encounters a FOR, REPEAT, WHILE, GOSUB, FN or PROC statement it 'pushes' the return address on to a 'stack' and every time it encounters a NEXT, UNTIL, ENDWHILE, RETURN statement or the end of a function or procedure it 'pops' the latest return address of the stack and goes back there.
BBC BASIC (Z80) uses a single control stack (the processor's hardware stack) for all looping and nesting operations. The main effects of this are discussed below.
Loop Operation Errors
Apart from memory size, there is no limit to the level of nesting of FOR…NEXT, REPEAT…UNTIL, WHILE…ENDWHILE and GOSUB…RETURN operations. The untrappable error message No room will be issued if all the stack space is used up.
Program Structure Limitations
The use of a common stack has one disadvantage (if it is a disadvantage) in that it forces stricter adherence to proper program structure. It is not good practice to exit from a FOR…NEXT loop without passing through the NEXT statement. It makes the program more difficult to understand and the FOR address is left on the stack. Similarly, the loop or return address is left on the stack if a REPEAT…UNTIL loop, WHILE…ENDWHILE loop or a GOSUB…RETURN structure is incorrectly exited. This means that if you leave a FOR…NEXT loop without executing the NEXT statement, and then subsequently encounter, for example, a RETURN statement, BBC BASIC (Z80) will report an error. (In this case, a No GOSUB error.) The example below would result in the error message 'No PROC at line 500'.
400 - - - 410 INPUT "What number should I stop at", num 420 PROC_error_demo 430 END 440 : 450 DEF PROC_error_demo 460 FOR i=1 TO 100 470 PRINT i; 480 IF i=num THEN 500 490 NEXT i 500 ENDPROC
BBC BASIC (Z80) is a little unusual in detecting this error, but it is always risky. It usually results in an inconsistent program structure.
Leaving Program Loops
There are a number of ways to leave a program loop which do not conflict with the need to write tidy program structures. These are discussed below.
EXIT
The easiest and safest way to simply leave a loop (or several nested loops of different types) is to use a suitable EXIT statement.
10 i=1 20 REPEAT 30 PRINT i 40 i=i+1 50 IF i=6 THEN EXIT REPEAT 60 UNTIL FALSE 70 PRINT "Done"
EXIT is not a standard feature of BBC BASIC (Z80) and so may not be available in other implementations. Even though the other methods for leaving a loop prematurely may not seem as practical as EXIT they have the advantage of increased compatibility as well as smaller code size and higher performance by being supported directly by the interpreter with dedicated tokens.
REPEAT…UNTIL Loops
The simplest way to overcome the problem of exiting a FOR…NEXT loop is to restructure it as a REPEAT…UNTIL loop. The example below performs the same function as the previous example, but exits the structure properly. It has the additional advantage of more clearly showing the conditions which will cause the loop to be terminated.
400 - - - 410 INPUT "What number should I stop at", num 420 PROC_error_demo 430 END 440 : 450 DEF PROC_error_demo 460 i=0 470 REPEAT 480 i=i+1 490 PRINT i; 500 UNTIL i=100 OR i=num 510 ENDPROC
Changing the Loop Variable
A simple way of forcing an exit from a FOR…NEXT loop is to set the loop variable to a value equal to the limit value and then GOTO to the NEXT statement. alternatively, you could set the loop variable to a value greater than the limit (assuming a positive step), but in this case the value on exit would be different depending on why the loop was terminated. (In some circumstances, this may be an advantage). The example below uses this method to exit from the loop. Notice, however, that the conditions which cause the loop to terminate are less clear since they do not appear together.
400 - - - 410 INPUT "What number should I stop at", num 420 PROC_error_demo 430 END 440 : 450 DEF PROC_error_demo 460 FOR i=1 TO 100 470 PRINT i; 480 IF i=num THEN i=500: GOTO 510 490 … 500 (More program here if necessary) 510 NEXT 520 ENDPROC
Popping the Inner Variable
A less satisfactory way of exiting a FOR…NEXT loop is to enclose the loop in a dummy outer loop and rely on BBC BASIC (Z80)'s ability to 'pop' inner control variables off the stack until they match. If you use this method you MUST include the variable name in the NEXT statement. This method, which is demonstrated below, is very artificial and the conditions which cause the loop to terminate are unclear.
400 - - - 410 INPUT "What number should I stop at", num 420 PROC_error_demo 430 END 440 : 450 DEF PROC_error_demo 460 FOR dummy=1 TO 1 :REM Loop once only 470 FOR i=1 TO 100 480 PRINT i; 490 IF i=num THEN 530 :REM Jump to outer NEXT 500 - - - 510 (More program here if necessary) 520 NEXT i 530 NEXT dummy 540 ENDPROC
Local Variables
Since local variables are also stored on the processor's stack, you cannot use a FOR…NEXT loop to make an array LOCAL. For example, the following program will give the the error message 'Not LOCAL at line 400'.
380 DEF PROC_error_demo 390 FOR i=1 TO 10 400 LOCAL data(i) 410 NEXT 420 ENDPROC
You can overcome this by fabricating the loop using an IF…THEN statement as shown below. This is probably the only occasion when the use of a single stack promotes poor program structure.
380 DEF PROC_error_demo 390 i=1 400 LOCAL data(i) 410 i=i+1 420 IF i<11 THEN 400 430 ENDPROC
Stack Pointer
The program stack is initialised to begin at HIMEM and, because of this, you cannot change the value of HIMEM when there is anything on the stack. As a result, you cannot change HIMEM from within a procedure, function, subroutine, FOR…NEXT loop, REPEAT…UNTIL loop or WHILE…ENDWHILE loop.