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