changeset 94:5fa8c479dbf7

Make E notation parse correctly, and also leading decimals, and other details
author William Astle <lost@l-w.ca>
date Sun, 22 Oct 2023 17:25:16 -0600
parents a4db504611e2
children 25b44f1ac2aa
files src/number.s
diffstat 1 files changed, 43 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/number.s	Tue Oct 17 17:26:45 2023 -0600
+++ b/src/number.s	Sun Oct 22 17:25:16 2023 -0600
@@ -125,8 +125,7 @@
 ; 4b. If the number is an integer in the range of -0x80000000 to 0x7fffffff, it is converted to a signed binary integer
 ;    and the result is returned
 ; 4b. Set the exponent correctly then normalize the result to val0
-val_parsenum    lbeq SNERROR                    ; brif no numberr to parse
-                ldd zero                        ; zero out digit accumulator
+val_parsenum    ldd zero                        ; zero out digit accumulator
                 std fpa0+fpa.sig
                 std fpa0+fpa.sig+2
                 std fpa0+fpa.sig+4
@@ -136,21 +135,24 @@
                 std fpaextra+4                  ; clear out decimal exponent and sign
                 std fpaextra                    ; set digit count and decimal flag to zero and no decimal
                 sta fpaextra+2                  ; set decimal position to 0 - unused if decimal not seen
+                sta fpaextra+6                  ; set number of leading zeroes seen
                 ldx #fpa0+fpa.sig               ; point to digit storage location
                 lda #0xf0                       ; set digit mask
                 sta fpaextra+3
                 jsr curchar                     ; get back current input
-                bra val_parsenum1
+                bne val_parsenum1               ; brif we have input
+                jmp SNERROR                     ; raise syntax error
 val_parsenum0   jsr nextchar                    ; fetch next input
 val_parsenum1   bcs val_parsenum3               ; brif digit - short ciruit other checks
                 cmpa #'.                        ; does it start with a decimal?
-                beq val_parsenum5               ; brif so
+                beq val_parsenum5a              ; brif so
                 cmpa #'+                        ; unary plus?
                 beq val_parsenum0               ; brif so - it's a no-op but supported for symmetry with unary minus
                 cmpa #'-                        ; negative?
                 bne val_parsenum5               ; brif not
                 com fpa0+fpa.sign               ; invert the sign
                 bra val_parsenum0               ; eat the sign and see if there's more signs
+val_parsenum1a  inc fpaextra+6                  ; bump zero counter
 val_parsenum2   jsr nextchar                    ; fetch next character in number
                 bcc val_parsenum5               ; brif not a digit
 val_parsenum3   ldb fpaextra                    ; is it within the digit count?
@@ -161,7 +163,8 @@
                 tstb                            ; no digits?
                 bne val_parsenum3a              ; brif not - we've seen something significant
                 ldb fpaextra+1                  ; decimal seen?
-                bne val_parsenum2               ; brif not - skip leading zeroes
+                bne val_parsenum1a              ; brif so - count the leading zeros
+                bra val_parsenum2               ; otherwise don't count it and skip it
 val_parsenum3a  ldb #0x11                       ; put in both digit spots
                 mul
                 andb fpaextra+3                 ; only keep the one we need
@@ -171,20 +174,27 @@
                 bpl val_parsenum4               ; brif not moving to new location
                 leax 1,x                        ; move to new digit storage location
 val_parsenum4   inc fpaextra                    ; bump digit count
-                lbmi OVERROR                    ; brif it overflowed - we can't parse more than 127 digits!
-                ldb fpaextra+2                  ; get decimal position counter
-                subb fpaextra+1                 ; subtract decimal flag (will be 0xff or -1 if decimal seen)
-                stb fpaextra+2
+                bmi val_overror                 ; brif it overflowed - we can't parse more than 127 digits!
                 bra val_parsenum2               ; go handle another digit or whatever
 val_parsenum5   cmpa #'.                        ; decimal?
                 bne val_parsenum6               ; brif not
+val_parsenum5a  ldb fpaextra                    ;* set decimal offset (digits to the left of decimal), account for
+                stb fpaextra+2
                 com fpaextra+1                  ; flag decimal seen
                 lbeq SNERROR                    ; brif already seen a decimal point - syntax error
