mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 14:18:06 +11:00
lib/parse: make parseDecimal "tail" HL
HL, instead of being preserved, is set to the character following the last read character.
This commit is contained in:
parent
dcb96aefe9
commit
289037a3dd
@ -43,10 +43,8 @@ basLDBAS:
|
|||||||
; Ok, line ready
|
; Ok, line ready
|
||||||
push hl ; --> lvl 1. current file position
|
push hl ; --> lvl 1. current file position
|
||||||
ld hl, SCRATCHPAD
|
ld hl, SCRATCHPAD
|
||||||
call parseDecimal
|
call parseDecimalC
|
||||||
jr nz, .notANumber
|
jr nz, .notANumber
|
||||||
push ix \ pop de
|
|
||||||
call toSepOrEnd
|
|
||||||
call rdSep
|
call rdSep
|
||||||
call bufAdd
|
call bufAdd
|
||||||
pop hl ; <-- lvl 1
|
pop hl ; <-- lvl 1
|
||||||
|
@ -38,7 +38,7 @@ basLoop:
|
|||||||
call printstr
|
call printstr
|
||||||
call stdioReadLine
|
call stdioReadLine
|
||||||
call printcrlf
|
call printcrlf
|
||||||
call parseDecimal
|
call parseDecimalC
|
||||||
jr z, .number
|
jr z, .number
|
||||||
ld de, basCmds1
|
ld de, basCmds1
|
||||||
call basCallCmds
|
call basCallCmds
|
||||||
@ -47,8 +47,6 @@ basLoop:
|
|||||||
call basERR
|
call basERR
|
||||||
jr basLoop
|
jr basLoop
|
||||||
.number:
|
.number:
|
||||||
push ix \ pop de
|
|
||||||
call toSepOrEnd
|
|
||||||
call rdSep
|
call rdSep
|
||||||
call bufAdd
|
call bufAdd
|
||||||
jp nz, basERR
|
jp nz, basERR
|
||||||
|
@ -91,14 +91,14 @@ cmdParse:
|
|||||||
jr z, .eof
|
jr z, .eof
|
||||||
|
|
||||||
; inline parseDecimalDigit
|
; inline parseDecimalDigit
|
||||||
add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
add a, 0xff-'9'
|
||||||
sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
sub 0xff-9
|
||||||
|
|
||||||
jr c, .notHandled
|
jr c, .notHandled
|
||||||
; straight number
|
; straight number
|
||||||
ld a, ABSOLUTE
|
ld a, ABSOLUTE
|
||||||
ld (ix), a
|
ld (ix), a
|
||||||
call .parseDecimalM
|
call parseDecimal
|
||||||
ret nz
|
ret nz
|
||||||
dec de ; from 1-based to 0-base
|
dec de ; from 1-based to 0-base
|
||||||
jr .end
|
jr .end
|
||||||
@ -127,11 +127,11 @@ cmdParse:
|
|||||||
ld de, 1 ; if .pmNoSuffix
|
ld de, 1 ; if .pmNoSuffix
|
||||||
|
|
||||||
; inline parseDecimalDigit
|
; inline parseDecimalDigit
|
||||||
add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
add a, 0xff-'9'
|
||||||
sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
sub 0xff-9
|
||||||
|
|
||||||
jr c, .pmNoSuffix
|
jr c, .pmNoSuffix
|
||||||
call .parseDecimalM ; --> DE
|
call parseDecimal ; --> DE
|
||||||
.pmNoSuffix:
|
.pmNoSuffix:
|
||||||
pop af ; bring back that +/-
|
pop af ; bring back that +/-
|
||||||
cp '-'
|
cp '-'
|
||||||
@ -148,39 +148,3 @@ cmdParse:
|
|||||||
ld (ix+2), d
|
ld (ix+2), d
|
||||||
cp a ; ensure Z
|
cp a ; ensure Z
|
||||||
ret
|
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)
|
|
||||||
|
|
||||||
; inline parseDecimalDigit
|
|
||||||
add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
|
||||||
sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
|
||||||
|
|
||||||
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, (hl) ; refetch (HL), A has been mucked with in
|
|
||||||
; parseDecimalDigit
|
|
||||||
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
|
|
||||||
|
|
||||||
|
@ -22,87 +22,83 @@ parseHex:
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
|
; Parse string at (HL) as a decimal value and return value in DE.
|
||||||
; result in A.
|
; Reads as many digits as it can and stop when:
|
||||||
;
|
; 1 - A non-digit character is read
|
||||||
; On success, the carry flag is reset. On error, it is set.
|
; 2 - The number overflows from 16-bit
|
||||||
; Also, zero flag set if '0'
|
; HL is advanced to the character following the last successfully read char.
|
||||||
; parseDecimalDigit has been replaced with the following code inline:
|
; Error conditions are:
|
||||||
; add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
; 1 - There wasn't at least one character that could be read.
|
||||||
; sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
; 2 - Overflow.
|
||||||
|
|
||||||
; Parse string at (HL) as a decimal value and return value in DE under the
|
|
||||||
; same conditions as parseLiteral.
|
|
||||||
; Sets Z on success, unset on error.
|
; Sets Z on success, unset on error.
|
||||||
; To parse successfully, all characters following HL must be digits and those
|
|
||||||
; digits must form a number that fits in 16 bits. To end the number, both \0
|
|
||||||
; and whitespaces (0x20 and 0x09) are accepted. There must be at least one
|
|
||||||
; digit in the string.
|
|
||||||
|
|
||||||
parseDecimal:
|
parseDecimal:
|
||||||
push hl ; --> lvl 1
|
; First char is special: it has to succeed.
|
||||||
|
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
|
; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
|
||||||
|
; result in A.
|
||||||
|
; On success, the carry flag is reset. On error, it is set.
|
||||||
add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
||||||
sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
||||||
jr c, .error ; not a digit on first char? error
|
ret c ; Error. If it's C, it's also going to be NZ
|
||||||
exx ; preserve bc, hl, de
|
; During this routine, we switch between HL and its shadow. On one side,
|
||||||
|
; we have HL the string pointer, and on the other side, we have HL the
|
||||||
|
; numerical result. We also use EXX to preserve BC, saving us a push.
|
||||||
|
exx ; HL as a result
|
||||||
ld h, 0
|
ld h, 0
|
||||||
ld l, a ; load first digit in without multiplying
|
ld l, a ; load first digit in without multiplying
|
||||||
ld b, 3 ; Carries can only occur for decimals >=5 in length
|
ld b, 0 ; We use B to detect overflow
|
||||||
|
|
||||||
.loop:
|
.loop:
|
||||||
exx
|
exx ; HL as a string pointer
|
||||||
inc hl
|
inc hl
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
exx
|
exx ; HL as a numerical result
|
||||||
|
|
||||||
; inline parseDecimalDigit
|
; same as other above
|
||||||
add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
|
add a, 0xff-'9'
|
||||||
sub 0xff-9 ; maps to 0-9 and carries if not a digit
|
sub 0xff-9
|
||||||
jr c, .end
|
jr c, .end
|
||||||
|
|
||||||
add hl, hl ; x2
|
add hl, hl ; x2
|
||||||
|
; We do this to detect overflow at each step
|
||||||
|
rl b
|
||||||
ld d, h
|
ld d, h
|
||||||
ld e, l ; de is x2
|
ld e, l ; de is x2
|
||||||
add hl, hl ; x4
|
add hl, hl ; x4
|
||||||
|
rl b
|
||||||
add hl, hl ; x8
|
add hl, hl ; x8
|
||||||
|
rl b
|
||||||
add hl, de ; x10
|
add hl, de ; x10
|
||||||
|
rl b
|
||||||
ld d, 0
|
ld d, 0
|
||||||
ld e, a
|
ld e, a
|
||||||
add hl, de
|
add hl, de
|
||||||
jr c, .end ; if hl was 0x1999, it may carry here
|
rl b
|
||||||
djnz .loop
|
; Did we oveflow?
|
||||||
|
xor a
|
||||||
|
or b
|
||||||
|
jr z, .loop ; No? continue
|
||||||
|
; error, NZ already set
|
||||||
|
exx ; HL is now string pointer, restore BC
|
||||||
|
; HL points to the char following the last success.
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
inc b ; so loop only executes once more
|
|
||||||
; only numbers >0x1999 can carry when multiplied by 10.
|
|
||||||
ld de, 0xE666
|
|
||||||
ex de, hl
|
|
||||||
add hl, de
|
|
||||||
ex de, hl
|
|
||||||
jr nc, .loop ; if it doesn't carry, it's small enough
|
|
||||||
|
|
||||||
exx
|
|
||||||
inc hl
|
|
||||||
ld a, (hl)
|
|
||||||
exx
|
|
||||||
add a, 0xd0 ; the next line expects a null to be mapped to 0xd0
|
|
||||||
.end:
|
.end:
|
||||||
; Because of the add and sub in parseDecimalDigit, null is mapped
|
push hl ; --> lvl 1, result
|
||||||
; to 0x00+(0xff-'9')-(0xff-9)=-0x30=0xd0
|
exx ; HL as a string pointer, restore BC
|
||||||
sub 0xd0 ; if a is null, set Z
|
pop de ; <-- lvl 1, result
|
||||||
; a is checked for null before any errors
|
cp a ; ensure Z
|
||||||
push hl ; --> lvl 2, result
|
ret
|
||||||
exx ; restore original bc
|
|
||||||
pop de ; <-- lvl 2, result
|
; Call parseDecimal and then check that HL points to a whitespace or a null.
|
||||||
pop hl ; <-- lvl 1, orig
|
parseDecimalC:
|
||||||
ret z
|
call parseDecimal
|
||||||
; A is not 0? Ok, but if it's a space, we're happy too.
|
ret nz
|
||||||
|
ld a, (hl)
|
||||||
|
or a
|
||||||
|
ret z ; null? we're happy
|
||||||
jp isWS
|
jp isWS
|
||||||
.error:
|
|
||||||
pop hl ; <-- lvl 1, orig
|
|
||||||
jp unsetZ
|
|
||||||
|
|
||||||
; Parse string at (HL) as a hexadecimal value without the "0x" prefix and
|
; Parse string at (HL) as a hexadecimal value without the "0x" prefix and
|
||||||
; return value in DE.
|
; return value in DE.
|
||||||
@ -188,7 +184,10 @@ parseLiteral:
|
|||||||
jr z, .char
|
jr z, .char
|
||||||
cp '0'
|
cp '0'
|
||||||
jr z, .hexOrBin
|
jr z, .hexOrBin
|
||||||
jp parseDecimal
|
push hl
|
||||||
|
call parseDecimalC
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
|
||||||
; Parse string at (HL) and, if it is a char literal, sets Z and return
|
; Parse string at (HL) and, if it is a char literal, sets Z and return
|
||||||
; corresponding value in E. D is always zero.
|
; corresponding value in E. D is always zero.
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
.equ RAMSTART 0x4000
|
|
||||||
; declare DIREC_LASTVAL manually so that we don't have to include directive.asm
|
|
||||||
.equ DIREC_LASTVAL RAMSTART
|
|
||||||
|
|
||||||
jp test
|
jp test
|
||||||
|
|
||||||
.inc "core.asm"
|
.inc "core.asm"
|
||||||
@ -9,7 +5,6 @@ jp test
|
|||||||
.inc "lib/util.asm"
|
.inc "lib/util.asm"
|
||||||
.inc "zasm/util.asm"
|
.inc "zasm/util.asm"
|
||||||
.inc "lib/parse.asm"
|
.inc "lib/parse.asm"
|
||||||
.inc "zasm/parse.asm"
|
|
||||||
|
|
||||||
; mocks. aren't used in tests
|
; mocks. aren't used in tests
|
||||||
zasmGetPC:
|
zasmGetPC:
|
||||||
@ -28,8 +23,7 @@ s0b01010101: .db "0b01010101", 0
|
|||||||
sFoo: .db "Foo", 0
|
sFoo: .db "Foo", 0
|
||||||
|
|
||||||
test:
|
test:
|
||||||
ld hl, 0xffff
|
ld sp, 0xffff
|
||||||
ld sp, hl
|
|
||||||
|
|
||||||
call testLiteral
|
call testLiteral
|
||||||
call testDecimal
|
call testDecimal
|
||||||
@ -42,11 +36,10 @@ testLiteral:
|
|||||||
ld hl, s99
|
ld hl, s99
|
||||||
call parseLiteral
|
call parseLiteral
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
push ix \ pop hl
|
ld a, d
|
||||||
ld a, h
|
|
||||||
or a
|
or a
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, l
|
ld a, e
|
||||||
cp 99
|
cp 99
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
call nexttest
|
call nexttest
|
||||||
@ -54,11 +47,10 @@ testLiteral:
|
|||||||
ld hl, s0x100
|
ld hl, s0x100
|
||||||
call parseLiteral
|
call parseLiteral
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
push ix \ pop hl
|
ld a, d
|
||||||
ld a, h
|
|
||||||
cp 1
|
cp 1
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, l
|
ld a, e
|
||||||
or a
|
or a
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
call nexttest
|
call nexttest
|
||||||
@ -71,11 +63,10 @@ testLiteral:
|
|||||||
ld hl, s0b0101
|
ld hl, s0b0101
|
||||||
call parseLiteral
|
call parseLiteral
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
push ix \ pop hl
|
ld a, d
|
||||||
ld a, h
|
|
||||||
or a
|
or a
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, l
|
ld a, e
|
||||||
cp 0b0101
|
cp 0b0101
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
call nexttest
|
call nexttest
|
||||||
@ -83,11 +74,10 @@ testLiteral:
|
|||||||
ld hl, s0b01010101
|
ld hl, s0b01010101
|
||||||
call parseLiteral
|
call parseLiteral
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
push ix \ pop hl
|
ld a, d
|
||||||
ld a, h
|
|
||||||
or a
|
or a
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, l
|
ld a, e
|
||||||
cp 0b01010101
|
cp 0b01010101
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
call nexttest
|
call nexttest
|
||||||
@ -108,14 +98,15 @@ testDecimal:
|
|||||||
|
|
||||||
.loop1:
|
.loop1:
|
||||||
push hl ; --> lvl 1
|
push hl ; --> lvl 1
|
||||||
; put expected number in DE
|
; put expected number in IX
|
||||||
ld e, (hl)
|
ld e, (hl)
|
||||||
inc hl
|
inc hl
|
||||||
ld d, (hl)
|
ld d, (hl)
|
||||||
inc hl
|
inc hl
|
||||||
call parseDecimal
|
push de \ pop ix
|
||||||
|
call parseDecimalC ; --> DE
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
push ix \ pop hl
|
push ix \ pop hl ; push expected number in HL
|
||||||
ld a, h
|
ld a, h
|
||||||
cp d
|
cp d
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
@ -133,7 +124,9 @@ testDecimal:
|
|||||||
ld hl, .invalid
|
ld hl, .invalid
|
||||||
|
|
||||||
.loop2:
|
.loop2:
|
||||||
call parseDecimal
|
push hl
|
||||||
|
call parseDecimalC
|
||||||
|
pop hl
|
||||||
jp z, fail
|
jp z, fail
|
||||||
ld de, 7 ; row size
|
ld de, 7 ; row size
|
||||||
add hl, de
|
add hl, de
|
||||||
|
Loading…
Reference in New Issue
Block a user