# HG changeset patch # User William Astle # Date 1698017116 21600 # Node ID 5fa8c479dbf71788e61701c9b97e1b402e6b286f # Parent a4db504611e2bdbf4bd15bba1d8e9a5c5aef0bbb Make E notation parse correctly, and also leading decimals, and other details diff -r a4db504611e2 -r 5fa8c479dbf7 src/number.s --- 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