R. T. RUSSELL
BBC BASIC (Z80) Manual
General Information
Line numbers up to 65535 are allowed. If line 65535 does not exist,
then GOTO 65535 is equivalent to END. Line number 0 is not permitted.
When it is necessary to write more than one statement on a line, the
statements may be separated by a colon ':'. BBC BASIC (Z80) will tolerate
the omission of the separator if this does not lead to ambiguity. It's
safer to leave it in and the program is easier to read.
For example, the following will work.
10 FOR i=1 TO 5 PRINT i : NEXT
The EDIT command may be used to edit or
concatenate-and-edit the specified
program line(s). The specified lines (including their line numbers)
are listed as a single line. By changing only the line number, you
can also use EDIT to duplicate a line.
EDIT 230
EDIT 200,230
The following control
functions are active in the immediate and edit modes and in response
to an INPUT command in a program. The codes
shown are the default codes as supplied; they may be changed by editing the BBCDIST.MAC
patch program:
Ctrl/E | Move the cursor up one line |
Ctrl/X | Move the cursor down one line |
Ctrl/S | Move the cursor left one character |
Ctrl/D | Move the cursor right one character |
Ctrl/A | Move the cursor to the start of the line |
Ctrl/F | Move the cursor to the end of the line |
Del | Backspace and delete |
Ctrl/G | Delete the character at the cursor |
Ctrl/U | Clear line to the left of the cursor |
Ctrl/T | Clear the line to the right of the cursor |
Ctrl/V | Insert a space at the cursor position |
Enter | Enter the line and exit the edit mode |
Esc | Abort and leave the line unchanged |
To abort the single line editor and leave the line unchanged, press <Esc>.
You can use the EDIT command to edit and join (concatenate) program lines. When
you use it to join lines, remember to delete any unwanted ones. EDIT
on its own will start at the beginning of the program and concatenate
as many lines as it can. This process will stop when the concatenated
line length exceeds 255.
The various mathematical and logical operators have a priority order. The
computer will evaluate an expression taking this priority order into
account. Operators with the same priority will be evaluated from
left to right. For example, in a line containing multiplication and
subtraction, ALL the multiplications would be performed before any
of the subtractions were carried out. The various operators are listed
below in priority order.
variables functions () ! ? & unary+- NOT
^
* / MOD DIV
+ -
= <> <= >= > <
AND
EOR OR
The following are some examples of the way expression priority can
be used. It often makes things easier for us humans to understand
if you include the brackets whether the computer needs them or not.
IF A=2 AND B=3 THEN
IF ((A=2)AND(B=3))THEN
IF A=1 OR C=2 AND B=3 THEN
IF((A=1)OR((C=2)AND(B=3)))THEN
IF NOT(A=1 AND B=2) THEN
IF(NOT((A=1)AND(B=2)))THEN
N=A+B/C-D N=A+(B/C)-D
N=A/B+C/D N=(A/B)+(C/D)
Variable names may be of unlimited length and all characters are significant. Variable
names must start with a letter. They can only contain the characters
A..Z, a..z, 0..9 and underline. Embedded keywords are allowed. Upper
and lower case variables of the same name are different.
The following types of variable are allowed:
A real numeric
A% integer numeric
A$ string
Real variables have a range of ±5.9E-39 to ±3.4E38
and numeric functions evaluate to 9 significant figure accuracy. Internally
every real number is stored in 40 bits (5 bytes). The number is composed
of a 4 byte mantissa and a single byte exponent. An explanation of
how variables are stored is given at Annex D.
Integer variables are stored in 32 bits and have a range of +2147483647
to -2147483648. It is not necessary to declare a variable as
an integer for advantage to be taken of fast integer arithmetic. For
example, FOR...NEXT loops execute at integer speed whether or not
the control variable is an 'integer variable' (% type), so long as
it has an integer value.
The variables A%..Z% are a special type of integer variable in that
they are not cleared by the statements RUN,
CHAIN and CLEAR.
In addition A%, B%, C%, D%, E%, H% and L% have special uses in CALL and USR routines
and P% and O% have a special meaning in the assembler
(P% is the program counter and O% points to the code origin). The special variable @%
controls numeric print formatting.
The variables @%..Z% are called 'static', all other variables are called 'dynamic'.
Boolean variables can only take one of the two values TRUE or FALSE. Unfortunately,
BBC BASIC does not have true boolean variables. However, it does allow
numeric variables to be used for logical operations. The operands
are converted to 4 byte integers (by truncation) before the logical
operation is performed. For example:
PRINT NOT 1.5
-2
|
The argument, 1.5, is truncated to 1 and the logical inversion of this gives -2
|
PRINT NOT -1.5
0
|
The argument is truncated to -1 and the logical inversion of this gives 0
|
Two numeric functions, TRUE and FALSE, are provided. TRUE returns
the value -1 and FALSE the value 0. These values allow the logical
operators (NOT, AND, EOR and OR) to work properly. However, anything
which is non-zero is considered to be TRUE. This can give rise to
confusion, since +1 is considered to be TRUE and NOT(+1) is -2,
which is also considered to be TRUE.
Numbers are stored in binary format. Integers and the mantissa of
real numbers are stored in 32 bits. This gives a maximum accuracy
of just over 9 decimal digits. It is possible to display up to 10
digits before switching to exponential (scientific) notation (PRINT and STR$).
This is of little use when displaying real numbers because
the accuracy of the last digit is suspect, but it does allow the full
range of integers to be displayed. Numbers up to the maximum integer
value may be entered as a decimal constant without any loss of accuracy. For
instance, A%=2147483647 is equivalent to A%=&7FFFFFFF.
String variables may contain up to 255 characters. An explanation
of how variables are stored is given at the Annex entitled Format
of Program and Variables in Memory.
Unlike numeric variables, string variables do not have a fixed length. When
you create a string variable, the memory used is sufficient for the
initial value of the string. If you subsequently assign a longer
string to the variable there will be insufficient room for it and
the string will have to occupy a different area in memory. The initial
area will then become 'dead'. These areas of 'dead' memory are called
garbage. As more and more re-assignments take place, the area of
memory used for the variables grows and eventually there is no more
room. Several versions of BASIC have automatic 'garbage collection'
routines which tidy up the variable memory space when this occurs. Unfortunately,
this can take several seconds and can be embarrassing if your program
is time conscious. BBC BASIC does not incorporate 'garbage collection'
routines and it is possible to run out of room for variables even
though there should be enough space.
You can overcome the problem of 'garbage' by reserving enough memory
for the longest string you will ever put into a variable before you
use it. You do this simply by assigning a string of spaces to the
variable. If your program needs to find an empty string the first
time it is used, you can subsequently assign a null string to it. The
same technique can be used for string arrays. The example below sets
up a single dimensional string array with room for 20 characters in
each entry, and then empties it ready for use.
10 DIM names$(10)
20 FOR i=0 TO 10
30 name$(i)=STRING$(20," ")
40 NEXT
50 stop$="";
60 FOR i=0 TO 10
70 name$(i)="";
80 NEXT
Assigning a null string to stop$ prevents the space for the
last entry in the array being recovered when it is emptied.
Arrays of integer, real and string variables are allowed. All arrays
must be dimensioned before use. Integers, reals and strings cannot
be mixed in a multi-dimensional array; you have to use one array for
each type of variable you need.
Whenever BBC BASIC (Z80) comes across a FOR, REPEAT, 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 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, GOSUB, FN or PROC
statement it 'pushes' the return address on to a 'stack' and every
time it encounters a NEXT, UNTIL, RETURN statement or the end of a
function or procedure it 'pops' the latest return address of the stack
and goes back there.
Unlike the BBC Micro, which has separate stacks for FOR...NEXT, REPEAT...UNTIL
GOSUB...RETURN and FN/PROC operations, BBC BASIC (Z80) uses a single
control stack (the processor's hardware stack) for all looping and
nesting operations. The main effects of this difference are discussed
below.
Apart from memory size, there is no limit to the level of
nesting of FOR...NEXT, REPEAT...UNTIL and GOSUB...RETURN operations. The untrappable error message
'No room' will be issued if all the stack
space is used up. Because a single stack is used, the following error
messages do not exist.
Too many FORs
Too many REPEATs
Too many GOSUBs
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
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 at line nnnn' 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
and an unexpected 'Too many FORs/REPEATs/GOSUBs' error on the BBC
Micro when the control stack overflows.
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.
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
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
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
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
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 or REPEAT...UNTIL
loop.
Most versions of BASIC allow access to the computer's
memory with the PEEK function and the POKE command. Such access,
which is limited to one byte at a time, is sufficient for setting
and reading screen locations or 'flags', but it is difficult to use
for building more complicated data structures. The indirection operators
provided in BBC BASIC (Z80) enable you to read and write to memory in
a far more flexible way. They provide a simple equivalent of PEEK
and POKE, but they come into their own when used to pass data between
CHAINed programs, build complicated
data structures or for use with machine code programs.
The addresses used by the indirection operators are offsets from the
base of the BBC BASIC's data area (virtual addresses). Consequently,
you cannot use the indirection operators to modify the BBC BASIC program
or the value of its internal variables.
When running BBC BASIC (Z80) you
only 'see' the data segment. Thus, the indirection operators can
only access this region of memory.
BIGBASIC can 'see' all the computer's memory up from the base of the
data area and the indirection operators will accept 20-bit addresses
in the range &00000 to &FFFFF. However, these addresses are still
referenced to the base of the data areas; they are not true machine
addresses.
There are three indirection operators:
Name | Symbol | Purpose |
No. of Bytes Affected |
Query | ? | Byte Indirection Operator | 1 |
Exclamation | ! | Word Indirection Operator | 4 |
Dollar | $ | String Indirection Operator | 1 to 256 |
The query operator accesses individual bytes of memory. ?M means
'the contents of' memory location 'M'. The first two examples below
write &23 to memory location &4FA2, the second two examples set 'number'
to the contents of that memory location and the third two examples print
the contents of that memory location.
?&4FA2=&23
or
memory=&4FA2
?memory=&23
number=?&4FA2
or
memory=&4FA2
number=?memory
PRINT ?&4FA2
or
memory=&4FA2
PRINT ?memory
Thus, '?' provides a direct replacement for PEEK and POKE.
?A=B is equivalent to POKE A,B
B=?A is equivalent to B=PEEK(A)
A byte variable, '?count' for instance, may be used as the control
variable in a FOR...NEXT loop and only one byte of memory will be used.
DIM count% 0
FOR ?count%=0 TO 20
- - -
- - -
NEXT
The query (?) indirection operator works on one byte of memory. The
word indirection operator (!) works on 4 bytes (an integer word) of
memory. Thus,
!M=&12345678
would load
&78 into address M
&56 into address M+1
&34 into address M+2
&12 into address M+3.
and
PRINT ~!M (print !M in hex format)
would give
12345678
The string indirection operator ($) writes a string followed by a
carriage-return (&0D) into memory starting at the specified address. Do
not confuse M$ with $M. The former is the familiar string variable
whilst the latter means 'the string starting at memory location M'. For
example,
$M="ABCDEF"
would load the ASCII characters A to F into addresses
M to M+5 and &0D into address M+6, and
PRINT $M
would print
ABCDEF
All the examples so far have used only one operand with the byte and
word indirection operators. Provided the left-hand operand is a variable
(such as 'memory') and not a constant, '?' and '!' can also be used
as binary operators. (In other words, they can be used with two operands.)
For instance, M?3 means 'the contents of memory location M plus 3'
and M!3 means 'the contents of the 4 bytes starting at M plus 3'. In
the following example, the contents of memory location &4000 plus
5 (&4005) is first set to &50 and then printed.
memory=&4000
memory?5=&50
PRINT memory?5
Thus,
A?I=B is equivalent to POKE A+I,B
B=A?I is equivalent to B=PEEK(A+I)
The two examples below show how two operands
can be used with the byte indirection operator (?) to examine the
contents of memory. The first example displays the contents of 12
bytes of memory from location &4000. The second example displays
the memory contents for a real numeric variable. (See the Annex
entitled Format of Program and Variables in Memory.)
10 memory=&4000
20 FOR offset=0 TO 12
30 PRINT ~memory+offset, ~memory?offset
40 NEXT
Line 30 prints the memory address and the contents in hexadecimal
format.
10 NUMBER=0
20 DIM A% -1
30 REPEAT
40 INPUT"NUMBER PLEASE "NUMBER
50 PRINT "& ";
60 FOR I%=2 TO 5
70 NUM$=STR$~(A%?-I%)
80 IF LEN(NUM$)=1 NUM$="0"+NUM$
90 PRINT NUM$;" ";
100 NEXT
110 N%=A%?-1
120 NUM$=STR$~(N%)
130 IF LEN(NUM$)=1 NUM$="0"+NUM$
140 PRINT " & "+NUM$''
150 UNTIL NUMBER=0
See the Annex entitled Format of Program and Variables In Memory for an explanation of this program.
Indirection operators can be used to create special data structures,
and as such they are an extremely powerful feature. For example,
a structure consisting of a 10 character string, an 8 bit number and
a reference to a similar structure can be constructed.
If M is the address of the start of the structure then:
$M is the string
M?11 is the 8 bit number
M!12 is the address of the related structure
Linked lists and tree structures can easily be created and manipulated
in memory using this facility.
The following list is a rather terse summary of the
meaning of the various operators and special symbols used by BBC BASIC (Z80). It
is provided for reference purposes; you will find more detailed explanations
elsewhere in this manual.
? |
A unary and binary operator giving 8 bit indirection. |
! |
A unary and binary operator giving 32 bit indirection. |
" |
A delimiting character in strings. Strings always have
an even number of " in them. " may be introduced into a string by
the escape convention "". |
# |
Precedes reference to a file channel number (and is not
optional). |
$ |
A character indicating that the object has something
to do with a string. The syntax $<expression> may be used to position a string anywhere in memory, overriding the interpreter's space allocation. As
a suffix on a variable name it indicates a string variable.
$A="WOMBAT" Store WOMBAT at address A followed by CR. |
% |
A suffix on a variable name indicating an integer variable. |
& |
Precedes hexadecimal constants e.g. &EF. |
' |
A character which causes new lines in PRINT or INPUT. |
( ) |
Objects in parentheses have highest priority. |
= |
'Becomes' for LET statement and FOR, 'result is' for
FN, relation of equal to on integers, reals and strings. |
- |
Unary negation and binary subtraction on integers and reals. |
* |
Binary multiplication on integers and reals; statement
indicating operating system command (*DIR, *OPT). |
: |
Multi-statement line statement delimiter. |
; |
Suppresses forthcoming action in PRINT. Comment delimiter
in the assembler. Delimiter in VDU and INPUT. |
+ |
Unary plus and binary addition on integers and reals;
concatenation between strings. |
, |
Delimiter in lists. |
. |
Decimal point in real constants; abbreviation symbol
on keyword entry; introduce label in assembler. |
< |
Relation of less than on integers, reals and strings. |
> |
Relation of greater than on integers, reals and strings. |
/ |
Binary division on integers and reals. |
\ |
Alternative comment delimiter in the assembler. |
<= |
Relation of less than or equal on integers, reals and strings. |
>= |
Relation of greater than or equal on integers, reals and strings. |
<> |
Relation of not equal on integers, reals and strings. |
[ ] |
Delimiters for assembler statements. Statements between these delimiters may need to be assembled twice in order to resolve
any forward references. The pseudo operation OPT
(initially 3) controls errors and listing. |
^ |
Binary operation of exponentation between integers and reals. |
~ |
A character in the start of a print field indicating
that the item is to be printed in hexadecimal. Also used with STR$
to cause conversion to a hexadecimal string. |
Keywords are recognized before anything
else. (For example, DEG and ASN in DEGASN are recognized, but neither
is recognized in ADEGASN.) Consequently, you don't have to type a
space between a keyword and a variable (but it does make it easier
to read your program).
Although they are keywords,
the names of pseudo variables such as PI, LOMEM, HIMEM, PAGE, TIME,
etc, act as variables in that their names can form the first part
of the name of another variable. For example, if A is a variable,
then AB can also be a variable. Similarly, the name PI is not recognized
in the name PILE; they are both unique variable names. However, PI%,
PI$ etc. are not allowed. Since variables named in lower case will
never be confused with keywords, many programmers use upper case only
for keywords.
Ninety-three out of the total of 123 keywords are not allowed in upper
case at the start of a variable name (anything may be used in lower
case). Those keywords that are allowed are shown in bold type.
Keywords Available
Once you have written your program and removed all the syntax errors,
you might think that your program is error free. Unfortunately life
is not so simple, you have only passed the first hurdle. There are
two kinds of errors which you could still encounter; errors of logic
and run-time errors. Errors of logic are where BBC BASIC (Z80) understands
exactly what you said, but what you said is not what you meant. Run-time
errors are where something occurs during the running of the program
which BBC BASIC (Z80) is unable to cope with. For example,
answer=A/B
is quite correct and it will work for all values of A. But
if B is zero, the answer is 'infinity'. BBC BASIC (Z80) has no way of
dealing with 'infinity' and it will report a
'Division by zero' error.
There is no way that BBC BASIC (Z80) can trap errors of logic, since
it has no way of understanding what you really meant it to do. However,
you can generally predict which of the run-time errors are likely
to occur and include a special 'error handling' routine in your program
to recover from them.
Why would you want to take over responsibility for handling run-time
errors? When BBC BASIC (Z80) detects a run-time error, it reports it
and RETURNS TO THE COMMAND MODE. When you write a program for yourself,
you know what you want it to do and you also know what it can't do. If,
by accident, you try to make it do something which could give rise
to an error, you accept the fact that BBC BASIC (Z80) might terminate
the program and return to the command mode. However, when somebody
else uses your program they are not blessed with your insight and
they may find the program 'crashing out' to the command mode without
knowing what they have done wrong. Such programs are called 'fragile'. You
can protect your user from much frustration if you predict what these
problems are likely to be and include an error handling routine. In
the example below, a '-ve root' error would occur if the number input
was negative and BBC BASIC (Z80) would return to the command mode.
10 REPEAT
20 INPUT "Type in a number " num
30 PRINT num," ",SQR(num)
40 PRINT
50 UNTIL FALSE:REM Loop until the ESCape
60 :REM key is pressed
Example run:
RUN
Type in a number 5
5 2.23606798
Type in a number 23
23 4.79583152
Type in a number 2
2 1.41421356
Type in a number -2
-2
-ve root at line 30
The ON ERROR command directs BBC BASIC (Z80) to execute the
statement(s) following ON ERROR when a trappable error occurs:
ON ERROR PRINT '"Oh No!":END
If an error was detected in a program after this line
had been encountered, the message 'Oh No!' would be printed and the program
terminated. If, as in this example, the ON ERROR line contains the END statement
or transfers control elsewhere (e.g. using GOTO) then the position of the line within the program is unimportant so long as it is encountered before the error
occurs. If there is no transfer of control, execution following the error
continues as usual on the succeeding line, so in this case the position of the
ON ERROR line can matter.
As explained in the Program Flow Control sub-section, every time
BBC BASIC (Z80) encounters a FOR, REPEAT, GOSUB, FN or PROC statement
it 'pushes' the return address on to a 'stack' and every time it encounters
a NEXT, UNTIL, RETURN statement or the end of a function or procedure
it 'pops' the latest return address of the stack and goes back there.
The program stack is where BBC BASIC (Z80) records where it is within
the structure of your program.
When an error is detected by BBC BASIC (Z80), the stack is cleared. Thus,
you cannot just take any necessary action depending on the error and
return to where you were because BBC BASIC (Z80) no longer knows where
you were.
If an error occurs within a procedure or function, the value of any
PRIVATE variables will be the last value they were set to within the
procedure or function which gave rise to the error.
There are two functions, ERR and ERL, and one statement, REPORT, which
may be used to investigate and report on errors. Using these, you
can trap out errors, check that you can deal with them and abort the
program run if you cannot.
ERR returns the error number (see the Annex entitled Error Messages and Codes).
ERL returns the line number where the
error occurred. If an error
occurs in a procedure or function call, ERL will return the number
of the calling line, not the number of the line in which the procedure/function
is defined. If an error in a DATA statement
causes a READ to fail,
ERL will return the number of the line containing the READ statement,
not the number of the line containing the DATA.
REPORT prints out the error string associated
with the last error which occurred.
The example below does not try to deal with errors, it just uses ERR, ERL and
REPORT to tell the user about the error. Its only advantage over BBC BASIC (Z80)'s normal error handling is that it gives the error
number; it would probably not be used in practice. As you can see
from the second run, pressing <ESC> is treated as an error (number
17).
5 ON ERROR GOTO 100
10 REPEAT
20 INPUT "Type a number " num
30 PRINT num," ",SQR(num)
40 PRINT
50 UNTIL FALSE
60 :
70 :
100 PRINT
110 PRINT "Error No ";ERR
120 REPORT:PRINT " at line ";ERL
130 END
Example run:
RUN
Type a number 1
1
Type a number -2
-2
Error No 21
-ve root at line 30
RUN
Type a number <Esc>
Error No 17
Escape at line 20
The example below has been further expanded to include error trapping. The
only 'predictable' error is that the user will try a negative number. Any
other error is unacceptable, so it is reported and the program aborted. Consequently,
when <ESC> is used to abort the program, it is reported as an error. However,
a further test for ERR=17 could be included so that the program would
halt on ESCAPE without an error being reported.
5 ON ERROR GOTO 100
10 REPEAT
20 INPUT "Type a number " num
30 PRINT num," ",SQR(num)
40 PRINT
50 UNTIL FALSE
60 :
70 :
100 PRINT
110 IF ERR=21 THEN PRINT "No negatives":GOTO 10
120 REPORT:PRINT " at line ";ERL
130 END
Example run:
RUN
Type a number 5
5 2.23606798
Type a number 2
2 1.41421356
Type a number -1
-1
No negatives
Type a number 4
4 2
Type a number <Esc>
Escape at line 20
The above example is very simple and was chosen for clarity. In practice,
it would be better to test for a negative number before using SQR
rather than trap the
'-ve root' error. A more realistic example is
the evaluation of a user-supplied HEX number, where trapping
'Bad hex' would be much
easier than testing the input string beforehand.
10 ON ERROR GOTO 100
20 REPEAT
30 INPUT "Type a HEX number " input$
40 num=EVAL("&"+input$)
50 PRINT input$,num
60 PRINT
70 UNTIL FALSE
80 :
90 :
100 PRINT
110 IF ERR=28 THEN PRINT "Not hex":GOTO 20
120 REPORT:PRINT " at line ";ERL
130 END
Procedures and functions are similar to subroutines in that they are
'bits' of program which perform a discrete function. Like subroutines,
they can be performed (called) from several places in the program. However,
they have two great advantages over subroutines: you can refer to them
by name and the variables used within them can be made private to
the procedure or function.
Arguably, the major advantage of procedures and functions is that
they can be referred to by name. Consider the two similar program lines
below.
100 IF name$="ZZ" THEN GOSUB 500 ELSE GOSUB 800
100 IF name$="ZZ" THEN PROC_end ELSE PROC_print
The first statement gives no indication of what the subroutines at
500 and 800 actually do. The second, however, tells you what to expect
from the two procedures. This enhanced readability stems from the choice
of meaningful names for the two procedures.
A function often carries out a number of actions, but it always produces
a single result. For instance, the 'built in' function INT
returns the integer part of its argument.
age=INT(months/12)
A procedure on the other hand, is specifically intended to carry out
a number of actions, some of which may affect program variables, but
it does not directly return a result.
Whilst BBC BASIC (Z80) has a large number of pre-defined functions (INT and LEN
for example) it is very useful to be able to define your own
to do something special. Suppose you had written a function called
FN_discount to calculate the discount price from the normal retail
price. You could write something similar to the following example
anywhere in your program where you wished this calculation to be carried
out.
discount_price=FN_discount(retail_price)
It may seem hardly worth while defining a function to do something
this simple. However, functions and procedures are not confined to
single line definitions and they are very useful for improving the
structure and readability of your program.
The names of procedures and functions MUST start with
PROC or FN and, like variable names, they cannot contain spaces. (A
space tells BBC BASIC (Z80) that it has reached the end of the word.)
This restriction can give rise to some pretty unreadable names. However,
the underline character can be used to advantage. Consider the procedure
and function names below and decide which is the easier to read.
PROCPRINTDETAILS FNDISCOUNT
PROC_print_details FN_discount
Function and procedure names may end with a '$'. However, this is
not compulsory for functions which return strings.
Functions and procedure definitions are 'signalled' to BBC BASIC (Z80)
by preceding the function or procedure name with the keyword DEF. DEF
must be at the beginning of the line. If the computer encounters
DEF during execution of the program, the rest of the line is ignored. Consequently,
you can put single line definitions anywhere in your program.
The 'body' of a procedure or function must not be executed directly
- it must be performed (called) by another part of the program. Since
BBC BASIC (Z80) only skips the rest of the line when it encounters DEF,
there is a danger that the remaining lines of a multi-line definition
might be executed directly. You can avoid this by putting multi-line
definitions at the end of the main program text after the
END statement. Procedures
and functions do not need to be declared before they are used and
there is no speed advantage to be gained by placing them at the start
of the program.
The end of a procedure definition is indicated by the keyword ENDPROC. The
end of a function definition is signalled by using a statement which
starts with an equals (=) sign. The function returns the value of
the expression to the right of the equals sign.
For single line definitions, the start and end are signalled
on the same line. The first example below defines a function which
returns the average of two numbers. The second defines a procedure
which clears from the current cursor position to the end of line on
a 40 column screen.
120 DEF PROC_clear:PRINT SPC(40-POS);:ENDPROC
You can define a whole library of procedures and functions and include
them in your programs. By doing this you can effectively extend the
scope of the language. For instance, BBC BASIC (Z80) does not have a
'clear to end of screen' command. Some computers will perform this
function on receipt of a sequence of control characters and in this
case you can use VDU or CHR$ to send the appropriate codes. However,
many computers do not have this facility and a procedure to clear
to the end of the screen would be useful. The example below is a
procedure to clear to the end of screen on a computer with an 80 by
24 display. In order to prevent the display from scrolling, you must
not write to the last column of the last row. The three variables used
(i, x, and y) are declared as LOCAL to the procedure
(see later).
100 DEF PROC_clear_to_end
110 LOCAL i,x,y
120 x=POS:y=VPOS
130 REM If not last line, print lines of spaces which
140 REM will wrap around and end up on last line
150 IF y<23 FOR i=y TO 22:PRINT SPC(80);:NEXT
160 REM Print spaces to end-1 of last line.
170 PRINT SPC(79-x);
180 PRINT TAB(x,y);
190 ENDPROC
When you define a procedure or a function, you list the parameters
to be passed to it in brackets. For instance, the discount example
expected one parameter (the retail price) to be passed to it. You
can write the definition to accept any number of parameters. For
example, we may wish to pass both the retail price and the discount
percentage. The function definition would then look something like
this:
DEF FN_discnt(price,pcent)=price*(1-pcent/100)
In this case, to use the function we would need to pass two parameters.
90 ....
100 retail_price=26.55
110 discount_price=FN_discount(retail_price,25)
120 ....
or
90 ....
100 price=26.55
110 discount=25
120 price=FN_discount(price,discount)
130 ....
or
90 ....
100 price=FN_discount(26.55,25)
110 ....
The value of the first parameter in the line using the procedure or
function is passed to the first variable named in the parameter list
in the definition, the second to the second, and so on. This is termed
'passing by value'. The parameters declared in the definition are
called 'formal parameters' and the values passed in the lines which
perform (call) the procedure or function are called 'actual parameters'. There
must be as many actual parameters passed as there are formal parameters
declared in the definition. You can pass a mix of string and numeric
parameters to the same procedure or function and a function can return
either a string or numeric value, irrespective of the type of parameters
passed to it. However, you must make sure that the parameter types
match up. The first example below is correct; the second would give
rise to an
'Arguments at line 10' error
message and the third would cause a
'Type mismatch at line 10'
error to be reported.
Correct
10 PROC_printit(1,"FRED",2)
20 END
30 :
40 DEF PROC_printit(num1,name$,num2)
50 PRINT num1,name$,num2
60 ENDPROC
Arguments Error
10 PROC_printit(1,"FRED",2,4)
20 END
30 :
40 DEF PROC_printit(num1,name$,num2)
50 PRINT num1,name$,num2
60 ENDPROC
Type Mismatch
10 PROC_printit(1,"FRED","JIM")
20 END
30 :
40 DEF PROC_printit(num1,name$,num2)
50 PRINT num1,name$,num2
60 ENDPROC
You can use the statement LOCAL
to define variables which are only
known locally to individual procedures and functions. In addition,
formal parameters are local to the procedure or function declaring
them. These variables are only known locally to the defining procedure
or function. They are not known to the rest of the program and they
can only be changed from within the procedure or function where they
are defined. Consequently, you can have two variables of the same name,
say FLAG, in various parts of your program, and change the value of
one without changing the other. This technique is used extensively
in the example file handling programs in this manual.
Declaring variables as local, creates them locally and initialises
them to zero/null.
Variables which are not formal
variables or declared as LOCAL are known to the whole program, including
all the procedures and functions. Such variables are called GLOBAL
Because the formal parameters which receive the passed parameters
are local, all procedures and functions can be re- entrant. That
is, they can call themselves. But for this feature, the short example
program below would be very difficult to code. It is the often used
example of a factorial number routine. (The factorial of a number
n is n * n-1 * n-2 *....* 1. Factorial 6, for instance, is 6*5*4*3*2*1)
10 REPEAT
20 INPUT "Enter an INTEGER less than 35 "num
30 UNTIL INT(num)=num AND num<35
40 fact=FN_fact_num(num)
50 PRINT num,fact
60 END
70:
80 DEF FN_fact_num(n)
90 IF n=1 OR n=0 THEN =1
100 REM Return with 1 if n= 0 or 1
110 =n*FN_fact_num(n-1)
120 REM Else go round again
Since 'n' is the input variable to the function FN_fact_num, it is
local to each and every use of the function. The function keeps calling
itself until it returns the answer 1. It then works its way back
through all the calls until it has completed the final multiplication,
when it returns the answer. The limit of 35 on the input number prevents
the answer being too big for the computer to handle.
© Doug Mounter and
Richard Russell 2009