RTR logo

R. T. RUSSELL

BBC BASIC (86) Manual



General Information

Introduction

Control Codes and Functions

Generation

Control codes are generated by holding down the <Ctrl> key and pressing another key. Thus 'control A' is generated by holding the <Ctrl> key down and pressing <A>. Since phrases like 'control A' are a little clumsy, we have used the generally accepted convention of preceding the character with the '^' symbol to indicate it is a control code. Thus 'control C' is shown as ^C, etc.

What Happens to Control Codes?

In the BBC Micro, all control codes (with the exception of <Esc> and ^U) are echoed to the micro's VDU software where they initiate the same functions as if they had been sent by the VDU statement. With the exceptions mentioned below, the same happens with BBCBASIC(86). Thus, pushing ^B will start the printer, pushing ^C will stop the printer and pushing ^L will clear the text area and home the cursor. (Pushing ^P will also toggle the printer on and off.) BBCBASIC(86) extensively emulates the standard BBC Micro VDU codes and these codes are described in the VDU Emulation section.

Special Control Codes

In order to maximise compatibility with MS-DOS and the BBC Micro, five control codes are trapped and used for special functions. These codes are ^H, ^J, ^P, ^U and ^[ (Esc) and they are not particularly useful in the direct mode. (These codes can still be sent in the direct mode by using VDU8, VDU10, VDU16, VDU21 and VDU27.) The function of these five control codes is listed below.

^PToggle printer
^HBackspace and delete
^JClear line to right of cursor
^UClear line to left of cursor
EscapeProgram/Command Abort

Pressing the <Esc> key aborts the program or command (unless disabled by *ESC OFF). Unlike the BBC Micro, VDU27 is not ignored. See the VDU Emulation section for more details.

Line Numbers

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.

Statement Separators

When it is necessary to write more than one statement on a line, the statements may be separated by a colon ':'. BBCBASIC(86) 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

Editing

Introduction

Three modes of editing are available; copy-key editing, single line editing and screen editing.

Since the PC does not have an obvious copy-key, BBCBASIC(86) uses the Tab key and copy-key editing is instigated by pressing this key. Copy-key editing is available during program and command entry and in response to an INPUT statement; it is not available with GET or INKEY.

The single line editor is active in the immediate mode, in response to an INPUT statement in a program and when the EDIT<line_number> command has been issued.

The screen editor is activated by the *EDIT<line_number> command. The line editor is preferred for changes to single lines, but the screen editor is most useful when you have a large number of changes or additions to make to your program.

All three editing methods are described below. EDIT and *EDIT are also described in their appropriate alphabetical position in the 'Statements and Functions' section (EDIT) and the 'Operating System Interface' section (*EDIT).

Copy Key Editing

As previously mentioned, the Tab key is used as the copy key and, unlike the BBC Micro, copy-key editing must be initiated by first pressing this key.

When you press the Tab (copy) key, BBCBASIC(86) enters the copy-key editing mode and two cursors are displayed. The large 'block' cursor shows where anything you enter will appear; it is called the write cursor. The other small flashing cursor is the one that can be moved around by the cursor control keys. For reasons which will become clear later, this is called the read cursor.

You can use the cursor control keys on the right hand side of the keyboard to edit or alter lines that are displayed on the screen. These keys are used to move the cursor around the screen to the line or lines you wish to edit or copy.

You can exit the copy-key editing mode (without pressing <Enter>) by pressing <Shift>/<Tab>; this restores the normal line-editing features. Thus, you can switch between the two forms of editing within one line by using <Tab> and <Shift>/<Tab>.

The Copy Key

Once you have moved the read cursor to the line on the screen you wish to edit, you may copy the characters on that line to the write cursor's position by pressing the Tab (copy) key. Every time you press the Tab key, the character at the read cursor's position will be written to the write cursor's position; then, the read cursor and the write cursor will move on one character position. At any time you wish, you may type characters on the keyboard and they will be entered at the write cursor's position. The write cursor will move on one character position after each character is typed on the keyboard.

You don't have to confine yourself to copying from a single line. You can move the read cursor around the screen and copy any character or sequence of characters displayed in any position on the screen. You can copy the same thing over and over again, or skip bits of a line by moving the read cursor over words you don't want in the new line.

The Back-space Key

The back-space key works as it always has done in BBCBASIC(86). When you press the back-space key, the character to the left of the write cursor is deleted and the write cursor moves back one character position. Thus, you can delete characters you have copied or entered in error.

The Line Editor - EDIT

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:

Line Editing Keys
UpMove the cursor up
DownMove the cursor down
LeftMove the cursor left one character
RightMove the cursor right one character
Ctrl/LeftMove the cursor to the start of the line
Ctrl/RightMove the cursor to the end of the line
BackSpaceBackspace and delete
DeleteDelete the character at the cursor
InsertToggle between the insert and overwrite modes
Ctrl/UClear line to the left of the cursor
Ctrl/EnterClear the line to the right of the cursor
EnterEnter the line and exit the edit mode
EscAbort and leave the line unchanged
Ctrl/PToggle the output to the printer
(in the insert mode, the cursor is an underline; in the overwrite mode it fills the character cell.)

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 Screen Editor - *EDIT

You enter the screen editor by using the *EDIT command. You may specify the first line number which is to be displayed on the screen.
*EDIT
*EDIT 120
This command will clear the screen, display the program on the screen starting with the specified line and enter the screen editing mode. Pressing the <Esc> key will exit the screen editing mode, clear the screen and return you to your original display mode.

Whilst in the screen editing mode, the control keys have the following effect:

Screen Editing Keys
Up Move up to the previous screen line
Down Move down to the following screen line
Left Move the cursor left one character
Right Move the cursor right one character
Ctrl/Left Move the cursor to the start of the program line
Ctrl/Right Move the cursor to the end of the program line
Enter Move the cursor to the start of the next program line
BackSpace Backspace and delete
Delete Delete the character at the cursor
Insert Toggle between the insert and overwrite modes. In the
insert mode the cursor is an underline; in the overwrite
mode it fills the character cell
Tab Insert a line immediately following the current line
Ctrl/U Clear the current line. The line number is not deleted
Ctrl/Enter Delete the entire line including the line number
PageUp Display the previous 12 program lines and move the
cursor to the start of the first line displayed
PageDn Display the next 12 lines and move the cursor to the
start of the first line displayed
Home Move the cursor to the start of the program
End Move the cursor to the end of the program
Esc Exit the screen editing mode

If you are at the top of the screen, pressing the cursor up key will cause the display to scroll back one line. The cursor will remain at the top of the screen on this newly displayed line. Similarly, if you are at the bottom of the screen, pressing the cursor down key will cause the display to scroll forward one line.

Editing takes place as you type; there is no opportunity to abort the edit as there is with the single line editor. The <Esc> key ends the edit; it does not abort it. Any changes you have made will remain. Also, unlike the single line editor, it is not possible to edit the line numbers. Consequently, the line editor may be more useful for making changes to individual program lines. See above for more details.


Expression Priority

Order of Evaluation

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

Examples

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)

