changeset 101:b0422868a7b1

Clean up numeric operator dispatch.
author William Astle <lost@l-w.ca>
date Mon, 23 Oct 2023 23:15:55 -0600
parents 6db72a92ff7a
children baead5689afc
files src/expr.s src/number.s
diffstat 2 files changed, 47 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/src/expr.s	Mon Oct 23 22:46:55 2023 -0600
+++ b/src/expr.s	Mon Oct 23 23:15:55 2023 -0600
@@ -32,7 +32,6 @@
                 puls b,pc                       ; return current value to complete previous operation
 eval_expr3      jsr nextchar                    ; eat the operator token
                 ldx 1,x                         ; get handler address of this operator
-                leas -val.size,s                ; make room for the result accumulator
                 pshs x                          ; save handler address for later
                 lda val0+val.type               ; get current value type
                 ldx val0                        ; get value accumlator contents (6 bytes)
@@ -45,15 +44,7 @@
                 sty val1+2
                 stu val1+4
                 sta val1+val.type               ; save previous value type
-                ldx #val1                       ; point to left operand
-                ldu #val0                       ; point to right operand
-                leay 2,s                        ; point to return value location
                 jsr [,s++]                      ; go handle the operator
-                puls a,x,y,u                    ; get return value
-                sta val0
-                stx val0+1
-                sty val0+3
-                stu val0+5
                 puls b                          ; get back the previous operator precedence
                 bra eval_expr0                  ; go process another operator or end of expression
 eval_term       jsr curchar                     ; get current input character
@@ -99,9 +90,9 @@
                 fcb 0x79                        ; subtraction
                 fdb oper_minus
                 fcb 0x7b                        ; multiplication
-                fdb SNERROR
+                fdb oper_times
                 fcb 0x7b                        ; division
-                fdb SNERROR
+                fdb oper_divide
                 fcb 0x7f                        ; exponentiation
                 fdb SNERROR
                 fcb 0x64                        ; less than
@@ -124,14 +115,41 @@
 ; Operator handling routines
 ;
 ; binary plus: addition and concatenation
-oper_plus       ldb val.type,x                  ; get type of the left operand
+oper_plus1      fdb int32_add
+                fdb fps_add
+oper_plus       ldb val1+val.type               ; get type of the left operand
                 cmpb valtype_string             ; is it string?
                 bne oper_plus0                  ; brif not
-                cmpb val.type,u                 ; is right operand also string?
+                cmpb val0+val.type              ; is right operand also string?
                 lbeq SNERROR                    ; brif so - do string concatenation
-oper_plus0      jsr val_matchtypes              ; go match data types
-                jmp val_add                     ; go add the values
+oper_plus0      ldd #oper_plus1-2               ; point to operation destination
+                ; fall through
+; Match numeric operand types and dispatch operator based on the resulting matched type. Enter with *D* pointing to
+; the dispatch table. Note that type 0 will need to be skipped. Typically this will be called with JMP.
+oper_dispatch   pshs d                          ; save the dispatch table location
+                jsr val_matchtypes              ; match operand types
+                puls x                          ; get back type pointer
+                ldb val1+val.type               ; get operation type
+                lslb                            ; two bytes per pointer
+                ldx b,x                         ; get destination routine
+                pshs x                          ; save routine address
+                ldx #val1                       ; point to left operand
+                ldu #val0                       ; point to right operand
+                leay ,u                         ; point to return location
+                rts                             ; call routine
 ; binary minus: subtraction
-oper_minus      jsr val_matchtypes              ; go match data types
-                jmp val_sub                     ; do subtraction
+oper_minus      ldd #oper_minus0-2              ; point to jump table
+                bra oper_dispatch               ; go handle it
+oper_minus0     fdb int32_sub
+                fdb fps_sub
+; multiplication
+oper_times      ldd #oper_times0-2              ; point to jump table
+                bra oper_dispatch               ; go handle it
+oper_times0     fdb int32_mul
+                fdb fps_mul
+; division
+oper_divide     ldd #oper_divide0-2             ; point to jump table
+                bra oper_dispatch               ; go handle it
+oper_divide0    fdb int32_div
+                fdb fps_div
                 *pragmapop list
--- a/src/number.s	Mon Oct 23 22:46:55 2023 -0600
+++ b/src/number.s	Mon Oct 23 23:15:55 2023 -0600
@@ -6,100 +6,39 @@
 ; This section contains routines that handle floating point and integer arithmetic. It mostly delegates to int.s and
 ; fps.s.
 ;
-; Most routines take a pointer to a value accumulator in X. Some take two pointers with the second in U.
+; Most of these routines take a single parameter in val0 or two parameters in val0 and val1. They will typically return
+; their results in val0.
+;
+; For binary operations, the left operand will be in val1 and the right operand will be in val0.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; Match operands for a numeric calculation. This works as follows:
 ;
 ; * If both operands are the same, ensure the type is numeric and return
 ; * If one operand is floating point, convert the other to floating point, as long as it is numeric
 ; * If one or both operands are not numeric, raise a type mismatch
