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