From 0fec0f45be3a921aae168cced64485dba58d0060 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Thu, 20 Aug 2020 10:25:50 +0300 Subject: [PATCH] replaced expression parse in asm with table-driven: it is slower, but smaller by 23 bytes --- bzasm80.zas | 417 +++++++++++++++++++++++++++++++++--------------------------- main.zas | 1 + 2 files changed, 229 insertions(+), 189 deletions(-) diff --git a/bzasm80.zas b/bzasm80.zas index 7e403d0..2a10858 100644 --- a/bzasm80.zas +++ b/bzasm80.zas @@ -1225,7 +1225,7 @@ PARSE_NUMBER: jr nc,.success ; lone dollar is good too ; IY points right after the dollar here - ld hl,(BZ80ASM.PC) + ld hl,(PC) jr .success .binprefix: @@ -1425,6 +1425,190 @@ csizest = $ ;; math expression parser ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; operator table, to avoid pasta +;; bit 0 of operator name means "two equal chars" +;; name,priority,handler +;; priority 1 is term/unary +;; priority 0 is nothing, and it should stay nothing +expr_optable: + db 0+'*'*2,2 + dw expr_do_mul + db 0+'/'*2,2 + dw expr_do_div + db 0+'%'*2,2 + dw expr_do_mod + + db 0+'+'*2,3 + dw expr_do_add + db 0+'-'*2,3 + dw expr_do_sub + + db 1+'<'*2,4 + dw expr_do_shl + db 1+'>'*2,4 + dw expr_do_shr + + db 0+'&'*2,5 + dw expr_do_bitand + + db 0+'^'*2,6 + dw expr_do_bitxor + + db 0+'|'*2,7 + dw expr_do_bitor + + db 0 ; no more + +expr_max_priority equ 7 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; operator doers +;; HL is op0, DE is op1 +;; result in HL +;; preserve IY +;; +expr_do_mul: + ld bc,hl + jp PARSER_UMUL_BC_DE + +expr_do_div: + call expr_do_mod + ld hl,bc + ret + +expr_do_mod: + ld bc,hl + jp PARSER_UDIV_BC_DE + +expr_do_add: + add hl,de + ret + +expr_do_sub: + or a + sbc hl,de + ret + +expr_do_shl: + ld c,1 + jr expr_do_shl_shl + +expr_do_shr: + ld c,0 + +expr_do_shl_shl: + ; HL: number to shift + ; DE: amount + ; C: =1 means "shl" + ld a,d + or a + jr nz,.shift_too_far + ld a,e + cp 16 + jr nc,.shift_too_far + ld b,a + dec c + jr z,.do_shl + ; shr +.do_shr_loop: + srl h + rr l + djnz .do_shr_loop + ret + ; shl +.do_shl: + ; shl + sla l + rl h + djnz .do_shl + ret +.shift_too_far: + ld hl,0 + ret + +expr_do_bitand: + ld a,l + and e + ld l,a + ld a,h + and d + ld h,a + ret + +expr_do_bitxor: + ld a,l + xor e + ld l,a + ld a,h + xor d + ld h,a + ret + +expr_do_bitor: + ld a,l + or e + ld l,a + ld a,h + or d + ld h,a + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; find operator +;; +;; IN: +;; IY: text buffer +;; OUT: +;; IY: text buffer after the operator +;; DE: handler address +;; HL: dead +;; A: operator priority +;; flags: dead +;; zero set if no operator found (and IY is not modified) +PARSE_EXPR_FINDOP: + ld hl,expr_optable-4 +.findloop: + inc hl + inc hl + inc hl + inc hl + ld a,(hl) + or a + ret z + rra ; carry is "two chars" + jr nc,.onechar + ; two chars + cp (iy) + jr nz,.findloop + cp (iy+1) + jr nz,.findloop + inc iy ; skip first char + ; it is guaranteed to match, so don't bother skipping it +.onechar: + cp (iy) + jr nz,.findloop + ; skip operator + inc iy + ; load priority + inc hl + ld a,(hl) + ; load handler address + inc hl + ld e,(hl) + inc hl + ld d,(hl) + or a ; reset zero flag + ret + +PARSE_EXPR_CALL_BC: + push bc + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PARSE_EXPR_ERROR_A: ld hl,(EXPR_ERROR_CB) jp (hl) @@ -1458,7 +1642,7 @@ PARSE_INT_EXPR: call PARSER_SKIP_BLANKS jr z,PARSE_EXPR_ERROR_INT ; unary "+" or "-"? - call BZ80ASM.SIGN + call SIGN jr nz,.doexpr push af inc iy @@ -1475,180 +1659,54 @@ PARSE_INT_EXPR: ret .doexpr: -;; | -.bitor: - ; get first operand - ; already done above - call .bitxor -.bitor_next: - ; check for operation - call PARSER_SKIP_BLANKS - ret z ; exit on EOL - cp '|' - ret nz - ; get second operand - ld bc,.bitxor - call .go_down_bc - ld a,l - or e - ld l,a - ld a,h - or d - ld h,a - jr .bitor_next - -;; ^ -.bitxor: - ; get first operand - call .bitand -.bitxor_next: - ; check for operation - call PARSER_SKIP_BLANKS - ret z ; exit on EOL - cp '^' - ret nz - ; get second operand - ld bc,.bitand - call .go_down_bc - ld a,l - xor e - ld l,a - ld a,h - xor d - ld h,a - jr .bitxor_next - -;; & -.bitand: - ; get first operand - call .shlshr -.bitand_next: - ; check for operation - call PARSER_SKIP_BLANKS - ret z ; exit on EOL - cp '&' - ret nz - ; get second operand - ld bc,.shlshr - call .go_down_bc - ld a,l - and e - ld l,a - ld a,h - and d - ld h,a - jr .bitand_next - -;; << >> -.shlshr: - call .addsub -.shlshr_next: - ; check for operation - call PARSER_SKIP_BLANKS - ret z ; exit on EOL - ; (iy+0) and (iy+1) should be equal - cp (iy+1) - ret nz - cp '<' ; %0011_1100 - jr z,.doshift - cp '>' ; %0011_1110 - ret nz -.doshift: - ; get second operand - inc iy ; skip operation part - ld bc,.addsub - call .go_down_bc - ex af,af' - ; HL: number to shift - ; DE: amount - ld a,d - or a - jr nz,.shift_too_far - ld a,e - cp 16 - jr nc,.shift_too_far - ld b,a - ex af,af' - cp '<' - jr z,.do_shl - ; shr -.do_shr_loop: - srl h - rr l - djnz .do_shr_loop - jr .shlshr_next - ; shl -.do_shl: - ; shl - sla l - rl h - djnz .do_shl - jr .shlshr_next -.shift_too_far: - ld hl,0 - jr .shlshr_next + ; start with maximum priority + ld c,expr_max_priority -;; + - -.addsub: +.expr_prios: + ; term? + dec c + jr z,.term ; get first operand - call .muldiv -.addsub_next: - ; check for operation + push bc + call .expr_prios + pop bc + ; loop until the priority is right +.expr_prios_loop: + ; C is priority-1 here + ; check if we have an operator call PARSER_SKIP_BLANKS ret z ; exit on EOL - cp '+' ; %0010_1011 - jr z,.doaddsub - cp '-' ; %0010_1101 - ret nz -.doaddsub: + ; check for operator + push hl ; save op0 + push iy ; save input pointer, we may need to restore it later + call PARSE_EXPR_FINDOP + jr z,.expr_prios_no_op + ; compare priorities + dec a + cp c + jr nz,.expr_prios_no_op ; get second operand - ld bc,.muldiv - call .go_down_bc - cp '-' - jr z,.dosub - add hl,de - jr .addsub_next -.dosub: - sbc hl,de - jr .addsub_next + pop hl ; drop iy + pop hl ; op0 + push bc ; save priority + push hl ; save op0 + push de ; save doer + ; stack: prio, op0, doer + call .expr_prios + ; stack: prio, op0, doer + ex de,hl ; de is op1 + pop bc ; bc is doer + pop hl ; hl is op0 + call PARSE_EXPR_CALL_BC + ; hl is result + pop bc ; bc is prio + jr .expr_prios_loop + +.expr_prios_no_op: + pop iy + pop hl + ret -;; * / % -.muldiv: - ; get first operand - call .term -.muldiv_next: - ; check for operation - call PARSER_SKIP_BLANKS - ret z ; exit on EOL - cp '*' ; %0010_1010 - jr z,.domuldiv - cp '/' ; %0010_1111 - jr z,.domuldiv - cp '%' ; %0010_0101 - ret nz -.domuldiv: - ; get second operand - ld bc,.term - call .go_down_bc - ld bc,hl - cp '*' - jr z,.domul - ex af,af' ; save operation - ; div or mod - ld a,e - or d - jp z,PARSE_EXPR_ERROR_0DIV - call PARSER_UDIV_BC_DE - ; was it div or mod? - ex af,af' - cp '%' - jr z,.muldiv_next ; remainder already in hl - ; division - ld hl,bc - jr .muldiv_next -.domul: - call PARSER_UMUL_BC_DE - jr .muldiv_next ;; parse term, also process unaries and parens .term: @@ -1708,25 +1766,6 @@ PARSE_INT_EXPR: ld l,a ret - ;; call subroutine at BC - ;; AF: preserved - ;; HL: preserved - ;; DE: subroutine result - ;; i.e. HL is op0, DE is op1 -.go_down_bc: - push hl - push af ; A holds operation - inc iy ; skip operation - ld hl,.go_down_bc_ret - push hl - push bc - ret -.go_down_bc_ret: - pop af - pop de - ex de,hl - ret - PARSE_EXPR_ERROR_RPAREN: ld a,EXPR_ERR_RPAREN_EXPECTED jp PARSE_EXPR_ERROR_A diff --git a/main.zas b/main.zas index 9a81408..bad4293 100644 --- a/main.zas +++ b/main.zas @@ -234,6 +234,7 @@ msg_pass_footer: defx "***************" strbuf: + defm "ld bc,2+3*5",13 defm "push ix",13 defm "pop iy",13 defm "ex (sp),hl",13 -- 2.11.4.GIT