accumulated fixes

Fixing string compare issues, stack floor protection and conditional
NEXT.
This commit is contained in:
Klaus2m5 2018-07-20 12:27:18 +02:00
parent 241c4dc247
commit d9f570859a
2 changed files with 293 additions and 20 deletions

View File

@ -23,6 +23,7 @@ filled/emptied or a count is reached.
2. String handling when the string is in the input buffer.
fixed in 2.22p3
When a string is entered via the input buffer (Ibuffs - Ibuffe) in Ehbasic it
is transient because it gets overwritten by the next input. In this case it
@ -87,6 +88,7 @@ evaluate -1 correctly.
4. Use of decimal mode and invalid BCD
fixed in 2.22p
There is only one place in EhBASIC where decimal mode is used. HEX$() uses
invalid BCD to convert a number to a hexadecimal string. Some processors do not
@ -140,6 +142,7 @@ LAB_HEXS
5. Ibuffs located at $xx00
fixed in 2.22p
If the input buffer is located at the beginning of a page then any direct
statement (RUN, LIST, ...) is read from Ibuffs-$100 resulting in unexpected
@ -183,6 +186,7 @@ Ibuffe = Ibuffs+$47; end of input buffer
6. First statement after direct mode does not set the continue pointer
fixed in 2.22p2
After a RUN or GOTO in direct mode CONT does not work for the first statement in
run mode. It throws a "Can't continue error". If that first statement is INPUT
@ -195,4 +199,218 @@ only cleared later in the same loop.
The fix is in the patched folder (version 2.22p2). The continue counter is now
always saved and the decision to continue is postponed until the CONT statement
is executed and based on the fact that the continue pointer must not point to
the input buffer in run mode.
the input buffer in run mode.
LAB_1491
LDX #des_sk ; set descriptor stack pointer
STX next_s ; save descriptor stack pointer
PLA ; pull return address low byte
TAX ; copy return address low byte
PLA ; pull return address high byte
STX LAB_SKFE ; save to cleared stack
STA LAB_SKFF ; save to cleared stack
LDX #$FD ; new stack pointer
TXS ; reset stack
LDA #$00 ; clear byte
;*** fix p2: no longer necessary as the continue pointer is saved anyway
; STA Cpntrh ; clear continue pointer high byte
STA Sufnxf ; clear subscript/FNX flag
.........................................................................
LAB_15C2
JSR LAB_1629 ; do CRTL-C check vector
LDA Bpntrl ; get BASIC execute pointer low byte
LDY Bpntrh ; get BASIC execute pointer high byte
LDX Clineh ; continue line is $FFxx for immediate mode
; ($00xx for RUN from immediate mode)
INX ; increment it (now $00 if immediate mode)
;*** fix p2: skip no longer necessary as the continue pointer is saved anyway
; BEQ LAB_15D1 ; branch if null (immediate mode)
STA Cpntrl ; save continue pointer low byte
STY Cpntrh ; save continue pointer high byte
.........................................................................
LAB_163B
BNE LAB_167A ; if wasn't CTRL-C or there is a following byte return
LDA Bpntrh ; get the BASIC execute pointer high byte
;*** fix p2: skip no longer necessary as the continue pointer is saved anyway
; EOR #>Ibuffs ; compare with buffer address high byte (Cb unchanged)
; BEQ LAB_164F ; branch if the BASIC pointer is in the input buffer
; ; (can't continue in immediate mode)
; ; else ..
; EOR #>Ibuffs ; correct the bits
LDY Bpntrl ; get BASIC execute pointer low byte
.........................................................................
LAB_CONT
BNE LAB_167A ; if following byte exit to do syntax error
LDY Cpntrh ; get continue pointer high byte
CPY #>Ibuffs ; *** fix p2: test direct mode
BNE LAB_166C ; go do continue if we can
.........................................................................
LAB_1934
JSR LAB_CKRN ; check not Direct, back here if ok
JSR LAB_INLN ; print "? " and get BASIC input
LDA #$00 ; set mode = INPUT
CMP Ibuffs ; test first byte in buffer
BNE LAB_1953 ; branch if not null input
; *** change p2: keep carry set to throw break message
; CLC ; was null input so clear carry to exit program
JMP LAB_1647 ; go do BREAK exit
7. String compare of equal strings in direct mode returns FALSE
fixed in 2.22p4
The string descriptor pointer of the 1st string is loaded to FAC1 mantissa
bytes 2 & 3 and is later tranferred to FAC2 via the stack. The subroutine to put
FAC1 on the stack is rounding up if FAC1_r is > $7F. In string operations FAC1_r
is not initialized and rounding up may offset the string pointer high byte.
A patch is available to initialize FAC1_r to < $80 if the variable type is
string.
LAB_1C25
; *** begin patch string pointer high byte trashed when moved to stack
; *** add
LSR FAC1_r ; clear bit 7 (<$80) = do not round up
; *** end patch
RTS
8. FALSE value stored to a variable after string compare is not exactly zero
fixed in 2.22p4
When strings are compared and the result is stored to a variable (x=a$=b$) a
FALSE result is not exactly 0 but only less than 1-E16. So IF var evaluates as
true and falsely executes the statements after THEN.
After a compare FAC1 contains the result. The LET command should store FAC1 into
the variable but actually stores a string pointer.
A patch is available to fix the LET command.
LAB_LET
JSR LAB_GVAR ; get var address
STA Lvarpl ; save var address low byte
STY Lvarph ; save var address high byte
LDA #TK_EQUAL ; get = token
JSR LAB_SCCA ; scan for CHR$(A), else do syntax error then warm start
LDA Dtypef ; get data type flag, $FF=string, $00=numeric
PHA ; push data type flag
JSR LAB_EVEX ; evaluate expression
PLA ; pop data type flag
ROL ; set carry if type = string
; *** begin patch result of a string compare stores string pointer to variable
; but should store FAC1 (true/false value)
; *** replace
; JSR LAB_CKTM ; type match check, set C for string
; BNE LAB_17D5 ; branch if string
; *** with
JSR LAB_CKTM ; type match check, keep C (expected type)
BCS LAB_17D5 ; branch if string
; *** end patch
JMP LAB_PFAC ; pack FAC1 into variable (Lvarpl) and return
9. The stack floor protection does not cater for background interrupts
fixed in 2.22p4
EhBASIC makes heavy use of the stack. FOR, DO and GOSUB put their data
structures on the stack and can be nested only limited by the stack size. The
remaining free bytes on the stack are checked everytime a data structure is to
be stored on the stack. However, this check is not catering for the additional
stack space required by background interrupts of a monitor or operating system.
A patch is available to configure a value to raise the protected stack floor.
LAB_1212
; *** patch - additional stack floor protection for background interrupts
; *** add
.IF Stack_floor
CLC ; prep ADC
ADC #Stack_floor ; stack pointer lower limit before interrupts
.ENDIF
; *** end patch
STA TempB ; save result in temp byte
TSX ; copy stack
CPX TempB ; compare new "limit" with stack
BCC LAB_OMER ; if stack < limit do "Out of memory" error then warm start
RTS
You should also define Stack_floor with other configuation items. I put it just
after RAM_top.
Stack_floor = 16 ; bytes left free on stack for background interrupts
10. Conditional NEXT throws a "NEXT without FOR Error"
fixed in 2.22p4
If a NEXT statement is executed after IF THEN the FOR structure cannot be found.
The NEXT expects the FOR structure at a fixed offset on the stack but the
IF THEN puts an additional address on the stack. The additional address is
required as EhBASIC allows an ELSE statement on the same line and the statement
after the ELSE needs to be skipped.
The same is also true for other commands that need to find a data structure on
the stack. The code already contained a fix for a conditional RETURN but it
could not be used for LOOP (UNTIL/WHILE) or NEXT as it does not allow resuming
execution after falling through.
I have a fix that simply discards the original call to the "interpret statement"
routine (The one that executed the IF) and replaces the final RTS with a JMP to
the interpreter loop. This also eliminates the need to have a separate fix for
RETURN. To my big surprise even nested IFs work correctly.
LAB_174D
; *** patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
; *** replace
; CMP #TK_RETURN ; compare the byte with the token for RETURN
; BNE LAB_174G ; if it wasn't RETURN go interpret BASIC code from (Bpntrl)
; ; and return to this code to process any following code
;
; JMP LAB_1602 ; else it was RETURN so interpret BASIC code from (Bpntrl)
; ; but don't return here
;
;LAB_174G
; JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
;
;; the IF was executed and there may be a following ELSE so the code needs to return
;; here to check and ignore the ELSE if present
;
; LDY #$00 ; clear the index
; LDA (Bpntrl),Y ; get the next BASIC byte
; CMP #TK_ELSE ; compare it with the token for ELSE
; BEQ LAB_DATA ; if ELSE ignore the following statement
;
;; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
;; following ELSE will, correctly, cause a syntax error
;
; RTS ; else return to the interpreter inner loop
;
; *** with
PLA ; discard interpreter loop return address
PLA ; so data structures are at the correct stack offset
JSR LAB_GBYT ; restore token or variable
JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
; the IF was executed and there may be a following ELSE so the code needs to return
; here to check and ignore the ELSE if present
LDY #$00 ; clear the index
LDA (Bpntrl),Y ; get the next BASIC byte
CMP #TK_ELSE ; compare it with the token for ELSE
BNE LAB_no_ELSE ; no - continue on this line
JSR LAB_DATA ; yes - skip the rest of the line
; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
; following ELSE will, correctly, cause a syntax error
LAB_no_ELSE
JMP LAB_15C2 ; return to the interpreter inner loop
; *** end patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack

View File

@ -1,5 +1,5 @@
; Enhanced BASIC to assemble under 6502 simulator, $ver 2.22p3
; Enhanced BASIC to assemble under 6502 simulator, $ver 2.22p4
; $E7E1 $E7CF $E7C6 $E7D3 $E7D1 $E7D5 $E7CF $E81E $E825
@ -24,9 +24,15 @@
; changed INPUT to throw "break in line ##" on empty line input
; 2.22p3 fixed RAM above code / Ibuff above EhBASIC patch breaks STR$()
; fix provided by github user mgcaret
; 2.22p4 fixed string compare of equal strings in direct mode returns FALSE
; fixed FALSE stored to a variable after a string compare
; is > 0 and < 1E-16
; added additional stack floor protection for background interrupts
; fixed conditional LOOP & NEXT cannot find their data strucure on stack
; zero page use ..
; the following locations are bulk initialized from StrTab at LAB_GMEM
LAB_WARM = $00 ; BASIC warm start entry point
Wrmjpl = LAB_WARM+1; BASIC warm start vector jump low byte
Wrmjph = LAB_WARM+2; BASIC warm start vector jump high byte
@ -40,6 +46,7 @@ TWidth = $0F ; BASIC terminal width byte
Iclim = $10 ; input column limit
Itempl = $11 ; temporary integer low byte
Itemph = Itempl+1 ; temporary integer high byte
; end bulk initialize from StrTab at LAB_GMEM
nums_1 = Itempl ; number to bin/hex string convert MSB
nums_2 = nums_1+1 ; number to bin/hex string convert
@ -248,6 +255,7 @@ Cptrh = Aspth ; BASIC pointer temp low byte
Sendl = Asptl ; BASIC pointer temp low byte
Sendh = Aspth ; BASIC pointer temp low byte
; the following locations are bulk initialized from LAB_2CEE at LAB_2D4E
LAB_IGBY = $BC ; get next BASIC byte subroutine
LAB_GBYT = $C2 ; get current BASIC byte subroutine
@ -255,6 +263,7 @@ Bpntrl = $C3 ; BASIC execute (get byte) pointer low byte
Bpntrh = Bpntrl+1 ; BASIC execute (get byte) pointer high byte
; = $D7 ; end of get BASIC char subroutine
; end bulk initialize from LAB_2CEE at LAB_2D4E
Rbyte4 = $D8 ; extra PRNG byte
Rbyte1 = Rbyte4+1 ; most significant PRNG byte
@ -273,10 +282,8 @@ IrqBase = $DF ; IRQ handler enabled/setup/triggered flags
; = $E0 ; IRQ handler addr low byte
; = $E1 ; IRQ handler addr high byte
; = $DE ; unused
; = $DF ; unused
; = $E0 ; unused
; = $E1 ; unused
; *** removed unused comments for $DE-$E1
; = $E2 ; unused
; = $E3 ; unused
; = $E4 ; unused
@ -426,16 +433,20 @@ LAB_SKFE = LAB_STAK+$FE
LAB_SKFF = LAB_STAK+$FF
; flushed stack address
; the following locations are bulk initialized from PG2_TABS at LAB_COLD
ccflag = $0200 ; BASIC CTRL-C flag, 00 = enabled, 01 = dis
ccbyte = ccflag+1 ; BASIC CTRL-C byte
ccnull = ccbyte+1 ; BASIC CTRL-C byte timeout
VEC_CC = ccnull+1 ; ctrl c check vector
; end bulk initialize from PG2_TABS at LAB_COLD
; the following locations are bulk initialized by min_mon.asm from LAB_vec at LAB_stlp
VEC_IN = VEC_CC+2 ; input vector
VEC_OUT = VEC_IN+2 ; output vector
VEC_LD = VEC_OUT+2 ; load vector
VEC_SV = VEC_LD+2 ; save vector
; end bulk initialize by min_mon.asm from LAB_vec at LAB_stlp
; Ibuffs can now be anywhere in RAM, ensure that the max length is < $80,
; the input buffer must not cross a page boundary and must not overlap with
@ -449,6 +460,8 @@ Ibuffe = Ibuffs+$47; end of input buffer
Ram_base = $0300 ; start of user RAM (set as needed, should be page aligned)
Ram_top = $C000 ; end of user RAM+1 (set as needed, should be page aligned)
Stack_floor = 16 ; bytes left free on stack for background interrupts
; This start can be changed to suit your system
*= $C000
@ -473,7 +486,7 @@ LAB_2D13
LDA #$4C ; code for JMP
STA Fnxjmp ; save for jump vector for functions
; copy block from LAB_2CEE to $00BC - $00D3
; copy block from LAB_2CEE to $00BC - $00D7
LDX #StrTab-LAB_2CEE ; set byte count
LAB_2D4E
@ -695,6 +708,13 @@ LAB_120A
; stack too deep? do OM error
LAB_1212
; *** patch - additional stack floor protection for background interrupts
; *** add
.IF Stack_floor
CLC ; prep ADC
ADC #Stack_floor ; stack pointer lower limit before interrupts
.ENDIF
; *** end patch
STA TempB ; save result in temp byte
TSX ; copy stack
CPX TempB ; compare new "limit" with stack
@ -2021,14 +2041,35 @@ LAB_174C
; is var or keyword
LAB_174D
CMP #TK_RETURN ; compare the byte with the token for RETURN
BNE LAB_174G ; if it wasn't RETURN go interpret BASIC code from (Bpntrl)
; and return to this code to process any following code
JMP LAB_1602 ; else it was RETURN so interpret BASIC code from (Bpntrl)
; but don't return here
LAB_174G
; *** patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
; *** replace
; CMP #TK_RETURN ; compare the byte with the token for RETURN
; BNE LAB_174G ; if it wasn't RETURN go interpret BASIC code from (Bpntrl)
; ; and return to this code to process any following code
;
; JMP LAB_1602 ; else it was RETURN so interpret BASIC code from (Bpntrl)
; ; but don't return here
;
;LAB_174G
; JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
;
;; the IF was executed and there may be a following ELSE so the code needs to return
;; here to check and ignore the ELSE if present
;
; LDY #$00 ; clear the index
; LDA (Bpntrl),Y ; get the next BASIC byte
; CMP #TK_ELSE ; compare it with the token for ELSE
; BEQ LAB_DATA ; if ELSE ignore the following statement
;
;; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
;; following ELSE will, correctly, cause a syntax error
;
; RTS ; else return to the interpreter inner loop
;
; *** with
PLA ; discard interpreter loop return address
PLA ; so data structures are at the correct stack offset
JSR LAB_GBYT ; restore token or variable
JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
; the IF was executed and there may be a following ELSE so the code needs to return
@ -2037,12 +2078,15 @@ LAB_174G
LDY #$00 ; clear the index
LDA (Bpntrl),Y ; get the next BASIC byte
CMP #TK_ELSE ; compare it with the token for ELSE
BEQ LAB_DATA ; if ELSE ignore the following statement
BNE LAB_no_ELSE ; no - continue on this line
JSR LAB_DATA ; yes - skip the rest of the line
; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
; following ELSE will, correctly, cause a syntax error
RTS ; else return to the interpreter inner loop
LAB_no_ELSE
JMP LAB_15C2 ; return to the interpreter inner loop
; *** end patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
; perform ELSE after IF
@ -2239,8 +2283,15 @@ LAB_LET
JSR LAB_EVEX ; evaluate expression
PLA ; pop data type flag
ROL ; set carry if type = string
JSR LAB_CKTM ; type match check, set C for string
BNE LAB_17D5 ; branch if string
; *** begin patch result of a string compare stores string pointer to variable
; but should store FAC1 (true/false value)
; *** replace
; JSR LAB_CKTM ; type match check, set C for string
; BNE LAB_17D5 ; branch if string
; *** with
JSR LAB_CKTM ; type match check, keep C (expected type)
BCS LAB_17D5 ; branch if string
; *** end patch
JMP LAB_PFAC ; pack FAC1 into variable (Lvarpl) and return
@ -3259,6 +3310,10 @@ LAB_1C24
JMP LAB_UFAC ; unpack memory (AY) into FAC1
LAB_1C25
; *** begin patch string pointer high byte trashed when moved to stack
; *** add
LSR FAC1_r ; clear bit 7 (<$80) = do not round up
; *** end patch
RTS
; get value from line .. continued
@ -7842,7 +7897,7 @@ LAB_MSZM
LAB_SMSG
.byte " Bytes free",$0D,$0A,$0A
.byte "Enhanced BASIC 2.22p3",$0A,$00
.byte "Enhanced BASIC 2.22p4",$0A,$00
; numeric constants and series