×   Main Menu ALL The 8BS News Manuals (New menu) Links Worth a Look Tools Disc and Basic Webring Site Map 8BS Guestbook Old Guest Book Me The Barnsley Rovers   
8-Bit Software

The BBC and Master Computer Public Domain Library

B75B ON

Submitted by Steve Fewell

Description:

Get the next non-space character pointed to by BASIC Text Pointer A.

If the character is #&85 ('ERROR-token') then jump to &B741 to set the BASIC ERROR pointer, as follows:
* [&B741] Get the next non-space character after the 'ERROR' keyword
* If the character is #&87 ('OFF-Token') then jump to &B739 to check for the end of statement (&9BA6),
    and issue 'Syntax error' if the end of statement was not found (i.e. the next character wasn't ':', '<cr>'
    (carriage return) or 'ELSE-token'). Call routine &B2A6 to reset BASIC's ON ERROR pointer, so that it points to
    BASIC's default error handling routine (which starts at location &B2AF) and jump to &9005 to continue
    executing the Program.
* Otherwise, Set Y to the BASIC Text Pointer A offset (location &0A) and decrement Y (so that it points to
    the first non-space character after the ERROR-keyword (the character that we just checked).
* Call &9BBC to Add the BASIC Text Pointer A offset (&0A) to the Base BASIC Text Pointer A address
    (&0B-&0C), and to reset the Offset (&0A) to 1.
* Zero BASIC text pointer A Offset (&0A).
* Set BASIC's ON ERROR handler (stored at locations &16-&17) to point to the address in BASIC text
    pointer A (&0B-&0C) - so that it points to the program code following the ON ERROR keywords.
* Jump to &8FAE to skip the rest of the current program line (as this is the error code that is only executed
    when an error occurs) and continue executing the program starting at the next program line.
Otherwise, the next character should be a numeric variable name or numeric expression, so decrement the BASIC text pointer
A offset value (&0A) to point to the start of this expression.
Call routine &926F to evaluate the expression at BASIC Text Pointer A and issue 'Type mismatch' error is a String
expression is found, a Floating-Point result will be converted to Integer.
Now, the IWA contains the Integer result of the expression (or the contents of the Integer variable specified) and X
contains the next character after the expression. This routine also sets BASIC Text Pointer B to the BASIC Text Pointer A
value.

If the next character (X) is #&E5 (GOTO-token) or #&E4 (GOSUB-token) then increment Y (to skip over the keyword).
If the next character (X) is not #&F2 (PROC-token), #&E5 (GOTO-token) or #&E4 (GOSUB-token) then issue an
'ON syntax' error as a valid ON statement (ON ERROR..., ON...GOTO, ON...GOSUB, ON...PROC) was not found.

[&B774] Push X to the 6502 Stack (this is the Keyword which indicates the type of ON-statement that we are processing).
Check whether IWA bytes &2B-&2D are zero, if they are not the the IWA contains a value greater than 255 - which is
not within the permitted ON range (1-127), so jump to &B7D5 to check each character of the current program line
(starting from the current character), looking for an 'ELSE-token' (#&8B). If an 'ELSE-token' is found then [&B817]
update the BASIC text pointer A offset (&0A) to point to the location of the ELSE-token, and call routine &9C29 to
execute the ELSE-statement. If a carriage return character ('<cr>') is found without finding an 'ELSE-token' then
issue 'ON range' error. Please see the note at the bottom for a flaw with this ELSE-statement search.

[&B77D] Decrement the IWA LSB (&2A) value.
If the IWA LSB (&2A) value is now zero then the original IWA value was 1, so jump to &B7B6 to execute the
PROC/GOTO/GOSUB statement that is pointed to by the BASIC Text Pointer A (i.e. the first statement after the GOTO/
GOSUB/PROC keyword).

[B781] If the IWA (&2A) value was less than 0 or greater than 127 (i.e. negative flag set) after the decrement, then
the value is not within the permitted ON range (1-127), so jump to &B7D5 to check each character of the current program
line (starting from the current character), looking for an 'ELSE-token' (#&8B). If an 'ELSE-token' is found then [&B817]
update the BASIC text pointer A offset (&0A) to point to the location of the ELSE-token, and call routine &9C29 to
execute the ELSE-statement. If a carriage return character ('<cr>') is found without finding an 'ELSE-token' then
issue 'ON range' error. Please see the note at the bottom for a flaw with this ELSE-statement search.

[&B783] If the current character (pointed to by PTR A (&0B-&0C) plus offset Y) is either a carriage return
('<cr>'), a colon (':') or an 'ELSE-token' clause, then the end of the ON statement has been found, (or the ELSE-part
of the ON-statement has been found), this means that the GOSUB,GOTO or PROC statement corresponding to the original
value specified in the IWA was not located within the statement, so jump to &B7D5 to check each character of the current
program line (starting from the current character), looking for an 'ELSE-token' (#&8B). If an 'ELSE-token' is found
then [&B817] update the BASIC text pointer A offset (&0A) to point to the location of the ELSE-token, and call
routine &9C29 to execute the ELSE-statement. If a carriage return character ('<cr>') is found without finding an
'ELSE-token' then issue 'ON range' error. Please see the note at the bottom for a flaw with this ELSE-statement search.

[&B791] Skip the current GOTO, GOSUB or PROC statement, and move forward to the next GOTO line,
GOSUB line or PROC call in the ON-statement (that is the next statement after a comma ',' has been located).
This is done as follows:

Increment Y offset (to point to the next character). The accumulator (A), however, still contains the current character.
If the current character (in A) was a double quote ("), then Exclusive-OR the character with the contents of location
&2B (this flag indicates whether the current character is inside a String literal or not).
If the value of the String Literal flag (location &2B) is not zero, then we are currently inside a String Literal,
so ignore the current character and jump back to &B783 to process the next character.
Note: the initial value of &2B is zero (as the IWA now only contains an 8-bit value).

If the current character is a close bracket ')', then decrement location &2C. Location &2C is a flag that
determines whether we have reached the end of a function call such as MID$(a$,3,4).
If the current character is an open bracket '(' then increment location &2C (the bracket counter).

If the current character is not a comma then jump back to &B783 to process the next character, as we haven't found
the next GOTO, GOSUB or PROC call yet.

Now, we have found a comma. However, if location &2C (the bracket counter) contains a positive value, then the
comma forms part of a function call, and is, therefore, not the ON list separator, so jump back to &B783 to process
the next character.

Now, we have found the next list element in the On-Statement, so decrement the IWA value (&2A) and check the value
of the IWA (location &2A). If the IWA has reached zero, then we have found the ON GOSUB, GOTO or PROC statement
for the original value of the IWA, so jump to &B783 to execute the statement.
Otherwise, we haven't found the GOTO, GOSUB or PROC call that corresponds to the original IWA value, so jump back to
&B783 to process the next character.


[&B7B6] Execute the PROC/GOTO/GOSUB statement:
Retrieve the ON statement type (either PROC/GOTO/GOSUB) from the 6502 stack.
If the statement type is 'PROC' then jump to &B803 to execute the PROCedure call.
Store Y back to the BASIC text pointer A offset (to update the offset value). This didn't need to be done for PROC, as
PROC sets the BASIC Text pointer B offset instead.
If the statement type is 'GOSUB' then:
* [&B7CA] Call routine &B82A to Read the Line Number at BASIC Text pointer A and find the Program address
    for the start of that Program line.
* Set Y to the BASIC Text pointer A offset (&0A), i.e. the character after the Line Number.
* Call &B81D to skip the rest of the ON-Statement until a ':' or carriage return ('<cr>') character is
    found. This is so that on return from the GOSUB routine, the program will correctly continue to execute at
    the next program statement.
* Jump to &B6DC to execute the GOSUB statement by checking for end of statement & GOSUBing the Line
    Number specified
Otherwise, the statement type must be 'GOTO', so:
* [&B7C1] Call routine &B82A to Read the Line Number at BASIC Text pointer A and find the Program address
    for the start of that Program line.
* Call routine &9BC6 to set the BASIC Text Pointer A offset (&0A) to 1 and to check for the Escape-Key
    pressed condition - if the Escape key has been pressed, then issue 'Escape' error.
* Jump to &B723 to Display the Line Number on the screen (if TRACE is currently active), Set the
    BASIC Text Pointer A Offset to 4 (to skip the 3-byte Line Number and 1-byte offset to the next line which
    are located at the start of the Program Line), Set the BASIC Text Pointer A to the address specified in
    locations &3D-&3E and jump to &900B to start executing the statement at the start of the specified
    Program Line.
* Note: The rest of the ON-Statement does not need to be skipped (using &B81D), as it is in the GOSUB call,
    as we will not be returning from the GOTO call.

[&B803] Execute the PROC statement:
Store Y in location &1B (to update BASIC text pointer B to the current character on the line (pointed to by Y)
- this should be the PROC-token).
Get the next non-space character pointed to by the BASIC text pointer B.
If the character is not PROC (note: that each comma-separated statement in an ON...PROC statement must begin with the
PROC-keyword (i.e. ON...PROCxxx,PROCyyy,PROCzzz)) then issue 'ON syntax' error.
Call the routine &B019 to execute the PROC statement.
Set Y to the BASIC text pointer B offset (the value after the PROCedure name)
Call routine &B81D to skip the rest of the program statement (until a ':' or carriage return ('<cr>') character
is found).
Jump to &9002 to execute the next program statement.


Flaws with the ON routine
The ON routine has one flaw, found in routine &B7D5. This routine keeps checking the rest of the Program line
until either an ELSE-token or a carriage-return character is found.
If an ELSE-token is found then the ELSE-statement will be executed, if a carriage return ('<cr>') character is found
'ON range' error will be issued, as an out of range value was found and the ON statement doesn't have an ELSE-Statement
part.
However, the problem is that the 'ON' keyword is a statement, which ends when a carriage return ('<cr>') or ':'
character is found - however BASIC will keep searching for the 'ELSE-statement' past the end of the ON-Statement, if the
ON-statement terminates with a colon.
E.g.:
5 ON ERROR A = A / B : GOTO 40
10 INPUT A
20 INPUT B
30 ON A GOSUB 100,110,120,130 : IF B > 0 THEN LET A = A / B ELSE LET A = 0
40 PRINT A
50 END
100 LET A = A * 20:RETURN
110 LET A = A * 30:RETURN
120 LET A = A * 40:RETURN
130 LET A = A * 50:RETURN
In the above program, if 5 is entered for A (which is out of range for the ON statement, as only 4 options are present),
then the ELSE-Statement part of the 'IF-Statement' will be executed - even though the ON-Statement terminated (with a ':'
character) before the IF statement started. This is basically due to BASIC not checking for a colon ':' character as well
as a carriage return. Therefore, in the above example, if A = 5 then A will be set to 0 - instead of being divided by B
(as per the code following the ON ERROR statement, as the ON statement should have issued 'ON Range' error).


Disassembly for the ON routine

B739   032 166 155 20 A6 9B JSR &9BA6 Check end of Statement
B73C   032 166 178 20 A6 B2 JSR &B2A6 Reset 'ON ERROR' pointer to BASIC's default error handling routine
B73F   128 217 80 D9 BRA -39 --> &B71A Jump to &9005 to continue running the program
B741   032 224 142 20 E0 8E JSR &8EE0 Get next non-space character pointed to by Ptr A
B744   201 135 C9 87 CMP#&87
B746   240 241 F0 F1 BEQ -15 --> &B739 Execute ON ERROR OFF statement
B748   164 010 A4 0A LDY &0A
B74A   136 88 DEY
B74B   032 188 155 20 BC 9B JSR &9BBC Update BASIC Text pointer A (Add offset value & then reset offset to 1)
B74E d 100 010 64 0A STZ &0A
B750   165 011 A5 0B LDA &0B
B752   133 022 85 16 STA &16
B754   165 012 A5 0C LDA &0C
B756   133 023 85 17 STA &17
B758 L 076 174 143 4C AE 8F JMP &8FAE Skip the rest of the line and process the next program line
B75B   032 224 142 20 E0 8E JSR &8EE0 Get next non-space character pointed to by Ptr A
B75E   201 133 C9 85 CMP#&85
B760   240 223 F0 DF BEQ -33 --> &B741 Execute 'ON ERROR' statement
B762   198 010 C6 0A DEC &0A
B764 o 032 111 146 20 6F 92 JSR &926F Evaluate Expression at BASIC Text pointer A & convert the result to integer
B767   224 242 E0 F2 CPX#&F2
B769   240 009 F0 09 BEQ 9 --> &B774
B76B   200 C8 INY
B76C   224 229 E0 E5 CPX#&E5
B76E   240 004 F0 04 BEQ 4 --> &B774
B770   224 228 E0 E4 CPX#&E4
B772 v 208 118 D0 76 BNE 118 --> &B7EA 'ON syntax' error
B774   218 DA PHX
B775 + 165 043 A5 2B LDA &2B
B777 , 005 044 05 2C ORA &2C
B779 - 005 045 05 2D ORA &2D
B77B X 208 088 D0 58 BNE 88 --> &B7D5 Check for ELSE-token (if found then execute ELSE statement) otherwise issue 'ON range' error
B77D * 198 042 C6 2A DEC &2A
B77F 5 240 053 F0 35 BEQ 53 --> &B7B6 Execute the PROC/GOTO/GOSUB statement
B781 0R 048 082 30 52 BMI 82 --> &B7D5 Check for ELSE-token (if found then execute ELSE statement) otherwise issue 'ON range' error
B783   177 011 B1 0B LDA (&0B),Y
B785   201 013 C9 0D CMP#&0D
B787 L 240 076 F0 4C BEQ 76 --> &B7D5 Check for ELSE-token (if found then execute ELSE statement) otherwise issue 'ON range' error
B789 : 201 058 C9 3A CMP#&3A
B78B H 240 072 F0 48 BEQ 72 --> &B7D5 Check for ELSE-token (if found then execute ELSE statement) otherwise issue 'ON range' error
B78D   201 139 C9 8B CMP#&8B
B78F D 240 068 F0 44 BEQ 68 --> &B7D5 Check for ELSE-token (if found then execute ELSE statement) otherwise issue 'ON range' error
B791   200 C8 INY
B792 " 201 034 C9 22 CMP#&22
B794   208 004 D0 04 BNE 4 --> &B79A
B796 E+ 069 043 45 2B EOR &2B
B798 + 133 043 85 2B STA &2B
B79A + 166 043 A6 2B LDX &2B
B79C   208 229 D0 E5 BNE -27 --> &B783
B79E ) 201 041 C9 29 CMP#&29
B7A0   208 002 D0 02 BNE 2 --> &B7A4
B7A2 , 198 044 C6 2C DEC &2C
B7A4 ( 201 040 C9 28 CMP#&28
B7A6   208 002 D0 02 BNE 2 --> &B7AA
B7A8 , 230 044 E6 2C INC &2C
B7AA , 201 044 C9 2C CMP#&2C
B7AC   208 213 D0 D5 BNE -43 --> &B783
B7AE , 166 044 A6 2C LDX &2C
B7B0   208 209 D0 D1 BNE -47 --> &B783
B7B2 * 198 042 C6 2A DEC &2A
B7B4   208 205 D0 CD BNE -51 --> &B783
B7B6 h 104 68 PLA
B7B7   201 242 C9 F2 CMP#&F2
B7B9 H 240 072 F0 48 BEQ 72 --> &B803 Execute the PROC statement
B7BB   132 010 84 0A STY &0A
B7BD   201 228 C9 E4 CMP#&E4
B7BF   240 009 F0 09 BEQ 9 --> &B7CA
B7C1 * 032 042 184 20 2A B8 JSR &B82A Get Line Number & find Program Address of the Line Number
B7C4   032 198 155 20 C6 9B JSR &9BC6 Set PTR A Offset to 1 & Check for Escape error condition
B7C7 L# 076 035 183 4C 23 B7 JMP &B723 Jump to Program Line spec ified
B7CA * 032 042 184 20 2A B8 JSR &B82A Get Line Number & find Program Address of the Line Number
B7CD   164 010 A4 0A LDY &0A
B7CF   032 029 184 20 1D B8 JSR &B81D Skip the rest of the program statement (until a ':' or carriage return ('<cr>') character is found)
B7D2 L 076 220 182 4C DC B6 JMP &B6DC Check for end of statement & GOSUB the Line Number specified in the IWA
B7D5 h 104 68 PLA
B7D6   177 011 B1 0B LDA (&0B),Y
B7D8   200 C8 INY
B7D9   201 139 C9 8B CMP#&8B
B7DB : 240 058 F0 3A BEQ 58 --> &B817 Update PTR A Offset & execute the ELSE-statement
B7DD   201 013 C9 0D CMP#&0D
B7DF   208 245 D0 F5 BNE -11 --> &B7D6
B7E1   'ON range' error
B7EA   'ON syntax' error
B7F4   'No such line' error
B803   132 027 84 1B STY &1B
B805   032 213 142 20 D5 8E JSR &8ED5 Get next non-space character (PTR B)
B808   201 242 C9 F2 CMP#&F2
B80A   208 222 D0 DE BNE -34 --> &B7EA 'ON syntax' error
B80C   032 025 176 20 19 B0 JSR &B019 PROC
B80F   164 027 A4 1B LDY &1B
B811   032 029 184 20 1D B8 JSR &B81D Skip the rest of the program statement (until a ':' or carriage return ('<cr>') character is found)
B814 L 076 002 144 4C 02 90 JMP &9002 'Syntax error' if not end of statement; otherwise, execute next statement/program line
B817   132 010 84 0A STY &0A
B819 L) 076 041 156 4C 29 9C JMP &9C29 Find and execute the ELSE statement (if one is found)
B81C   200 C8 INY
B81D   177 011 B1 0B LDA (&0B),Y
B81F   201 013 C9 0D CMP#&0D
B821   240 004 F0 04 BEQ 4 --> &B827
B823 : 201 058 C9 3A CMP#&3A
B825   208 245 D0 F5 BNE -11 --> &B81C
B827   132 010 84 0A STY &0A
B829 ` 096 60 RTS

 


 Back to 8BS
Or