changeset 77:ba559f231929

Initial modification for number parser that handles floats and ints
author William Astle <lost@l-w.ca>
date Thu, 10 Aug 2023 00:24:52 -0600
parents eb2681108660
children 718f9b7381b3
files src/defs.s src/expr.s
diffstat 2 files changed, 145 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/defs.s	Sun Aug 06 00:51:22 2023 -0600
+++ b/src/defs.s	Thu Aug 10 00:24:52 2023 -0600
@@ -46,6 +46,11 @@
 valtype_float   equ 2                           ; float type (40 bit) value
 valtype_string  equ 3                           ; string type (16 bit length, 16(32) bit data pointer
 ; Value accumulator structure definitions
+;
+; Notes:
+;
+; Much code using value accumulators depends on the specific layout of this structure so reorganizing it is dangerous.
+; Notably, the integer value and floating point mantissa must be at the same offset.
 val.type        equ 6                           ; value type offset
 val.fpexp       equ 0                           ; fp exponent offset
 val.fpmant      equ 1                           ; fp mantissa offset
--- a/src/expr.s	Sun Aug 06 00:51:22 2023 -0600
+++ b/src/expr.s	Thu Aug 10 00:24:52 2023 -0600
@@ -67,30 +67,52 @@
                 cmpa #'+                        ; positive sign?
                 beq eval_number                 ; brif so - evaluate number
 eval_term0      jmp SNERROR                     ; we have something unrecognized - raise error
-; Evaluate a number constant. Currently this only handles 32 bit integers.
-eval_number     ldb #valtype_int                ; start with integer value
-                stb val0+val.type               ; set return value
-                ldx zero                        ; blank out the value
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Evaluate a numeric constant. This process works as follows:
+;
+; 0. Clear the value to a zero integer
+; 1. Check for signs and flag appropriately
+; 2. Read character
+; 3. If decimal or exponential indicator, go to step 6
+; 4. If not digit, return integer result
+; 5. Multiply accumulator by 10 and add digit value; go back to step 2
+; 6. Convert accumulator to floating point; set accumulated decimal exponent and decimal flag to 0
+; 7. If decimal point, flag decimal seen (0xff) and go to step 15 (or raise error if second decimal point)
+; 8. If digit, multiply by 10 and add digit value; go to step 15
+; 9. If E or e, go handle decimal exponent at step 12
+; 10. Apply accumulated decimal exponent to the result (through multiplication/division by 10)
+; 11. Return floating point result
+; 12. Read character
+; 13. If not digit, go handle return at step 10
+; 14. Multiply exponent accumulator by 10 and add digit value; raise error on overflow or go back to step 12
+; 15. Read a character and go to step 7
+;
+; If the result ends up being larger than a floating point value can hold, return Overflow
+eval_number     ldb #valtype_int                ; flag result as an integer
+                stb val0_val.type
+                ldx zero                        ; blank out the value except type
                 stx val0
                 stx val0+2
                 stx val0+4
                 bra eval_number1                ; go do the parsing
 eval_number0    jsr nextchar                    ; fetch next input
-                beq eval_numberr                ; brif end of expression - bail
+                beq eval_number6                ; brif end of expression - bail
 eval_number1    cmpa #'-                        ; negative (ascii sign)?
                 beq eval_number3                ; brif so
                 cmpa #tok_minus                 ; negative (operator negative)?
                 bne eval_number2                ; brif not
-eval_number3    com val0+val.fpsign             ; invert sign
+eval_number3    com val0+val.fpsign             ; invert sign (multiple negatives will flip this multiple times)
                 bra eval_number0                ; deal with next input
 eval_number2    cmpa #'+                        ; unary +?
                 beq eval_number0                ; brif so - skip it
+                cmpa #tok_plus                  ; unary + (operator plus)?
+                beq eval_number0                ; brif so - skip it
 eval_number5    cmpa #'.        	; decimal point?
-	beq eval_float                  ; brif decimal - force float
+	beq eval_number8                ; brif decimal - force float
                 cmpa #'0                        ; is it a number?
-                blo eval_numberr                ; brif below digit
+                blo eval_number6                ; brif below digit
                 cmpa #'9                        ; is it still a number?
-                bhi eval_numberr                ; brif above digit
+                bhi eval_number6                ; brif above digit
                 suba #'0                        ; offset to binary digit value
                 pshs a                          ; save digit value
                 ldx val0+val.int                ; get current value for later (for quick multiply by 10)
@@ -100,12 +122,12 @@
                 rol val0+val.int+2
                 rol val0+val.int+1
                 rol val0+val.int
-                bcs OVERROR                     ; brif overflowed
+                rol val0+val.fpexp              ; overflow into fp exponent
                 lsl val0+val.int+3              ; times 4
                 rol val0+val.int+2
                 rol val0+val.int+1
                 rol val0+val.int
-                bcs OVERROR                     ; brif overflowed
+                rol val0+val.fpexp              ; brif overflowed
                 ldd val0+val.int+2              ; times 5 (add original value)
                 addd ,s++
                 std val0+val.int+2
@@ -113,12 +135,14 @@
                 adcb 1,s
                 adca ,s++
                 std val0+val.int
-                bcs OVERROR
+                ldb val0+val.fpexp              ; and handle overflow bits
+                adcb #0
+                stb val0+val.fpexp
                 lsl val0+val.int+3              ; times 10
                 rol val0+val.int+2
                 rol val0+val.int+1
                 rol val0+val.int
-                bcs OVERROR                     ; brif overflowed
+                rol val0+val.fpexp
                 ldd val0+val.int+2              ; get low word
                 addb ,s+                        ; add in current digit
                 adca #0
@@ -127,21 +151,116 @@
                 adcb #0
                 adca #0
                 std val0+val.int
-                bcs OVERROR                     ; brif overflowed
+                lda val0+val.fpexp              ; and handle overflow
+                adca #0
+                sta val0+val.fpexp
+                bne eval_number11               ; if we overflowed, go continue parsing as floating point
+                lda val0+val.int                ; get back high byte and check for overflow
                 bpl eval_number4                ; brif we haven't wrapped negative
                 cmpd #0x8000                    ; is it valid negative two's complement?
-                bhi OVERROR                     ; brif not
+                bhi eval_number11               ; brif not - we're in floating point territory
                 ldd val0+val.int+2              ; is it still valid two's complement (max negative)?
-                bne OVERROR                     ; brif so
+                bne eval_number11               ; brif not - we're in floating point territory
 eval_number4    jsr nextchar                    ; fetch next input character
                 bra eval_number5                ; go handle it
+eval_number6    cmpa #'E                        ; base 10 exponent?
+                beq eval_number8                ; brif so
+                cmpa #'e                        ; base 10 exponent in lower case?
+                beq eval_number8                ; brif so
+                ldb val0+val.fpsign             ; did we want a negative value?
+                beq eval_number7                ; brif not
+                jsr val_negint32                ; negate the 32 bit integer to correct two's complement
+eval_number7    clr val0+val.fpsign             ; clear sign bits for book keeping
+                rts
+eval_number11   jsr nextchar                    ; each the character already processed
+eval_number8    lda #0x9f                       ; exponent if binary point is to the right of the mantissa                           
+                clr val0extra                   ; clear extra precision bits for val0
+                ldb #valtype_float              ; flag value as floating point
+                stb val0+val.type
+                ldb val0+val.fpexp              ; do we have overflow bits to shift?
+                beq eval_number10               ; brif not
+eval_number9    inca                            ; bump exponent to account for extra bits
+                lsrb                            ; shift some bits over
+                ror val0+val.fpmant
+                ror val0+val.fpmant+1
+                ror val0+val.fpmant+2
+                ror val0+val.fpmant+3
+                ror val0extra
+                tstb                            ; all bits shifted into mantissa?
+                bne eval_number9                ; brif not
+eval_number10   sta val0+val.fpexp              ; save adjusted exponent
+                ldx #val0                       ; normalize the result for further operations
+                jsr fp_normalize
+                clr ,-s                         ; flag for decimal point seen
+                clr ,-s                         ; current decimal exponent value
+                jsr curchar                     ; get current input character
+                bra eval_number20               ; go evaluate the floating point value
+eval_number40   jsr nextchar                    ; fetch next input
+eval_number20   bcs eval_number29               ; brif digit
+                cmpa #'.                        ; is it a decimal?
+                bne eval_number21               ; brif not
+                com 1,s                         ; flag decimal seen
+                bne eval_number40
+                jmp SNERROR                     ; brif unexpected second decimal point
+eval_number21   cmpa #'E                        ; decimal exponent?
+                beq eval_number26               ; brif so
+                cmpa #'e                        ; decimal exponent lower case?
+                beq eval_number26
+eval_number22   ldb ,s                          ; get decimal exponent count and set flags
+                beq eval_number25               ; brif no adjustment needed
+                bmi eval_number24               ; brif we need to divide
+eval_number23   jsr fp_mul10                    ; multiply by 10
+                dec ,s                          ; done?
+                bne eval_number23               ; brif not
+                rts
+eval_number24   jsr fp_div10                    ; divide by 10
+                inc ,s                          ; done?
+                bne eval_number24               ; brif not
+eval_number25   rts
+eval_number26   clrb                            ; blank out decimal exponent accumulator
+                clr ,-s                         ; set sign positive
+                jsr nextchar                    ; get next input
+                bcs eval_number28               ; brif digit - positive exponent
+                cmpa #'+                        ; positive?
+                beq eval_number27               ; brif so - skip it
+                cmpa #tok_plus                  ; positive (plus operator)?
+                beq eval_number27
+                cmpa #'-                        ; negative?
+                beq eval_number30               ; brif so
+                cmpa #tok_minus                 ; negative (minus operator)?
+                bne eval_number31               ; brif not
+eval_number30   com ,s                          ; get sign negative
+eval_number27   jsr nextchar                    ; get next character
+                bcs eval_number28               ; brif digit
+eval_number31   lda ,s+                         ; get negative flag, set flags, and clean up the stack
+                beq eval_number32               ; brif positive
+                negb                            ; we have a negative decimal exponent - handle it
+eval_number32   addb ,s                         ; add in decimal exponent adjustment
+                stb ,s                          ; save it for cleanup
+                bra eval_number22               ; go finish up
+eval_number28   suba #'0                        ; digit-ize it
+                pshs a                          ; save it for later
+                lda #10                         ; multiply value by 10 and add digit
+                mul
+                addb ,s+
+                bpl eval_number27               ; go handle another digit if we didn't overflow negative
 OVERROR         ldb #err_ov                     ; flag overflow
                 jmp ERROR
-eval_numberr    ldb val0+val.fpsign             ; is the number we want negative?
-                beq eval_numberr0               ; brif not
-                jsr val_negint32                ; negate the integer
-eval_numberr0   rts
-eval_float      jmp SNERROR                     ; we don't handle floating point yet
+eval_number29   ldb ,s                          ; get exponent adjustment
+                addb 1,s                        ; subtract if decimal point was seen for later fixup
+                stb 1,s
+                suba #'0                        ; digit-ize the character
+                pshs a                          ; save it for later
+                jsr fp_mul10                    ; multiply by 10
+                jsr val0toval1                  ; save residue
+                puls b                          ; get back digit value
+                clra                            ; make it floating point
+                std val0+val.int+2
+                sta val0+val.int+1
+                sta val0+val.int
+                jsr val_int32tofloat            ; convert to floating point
+                jsr fp_add                      ; add val1 to val0
+                bra eval_number40               ; go handle another character
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; Operator table
 ;