Variables

Specification

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:

real numeric
A% integer numeric
A$ string

Numeric Variables

Real Variables

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 E.

Integer Variables

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.

Static Variables

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%, F%, X% and Y% 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

Boolean variables can only take one of the two values TRUE or FALSE. Unfortunately, BBCBASIC 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.

Numeric Accuracy

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 and Garbage

Strings

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.

Garbage Generation

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. BBCBASIC does not incorporate 'garbage collection' routines and it is possible to run out of room for variables even though there should be enough space.

Memory Allocation

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

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.

Program Flow Control

Introduction

Whenever BBCBASIC(86) 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 BBCBASIC(86) where it is in the structure of your program.

Every time BBCBASIC(86) 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, BBCBASIC(86) 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.

Loop Operation Errors

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

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 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, BBCBASIC(86) 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
BBCBASIC(86) 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.

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.

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 BBCBASIC(86)'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 or REPEAT...UNTIL loop.

Indirection

Introduction

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 BBCBASIC(86) 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 BBCBASIC's data area (virtual addresses). Consequently, you cannot use the indirection operators to modify the BBCBASIC program or the value of its internal variables.

When running BBCBASIC(86) 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:

NameSymbolPurpose No. of Bytes Affected
Query?Byte Indirection Operator1
Exclamation!Word Indirection Operator4
Dollar$String Indirection Operator1 to 256

Query

Byte Access

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)

Query as a Byte Variable

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

Exclamation

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

Dollar

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

Use as Binary Operators

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.

Power of Indirection Operators

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.

Operators and Special Symbols

The following list is a rather terse summary of the meaning of the various operators and special symbols used by BBCBASIC(86). 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

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.

Single key entry of selected keywords is provided. These keywords are listed at the beginning of the Statements and Functions section.

Keywords Available

