Mercurial > hg > index.cgi
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 ;