|^H||Backspace and delete|
|^J||Clear line to right of cursor|
|^U||Clear line to left of cursor|
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.
For example, the following will work.
10 FOR i=1 TO 5 PRINT i : NEXT
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).
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>.
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.
EDIT 230The following control functions are active in the immediate and edit modes and in response to an INPUT command in a program:
|Move the cursor up|
|Move the cursor down|
|Move the cursor left one character|
|Move the cursor right one character|
|Ctrl/||Move the cursor to the start of the line|
|Ctrl/||Move the cursor to the end of the line|
|BackSpace||Backspace and delete|
|Delete||Delete the character at the cursor|
|Insert||Toggle between the insert and overwrite modes|
|Ctrl/U||Clear line to the left of the cursor|
|Ctrl/Enter||Clear the line to the right of the cursor|
|Enter||Enter the line and exit the edit mode|
|Esc||Abort and leave the line unchanged|
|Ctrl/P||Toggle the output to the printer|
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.
*EDITThis 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:
|Move up to the previous screen line|
|Move down to the following screen line|
|Move the cursor left one character|
|Move the cursor right one character|
|Ctrl/||Move the cursor to the start of the program line|
|Ctrl/||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.
variables functions () ! ? & unary+- NOT ^ * / MOD DIV + - = <> <= >= > < AND EOR OR
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)
The following types of variable are allowed:
A real numeric
A% integer numeric
PRINT NOT 1.5
|The argument, 1.5, is truncated to 1 and the logical inversion of this gives -2|
PRINT NOT -1.5
|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.
Assigning a null string to stop$ prevents the space for the last entry in the array being recovered when it is emptied.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
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.
Too many FORs Too many REPEATs Too many GOSUBs
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.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
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
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
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
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 FOR i=1 TO 10 400 LOCAL data(i) 410 NEXT 420 ENDPROC
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 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:
|Name||Symbol||Purpose||No. of Bytes Affected|
|Query||?||Byte Indirection Operator||1|
|Exclamation||!||Word Indirection Operator||4|
|Dollar||$||String Indirection Operator||1 to 256|
?&4FA2=&23 or memory=&4FA2 ?memory=&23
number=?&4FA2 or memory=&4FA2 number=?memory
PRINT ?&4FA2 or memory=&4FA2 PRINT ?memoryThus, '?' provides a direct replacement for PEEK and POKE.
?A=B is equivalent to POKE A,B
B=?A is equivalent to B=PEEK(A)
DIM count% 0 FOR ?count%=0 TO 20 - - - - - - NEXT
&78 into address Mand
&56 into address M+1
&34 into address M+2
&12 into address M+3.
PRINT ~!M (print !M in hex format)would give
$M="ABCDEF"would load the ASCII characters A to F into addresses M to M+5 and &0D into address M+6, and
PRINT $Mwould print
Thus,memory=&4000 memory?5=&50 PRINT memory?5
A?I=B is equivalent to POKE A+I,BThe 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.)
B=A?I is equivalent to B=PEEK(A+I)
Line 30 prints the memory address and the contents in hexadecimal format.10 memory=&4000 20 FOR offset=0 TO 12 30 PRINT ~memory+offset, ~memory?offset 40 NEXT
See the Annex entitled Format of Program and Variables In Memory for an explanation of this program.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
If M is the address of the start of the structure then:
$M is the stringLinked lists and tree structures can easily be created and manipulated in memory using this facility.
M?11 is the 8 bit number
M!12 is the address of the related structure
|?||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.|
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.
answer=A/Bis 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.
Example run: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
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
ON ERROR ....and
ON ERROR LOCAL ....
ON ERROR PRINT '"Oh No!":ENDIf 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.
The following example program will continue after the inevitable 'Division by zero' error in line 30.
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.)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
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
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.
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).
Example run: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
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.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
Example run: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
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.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 next example is similar to the previous one, but it uses the ON ERROR LOCAL command to trap the error.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
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
Arguably, the major advantage of procedures and functions is that they can be referred to by name. Consider the two similar program lines below.
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.100 IF name$="ZZ" THEN GOSUB 500 ELSE GOSUB 800
100 IF name$="ZZ" THEN PROC_end ELSE PROC_print
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.
Function and procedure names may end with a '$'. However, this is not compulsory for functions which return strings.PROCPRINTDETAILS FNDISCOUNT
120 DEF PROC_clear:PRINT SPC(40-POS);:ENDPROC
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
DEF FN_discnt(price,pcent)=price*(1-pcent/100)In this case, to use the function we would need to pass two parameters.
or90 .... 100 retail_price=26.55 110 discount_price=FN_discount(retail_price,25) 120 ....
or90 .... 100 price=26.55 110 discount=25 120 price=FN_discount(price,discount) 130 ....
90 .... 100 price=FN_discount(26.55,25) 110 ....
10 PROC_printit(1,"FRED",2) 20 END 30 : 40 DEF PROC_printit(num1,name$,num2) 50 PRINT num1,name$,num2 60 ENDPROC
10 PROC_printit(1,"FRED",2,4) 20 END 30 : 40 DEF PROC_printit(num1,name$,num2) 50 PRINT num1,name$,num2 60 ENDPROC
10 PROC_printit(1,"FRED","JIM") 20 END 30 : 40 DEF PROC_printit(num1,name$,num2) 50 PRINT num1,name$,num2 60 ENDPROC
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
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.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