ABS ACS ADVAL AND ASC
ASN ATN AUTO BGET BPUT
CALL CHAIN CHR$ CLEAR CLG
CLOSE CLS COLOUR COLOR COS
COUNT DATA DEF DEG DELETE
DIM DIV DRAW ELSE END
ENDPROC ENVELOPE EOF EOR ERL
ERR ERROR EVAL EXP EXT
FALSE FN FOR GCOL GET
GET$ GOSUB GOTO HIMEM IF
INKEY INKEY$ INPUT INSTR( INT
LEFT$( LEN LET LINE LIST
LN LOAD LOCAL LOG LOMEM
MID$( MOD MODE MOVE NEW
NEXT NOT OFF OLD ON
OPENIN OPENOUT OPENUP OR OSCLI
PAGE PI PLOT POINT() POS
PRINT PROC PTR PUT RAD
READ REM RENUMBER REPEAT REPORT
RESTORE RETURN RIGHT$( RND RUN
SAVE SGN SIN SOUND SPC
SQR STEP STOP STR STRING$(
TAB( TAN THEN TIME TO
TRACE TRUE UNTIL USR VAL
VDU VPOS WIDTH


Error Handling

Introduction

Types of Errors

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 BBCBASIC(86) 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 BBCBASIC(86) 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'. BBCBASIC(86) has no way of dealing with 'infinity' and it will report a 'Division by zero' error.

Trapping Errors

There is no way that BBCBASIC(86) 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.

Reasons for Trapping Errors

Why would you want to take over responsibility for handling run-time errors? When BBCBASIC(86) 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 BBCBASIC(86) 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 BBCBASIC(86) 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

Error Trapping Commands

The two main commands provided by BBCBASIC(86) for error trapping and recovery are:
ON ERROR ....
and
ON ERROR LOCAL ....

ON ERROR

The ON ERROR command directs BBCBASIC(86) 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 BBCBASIC(86) 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 BBCBASIC(86) records where it is within the structure of your program.

When an error is detected by BBCBASIC(86), the stack is cleared. Thus, you cannot just take any necessary action depending on the error and return to where you were because BBCBASIC(86) 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.

ON ERROR LOCAL

The ON ERROR LOCAL command prevents BBCBASIC(86) clearing the program stack. By using this command, you can trap errors within a FOR...NEXT or REPEAT...UNTIL loop or a subroutine, function or procedure without BBCBASIC(86) losing its place within the program structure.

The following example program will continue after the inevitable 'Division by zero' error in line 30.

10 FOR n=-5 TO 5
20   ON ERROR LOCAL PRINT "Infinity":GOTO 40
30   PRINT "The reciprocal of ";n;" is ";1/n
40 NEXT n
This is, of course, a very bad use of error trapping. You should test for n=0 rather than allow the error to occur. However, it does provide a simple demonstration of the action of ON ERROR LOCAL. Also, you should test ERR to ensure that the error was the one you expected rather than, for example, Escape. (ERR is a function which returns the number of the last error; it is explained later in this sub-section.)

You can call a subroutine, function or procedure to 'process' the error, but it is essential that the section of program that handles the error returns to the loop, subroutine, function or procedure where the error was trapped. The following example would give rise to a 'No repeat' error at line 120. Changing line 190 to GOTO 50 would cure the problem.

 10 x=OPENOUT "TEST"
 20 FOR i=-5 TO 5
 30   ON ERROR LOCAL GOTO 160
 40   PRINT#x,1/i
 50 NEXT
 60 CLOSE#x
 70 :
 80 x=OPENIN "TEST"
 90 REPEAT
100   INPUT#x,i
110   PRINT i
120 UNTIL EOF#x
130 CLOSE#x
140 END
150 :
160 IF ERR  18 REPORT:PRINT " at line ";ERL:END
170 PRINT "Infinity"
180 PRINT#x,3.4E38
190 GOTO 100

ON ERROR or ON ERROR LOCAL?

If you use ON ERROR, BBCBASIC(86) clears the program stack. Once your program has decided what to do about the error, it must re-enter the program at a point that is not within a loop, subroutine, function or procedure. In practice, this generally means somewhere towards the start of the program. This is often undesirable as it makes it difficult to build well structured programs which include error handling. On the other hand, you will probably only need to write one or two program sections to deal with errors.

At first sight ON ERROR LOCAL seems a more attractive proposition since BBCBASIC(86) remembers where it is within the program structure. The one disadvantage of ON ERROR LOCAL is that you will need to include an error handling section at every level of your program where you need to trap errors. Many of these sections of program could be identical.

You can mix the use of ON ERROR and ON ERROR LOCAL within your program. The ON ERROR command can take care of all the 'fatal' errors and every time your program could recover from any errors, you can use ON ERROR LOCAL. ON ERROR LOCAL 'remembers' the current ON ERROR setting, and restores it when the loop, procedure or function containing the ON ERROR LOCAL command is finished.

Error Reporting

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

ERR returns the error number (see the Annex entitled Error Messages and Codes).

ERL

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

REPORT prints out the error string associated with the last error which occurred.

Error Trapping Examples

The majority of the following error trapping examples are all very simple programs without nested loops, subroutines, functions or procedures. Consequently, they use ON ERROR for error trapping in preference to ON ERROR LOCAL.

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 BBCBASIC(86)'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
The next example is similar to the previous one, but it uses the ON ERROR LOCAL command to trap the error.
 10 REPEAT
 20   ON ERROR LOCAL GOTO 100
 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 30
120 REPORT:PRINT " at line ";ERL
130 END

Procedures and Functions

Introduction

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 BBCBASIC(86) 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.

Names

The names of procedures and functions MUST start with PROC or FN and, like variable names, they cannot contain spaces. (A space tells BBCBASIC(86) 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

Starting a Definition

Functions and procedure definitions are 'signalled' to BBCBASIC(86) 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 Function/Procedure Body

The 'body' of a procedure or function must not be executed directly - it must be performed (called) by another part of the program. Since BBCBASIC(86) 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.

Ending a Definition

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.

Single Line Functions/Procedures

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

Extending the Language

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, BBCBASIC(86) 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

Passing Parameters

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 ....

Formal and Actual Parameters

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

Local Variables

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

Re-entrant Functions/Procedures

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.

Left CONTENTS

CONTINUE Right


Best viewed with Any Browser Valid HTML 3.2!
© Doug Mounter and Richard Russell