From ffff33d512e3f737b16116658c557a4a1a6cb005 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Fri, 14 Aug 2020 22:18:22 +0300 Subject: [PATCH] moved number parser to separate source file --- bzasm80.zas | 8 +- main.zas | 19 ++- parser_expr.zas | 80 ++++++++++++ parser_misc.zas | 19 +++ parser.zas => parser_number.zas | 273 +++++++++------------------------------- parser_stack.zas | 138 -------------------- 6 files changed, 181 insertions(+), 356 deletions(-) create mode 100644 parser_expr.zas rename parser.zas => parser_number.zas (51%) delete mode 100644 parser_stack.zas diff --git a/bzasm80.zas b/bzasm80.zas index 74095fe..21be3e5 100644 --- a/bzasm80.zas +++ b/bzasm80.zas @@ -32,7 +32,7 @@ ENDIF PC: defw #C000 ; logical program counter for the code -IF BZ80ASM_ORGENTDISP +IF @BZ80ASM_ORGENTDISP ; ORG/DISP sets this to its value NEW_ORGENT: defw 0 ; ORG/ENT sets this to the corresponding type @@ -98,7 +98,7 @@ csizestart = $ ASSEM: ; reset org/ent type xor a - IF BZ80ASM_ORGENTDISP + IF @BZ80ASM_ORGENTDISP ld (ORGENT_TYPE),a ENDIF ld (ASM_BAD_B),a @@ -751,7 +751,7 @@ DEFM1_DONE_ONE: ;; ORG ;; MISC_ORG: - IF BZ80ASM_ORGENTDISP + IF @BZ80ASM_ORGENTDISP djnz MISC_DISP ld a,ORGENT_ORG COM_ORGENT: @@ -1196,7 +1196,7 @@ OPCODS: defx "DEFM" defb 0 - IF BZ80ASM_ORGENTDISP + IF @BZ80ASM_ORGENTDISP defx "ORG" defb 0 ; diff --git a/main.zas b/main.zas index 403ee4a..2733497 100644 --- a/main.zas +++ b/main.zas @@ -6,9 +6,19 @@ include "bzasm80.zas" csizestart = $ - include "parser.zas" + include "parser_misc.zas" csizeend = $ -$printf "parser size: %d", csizeend-csizestart +$printf "parser_misc size: %d", csizeend-csizestart + +csizestart = $ + include "parser_number.zas" +csizeend = $ +$printf "parser_number size: %d", csizeend-csizestart + +csizestart = $ + include "parser_expr.zas" +csizeend = $ +$printf "parser_expr size: %d", csizeend-csizestart csizestart = $ include "labman.zas" @@ -56,7 +66,7 @@ doasm: push ix ; save code destination push iy ; we'll need it for listing doasm_nopush: - call EXPR_STACK_RESET + ;call EXPR_STACK_RESET call BZ80ASM.ASSEM jp c,list_and_error doasm_done_line: @@ -134,6 +144,7 @@ strbuf: defm "exx",13 defm "ld hl,#4001",13 defm "ld a,(ix-2)",13 + defm "ld c,(ix)",13 defm "call 0BEEFh",13 defm "or c",13 defm "and (hl)",13 @@ -142,6 +153,8 @@ strbuf: defm "ld bc,0x5b02",13 defm "ld a,0b1001",13 defm "ld a,%1010",13 + defm "ld ix,-1234",13 + defm "ld iy,-0x602a",13 defb 0 dest: defs 64,0 diff --git a/parser_expr.zas b/parser_expr.zas new file mode 100644 index 0000000..d630dc1 --- /dev/null +++ b/parser_expr.zas @@ -0,0 +1,80 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; math expression parser +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; parse an integer expression +;; IN: +;; IY: text buffer +;; OUT: +;; IY: text buffer after the expression +;; HL: expression value +;; everything other (including all alternate registers) is dead +;; +PARSE_INT_EXPR: + call skipBlanks + jp z,error_integer_expected + ld c,#FF ; use this, as we need bit 1 to be set + call BZ80ASM.SIGN + jr nz,.ccnum + ld c,a + inc iy +.ccnum: + call PARSE_NUMBER + jp c,error_integer_expected + ; check for negate + xor a + bit 1,c ; '+' has bit 1 set, '-' hasn't + ret nz + ; negate HL + ld de,0 + ex de,hl + sbc hl,de + or a + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; parse a string expression +;; +;; IN: +;; IY: text buffer +;; OUT: +;; HL: string buffer start +;; E: parsed string length +;; everything other (including all alternate registers) is dead +;; +PARSE_STR_EXPR: + call skipBlanks + jp z,error_string_expected + cp 34 + jr z,.strok + cp 39 + jp nz,error_string_expected +.strok: + ld c,a ; terminator + inc iy + ld hl,ACCS + push hl +.strloop: + ld a,(iy) + or a + jp z,error_string_expected + inc iy + cp c + jr z,.strdone + ld (hl),a + inc hl + jr .strloop +.strdone: + pop de + or a + sbc hl,de + ex de,hl + ret + +;; string accumulator +ACCS: defs 256,0 diff --git a/parser_misc.zas b/parser_misc.zas index 2c1cd49..210e207 100644 --- a/parser_misc.zas +++ b/parser_misc.zas @@ -29,6 +29,25 @@ skipBlanks: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; check for EOL +;; returns current char in A +;; sets zero flag on EOL +;; IN: +;; IY: text buffer +;; OUT: +;; IY: text buffer (unchanged) +;; A: current or EOL char +;; zero flag is set on EOL +;; +checkEOL: + ld a,(iy) + or a + ret z + cp 13 + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; check if A is an alpha char ;; carry set: not an alpha char ;; diff --git a/parser.zas b/parser_number.zas similarity index 51% rename from parser.zas rename to parser_number.zas index 292a23b..7102e59 100644 --- a/parser.zas +++ b/parser_number.zas @@ -1,77 +1,30 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; math expression parser +;; parse integer number (without sign) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; this is classical shunting-yard math expression parser -;; lurk the web to find out what it is - -;; evaluation stack holds 3-byte value: -;; db type -;; dw data -;; -;; for numbers, data is 16-bit unsigned number (negative numbers -;; are 2-complement, and treated as positive, except for when -;; one does "<0", ">0", "<=0", ">=0") -;; -;; for operators, type is precedence, and data is handler address - -;; set this to the address of error routine -;; note that you cannot return from it, you HAVE to abort everything -;; also note that machine stack is undefined, and SP should be set -;; to some initial value -;; "undefined" means that machine stack can contain alot of garbage, -;; but will never be underflowed -;; -;; numeric stack state is undefined (REALLY undefined!) -;; the only thing you can do with it is call `EXPR_STACK_RESET` -;; -;; this function calls with error code in A -EXPR_ERROR_CB: defw 0 - -;; error codes -;; expression stack overflow -EXPR_ERR_STACK_OVERFLOW equ 1 -;; expected number, but got something incomprehensible -EXPR_ERR_NUMBER_EXPECTED equ 2 -;; expected string, but got something incomprehensible -EXPR_ERR_STRING_EXPECTED equ 3 -;; expression stack underflow -;; this usually means invalid expression -;; so you can write "invalid expression" diagnostic message in this case -EXPR_ERR_STACK_UNDERFLOW equ 4 -;; general error -- something is wrong with the expression -;; write "invalid expression" diagnostic message in this case -EXPR_ERR_INVALID equ 5 - -;; should be more than enough for most expressions -EXPR_STACK_SIZE equ 16 - -;; user must set this -;; the stack grows to higher addresses -EXPR_STACK_S0: defw 0 - -;; this points to the *LAST* *USED* *SLOT* -EXPR_STACK_SP: defw 0 -;; last usable item on the expression stack -;; inited with `EXPR_STACK_RESET` -EXPR_STACK_END: defw 0 - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; no user-serviceable parts beyond this point! ;-) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -EXPR_STITEM_NUMBER equ 0 -EXPR_STITEM_LPAREN equ 255 - - include "parser_misc.zas" - include "parser_stack.zas" +;; this is advanced number parser +;; it understands alot of suffixes and prefixes: +;; $ -- lone "$" means "current PC" +;; #nnnn -- hex +;; $nnnn -- hex +;; &nnnn -- hex +;; %nnnn -- binary +;; 0Xnnn -- hex +;; 0Onnn -- octal +;; 0Bnnn -- binary +;; nnnnH -- hex +;; nnnnB -- binary +;; nnnnO -- octal +;; everything is case-insensitive +;; you can separate digits with underscores +;; (i.e. "12_34_5" will work, underscores are simply ignored) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; parse a number, push it onto the stack ;; understands prefixes and suffixes +;; ;; IN: ;; IY: text buffer ;; OUT: @@ -103,19 +56,18 @@ PARSE_NUMBER: jr z,.maybe_zero_prefix ; check if we have a digit here call convDigit - jp c,.not_a_number_carry_set + jr c,.not_a_number_carry_set cp 10 ; nope, do not allow it, all numbers must start with a digit ;jp nc,.must_be_hex_with_sfx ccf - jp c,.not_a_number_carry_set + jr c,.not_a_number_carry_set .do_normal_decimal: ; done with prefixes, try decimal number ; we'll switch to suffix checking on hex digit ld hl,0 ; accumulator .decimal_loop: - ld a,(iy) - call convDigit + call .getDigit jr c,.decimal_done cp 10 jp nc,.must_be_hex_with_sfx @@ -143,18 +95,23 @@ PARSE_NUMBER: cp 'O' jp z,.oct_with_sfx ; no suffix, we're done + .success: pop de ; drop iy ; reset carry flag or a ret +.not_a_number_carry_set: + pop iy + ret + .hexprefix: ; skip prefix inc iy call .parse_as_hex .after_prefix: - jp c,.not_a_number_carry_set + jr c,.not_a_number_carry_set jr .success .maybe_lone_dollar: @@ -210,44 +167,9 @@ PARSE_NUMBER: jr z,.maybe_binprefix cp 'O' jr z,.octprefix - cp 'D' - jr z,.parse_as_dec ; do not reparse '0', no need to backup jp .do_normal_decimal -.parse_as_dec: - ; skip prefix - inc iy - ld hl,0 ; accumulator - ; check first digit (as this is general parser) - ld a,(iy) - call convDigit - ret c - cp 10 - ccf - ret c -.parse_as_dec_loop: - inc iy - ; HL=HL*10 - add hl,hl - ld de,hl - add hl,hl - add hl,hl - add hl,de - ; HL=HL+A - ld e,a - ld d,0 - add hl,de - ld a,(iy) - call convDigit - jr c,.parse_as_dec_done - cp 10 - jr nc,.parse_as_hex_loop - ; clear carry flag (it is always set here) -.parse_as_dec_done: - ccf - ret - .must_be_hex_with_sfx: ; reparse as hex, and check for suffix pop iy @@ -260,12 +182,6 @@ PARSE_NUMBER: cp 'H' jp z,.success -.not_a_number: - scf -.not_a_number_carry_set: - pop iy - ret - .bin_with_sfx: ; reparse as bin, skip suffix (it is guaranteed to be there) pop iy @@ -287,8 +203,7 @@ PARSE_NUMBER: .parse_as_hex: ld hl,0 ; accumulator ; check first digit (as this is general parser) - ld a,(iy) - call convDigit + call .getDigitNoUnder ret c .parse_as_hex_loop: inc iy @@ -299,8 +214,7 @@ PARSE_NUMBER: ld e,a ld d,0 add hl,de - ld a,(iy) - call convDigit + call .getDigit jr nc,.parse_as_hex_loop ; clear carry flag (it is always set here) ccf @@ -310,10 +224,7 @@ PARSE_NUMBER: ld hl,0 ; accumulator ; check first digit (as this is general parser) ld a,(iy) - call convDigit - ret c - cp 2 - ccf + call .getDigitNoUnderBin ret c .parse_as_bin_loop: inc iy @@ -321,14 +232,9 @@ PARSE_NUMBER: ld e,a ld d,0 add hl,de - ld a,(iy) - call convDigit - jr c,.parse_as_bin_done - cp 2 - ccf + call .getBinDigit jr nc,.parse_as_bin_loop ; clear carry flag (it is always set here) -.parse_as_bin_done: ccf ret @@ -336,11 +242,7 @@ PARSE_NUMBER: ld hl,0 ; accumulator ; check first digit (as this is general parser) ld a,(iy) - call convDigit - ret c - cp 8 - ccf - ret c + call .getDigitNoUnderOct .parse_as_oct_loop: inc iy add hl,hl @@ -349,96 +251,45 @@ PARSE_NUMBER: ld e,a ld d,0 add hl,de - ld a,(iy) - call convDigit - jr c,.parse_as_oct_done - cp 8 - ccf + call .getOctDigit jr nc,.parse_as_oct_loop ; clear carry flag (it is always set here) -.parse_as_oct_done: ccf ret - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; parse an integer expression -;; IN: -;; IY: text buffer -;; OUT: -;; IY: text buffer after the expression -;; HL: expression value -;; everything other (including all alternate registers) is dead -;; -PARSE_INT_EXPR: - call skipBlanks - jp z,error_integer_expected - ld c,0 - cp '-' - jr nz,.notneg - inc c +.getDigit_inc: inc iy - jr .ccnum -.notneg: - cp '+' - jr nz,.ccnum - inc iy -.ccnum: - call PARSE_NUMBER - jp c,error_integer_expected - ld a,c - or a - jr z,.noneg - ; net hl - ld de,0 - ex de,hl - sbc hl,de -.noneg: - call skipBlanks +.getDigit: + ld a,(iy) + cp '_' + jr z,.getDigit_inc + jp convDigit + + ; d: base +.getDigitInBase: + call .getDigit + ret c + cp d + ccf ret +.getDigitNoUnder: + ld a,(iy) + jp convDigit -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; parse a string expression -;; -;; IN: -;; IY: text buffer -;; OUT: -;; HL: string buffer start -;; E: parsed string length -;; everything other (including all alternate registers) is dead -;; -PARSE_STR_EXPR: - call skipBlanks - jp z,error_string_expected - cp 34 - jr z,.strok - cp 39 - jp nz,error_string_expected -.strok: - ld c,a ; terminator - inc iy - ld hl,ACCS - push hl -.strloop: +.getDecDigit: + ld d,10 + jr .getDigitInBase + +.getDigitNoUnderOct: ld a,(iy) - or a - jp z,error_string_expected - inc iy - cp c - jr z,.strdone - ld (hl),a - inc hl - jr .strloop -.strdone: - pop de - or a - sbc hl,de - ex de,hl - ret +.getOctDigit: + ld d,8 + jr .getDigitInBase -;; string accumulator -ACCS: defs 256,0 +.getDigitNoUnderBin: + ld a,(iy) +.getBinDigit: + ld d,2 + jr .getDigitInBase diff --git a/parser_stack.zas b/parser_stack.zas deleted file mode 100644 index e2035c0..0000000 --- a/parser_stack.zas +++ /dev/null @@ -1,138 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; math expression parser, general numeric stack management -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; clear numeric stack, setup stack vars -;; IN: -;; nothing -;; OUT: -;; HL,DE: dead -;; -EXPR_STACK_RESET: - ld de,EXPR_STACK_SIZE+1 - ld hl,de - add hl,hl - add hl,de - ex de,hl - ; DE=EXPR_STACK_SIZE*3 - ld hl,(EXPR_STACK_S0) - dec hl - dec hl - dec hl - ld (EXPR_STACK_SP),hl - add hl,de - ld (EXPR_STACK_END),hl - ret - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; loads addess of the next numeric stack slot into HL -;; increments numeric stack pointer -;; checks for stack overflow -;; -;; IN: -;; nothing -;; OUT: -;; HL: stack address -;; DE,flags: dead -;; -EXPR_STACK_GET_NEXT_SLOT_HL: - ld hl,(EXPR_STACK_SP) - inc hl - inc hl - inc hl - ld (EXPR_STACK_SP),hl - push hl - ld de,(EXPR_STACK_END) - or a - sbc hl,de - pop hl - ret c - ; stack overflow - ld a,EXPR_ERR_STACK_OVERFLOW -EXPR_CALL_ERROR_CB: - ld hl,(EXPR_ERROR_CB) - jp (hl) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; loads addess of the last numeric stack slot into HL -;; decrements numeric stack pointer -;; checks for stack underfloaw -;; -;; IN: -;; nothing -;; OUT: -;; HL: stack address -;; DE,flags: dead -;; -EXPR_STACK_POP_LAST_SLOT_HL: - ld hl,(EXPR_STACK_SP) - push hl - dec hl - dec hl - dec hl - ld (EXPR_STACK_SP),hl - ld de,(EXPR_STACK_S0) - pop hl - push hl - or a - sbc hl,de - pop hl - ret nc - ; stack underflow - ld a,EXPR_ERR_STACK_UNDERFLOW - jp EXPR_CALL_ERROR_CB - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; push number to numeric stack -;; IN: -;; HL: number -;; OUT: -;; HL,DE,flags: dead -;; -EXPR_PUSH_HL: - push hl - call EXPR_STACK_GET_NEXT_SLOT_HL - pop de - ex de,hl - ld (hl),EXPR_STITEM_NUMBER - inc hl - ld (hl),e - inc hl - ld (hl),d - ret - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; pop number from numeric stack -;; raises error if stack is empty or TOS is not a number -;; IN: -;; nothing -;; OUT: -;; HL: number -;; DE,flags: dead -;; -EXPR_POP_HL: - call EXPR_STACK_POP_LAST_SLOT_HL - ld a,(hl) - IF EXPR_STITEM_NUMBER == 0 - or a - ELSE - cp EXPR_STITEM_NUMBER - ENDIF - ld a,EXPR_ERR_INVALID - jp nz,EXPR_CALL_ERROR_CB - inc hl - ld e,(hl) - inc hl - ld d,(hl) - ex de,hl - ret -- 2.11.4.GIT