RISCOS.com

www.riscos.com Technical Support:
BBC BASIC Reference Manual

 


Error handling and debugging


By default, when the BASIC interpreter finds an error it halts execution of the program and prints an error message on the screen. Most errors are generated by incorrect programming, such as using a variable which has not had a value assigned to it. You have to correct this kind of error to make the program work. However, even if the syntax of the program is correct, errors can occur whilst it is being executed, because it cannot cope with the data it is given.

For example:

10 REPEAT
20   INPUT "Number",N
30   L = LOG(N)
40   PRINT "LOG of ";N" is ";L
50 UNTIL FALSE

This program takes a number from the keyboard and prints the logarithm of that number. If you type in a negative number, however, the program gives the message:

Logarithm range at line 30

The same thing happens if you type 0, or a character such as W, or a word such as TWELVE.

Trapping an error

You may decide that you would like to trap such an error and print a message to tell the user what he or she has done wrong instead of having the program end abruptly. You can do this using the ON ERROR statement.

For example:

  5 ON ERROR PROCerror
 10 REPEAT
 20   INPUT "Number",N
 30   L = LOG(N)
 40   PRINT "LOG of ";N" is ";L
 50 UNTIL FALSE
 60 END
100 DEFPROCerror
110 IF ERR=22 THEN
120   PRINT "The number must be greater than 0"
130 ELSE REPORT
140   PRINT " at line ";ERL
150   END
160 ENDIF
170 ENDPROC

The ON ERROR statement can be followed by a series of statements given on the same line. In many cases, it is more convenient to follow it with a call to an error handling procedure, as in the example above, which can then be as complex as you like.

When an error occurs, BASIC passes control to the first statement on the ON ERROR line, as if it jumped there using a GOTO. It will 'forget' about any loops or procedures that were active when the error occurred, as if the program had been re-started. Of course, the values of all the variables and so on will still be intact.

Each error has an error number associated with it. When a particular error occurs, its number is placed in a variable called ERR (these numbers are guaranteed to remain the same). A full list of error numbers is given in Appendix C: Error messages.

In the example above, the error handling procedure tests for error 22 which is the Logarithm range error. If it was this error which occurred, it is dealt with appropriately. If a different error occurred, the program executes the REPORT instruction which prints out the error message and then prints the number of the line where the error occurred which is given in the function ERL. Then it executes the END to end the execution of the program. Trapping all errors is not necessarily a good idea since you then would not be able to press Esc, which is treated as an error, to stop the program.

If a program contains more than one ON ERROR statement, the most recently executed one is used when an error occurs.

Turning off the error handler

Error handling can be turned off, and BASIC's default handler restored, at any stage in the program using the instruction ON ERROR OFF.

Generating errors

In addition to the error messages that the interpreter itself generates when it discovers a mistake in the program, you can cause your own errors. This can be useful when, for example, you find a mistake in the user's input data and want to notify the user through your standard error handler. To generate an error, use the statement:

ERROR errnum, errstring

The errnum expression is a number which will be passed to the error handler via the ERR function, as usual. The errstring is accessible to the error handler through the REPORT statement and REPORT$ function. ERL will be set to the line number at which the ERROR statement was executed.

If you use 0 as the error number, the error will be a 'fatal' one. As with built-in errors with that number, it cannot be trapped by using ON ERROR.

An example of the use of ERROR is:

1000 ch=OPENIN(f$)
1010 IF ch=0 THEN ERROR 214,"File '"+f$+"' not found"

External errors

If an error occurs in a program, you may wish to leave BASIC altogether and pass the error back to the program that called BASIC in the first place. You can do this using the ERROR EXT statement. Its syntax is very similar to ERROR, described above. If you say:

ERROR EXT 0,"Can't find template file"

then BASIC will quit and the error message and number will be passed back to the error handler of the program that called BASIC (e.g. the RISC OS Supervisor prompt or error box).

BASIC's default error handler uses this form of the ERROR statement if the program being executed was called from a command of the form

*BASIC -quit filename

(A BASIC program filename typed as a * command will behave like this.) When BASIC is called like this, it loads and executes the program stored in filename, and then QUITs automatically when the program terminates. In addition, the function QUIT will return TRUE instead of FALSE, as it usually does. This is used in BASIC's default error handler, which reads as follows:

TRACE OFF
IF QUIT THEN
  ERROR EXT ERR,REPORT$