-; The operands are in (X) and (U)
-val_matchtypes  ldb val.type,x                  ; get the type of first argument
+; The operands are in val0 and val1
+val_matchtypes  ldb val0+val.type               ; get the type of first argument
                 cmpb #valtype_int               ; is it integer?
                 beq val_matchtypes0             ; brif so
                 cmpb #valtype_float             ; is it floating point?
                 beq val_matchtypes1             ; brif so
 TMERROR         ldb #err_tm                     ; raise a type mismatch
                 jmp ERROR
-val_matchtypes0 ldb val.type,u                  ; get type of second operand
+val_matchtypes0 ldb val1+val.type               ; get type of second operand
                 cmpb #valtype_int               ; is it integer?
                 bne val_matchtypes2             ; brif not
 val_matchtypes3 rts                             ; both types int - we're good so return
 val_matchtypes2 cmpb #valtype_float             ; is it floating point?
                 bne TMERROR                     ; brif not - raise error
-                pshs x                          ; save X which may be clobbered
-                leay ,x                         ; point to input operand as destination for conversion
-;                jsr fps_fromint32               ; convert first argument to floating point
-                puls x,pc                       ; restore second operand pointer and return
-val_matchtypes1 ldb val.type,u                  ; get second argument type
+                ldx #val0                       ; convert the first argument to floating point
+                jmp fps_fromint
+val_matchtypes1 ldb val1+val.type               ; get second argument type
                 cmpb #valtype_float             ; is it floating point?
                 beq val_matchtypes3             ; brif so - we're good
                 cmpb #valtype_int               ; is it integer?
                 bne TMERROR                     ; brif not - invalid type combination
-                pshs x                          ; save X which mill be clobbered
-                leax ,u                         ; convert (U) to floating point
-                leay ,u
-;                jsr fps_fromint32
-                puls x,pc                       ; restore argument pointer and return
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Addition and subtraction of values; must enter with values of matching types and the result type already set
-; to the correct type.
-;
-; Calculates (X) + (U) -> (Y) (addition)
-; Calculates (X) - (U) -> (Y) (subtraction)
-val_add         ldb val.type,x                  ; get type of left operand
-                cmpb valtype_int                ; is it integer?
-                lbeq int32_add                  ; brif so - do integer addition
-                cmpb #valtype_float             ; floating point?
-                lbeq fps_add                    ; brif so - do floating point addition
-                jmp TMERROR                     ; we have a type we don't understand
-val_sub         ldb val.type,x                  ; get type of left operand
-                cmpb valtype_int                ; is it integer?
-                lbeq int32_sub                  ; brif so - do integer addition
-                cmpb #valtype_float             ; floating point?
-                lbeq fps_sub                    ; brif so - do floating point addition
-                jmp TMERROR                     ; we have a type we don't understand
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Multiplication
-;
-; Calculates (X) × (U) -> (Y)
-;
-; The result might overflow the integer type. In this case, an actual overflow error will occur.
-val_mul         ldb val.type,x                  ; get type of left operand
-                cmpb #valtype_int               ; integer?
-                lbeq int32_mul                  ; brif so - do integer multiplication
-                cmpb #valtype_float             ; is it float?
-                lbeq fps_mul                    ; brif so - do floating point multiplication
-                jmp TMERROR                     ; have an unhandled type - bail on it
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Division
-;
-; Calculates (X) ÷ (U) -> (Y)
-;
-; The integer operation simply truncates the result ("rounds toward zero")
-val_div         ldb val.type,x                  ; get type of left operand
-                cmpb #valtype_int               ; integer?
-                lbeq int32_div                  ; brif so - do integerdivision
-                cmpb #valtype_float             ; floating point?
-                lbeq fps_div                    ; brif so - do floating point division
-                jmp TMERROR                     ; unsupported type
-                if 0
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Modulus - note that this is a division operator returning effectively the remainder, not an absolute value as is
-; sometimes meant by "modulus".
-;
-; Calculates (X) <MOD> (U) -> (Y)
-;
-; Note: modulus will have the same sign as the quotient so that (U) * [(X) / (U)] + [(X) MOD (U)] gives (X) (integer)
-; Note2: the modulus can be calculated on floating point values in which case it will represent the fraction part
-;    of the quotient multiplied by the divisor, again with the same sign as the quotient
-val_mod         ldb val.type,x                  ; get type of left operand
-                cmpb #valtype_int               ; integer?
-                lbeq int32_mod                  ; do integer modulus
-                cmpb #valtype_float             ; floating point?
-                lbeq fps_mod                    ; floating point modulus
-                jmp TMERROR                     ; unsupported type
-                endc
+                ldx #val1                       ; convert the second argument to floating point
+                jmp fps_fromint
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; Parse a number to either an integer or a floating point value and return the result in val0
 ;