view src/expr.s @ 125:0607e4e20702

Correct offset error for keyword table lookup
author William Astle <lost@l-w.ca>
date Sun, 07 Jan 2024 20:35:51 -0700
parents cddbe8bc07e5
children 9d57279c900e
line wrap: on
line source

                *pragmapush list
                *pragma list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The LET command which is the default if no token begins a statement
cmd_let         jmp SNERROR                     ; not yet implemented
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Expression Evaluation Package
;
; This is the expression evaluator. It handles everything from parsing numbers to dispatching function calls. The main
; entry point is eval_expr which will evaluate an arbitrary expression. It returns as soon as it reaches something it
; doesn't understand as part of an expression.
;
; The special handling for relational operators is required because Basic allows them in all 
eval_expr       clrb                            ; flag previous operator as minimum precdence (end of expression)
eval_expraux    pshs b                          ; save precedence flag
                jsr eval_term                   ; evaluate the first term of the expression
                puls b                          ; get back operator precedence flag
eval_expr0      jsr curchar                     ; fetch current input
                beq eval_expr1                  ; brif end of expression - we're done
                cmpa #tok_or                    ; is it above operators?
                bhi eval_expr1                  ; brif so
                suba #tok_plus                  ; offset to zero for first operator token
                bcc eval_expr2                  ; brif it is an operator
eval_expr1      rts
eval_expr2      pshs b                          ; save previous operator precedence
                ldx #oper_tab                   ; point to operator table
                tfr a,b                         ; shift to B for "ABX"
                abx                             ; add three times (3 bytes per entry)
                abx                             ; OBS: TFR + ABX + ABX + ABX is faster than LDB + MUL + ABX
                abx                             ; now X points to the operator entry in the table
                ldb ,x                          ; get precedence of current operation
                cmpb ,s                         ; is it higher than the current operation?
                bhi eval_expr3                  ; brif so - process this operator
                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
                pshs x                          ; save handler address for later
                lda val0+val.type               ; get current value type
                ldx val0                        ; get value accumlator contents (6 bytes)
                ldy val0+2
                ldu val0+4
                pshs a,x,y,u                    ; save it on the stack
                jsr eval_expraux                ; evaluate the following term and higher precedence expressions
                puls a,x,y,u                    ; get back saved value
                stx val1                        ; save it to the second value accumulator
                sty val1+2
                stu val1+4
                sta val1+val.type               ; save previous value type
                jsr [,s++]                      ; go handle the operator
                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
                beq eval_term0                  ; brif end of input - this is an error
                bcs eval_number                 ; brif digit - we have a number
;                bmi eval_func                   ; brif we have a token - handle function call
                cmpa #'.                        ; decimal point?
                beq eval_number                 ; brif so - evaluate number
                cmpa #'-                        ; negative sign?
                beq eval_number                 ; brif so - evaluate number
                cmpa #'+                        ; positive sign?
                beq eval_number                 ; brif so - evaluate number
eval_term0      jmp SNERROR                     ; we have something unrecognized - raise error
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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     jmp val_parsenum                ; if we don't recognize anything else, just parse a numer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Operator table
;
; Each entry starts with the precedence value followed by the handler routine. Each handler will receive its left
; operand in val1 and its right operand in val0 and should return its result in val0.
oper_tab        fcb 0x79                        ; addition
                fdb oper_plus
                fcb 0x79                        ; subtraction
                fdb oper_minus
                fcb 0x7b                        ; multiplication
                fdb oper_times
                fcb 0x7b                        ; division
                fdb oper_divide
                fcb 0x7f                        ; exponentiation
                fdb SNERROR
                fcb 0x64                        ; less than
                fdb SNERROR
                fcb 0x64                        ; equal to
                fdb SNERROR
                fcb 0x64                        ; greater than
                fdb SNERROR
                fcb 0x64                        ; less than or equal to
                fdb SNERROR
                fcb 0x64                        ; greater than or equal to
                fdb SNERROR
                fcb 0x64                        ; not equal to
                fdb SNERROR
                fcb 0x50                        ; boolean AND
                fdb SNERROR
                fcb 0x46                        ; boolean OR
                fdb SNERROR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Operator handling routines
;
; binary plus: addition and concatenation
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 val0+val.type              ; is right operand also string?
                lbeq SNERROR                    ; brif so - do string concatenation
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      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