apps/ed: refactoring

This commit is contained in:
Virgil Dupras 2019-07-13 21:08:16 -04:00
parent 8cf68dc7ad
commit 2d9f74c2af
3 changed files with 163 additions and 101 deletions

135
apps/ed/cmd.asm Normal file
View File

@ -0,0 +1,135 @@
; cmd - parse and interpret command
;
; *** Consts ***
; address type
.equ ABSOLUTE 0
; handles +, - and ".". For +, easy. For -, addr is negative. For ., it's 0.
.equ RELATIVE 1
.equ BOF 2
.equ EOF 3
; *** Variables ***
; An address is a one byte type and a two bytes line number (0-indexed)
.equ CMD_ADDR1 CMD_RAMSTART
.equ CMD_ADDR2 CMD_ADDR1+3
.equ CMD_TYPE CMD_ADDR2+3
.equ CMD_RAMEND CMD_TYPE+1
; *** Code ***
; Parse command line that HL points to and set unit's variables
; Sets Z on success, unset on error.
cmdParse:
ld a, (hl)
cp 'q'
jr z, .quit
ld (CMD_TYPE), a
ld ix, CMD_ADDR1
jp .readAddr
.quit:
; Z already set
ld (CMD_TYPE), a
ret
; Parse the string at (HL) and sets its corresponding address in IX, properly
; considering implicit values (current address when nothing is specified).
; advances HL to the char next to the last parsed char.
; It handles "+" and "-" addresses such as "+3", "-2", "+", "-".
; Sets Z on success, unset on error. Line out of bounds isn't an error. Only
; overflows.
.readAddr:
ld a, (hl)
cp '+'
jr z, .plusOrMinus
cp '-'
jr z, .plusOrMinus
call parseDecimalDigit
jr c, .notHandled
; straight number
ld a, ABSOLUTE
ld (ix), a
call .parseDecimalM
ret nz
dec de ; from 1-based to 0-base
jr .end
.notHandled:
; something else. Something we don't handle. Our addr is therefore "."
ld a, RELATIVE
ld (ix), a
xor a ; sets Z
ld (ix+1), a
ld (ix+2), a
ret
.plusOrMinus:
push af ; preserve that + or -
ld a, RELATIVE
ld (ix), a
inc hl ; advance cmd cursor
ld a, (hl)
ld de, 1 ; if .pmNoSuffix
call parseDecimalDigit
jr c, .pmNoSuffix
call .parseDecimalM ; --> DE
.pmNoSuffix:
pop af ; bring back that +/-
cp '-'
jr nz, .end
; we had a "-". Negate DE
push hl
ld hl, 0
sbc hl, de
ex de, hl
pop hl
.end:
; We expect HL (rest of the cmdline) to be a null char, otherwise it's
; garbage
ld a, (hl)
or a
ret nz
; we still have to save DE in memory
ld (ix+1), e
ld (ix+2), d
ret
; call parseDecimal and set HL to the character following the last digit
.parseDecimalM:
push bc
push ix
push hl
.loop:
inc hl
ld a, (hl)
call parseDecimalDigit
jr nc, .loop
; We're at the first non-digit char. Let's save it because we're going
; to temporarily replace it with a null.
ld b, a
xor a
ld (hl), a
; Now, let's go back to the beginning of the string and parse it.
; but before we do this, let's save the end of string in DE
ex de, hl
pop hl
call parseDecimal
; Z is set properly at this point. nothing touches Z below.
ld a, b
ld (de), a
ex de, hl ; put end of string back from DE to HL
; Put addr in its final register, DE
push ix \ pop de
pop ix
pop bc
ret
; Make (IX) point to addr 1
cmdAddr1:
ld ix, CMD_ADDR1
ret
; Set A to CMD_TYPE
cmdType:
ld a, (CMD_TYPE)
ret

View File

@ -9,6 +9,8 @@
#include "ed/io.asm"
.equ BUF_RAMSTART IO_RAMEND
#include "ed/buf.asm"
.equ ED_RAMSTART BUF_RAMEND
.equ CMD_RAMSTART BUF_RAMEND
#include "ed/cmd.asm"
.equ ED_RAMSTART CMD_RAMEND
#include "ed/main.asm"

View File

@ -86,118 +86,43 @@ edMain:
; We're done. Process line.
call printcrlf
call stdioGetLine
call .processLine
ret z
jr .mainLoop
; Sets Z if we need to quit
.processLine:
ld a, (hl)
call cmdParse
jr nz, .error
call cmdType
cp 'q'
ret z
call edReadAddr
jr z, .processNumber
jr .processError
.processNumber:
; number is in DE
; We expect HL (rest of the cmdline) to be a null char, otherwise it's
; garbage
ld a, (hl)
or a
jr nz, .processError
ex de, hl
jr .doPrint
.doPrint:
call cmdAddr1
call edResolveAddr
ld (ED_CURLINE), hl
call bufGetLine
jr nz, .processError
jr nz, .error
call printstr
call printcrlf
; continue to end
.processEnd:
call printcrlf
jp unsetZ
.processError:
jr .mainLoop
.error:
ld a, '?'
call stdioPutC
call printcrlf
jp unsetZ
jr .mainLoop
; Parse the string at (HL) and sets its corresponding address in DE, properly
; considering implicit values (current address when nothing is specified).
; advances HL to the char next to the last parsed char.
; It handles "+" and "-" addresses such as "+3", "-2", "+", "-".
; Sets Z on success, unset on error. Line out of bounds isn't an error. Only
; overflows.
edReadAddr:
ld a, (hl)
cp '+'
jr z, .plusOrMinus
cp '-'
jr z, .plusOrMinus
call parseDecimalDigit
jr c, .notHandled
; straight number
call .parseDecimalM ; Z has proper value
dec de ; from 1-based to 0-base. 16bit doesn't affect flags.
; Transform an address "cmd" in IX into an absolute address in HL.
edResolveAddr:
ld a, (ix)
cp RELATIVE
jr z, .relative
; absolute
ld l, (ix+1)
ld a, l
ld h, (ix+2)
ret
.notHandled:
; something else. Something we don't handle. Our addr is therefore
; (ED_CURLINE).
push hl
.relative:
ld hl, (ED_CURLINE)
ex de, hl
pop hl
cp a ; ensure Z
ret
.plusOrMinus:
push af ; preserve that + or -
inc hl ; advance cmd cursor
ld a, (hl)
ld de, 1 ; if .pmNoSuffix
call parseDecimalDigit
jr c, .pmNoSuffix
call .parseDecimalM ; --> DE
.pmNoSuffix:
pop af ; bring back that +/-
push hl
ld hl, (ED_CURLINE)
cp '-'
jr z, .pmIsMinus
ld e, (ix+1)
ld d, (ix+2)
add hl, de
jr .pmEnd
.pmIsMinus:
sbc hl, de
.pmEnd:
ex de, hl
pop hl
cp a ; ensure Z
ret
; call parseDecimal and set HL to the character following the last digit
.parseDecimalM:
push bc
push ix
push hl
.loop:
inc hl
ld a, (hl)
call parseDecimalDigit
jr nc, .loop
; We're at the first non-digit char. Let's save it because we're going
; to temporarily replace it with a null.
ld b, a
xor a
ld (hl), a
; Now, let's go back to the beginning of the string and parse it.
; but before we do this, let's save the end of string in DE
ex de, hl
pop hl
call parseDecimal
; Z is set properly at this point. nothing touches Z below.
ld a, b
ld (de), a
ex de, hl ; put end of string back from DE to HL
; Put addr in its final register, DE
push ix \ pop de
pop ix
pop bc
ret