From 8cd400651a99654986e13bf0dd329160a2892197 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Tue, 16 Apr 2019 22:40:07 -0400 Subject: [PATCH] zasm: read each argument immediately insto an argspec Previously, we would go the other way around: match all available argspecs to raw argument strings. It's much better to go the other way around because we can "reduce" each argument much sooner. That will be important when we start to support constants and expressions. --- apps/zasm/zasm.asm | 155 +++++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 68 deletions(-) diff --git a/apps/zasm/zasm.asm b/apps/zasm/zasm.asm index 6b5cbb9..702ffc0 100644 --- a/apps/zasm/zasm.asm +++ b/apps/zasm/zasm.asm @@ -86,6 +86,22 @@ toWord: ret +; Read arg from (HL) into argspec at (DE) +; HL is advanced to the next word. Z is set if there's a next word. +readArg: + push de + ld de, tmpVal + call readWord + push hl + ld hl, tmpVal + call matchArg + pop hl + pop de + ld (de), a + call toWord + ret + +; Read line from (HL) into (curWord), (curArg1) and (curArg2) readLine: push de xor a @@ -97,71 +113,91 @@ readLine: call toWord jr nz, .end ld de, curArg1 - call readWord - call toWord + call readArg jr nz, .end ld de, curArg2 - call readWord + call readArg .end: pop de ret -; match argument string at (HL) with argspec A. -; Set Z/NZ on match +; Returns length of string at (HL) in A. +strlen: + push bc + push hl + ld bc, 0 + ld a, 0 ; look for null char +.loop: + cpi + jp z, .found + jr .loop +.found: + ; How many char do we have? the (NEG BC)-1, which started at 0 and + ; decreased at each CPI call. In this routine, we stay in the 8-bit + ; realm, so C only. + ld a, c + neg + dec a + pop hl + pop bc + ret + +; find argspec for string at (HL). Returns matching argspec in A. +; Return value 1 holds a special meaning: arg is not empty, but doesn't match +; any argspec (A == 0 means arg is empty). A return value of 1 means an error. matchArg: + call strlen + cp 0 + ret z ; empty string? A already has our result: 0 + push bc push de - push ix + push hl + + cp 1 + jr z, .matchsingle ; Arg is one char? We have a "single" type. - cp 0 - jr z, .matchnone - ; Let's see if our argspec is a "single" one. - ex hl, de ; For "simple" cmp, we don't need HL. But we'll - ; need it later. - ld hl, argspecsSingle - ld bc, ARGSPEC_SINGLE_CNT -.loop1: - cpi - jr z, .matchsingle ; our argspec in the "single" list - jp po, .loop1end - jr .loop1 -.loop1end: ; Not a "single" arg. Do the real thing then. - ex hl, de ; now we need HL back... ld de, argspecTbl + ; DE now points the the "argspec char" part of the entry, but what + ; we're comparing in the loop is the string next to it. Let's offset + ; DE by one so that the loop goes through strings. + inc de ld b, ARGSPEC_TBL_CNT -.loop2: - ld ixl, a - ld a, (de) - cp ixl +.loop1: + ld a, 4 + call JUMP_STRNCMP jr z, .found ; got it! ld a, 5 call JUMP_ADDDE - ld a, ixl - djnz .loop2 + djnz .loop1 ; exhausted? we have a problem os specifying a wrong argspec. This is ; an internal consistency error. + ld a, 1 jr .end .found: - ; found the matching argspec row. Let's compare the strings now. - inc de ; the string starts on the 2nd byte of the row - ld a, 4 - call JUMP_STRNCMP ; Z is set + ; found the matching argspec row. Our result is one byte left of DE. + dec de + ld a, (de) jr .end .matchsingle: - ; single match is easy: compare A with (HL). They must be equal. - ex hl, de - ld b, a ld a, (hl) - cp b ; Z set if A == B + ld hl, argspecsSingle + ld bc, ARGSPEC_SINGLE_CNT +.loop2: + cpi + jr z, .end ; found! our result is already in A. go straight + ; to end. + jp po, .loop2notfound + jr .loop2 +.loop2notfound: + ; something's wrong. error + ld a, 1 jr .end -.matchnone: - ld a, (hl) - cp 0 ; arg must be null to match .end: - pop ix + pop hl pop de pop bc ret @@ -178,13 +214,11 @@ matchPrimaryRow: ; name matches, let's see the rest ld ixh, d ld ixl, e - ld hl, curArg1 - ld a, (ix+4) - call matchArg + ld a, (curArg1) + cp (ix+4) jr nz, .end - ld hl, curArg2 - ld a, (ix+5) - call matchArg + ld a, (curArg2) + cp (ix+5) .end: pop ix pop hl @@ -243,30 +277,8 @@ argspecTbl: .db 'p', "(SP)" ; This is a list of primary instructions (single upcode) that lead to a -; constant (no group code to insert). -; That doesn't mean that they don't take any argument though. For example, -; "DEC IX" leads to a special upcode. These kind of constants are indicated -; as a single byte to save space. Meaning: +; constant (no group code to insert). Format: ; -; All single char registers (A/B/C etc) -> themselves -; HL -> h -; (HL) -> l -; DE -> d -; (DE) -> e -; BC -> b -; (BC) -> c -; IX -> X -; (IX) -> x -; IY -> Y -; (IY) -> y -; AF -> a -; AF' -> f -; SP -> s -; (SP) -> p -; None -> 0 -; -; This is a sorted list of "primary" (single byte) instructions along with -; metadata ; 4 bytes for the name (fill with zero) ; 1 byte for arg constant ; 1 byte for 2nd arg constant @@ -303,8 +315,15 @@ instTBlPrimary: ; enough space for 4 chars and a null curWord: .db 0, 0, 0, 0, 0 + +; Args are 3 bytes: argspec, then values of numerical constants (when that's +; appropriate) curArg1: - .db 0, 0, 0, 0, 0 + .db 0, 0, 0 curArg2: + .db 0, 0, 0 + +; space for tmp stuff +tmpVal: .db 0, 0, 0, 0, 0