You can use this function to select any part of a string. For instance, ifC$ = MID$(A$,start_posn,num) C$ = MID$(A$,Z) MID$(A$,4,2) = B$
thenname$="BBC BASIC for Windows"
would set part$ to "BAS". If the third parameter is omitted or there are insufficient characters to the right of the specified position, MID$ returns the right hand part of the string starting at the specified position. Thus,part$=MID$(name$,5,3)
would set part$ to "Windows".part$=MID$(name$,15)
For example,
would printname$="BBC BASIC for Windows" FOR i=5 TO 15 PRINT MID$(name$,i,11) NEXT
When using MID$ on the left of an equals sign, and the expression to the right of the equals sign evaluates to a string with fewer characters than the specified sub-string length, only that number of characters is changed. For example:BASIC for W ASIC for Wi SIC for Win IC for Wind C for Windo for Window for Windows or Windows r Windows Windows Windows
will set A$ equal to "BBC ZZSIC". Although the sub-string length is set to four, only two characters are actually modified since that is the length of the string "ZZ".A$ = "BBC BASIC" MID$(A$,5,4) = "ZZ"
<s-var>=MID$(<string>,<numeric>[,<numeric>]) MID$(<s-var>,<numeric>[,<numeric>])=<string>
LEFT$, RIGHT$, LEN, INSTR
MOD is defined such that,X=A MOD B
If you are doing integer division (DIV) of whole numbers it is often desirable to know the remainder (a 'teach children to divide' program for instance). For example, 23 divided by 3 is 7, remainder 2. Thus,A MOD B = A - ( A DIV B ) * B.
would printPRINT 23 DIV 3 PRINT 23 MOD 3
You can use real numbers in these calculations, but they are truncated to their integer part before BBC BASIC calculates the result. Thus,7 2
would give exactly the same results as the previous example.PRINT 23.1 DIV 3.9 PRINT 23.1 MOD 3.9
MOD can also be used as a function which operates on an entire numeric array. It returns the modulus (the square-root of the sum of the squares of all the elements) in the array. See the array arithmetic section.
<n-var>=<numeric> MOD <numeric> <n-var>MOD=<numeric> <n-var>=MOD(<array()>)
DIV
MODE |
MO. |
The following example sets the display to mode 3:
BBC BASIC for Windows and BBC BASIC for SDL 2.0 start in a default display mode, with black text on a white background. When a MODE statement is executed the window dimensions are changed to those appropriate to that mode, with (initially) white text on a black background.MODE 3
Graphics are available in all modes except MODE 7.
Mode Text (chars) Graphics (pixels) Graphics units Logical Colours 0 80x32 640x512 1280x1024 2 1 40x32 640x512 1280x1024 4 2 20x32 640x512 1280x1024 16 3 80x25 640x500 1280x1000 16 4 40x32 640x512 1280x1024 2 5 20x32 640x512 1280x1024 4 6 40x25 640x500 1280x1000 16 7 40x25 teletext teletext 8 8 80x32 640x512 1280x1024 16 9 40x32 640x512 1280x1024 16 10 90x36 720x576 1440x1152 16 11 45x36 720x576 1440x1152 16 12 120x48 960x768 1920x1536 16 13 60x48 960x768 1920x1536 16 14 160x64 1280x1024 2560x2048 16 15 80x64 1280x1024 2560x2048 16 16 80x25 640x400 1280x800 16 17 40x25 640x400 1280x800 16 18 80x30 640x480 1280x960 16 19 40x30 640x480 1280x960 16 20 100x30 800x600 1600x1200 16 21 50x30 800x600 1600x1200 16 22 128x48 1024x768 2048x1536 16 23 64x48 1024x768 2048x1536 16 24 144x54 1152x864 2304x1728 16 25 72x54 1152x864 2304x1728 16 26 160x60 1280x960 2560x1920 16 27 80x60 1280x960 2560x1920 16 28 180x54 1440x1080 2880x2160 16 29 90x54 1440x1080 2880x2160 16 30 200x75 1600x1200 3200x2400 16 31 100x75 1600x1200 3200x2400 16 32 80x25 640x400 1280x800 2 33 40x25 640x400 1280x800 4
As well as these predefined modes you can also select a 'custom' mode with VDU 23,22.
MODE n is equivalent to VDU 22,n.
MODE can also be used as a function. It returns the current mode number (or −1 if no MODE statement has been executed, or a 'custom' mode is in use).
MODE <numeric> <n-var> = MODE
CLS, CLG, VDU
Important note: On some Operating Systems MOUSE works whether or not your program has the input focus. This can occasionally be useful, but often you will prefer to detect a mouse button being pressed only when the user is working with your program. In that case you can check for input focus. Alternatively you may find ON MOUSE better suited to your needs.
The state of the mouse buttons can also be tested using INKEY with the parameters −10 (left), −11 (middle) and −12 (right). The mouse wheel, if any, cannot be tested directly but rotation of the wheel causes characters 140 or 141 to be inserted into the keyboard buffer; these can be read using GET or INKEY in the usual way.
MOUSE ON is equivalent to MOUSE ON 0. Note that MOUSE ON 137 and MOUSE ON 138 may not work on all Operating Systems.
Code Shape 0 1 2 3 130 131 132 133 134 136 137 138
Some Operating Systems, with some settings, may prohibit moving the mouse pointer in this way. This is because the mouse pointer is a shared resource and, on those systems, it is possible for the administrator to withhold privileges which could adversely affect other programs.
Because the mouse pointer is a shared resource, and confining it could adversely affect other programs, this statement only works if you have the appropriate administrative privileges.
MOUSE is also used in the ON MOUSE statement.
MOUSE <n-var>,<n-var>,<n-var> MOUSE ON [<numeric>] MOUSE OFF MOUSE TO <n-var>,<n-var> MOUSE RECTANGLE <n-var>,<n-var>,<n-var>,<n-var> MOUSE RECTANGLE OFF
INKEY, ON, OFF, ON MOUSE
The graphics origin (X=0, Y=0) is normally the bottom left of the 'screen' (BASIC's output window). The origin can be changed using the ORIGIN statement or the VDU 29 command.
MOVE x,y is equivalent to PLOT 4,x,y.MOVE X,Y MOVE 124,327
MOVE is also used in the ON MOVE statement.
MOVE <numeric>,<numeric> MOVE BY <numeric>,<numeric>
BY, DRAW, MODE, GCOL, PLOT, ON MOVE
NEXT |
N. |
If the control variable is present then FOR....NEXT loops may be 'popped' automatically in an attempt to match the correct FOR statement (this should not be necessary). If a matching FOR statement cannot be found, a 'Can't match FOR' error will be reported.NEXT NEXT J
Leaving out the control variable will make the program run quicker, but this is not to be encouraged.
See the keyword FOR for more details about the structure of FOR....NEXT loops.
NEXT [<n-var>{,<n-var>}]
FOR, TO, STEP
NOT is most commonly used in an IF....THEN....ELSE statement to reverse the effect of the test.A=NOT 3 flag=NOT flag flag=NOT(A=B)
BBC BASIC does not have true boolean variables; it makes do with numeric variables. This can lead to confusion because the testable condition in an IF....THEN....ELSE statement is evaluated numerically and can result in something other than −1 (TRUE) or 0 (FALSE).IF NOT(rate>5 AND TIME<100) THEN ..... IF NOT flag THEN .....
If you wish to use NOT to reverse the action of an IF statement it is important to ensure that the testable condition does actually evaluate to either 0 (FALSE) or −1 (TRUE).
If the testable condition evaluates to 1, for example, the test will be considered to have succeeded and the THEN part of the IF....THEN....ELSE statement would be carried out. However, using NOT in front of the testable condition would not reverse the action. NOT 1 evaluates to −2, which would also be considered to be success.
<n-var>=NOT<numeric>
AND, EOR, OR
CASE die% OF WHEN 1,2,3 : bet$ = "lose" WHEN 4,5,6 : bet$ = "win" OTHERWISE bet$ = "cheat" ENDCASE
CASE <var> OF
CASE, ENDCASE, OTHERWISE, WHEN
OFF is also used in the MOUSE OFF, MOUSE RECTANGLE OFF, ON CLOSE OFF, ON ERROR OFF, ON MOUSE OFF, ON MOVE OFF, ON SYS OFF, ON TIME OFF and TRACE OFF statements.
OFF
MOUSE, ON, TRACE
The ON statement alters the path through your program by transferring control to one of a selection of line numbers, labels or procedures depending on the value of a variable. For example,ON option GOTO 1000,2000,3000,4000 ON action GOSUB label1,label2,label3,label4 ON choice PROC_add,PROC_find(a$),PROC_delete
would send your program to line 1000 if 'number' was 1, to line 2000 if 'number' was 2, to line 500 if 'number' was 3 and to line 100 if 'number' was 4.ON number GOTO 1000,2000,500,100
If 'number' was less than 1 or greater than 4 the ON range error would result. You can trap this condition by using the ELSE statement delimiter:
If there is no statement after the ELSE, the program will 'drop through' to the following line if an exception occurs. In the following example, the program would drop through to the error handling part of the program if 'B−46' was less than one or more than 3.ON action GOTO 100,300,120 ELSE PRINT"Illegal"
You can use ON...GOTO, ON...GOSUB, and ON...PROC to execute the appropriate part of your program as the result of a menu selection. The following skeleton example offers a menu with three choices.ON B-46 GOTO 100,200,(C/200) ELSE PRINT "Illegal choice - try again"
CLS PRINT "Select the action you wish to take:" PRINT "1 Open a new data file" PRINT "2 Add data to the file" PRINT "3 Close the file and end"'' REPEAT INPUT TAB(10,20)"What is your choice",choice UNTIL choice>0 AND choice<4 ON choice PROC_open,PROC_add,PROC_close .....etc
ON <numeric> GOTO <l-num>{,<l-num>} [ELSE <stmt>{:<stmt>}] ON <numeric> GOSUB <l-num>{,<l-num>} [ELSE <stmt>{:<stmt>}] ON <numeric> PROC<name>[(<exp>{,<exp>})] {,PROC<name>[(<exp>{,<exp>})]} [ELSE <stmt>{:<stmt>}] ON
ON CLOSE, ON ERROR, ON MOUSE, ON MOVE, ON SYS, ON TIME, ON ERROR LOCAL, GOTO, GOSUB, PROC
Once ON CLOSE has been executed, any attempt to close the window (other than by QUIT) will cause control to be transferred to the statement following ON CLOSE. The current program pointer will be saved on the stack, so that you can resume execution from where it left off using RETURN. In this respect, attempting to close the window acts as a sort of 'interrupt' to the BASIC program.
For example, the following program segment asks the user to confirm whether he or she really wants to quit:
Note that the ON CLOSE 'interrupt' can only take place in between the execution of one BASIC statement and the next. If BBC BASIC is waiting in an INKEY, INPUT, GET, SOUND or WAIT statement, then the ON CLOSE procedure will not be called until the current statement has completed. If appropriate you can use the replacement routines in the NOWAIT library.ON CLOSE PROCclose : RETURN REPEAT REM Do something useful here! UNTIL FALSE ; DEF PROCclose : LOCAL ans$ REPEAT UNTIL INKEY(0) = -1 INPUT '"Do you really want to exit",ans$ IF LEFT$(ans$,1) = "y" OR LEFT$(ans$,1) = "Y" THEN QUIT ENDPROC
Be careful not to change anything within the ON CLOSE processing which could affect the operation of the rest of the program if the user chooses to continue. For example, PROCclose above ought really to save the current text cursor position and restore it before returning, and to ensure that the prompt and the user's response do not upset the display. See the notes on the use of interrupts for more details.
If you simply wish to disable the close button (and Alt-F4) you can use:
Trapping the close operation can be cancelled using ON CLOSE OFF, although it is possible for a queued event to be processed by a previous ON CLOSE procedure even after the ON CLOSE OFF statement has been executed. Note that returning to immediate mode automatically cancels event trapping.ON CLOSE RETURN
ON CLOSE LOCAL can be used inside a function or procedure. It has the same effect as ON CLOSE except that trapping set up by a previous ON CLOSE (if any) is saved, and restored on exit from the function or procedure.
ON CLOSE [LOCAL] <stmt>{:<stmt>}:RETURN ON CLOSE [LOCAL] OFF
LOCAL, ON MOUSE, ON MOVE, ON SYS, ON TIME, RETURN, PROC
ON ERROR OFF returns the control of error handling to BBC BASIC.
Error handling is explained more fully in the General Information section.ON ERROR PRINT"Suicide":END ON ERROR GOTO 100 ON ERROR OFF
ON ERROR <stmt>{:<stmt>} ON ERROR OFF
ON, ON ERROR LOCAL, GOTO, GOSUB, PROC
Unlike the ON ERROR statement, ON ERROR LOCAL prevents BBC BASIC clearing the program stack. By using this statement, you can trap errors within a FOR ... NEXT, REPEAT ... UNTIL or WHILE ... ENDWHILE, loop or a subroutine, function or procedure without BBC BASIC losing its place within the program structure.
ON ERROR OFF returns the control of error handling to BBC BASIC.
The following example program will continue after the inevitable 'Division by zero' error.ON ERROR LOCAL PRINT"Suicide":END ON ERROR LOCAL ENDPROC ON ERROR OFF
If ON ERROR LOCAL is used within a procedure, function, or loop structure then the previous error-trapping status (which might be an earlier ON ERROR LOCAL) is automatically restored on exit from the structure. However, ON ERROR LOCAL can be used anywhere within a BBC BASIC program, not just in these structures. In this case you must explicitly restore the previous error-trapping status using RESTORE ERROR.FOR n=-5 TO 5 ok% = TRUE ON ERROR LOCAL PRINT "Infinity" : ok% = FALSE IF ok% PRINT "The reciprocal of ";n;" is ";1/n NEXT n
Error handling is explained more fully in the General Information section.
ON ERROR LOCAL OFF temporarily disables error trapping; the default error reporting mechanism will be used until the previous error-trapping status is restored.
ON ERROR LOCAL <stmt>{:<stmt>} ON ERROR LOCAL OFF ON ERROR OFF
ON, ON ERROR, GOTO, GOSUB, PROC, RESTORE
If the ON MOUSE statement has been executed, pressing any of the three mouse buttons will cause a transfer of control to the statement after ON MOUSE. The current program pointer will be saved on the stack, so that you can resume execution from where it left off using RETURN.
Once the interrupt has occurred, you can test which button(s) are pressed by examining the @wparam% system variable. Its value depends on the button(s) pressed as follows:
(the values may be combined).
Button/key Value Left button 1 Right button 2 SHIFT key 4 CTRL key 8 Middle button 16
The position of the mouse pointer when the button was pressed can be discovered from the value of @lparam% as follows:
The coordinates are returned in pixels from the top left-hand corner of the window. If you need the coordinates in BBC BASIC graphics units then use the following code:xpos% = @lparam% AND &FFFF ypos% = @lparam% >>> 16
You should use the values of @wparam% and/or @lparam% in the statement immediately following ON MOUSE (e.g. by making them parameters of a procedure call), otherwise they might have changed as the result of a subsequent interrupt:xpos% = (@lparam% AND &FFFF)*2 - @vdu.o.x% ypos% = (@vdu%!212-1-(@lparam% >>> 16))*2 - @vdu.o.y%
Note that the ON MOUSE 'interrupt' can only take place in between the execution of one BASIC statement and the next. If BBC BASIC is waiting in an INKEY, INPUT, GET, SOUND or WAIT statement, then the ON MOUSE procedure will not be called until the current statement has completed. If appropriate you can use the replacement routines in the NOWAIT library.ON MOUSE PROCmouse(@wparam%,@lparam%) : RETURN
Be careful not to change anything within the ON MOUSE processing which could affect the operation of the rest of the program. See the notes on the use of interrupts for more details.
ON MOUSE OFF causes mouse-button events to be ignored, although it is possible for one or more queued events to be processed by a previous ON MOUSE procedure even after the ON MOUSE OFF statement has been executed. Note that returning to immediate mode automatically cancels event trapping.
ON MOUSE LOCAL can be used inside a function or procedure. It has the same effect as ON MOUSE except that trapping set up by a previous ON MOUSE (if any) is saved, and restored on exit from the function or procedure.
ON MOUSE [LOCAL] <stmt>{:<stmt>}:RETURN ON MOUSE [LOCAL] OFF
ON CLOSE, ON MOVE, ON SYS, ON TIME, RETURN, MOUSE, PROC
If the ON MOVE statement has been executed, moving or re-sizing the window will cause a transfer of control to the statement after ON MOVE. The current program pointer will be saved on the stack, so that you can resume execution from where it left off using RETURN.
Once the interrupt has occurred, you can take any action necessary to deal with the change in window size. For example, by issuing a VDU 26 command you can reset BASIC's text and graphics viewports to the new size:
If you need to distinguish between moving or re-sizing the window you can examine the value of the @msg% system variable. This will have the value 3 for a move and 5 for a re-size. ON MOVE also lets you intercept scroll messages if a scroll bar has been created. In this case @msg% will have the value &114 for a horizontal scroll message and &115 for a vertical scroll message.ON MOVE VDU 26 : RETURN
Following a change in the window size you might want to know what the new size actually is. Once you have checked that @msg% is 5 (signifying a re-size) you can discover the new size (in pixels) from @lparam% as follows:
In BBC BASIC for SDL 2.0 only, @wparam% contains additional information as follows:Width% = @lparam% AND &FFFF Height% = @lparam% >>> 16
@wparam% Meaning 0 Signifies that your application has been brought to the foreground after being suspended, on a mobile (Android or iOS) device. -1 Signifies that textures have been destroyed and need to be re-created. This can happen if an Android device is short of memory. Any other value Represents a window ID which can be useful if you have multiple windows and need to know which was moved or resized.
You should use the values of @msg%, @wparam% and @lparam%, as required, in the statement immediately following ON MOVE (e.g. by making them parameters of a procedure call), otherwise they might have changed as the result of a subsequent interrupt:
Note that the ON MOVE 'interrupt' can only take place in between the execution of one BASIC statement and the next. If BBC BASIC is waiting in an INKEY, INPUT, GET, SOUND or WAIT statement, then the ON MOVE procedure will not be called until the current statement has completed. If appropriate you can use the replacement routines in the NOWAIT library.ON MOVE PROCmove(@msg%,@wparam%,@lparam%) : RETURN ...... DEF PROCmove(M%,W%,L%) IF M%=5 Width%=L% AND &FFFF : Height%=L% >>> 16 ENDPROC
Be careful not to change anything within the ON MOVE processing which could affect the operation of the rest of the program. See the notes on the use of interrupts for more details.
ON MOVE OFF causes window-resizing or moving events to be ignored, although it is possible for one or more queued events to be processed by a previous ON MOVE procedure even after the ON MOVE OFF statement has been executed. Note that returning to immediate mode automatically cancels event trapping.
ON MOVE LOCAL can be used inside a function or procedure. It has the same effect as ON MOVE except that trapping set up by a previous ON MOVE (if any) is saved, and restored on exit from the function or procedure.
ON MOVE [LOCAL] <stmt>{:<stmt>}:RETURN ON MOVE [LOCAL] OFF
ON CLOSE, ON MOUSE, ON SYS, ON TIME, RETURN, PROC
When the interrupt occurs, the WPARAM and LPARAM values associated with the event can be recovered from the system variables @wparam% and @lparam%. These should be immediately passed as parameters to a procedure or function call, to ensure that they are copied to conventional variables before another interrupt can occur:
Note that the ON SYS 'interrupt' can only take place in between the execution of one BASIC statement and the next. If BBC BASIC is waiting in an INKEY, INPUT, GET, SOUND or WAIT statement, then the ON SYS procedure will not be called until the current statement has completed. If appropriate you can use the replacement routines in the NOWAIT library.ON SYS PROCmenu(@wparam%,@lparam%) : RETURN
Be careful not to change anything within the ON SYS processing which could affect the operation of the rest of the program. See the notes on the use of interrupts for more details.
ON SYS OFF causes menu events to be ignored, although it is possible for one or more queued events to be processed by a previous ON SYS procedure even after the ON SYS OFF statement has been executed. Note that returning to immediate mode automatically cancels event trapping.
ON SYS LOCAL can be used inside a function or procedure. It has the same effect as ON SYS except that trapping set up by a previous ON SYS (if any) is saved, and restored on exit from the function or procedure.
Control over what events are intercepted by ON SYS is provided by the *SYS command.
ON SYS [LOCAL] <stmt>{:<stmt>}:RETURN ON SYS [LOCAL] OFF
ON CLOSE, ON MOUSE, ON MOVE, ON TIME, RETURN, PROC
ON TIME allows you to perform a 'background task' without the complication of having to 'poll' the timer from (potentially) many different points in your program. If necessary you can have more than one timer, either using the code listed below or by means of the TIMERLIB library.
Note that the ON TIME 'interrupt' can only take place in between the execution of one BASIC statement and the next. If BBC BASIC is waiting in an INKEY, INPUT, GET, SOUND or WAIT statement, then the ON TIME procedure will not be called until the current statement has completed. If appropriate you can use the replacement routines in the NOWAIT library.
Be careful not to change anything within the ON TIME processing which could affect the operation of the rest of the program. See the notes on the use of interrupts for more details.
ON TIME OFF causes timer interrupt events to be cancelled, although it is possible for one or more queued events to be processed by a previous ON TIME procedure even after the ON TIME OFF statement has been executed. Note that returning to immediate mode automatically cancels event trapping.
ON TIME LOCAL can be used inside a function or procedure. It has the same effect as ON TIME except that trapping set up by a previous ON TIME (if any) is saved, and restored on exit from the function or procedure.
ON TIME [LOCAL] <stmt>{:<stmt>}:RETURN ON TIME [LOCAL] OFF
ON CLOSE, ON MOUSE, ON MOVE, ON SYS, RETURN, PROC
where period% is the required timer period in milliseconds. Don't expect the rate to be very accurate, and note that the shortest period you can use is 10 ms. If you need a faster timer you may be able to utilise the TIMERLIB library.OSCLI "TIMER " + STR$(period%)
Note that the timer period determines the flash rate of flashing characters in MODE 7. You are recommended not to change it when using that mode.
The problem with interrupts is that they occur at unpredictable times, therefore the part of your program being executed at the time is also unpredictable. If this part of your program can be affected by some change made by the interrupt service routine, the result may be a malfunction. Since only a small part of your program may be affected in this way, it will fail only rarely and in an apparently random fashion. Such faults are very hard to trace.
Ideally the interrupt service routine should be arranged to have no effects on the rest of the program. The following techniques can be valuable in achieving this:
DEF PROCinterrupt LOCAL X%,Y% X%=POS : Y%=VPOS REM. Output some text here PRINT TAB(X%,Y%); ENDPROC
If you don't do this the interrupt may adversely affect text or graphics output from the rest of the program. For example, when plotting a triangle, PLOT 85 takes the previous two points 'visited' as vertices of the triangle, and any interrupt which moves the graphics pointer in between will cause the triangle to be incorrectly plotted.DEF PROCinterrupt LOCAL vdusave{} DIM vdusave{} = @vdu{} vdusave{} = @vdu{} REM. Output some text or graphics here @vdu{} = vdusave{} ENDPROC
Beware of changing the current font and/or graphics viewport whilst the VDU state has been saved; special precautions are necessary in such cases.
If there is a danger that your interrupt service routine could be called re-entrantly, that is a second or subsequent interrupt occurs before the previous one has been completely processed, you must either write your code to be tolerant of that possibility or add a semaphore to cause the re-entrant interrupts to be ignored (if that is acceptable):
The likelihood of re-entrant calls is greatly increased if your program performs any operations which can stall interrupts (for example a WAIT statement with a non-zero parameter). To minimise this possibility you can use the replacement functions in the NOWAIT library.DEF PROCserviceroutine(parameters) PRIVATE semaphore% IF semaphore% THEN ENDPROC semaphore% = TRUE REM. Do the interrupt processing here semaphore% = FALSE ENDPROC
In general you should try to do as little as possible in the interrupt service routine, to minimise the chance of side-effects. Setting a flag within the interrupt routine, and performing the necessary action within your main code when the flag is found to be set, is generally preferable to performing the action within the interrupt routine itself. Ideally you should test and reset the interrupt flag within one non-interruptible unit, which can be done using the SWAP statement:
The SWAP statement both resets the interrupt flag and copies its previous value into temp% so it can be tested at leisure. If you need to know not only that the interrupt occurred, but also the associated @msg%, @wparam% and/or @lparam% values, you can extend the principle by using an array rather than a boolean flag:interrupt_flag% = FALSE ...... ON TIME interrupt_flag% = TRUE : RETURN ...... REM. within polling loop: temp% = FALSE SWAP interrupt_flag%,temp% IF temp% PROC_take_action
The SWAP both zeroes click%() and copies the old data into temp%(), so there is no danger of the data from two interrupts being mixed up. If you can guarantee to poll sufficiently often, this technique can eliminate many of the troublesome aspects of dealing with interrupts.DIM click%(2), temp%(2) ...... ON SYS click%() = @msg%,@wparam%,@lparam% : RETURN ...... REM. within polling loop: temp%() = FALSE SWAP click%(),temp%() IF temp%(0) PROC_click(temp%(0),temp%(1),temp%(2))
The LOCAL forms of event trapping (ON CLOSE LOCAL, ON MOUSE LOCAL, ON MOVE LOCAL, ON SYS LOCAL and ON TIME LOCAL) need special care. Because of the way events are queued it is possible that an event has occurred but has not yet been processed when the ON <event> LOCAL statement is executed. In that case the event may be processed by the previous ON <event> statement, if any. Similarly, a queued event may be processed by the ON <event> LOCAL statement even after the function or procedure in which it is contained has been exited. You should write your interrupt service routines to be tolerant of these possibilities.
OPENIN |
OP. |
If the extension is omitted, .BBC is assumed. To specify a filename with no extension, add a final full-stop. A returned value of zero signifies that the specified file was not found on the disk, or could not be opened for some other reason.
OPENIN may also be used to open a channel from an input device, such as COM1 (the first serial port) or COM2 (the second serial port). See the section Serial I/O for details.
The example below reads data from disk into an array. If the data file does not exist, an error message is printed and the program ends.X=OPENIN "jim" X=OPENIN A$ X=OPENIN (A$) X=OPENIN ("FILE1")
(BBC BASIC for Windows only)DIM posn(10),name$(10) fnum=OPENIN(@usr$+"TOPTEN.DAT") IF fnum=0 THEN PRINT "No TOPTEN data": END FOR i=1 TO 10 INPUT#fnum,posn(i),name$(i) NEXT CLOSE#fnum
<n-var>=OPENIN(<string>)
OPENOUT, OPENUP, CLOSE#, PTR#, PRINT#, INPUT#, READ#, BGET#, BPUT#, EOF#, GET$#
If the extension is omitted, .BBC is assumed. To specify a filename with no extension, add a final full-stop. A returned value of zero indicates that the specified file could not be created.
OPENOUT may also be used to open a channel to an output device, such as COM1 (the first serial port) or COM2 (the second serial port). See the section Serial I/O for details.
You can also read from a file which has been opened using OPENOUT. This is of little use until you have written some data to it. However, once you have done so, you can move around the file using PTR# and read back previously written data.X=OPENOUT(A$) X=OPENOUT("DATAFILE")
Data is not written to the file at the time it is opened. Consequently, it is possible to successfully open a file on a full disk. Under these circumstances, a 'Disk full' error would be reported when you tried to write data to the file for the first time.
The example below writes the contents of two arrays (tables) to a file called 'TOPTEN.DAT'.
(BBC BASIC for Windows only)A=OPENOUT(@usr$+"TOPTEN.DAT") FOR Z=1 TO 10 PRINT#A,N(Z),N$(Z) NEXT CLOSE#A END
<n-var>=OPENOUT(<string>)
OPENIN, OPENUP, CLOSE#, PTR#, PRINT#, INPUT#, BGET#, BPUT#, EOF#
If the extension is omitted, .BBC is assumed. To specify a filename with no extension, add a final full-stop. A returned value of zero signifies that the specified file was not found on the disk, or could not be opened for some other reason.
See the random file examples in the Disk files section for examples of the use of OPENUP.X=OPENUP "jim" X=OPENUP A$ X=OPENUP (A$) X=OPENUP ("FILE1")
OPENUP is also used to open a communications port (e.g. a serial port) for access. See the Serial I/O section for details.
(BBC BASIC for Windows only)
If the supplied filename is an empty string, or contains a wildcard (? or *) character anywhere,
an Open File dialogue box is displayed.
<n-var>=OPENUP(<string>)
OPENIN, OPENOUT, CLOSE#, PTR#, PRINT#, INPUT#, READ#, BGET#, BPUT#, EOF#, GET$#
OPT value Limit check Code stored at Errors reported Listing generated 0 No P% No No 1 No P% No Yes 2 No P% Yes No 3 No P% Yes Yes 4 No O% No No 5 No O% No Yes 6 No O% Yes No 7 No O% Yes Yes 8 Yes P% No No 9 Yes P% No Yes 10 Yes P% Yes No 11 Yes P% Yes Yes 12 Yes O% No No 13 Yes O% No Yes 14 Yes O% Yes No 15 Yes O% Yes Yes
OPT <numeric>
None
You can use OR as a logical operator or as a 'bit-by-bit' (bitwise) operator. The operands can be boolean (logical) or numeric.
Input A Input B Output 0 0 0 0 1 1 1 0 1 1 1 1
BBC BASIC does not have true boolean variables; this can lead to confusion at times (see NOT for more details).IF A=2 OR B=3 THEN 110 X=B OR 4
In the example below, the operands are boolean (logical). In other words, the result of the tests (IF) A=2 and (IF) B=3 is either TRUE or FALSE. The result of this example will be TRUE if A=2 or B=3.
The brackets are not necessary, they have been included to make the example easier to follow.answer=(A=2 OR B=3)
The last example, uses the OR in a similar fashion to the numeric operators (+, −, etc).
Suppose X was −20 in the following example,
the OR operation would be:A=X OR 11
11111111 11111111 11111111 11101100 00000000 00000000 00000000 00001011 11111111 11111111 11111111 11101111 = -17
<n-var>=<numeric> OR <numeric> <n-var>OR=<numeric>
AND, EOR, NOT
The graphics origin is reset to the bottom left-hand corner of the 'screen' (BASIC's output window) by a MODE statement or a VDU 26 command.
ORIGIN x,y is equivalent to VDU 29,x;y;
ORIGIN 640,512
ORIGIN <numeric>,<numeric>
MODE, PLOT, VDU
OSCLI can issue both resident operating system commands and external commands. See the Operating System interface section for more details.command$="DEL PHONE.DTA" OSCLI command$ command$="REN NAME.DTA ADDRESS.DTA" OSCLI command$
OSCLI <string>
None.
CASE die% OF WHEN 1,2,3 : bet$ = "lose" WHEN 4,5,6 : bet$ = "win" OTHERWISE bet$ = "cheat" ENDCASE
OTHERWISE [<stmt>]{:<stmt>}
CASE, ENDCASE, OF, WHEN
PAGE |
PA. |
PAGE is automatically initialised by BBC BASIC to the lowest available address. Normally PAGE should be treated as a read-only variable; you can change PAGE, but if you make it less than its initial value or greater than the value of HIMEM (less a safety margin of at least a kilobyte), you are almost certain to crash BASIC. If this happens you will lose all your unsaved work.PAGE = PAGE + &1000 PRINT ~PAGE
With care, several programs can be left around in RAM, at different values of PAGE, without the need for saving them. However you are strongly advised not to try this!
PAGE=<numeric> <n-var>=PAGE
TOP, LOMEM, HIMEM
You can use PI to calculate the circumference and area of a circle. The example below calculates the circumference and area of a circle of a given radius.X=PI
PI can also be used to convert degrees to radians and radians to degrees.CLS INPUT "What is the radius of the circle ",rad PRINT "The circumference is: ";2*PI*rad PRINT "The area is: ";PI*rad*rad END
However, BBC BASIC has two functions (RAD and DEG) which perform these conversions to a higher accuracy.radians=PI/180*degrees degrees=180/PI*radians
<n-var>=PI
RAD, DEG
PLOT |
PL. |
The graphics origin (X=0, Y=0) is normally the bottom left of the 'screen' (BASIC's output window). The origin can be changed using the ORIGIN statement or the VDU 29 command.PLOT Mode,X,Y
The two most commonly used examples, PLOT 4 and PLOT 5, have the duplicate keywords MOVE and DRAW.
PLOT X,Y is synonymous with PLOT 69,X,Y
PLOT BY X,Y is synonymous with PLOT 65,X,Y
.
See the Plotting modes section for full details of the different PLOT commands.
PLOT <numeric>,<numeric>,<numeric> PLOT <numeric>,<numeric> PLOT BY <numeric>,<numeric>
BY, CIRCLE, CLG, DRAW, ELLIPSE, FILL, GCOL, MODE, MOVE, ORIGIN, POINT, RECTANGLE, VDU
There must not be a space between POINT and the opening bracket.
You can use POINT to find out the colour of the screen at the specified point and take action accordingly. In an adventure game, for example, the swamps may be marked in green. If the explorer ventured into a green area he must be in the swamp and 'swamp type demons' would be activated.colour=POINT(X,Y) IF POINT(X,Y)=3 THEN 300
Beware that when your display is set to a 'true colour' mode (usually 32768 colours or more) POINT may not always produce the result you expect. Suppose you have set two or more logical colours to correspond to the same physical colour. You may know which logical colour you used to plot at a certain point, but BASIC only knows the physical colour. The value returned by POINT will depend upon which matching logical colour is found in the palette first. This problem doesn't arise with a 'paletted' display (usually 256 colours or fewer).
You can use TINT rather than POINT; this returns the physical (RGB) colour rather than the logical colour. Beware that in BBC BASIC for SDL 2.0 POINT and TINT are very slow.
<n-var>=POINT(<numeric>,<numeric>)
PLOT, DRAW, MOVE, GCOL, TINT
The difference between POS and COUNT is that POS always returns the true column number of the text cursor whereas COUNT returns the number of 'printing' characters output since the last carriage-return. These will often be the same, but may differ if direct cursor addressing (TAB(X,Y)) has been used, or if the cursor has 'wrapped around' at the end of the line.X=POS
See VPOS for an example of the use of POS and VPOS.
<n-var>=POS
COUNT, TAB, VPOS
P. |
The items following PRINT are called the print list. The print list may contain a sequence of string or numeric literals, variables and formatting instructions. The spacing between the items printed will vary depending on the punctuation used. If the print list does not end with a semi-colon, a new-line will be printed after all the items in the print list.
In the examples which follow, commas have been printed instead of spaces to help you count.
The 'screen' (BASIC's output window) is divided into zones (initially) 10 characters wide. By default, numeric quantities are printed right justified in the print zone and strings are printed just as they are (with no leading spaces). Numeric quantities can be printed left justified by preceding them with a semi-colon. In the examples the zone width is indicated as z10, z4 etc.
Initially numeric items are printed in decimal. If a tilde (~) is encountered in the print list, the numeric items which follow it are printed in hexadecimal. If a comma or a semi-colon is encountered further down the print list, the format reverts to decimal.z10 012345678901234567890123456789 PRINT 23.162 ,,,,23.162 PRINT "HELLO" HELLO PRINT ;23.162 23.162
A comma (,) causes the cursor to TAB to the beginning of the next print zone unless the cursor is already at the start of a print zone. A semi-colon causes the next and following items to be printed immediately after the previous item. This 'no-gap' printing continues until a comma (or the end of the print list) is encountered. An apostrophe (') will force a new line. TAB(X) and TAB(Y,Z) can also be used at any position in the print line to position the cursor.z10 012345678901234567890123456789 PRINT ~10 58,58 ,,,,,,,,,A,,,,,,,,3A,,,,,,,,58
Unlike most other versions of BASIC, a comma at the end of the print list will not suppress the new line and advance the cursor to the next zone. If you wish to split a line over two or more PRINT statements, end the previous print list with a semicolon and start the following list with a comma or end the line with a comma followed by a semicolon.z10 012345678901234567890123456789 PRINT "HELLO",24.2 HELLO ,,,,,,24.2 PRINT "HELLO";24.2 HELLO24.2 PRINT ;2 5 4.3,2 254.3 ,,,,,,,,,2 PRINT "HELLO"'2.45 HELLO ,,,,,,2.45
orz10 012345678901234567890123456789 PRINT "HELLO" 12; HELLO,,,,,,,,12,,,,,,,,,,23.67 PRINT ,23.67
Printing a string followed by a numeric effectively moves the start of the print zones towards the right by the length of the string. This displacement continues until a comma is encountered.PRINT "HELLO" 12,; PRINT 23.67
z10 012345678901234567890123456789 PRINT "HELLO"12 34 HELLO,,,,,,,,12,,,,,,,,34 PRINT "HELLO"12,34 HELLO,,,,,,,,12 ,,,,,,,,34
@%=&SSNNPPWW
Byte Range Initial Purpose SS 00-01 00 STR$ Format Control NN 00-C2 00 Format Selection PP ??-?? 09 Number of Digits Printed WW 00-0F 0A(10) Zone and Print Field Width
00 General Format (G).Adding &80 (i.e. 80, 81 or 82) causes a comma to be output instead of a decimal point.
01 Exponential Format (E).
02 Fixed Format (F).
G Format | Numbers that are integers are printed as such. Numbers in the range 0.0001 to 1 will be printed as such. Numbers less than 0.0001 will be printed in E format. Numbers greater than the range set by Byte 1 will be printed in E format. In which case, the number of digits printed will still be controlled by Byte 1, but according to the E format rules. |
The earlier examples were all printed in G9 format. | |
E Format | Numbers are printed in the scientific (engineering) notation. |
F Format | Numbers are printed with a fixed number of decimal places. |
Format | Range | Control Function |
---|---|---|
G | 01-14 | The maximum number of digits which can be printed, excluding
the decimal point, before changing to the E format.
01234567890123456789 &030A - G3z10 (00'00'03'0A) PRINT 1000.31 ,,,,,,,1E3 PRINT 1016.31 ,,,,1.02E3 PRINT 10.57 ,,,,,,10.6 |
E | 01-FF | The total number of digits to be printed excluding the
decimal point and the digits after the E. Three characters or spaces
are always printed after the E. If the number of significant figures
called for is greater than 10, then trailing zeros will be printed.
01030A - E3z10 (00'01'03'0A) 01234567890123456789 PRINT 10.57 ,,1.06E1 &010F0A - E15z10 (00'01'0F'0A) 01234567890123456789 PRINT 10.57 1.05700000000000E1 |
F | 00-14 | The number of digits to be printed after the decimal
point.
&02020A - F2z10 (00'02'02'0A) 01234567890123456789 PRINT 10.57 ,,,,,10.57 PRINT 100.5864 ,,,,100.59 PRINT .64862 ,,,,,,0.65 |
followed by&020208 - F2z8 (00'00'02'08)
&020206 - F2z6 (00'02'02'06) 01234567890123456789 PRINT 10.2,3.8 ,,,10.20,,,,3.80 PRINT 10.2,3.8 ,10.20,,3.80
Functions have to return an answer, but the value returned by this function is a null string. Consequently, its only effect is to change the print control variable. Thus the PRINT statementDEF FN_pformat(N):@%=N:=""
will print x in G9z10 format and y in F2z10 format. If you try to alter the zone width using this method the change will only take place at the next comma (if any) in the print list.PRINT FN_pformat(&90A) x FN_pformat(&2020A) y
The results obtained by running the following example program show the effect of changing the zone width. The results for zone widths of 5 and 10 (&0A) illustrate what happens when the zone width is too small for the number to be printed properly. The example also illustrates what happens when the number is too large for the chosen precision.G9z10 G2z10 &00090A &00020A 012345678901234 012345678901234 1111.11111 ,,,,,1.1E3 13.7174211 ,,,,,,,,14 ,1.5241579 ,,,,,,,1.5 1.88167642E-2 ,,,,1.9E-2 2.09975158E-3 ,,,,2.1E-3 F2z10 E2z10 &02020A &0102A 012345678901234 012345678901234 ,,,1111.11 ,,,1.1E3 ,,,,,13.72 ,,,1.4E1 ,,,,,,1.52 ,,,1.5E0 ,,,,,,0.02 ,,,1.9E-2 ,,,,,,0.00 ,,,2.1E-3
test=7.8123 FOR i=5 TO 25 STEP 5 PRINT @%=&020200+i PRINT "@%=&000";~@% PRINT STRING$(3,"0123456789") FOR j=1 TO 10 PRINT test^j NEXT PRINT ' NEXT @%=&90A &00020205 012345678901234567890123456789 7.81 61.03 476.80 3724.91 29100.11 227338.75 1776038.54 13874945.89 1.083952398E8 8.46816132E8 &0002020A 012345678901234567890123456789 7.81 61.03 476.80 3724.91 29100.11 227338.75 1776038.54 13874945.89 1.083952398E8 8.46816132E8 &0002020F 012345678901234567890123456789 7.81 61.03 476.80 3724.91 29100.11 227338.75 1776038.54 13874945.89 1.083952398E8 8.46816132E8 &00020214 012345678901234567890123456789 7.81 61.03 476.80 3724.91 29100.11 227338.75 1776038.54 13874945.89 1.083952398E8 8.46816132E8 &00020219 012345678901234567890123456789 7.81 61.03 476.80 3724.91 29100.11 227338.75 1776038.54 13874945.89 1.083952398E8 8.46816132E8
PRINT {[TAB(<numeric>[,<numeric>])][SPC(<numeric>] ['][,][;][~][<string>|<numeric>]}
PRINT#, TAB, POS, STR$, WIDTH, INPUT, VDU
CONTENTS |
CONTINUE |