ELSE
  RESTORE
  !(HIMEM-4)=@% : REM save current @%
  @%=&900       : REM print line numbers as integers
  REPORT
  IF ERL THEN PRINT " at line "ERL ELSE PRINT
  @%=!(HIMEM-4) : REM restore @%
  END
ENDIF

Local error handling

When an error occurs, the ON ERROR command can be used to deal with it. BASIC, however, forgets all about what it was doing at the time the error happened. For example, if it was in the middle of a FOR ... NEXT loop or executing a procedure, it is not possible to jump back to the place the error occurred and carry on as though nothing had happened.

Trapping an error; procedures & functions

The ON ERROR LOCAL command can be used to get around this problem. This command traps errors which occur inside an individual procedure or function and then continues executing within the procedure or function rather than jumping back to the top level. For example:

 10 PROCcalculate(100)
 20 END
100 DEFPROCcalculate(A)
110 LOCAL I
120 LOCAL ERROR
130 FOR I = -15 TO 15
140 ON ERROR LOCAL PRINT"Infinite Result":NEXT I:ENDPROC
150 PRINT A / I
160 NEXT I
180 ENDPROC

Local error handlers can be used in any loops, not just inside procedures and functions.

Restoring the previous error handler

Normally, when one ON ERROR or ON ERROR LOCAL statement is used, all previous ON ERROR statements are forgotten about. It is possible, however, to use one error handler and then restore the previous one. To do this, use the instruction LOCAL ERROR to store the old error handler, and RESTORE ERROR to activate it again.

For example:

  1 ON ERROR PRINT "Error ";REPORT$;:END
 10 PROCcalculate(100)
 15 this line will give an error !!!
 20 END
100 DEFPROCcalculate(A)
110 LOCAL I
120 LOCAL ERROR
130 FOR I = -15 TO 15
140 ON ERROR LOCAL PRINT"Infinite Result":NEXT I:ENDPROC
150 PRINT A / I
160 NEXT I
170 RESTORE ERROR
180 ENDPROC

This shows that the local error handler is in force during the procedure, but that the original one set up by the first line of the program is restored when the PROC has finished.

Strictly speaking, the RESTORE ERROR is not required here because it is done automatically when the ENDPROC is reached. RESTORE ERROR is also executed automatically at the end of a user-defined function. However, if you set up a local error handler in a loop at the top level, then you would need to use it explicitly.

For example:

100 LOCAL ERROR
110 WHILE ...
120   ON ERROR LOCAL ...
130   ...
140 ENDWHILE
150 RESTORE ERROR
160 ...

Debugging

A program may contain errors which cause it to behave differently from the way you intended. In these circumstances, you may wish to watch more closely how the program is being executed.

Stopping execution of the program

One option you have available is to place a STOP statement at a particular point in the program. When this line is reached, execution of the program stops and you can then investigate the values assigned to any of its variables using the PRINT statement or LVAR command.

Tracing the path through the program

Another option is to use the TRACE facility. The standard trace prints the BASIC line numbers in the order these lines are executed, thus showing the path being taken through the program. This can be invoked by typing

TRACE ON

To trace only those lines with a line number below 1000, for example, type

TRACE 1000

Alternatively you may trace procedures and functions only as follows:

TRACE PROC

You can also trace both at once if you wish by typing

TRACE 1000 : TRACE PROC

Tracing can be performed in single-step mode where the computer stops after each line or procedure call and waits for a key to be pressed before continuing. Single-step tracing can be invoked by typing

TRACE STEP ON

to stop after every line traced, or

TRACE STEP n

to trace all lines below n and stop after each one, or

TRACE STEP PROC

to stop after every procedure call.

Instead of having TRACE output displayed on the screen, you can send it to a file. To do this, type

TRACE TO filename

This means that you have a permanent record of the path taken through your program.

Any TRACE option affects all programs which are subsequently run until tracing is turned off by

TRACE OFF

or until an error occurs.

Because TRACE is a statement, you can also use it from within a program. Thus if you know that a program is going wrong within a particular procedure, you could insert a TRACE ON statement at the start of the procedure, and a TRACE OFF just before the ENDPROC. That way, trace information will only be produced while the procedure is executing.

This edition Copyright © 3QD Developments Ltd 2015
Last Edit: Tue,03 Nov 2015