diff --git a/apps/zasm/directive.asm b/apps/zasm/directive.asm index 81aa3e5..9a88272 100644 --- a/apps/zasm/directive.asm +++ b/apps/zasm/directive.asm @@ -17,11 +17,8 @@ directiveHandlers: .dw handleDW handleDB: - push de push hl call toWord - ld de, scratchpad - ld a, 8 call readWord ld hl, scratchpad call parseNumber @@ -29,15 +26,11 @@ handleDB: ld (direcData), a ld a, 1 pop hl - pop de ret handleDW: - push de push hl call toWord - ld de, scratchpad - ld a, 8 call readWord ld hl, scratchpad call parseNumber @@ -47,7 +40,6 @@ handleDW: ld (direcData+1), a ld a, 2 pop hl - pop de ret ; Reads string in (HL) and returns the corresponding ID (D_*) in A. Sets Z if diff --git a/apps/zasm/emul/Makefile b/apps/zasm/emul/Makefile index e938f20..6a1bd8c 100644 --- a/apps/zasm/emul/Makefile +++ b/apps/zasm/emul/Makefile @@ -8,5 +8,5 @@ libz80/libz80.o: libz80/z80.c kernel.h: glue.asm scas -o - -I ../../../parts/z80 $< | ./bin2c.sh KERNEL | tee $@ > /dev/null -zasm.h: $(addprefix ../, main.asm instr.asm directive.asm tok.asm literal.asm util.asm) +zasm.h: $(addprefix ../, main.asm instr.asm directive.asm tok.asm parse.asm literal.asm util.asm) scas -o - -I.. $< | ./bin2c.sh ZASM | tee $@ > /dev/null diff --git a/apps/zasm/instr.asm b/apps/zasm/instr.asm index 45b29a6..ecbcc9e 100644 --- a/apps/zasm/instr.asm +++ b/apps/zasm/instr.asm @@ -688,17 +688,11 @@ getUpcode: ; Parse next argument in string (HL) and place it in (DE) ; Sets Z on success, reset on error. processArg: - push de call toWord - xor a - ld de, scratchpad - ld (de), a - ld a, 8 call readWord - pop de - ; Read word is in scratchpad, (DE) is back to initial value, HL is - ; properly advanced. Now, let's push that HL value and replace it with - ; (scratchpad) so that we can parse that arg. + ; Read word is in scratchpad, HL is properly advanced. Now, let's push + ; that HL value and replace it with (scratchpad) so that we can parse + ; that arg. push hl ld hl, scratchpad diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index dbfa5f1..fa5cf6f 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -20,6 +20,7 @@ main: ret #include "util.asm" +#include "parse.asm" #include "literal.asm" #include "instr.asm" #include "tok.asm" @@ -76,6 +77,3 @@ parseLine: pop bc ret -; *** Variables *** -scratchpad: - .fill 0x20 diff --git a/apps/zasm/parse.asm b/apps/zasm/parse.asm new file mode 100644 index 0000000..5036c75 --- /dev/null +++ b/apps/zasm/parse.asm @@ -0,0 +1,128 @@ +; *** Consts *** +.equ SCRATCHPAD_SIZE 0x20 +; *** Variables *** +scratchpad: + .fill SCRATCHPAD_SIZE + +; *** Code *** + +; Sets Z is A is ';', CR, LF, or null. +isLineEndOrComment: + cp ';' + ret z + ; Continues onto isLineEnd... + +; Sets Z is A is CR, LF, or null. +isLineEnd: + or a ; same as cp 0 + ret z + cp 0x0d + ret z + cp 0x0a + ret + +; Sets Z is A is ' ' '\t' or ',' +isSep: + cp ' ' + ret z + cp 0x09 + ret z + cp ',' + ret + +; Sets Z is A is ' ', ',', ';', CR, LF, or null. +isSepOrLineEnd: + call isSep + ret z + call isLineEndOrComment + ret + +; read word in (HL) and put it in (scratchpad), null terminated, for a maximum +; of SCRATCHPAD_SIZE-1 characters. As a result, A is the read length. HL is +; advanced to the next separator char. +readWord: + push bc + push de + ld de, scratchpad + ld b, SCRATCHPAD_SIZE-1 +.loop: + ld a, (hl) + call isSepOrLineEnd + jr z, .success + call JUMP_UPCASE + ld (de), a + inc hl + inc de + djnz .loop +.success: + xor a + ld (de), a + ld a, SCRATCHPAD_SIZE-1 + sub a, b +.end: + pop de + pop bc + ret + +; (HL) being a string, advance it to the next non-sep character. +; Set Z if we could do it before the line ended, reset Z if we couldn't. +toWord: +.loop: + ld a, (hl) + call isLineEndOrComment + jr z, .error + call isSep + jr nz, .success + inc hl + jr .loop +.error: + call JUMP_UNSETZ + ret +.success: + xor a ; ensure Z + ret + +; Advance HL to the beginning of the next line, that is, right after the next +; 0x10 or 0x13 or both. If we reach null, we stop and error out. +; Sets Z on success, unsets it on error. +gotoNextLine: + dec hl ; a bit weird, but makes the looping easier +.loop: + inc hl + ld a, (hl) + call isLineEnd + jr nz, .loop + ; (HL) is 0x10, 0x13 or 0 + or a ; is 0? + jr z, .error + ; we might have 0x13 followed by 0x10, let's account for this. + ; Yes, 0x10 followed by 0x10 will make us skip two lines, but this is of + ; no real consequence in our context. + inc hl + ld a, (hl) + call isLineEnd + jr nz, .success + or a ; is 0? + jr z, .error + ; There was another line sep. Skip this char + inc hl + ; Continue on to .success +.success: + xor a ; ensure Z + ret +.error: + call JUMP_UNSETZ + ret + +; Repeatedly calls gotoNextLine until the line in (HL) points to a line that +; isn't blank or 100% comment. Sets Z if we reach a line, Unset Z if we reach +; EOF +gotoNextNotBlankLine: + call toWord + ret z ; Z set? we have a not-blank line + ; Z not set? (HL) is at the end of the line or at the beginning of + ; comments. + call gotoNextLine + ret nz + jr gotoNextNotBlankLine + diff --git a/apps/zasm/tok.asm b/apps/zasm/tok.asm index d400af3..4c655a9 100644 --- a/apps/zasm/tok.asm +++ b/apps/zasm/tok.asm @@ -1,7 +1,3 @@ -; tok -; -; Tokenizes an ASM source file into 1, 2 or 3-sized structures. -; ; *** Requirements *** ; JUMP_UPCASE @@ -17,10 +13,7 @@ TOK_BAD .equ 0xff ; Advance HL to after the read word. ; If no token matches, TOK_BAD is written to B tokenize: - push de call toWord - ld a, 4 - ld de, scratchpad call readWord push hl ; Save advanced HL for later ld hl, scratchpad @@ -39,125 +32,4 @@ tokenize: .end: ld c, a pop hl - pop de ret - -; Sets Z is A is ';', CR, LF, or null. -isLineEndOrComment: - cp ';' - ret z - ; Continues onto isLineEnd... - -; Sets Z is A is CR, LF, or null. -isLineEnd: - or a ; same as cp 0 - ret z - cp 0x0d - ret z - cp 0x0a - ret - -; Sets Z is A is ' ' '\t' or ',' -isSep: - cp ' ' - ret z - cp 0x09 - ret z - cp ',' - ret - -; Sets Z is A is ' ', ',', ';', CR, LF, or null. -isSepOrLineEnd: - call isSep - ret z - call isLineEndOrComment - ret - -; read word in (HL) and put it in (DE), null terminated, for a maximum of A -; characters. As a result, A is the read length. HL is advanced to the next -; separator char. -readWord: - push bc - push de - ld b, a -.loop: - ld a, (hl) - call isSepOrLineEnd - jr z, .success - call JUMP_UPCASE - ld (de), a - inc hl - inc de - djnz .loop -.success: - xor a - ld (de), a - ld a, 4 - sub a, b -.end: - pop de - pop bc - ret - -; (HL) being a string, advance it to the next non-sep character. -; Set Z if we could do it before the line ended, reset Z if we couldn't. -toWord: -.loop: - ld a, (hl) - call isLineEndOrComment - jr z, .error - call isSep - jr nz, .success - inc hl - jr .loop -.error: - call JUMP_UNSETZ - ret -.success: - xor a ; ensure Z - ret - -; Advance HL to the beginning of the next line, that is, right after the next -; 0x10 or 0x13 or both. If we reach null, we stop and error out. -; Sets Z on success, unsets it on error. -gotoNextLine: - dec hl ; a bit weird, but makes the looping easier -.loop: - inc hl - ld a, (hl) - call isLineEnd - jr nz, .loop - ; (HL) is 0x10, 0x13 or 0 - or a ; is 0? - jr z, .error - ; we might have 0x13 followed by 0x10, let's account for this. - ; Yes, 0x10 followed by 0x10 will make us skip two lines, but this is of - ; no real consequence in our context. - inc hl - ld a, (hl) - call isLineEnd - jr nz, .success - or a ; is 0? - jr z, .error - ; There was another line sep. Skip this char - inc hl - ; Continue on to .success -.success: - xor a ; ensure Z - ret -.error: - call JUMP_UNSETZ - ret - -; Repeatedly calls gotoNextLine until the line in (HL) points to a line that -; isn't blank or 100% comment. Sets Z if we reach a line, Unset Z if we reach -; EOF -gotoNextNotBlankLine: - call toWord - ret z ; Z set? we have a not-blank line - ; Z not set? (HL) is at the end of the line or at the beginning of - ; comments. - call gotoNextLine - ret nz - jr gotoNextNotBlankLine -