-                bra val_parsenum2               ; go parse more digits
-val_parsenum6   cmpa #'E                        ; decimal exponent?
+                bra val_parsenum2               ; process more digits
+val_parsenum6   ldb fpaextra                    ; get number of digits provided; will be exponent if no decimal
+                tst fpaextra+1                  ; decimal seen?
+                beq val_parsenum6a              ; brif not
+                ldb fpaextra+2                  ; get decimal offset - this is the exponent
+val_parsenum6a  decb                            ; adjust for the decimal position in the significand
+                subb fpaextra+6                 ; account for leading zeroes after the decimal point
+                bvs val_overror                 ; brif it overflowed
+                stb fpa0+fpa.exp                ; save base exponent of number
+                cmpa #'E                        ; decimal exponent?
                 beq val_parsenum7               ; brif so
                 cmpa #'e                        ; lower case exponent indicator?
-                bne val_parsenum11              ; brif not - we have the end of the number here
+                bne val_parsenum11b             ; brif not - we have the end of the number here
 val_parsenum7   jsr nextchar                    ; eat exponent indicator
                 bcs val_parsenum9               ; brif digit
                 cmpa #'+                        ; positive?
@@ -201,24 +211,35 @@
 val_parsenum9   suba #0x30                      ; binary-ize the digit
                 sta fpaextra+6                  ; save digit value
                 ldb fpaextra+4                  ; get calculated exponent
-                lda #10                         ; multiply by 10
+                lda #10                         ; multiply by 10, MUL sets C equal to bit 7 of B
                 mul
-                lbcs OVERROR                    ; brif decimal exponent overlows ±127 - we just don't handle that
-                addb fpaextra+6                 ; add digit in
-                lbmi OVERROR                    ; same as above - make sure exponent in range
+                bcc val_parsenum9a              ; don't brif ±127 - we just don't handle that
+val_overror     jmp OVERROR                     ; raise overflow
+val_parsenum9a  addb fpaextra+6                 ; add digit in
+                bvs val_overror                 ; brif we went above 63
                 stb fpaextra+4                  ; save new decimal exponent
                 bra val_parsenum8               ; handle another digit
 val_parsenum10  lda fpaextra+5                  ; get sign of exponent
                 bpl val_parsenum11              ; brif positive
                 neg fpaextra+4                  ; negate resulting exponent
-val_parsenum11  ldb fpaextra                    ; get number of digits provided
-                subb fpaextra+2                 ; subtract out count of fractional digits giving whole number digits
+val_parsenum11  ldb fpa0+fpa.exp                ; get significand exponent
                 addb fpaextra+4                 ; add in decimal exponent adjustment
-                stb fpa0+fpa.exp                ; set result exponent
+                bvs val_overror                 ; brif it overflowed
+                stb fpa0+fpa.exp
+val_parsenum11b cmpb #63                        ; too high?
+                bgt val_overror                 ; brif too high
+                cmpb #-64                       ; too low?
+                bge val_parsenum11a             ; brif so - minimize to "0"
+                ldb #valtype_int                ; set result to integer
+                stb val0+val.type
+                ldd zero                        ; set result to zero
+                std val0+val.int
+                std val0+val.int+2
+                rts
 ; Normalization is not required here though rounding might be. Rounding will be handled during floating point return.
 ; By ensuring there were no leading zeroes converted, the result is already pre-normalized without losing precision due
 ; to an aribtrary number of leading zeroes.
-                cmpb fpaextra                   ; is the exponent less than the number of digits?
+val_parsenum11a cmpb fpaextra                   ; is the exponent less than the number of digits?
                 blt val_parsenum13              ; brif so - return floating point (signed comparison!)
                 cmpb #10                        ; is exponent in the range for a binary integer?
                 bgt val_parsenum13              ; brif not - return floating point
@@ -241,8 +262,8 @@
                 bpl val_parsenum14              ; brif not - doesn't fit in integer
 val_parsenum13  lda #valtype_float              ; set return value to floating point
                 sta val0+val.type
-                lda fpa0+fpa.exp                ; put the bias into the exponent but subtract one for leading digit
-                adda #63
+                lda fpa0+fpa.exp                ; put the bias into the exponent
+                adda #64
                 sta fpa0+fpa.exp
                 ldy #val0+val.value             ; normalize/round and return the result
                 jmp fps_normalize