mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-26 08:48:05 +11:00
Compare commits
5 Commits
15628da7de
...
dcb96aefe9
Author | SHA1 | Date | |
---|---|---|---|
|
dcb96aefe9 | ||
|
2503bdfced | ||
|
5f2615a134 | ||
|
346bcc3d3d | ||
|
d0f031939f |
@ -74,6 +74,8 @@ There are decimal, hexadecimal and binary literals. A "straight" number is
|
||||
parsed as a decimal. Hexadecimal literals must be prefixed with `0x` (`0xf4`).
|
||||
Binary must be prefixed with `0b` (`0b01100110`).
|
||||
|
||||
A decimal literal cannot start with `0`, with the exception of the `0` literal.
|
||||
|
||||
Decimals and hexadecimal are "flexible". Whether they're written in a byte or
|
||||
a word, you don't need to prefix them with zeroes. Watch out for overflow,
|
||||
however.
|
||||
|
@ -22,6 +22,5 @@ jp at28wMain
|
||||
.inc "core.asm"
|
||||
.inc "lib/util.asm"
|
||||
.inc "lib/parse.asm"
|
||||
.inc "lib/args.asm"
|
||||
.inc "at28w/main.asm"
|
||||
USER_RAMSTART:
|
||||
|
@ -11,15 +11,15 @@
|
||||
; *** Code ***
|
||||
|
||||
at28wMain:
|
||||
ld de, .argspecs
|
||||
ld ix, AT28W_MAXBYTES
|
||||
call parseArgs
|
||||
ld de, AT28W_MAXBYTES
|
||||
ld a, (hl)
|
||||
or a
|
||||
jr z, at28wInner ; no arg
|
||||
call parseHexadecimal ; --> DE
|
||||
jr z, at28wInner
|
||||
; bad args
|
||||
ld a, SHELL_ERR_BAD_ARGS
|
||||
ret
|
||||
.argspecs:
|
||||
.db 0b111, 0b101, 0
|
||||
|
||||
at28wInner:
|
||||
; Reminder: words in parseArgs aren't little endian. High byte is first.
|
||||
|
@ -1,111 +0,0 @@
|
||||
; *** Requirements ***
|
||||
; lib/parse
|
||||
;
|
||||
; *** Consts ***
|
||||
; maximum number of bytes to receive as args in all commands. Determines the
|
||||
; size of the args variable.
|
||||
.equ PARSE_ARG_MAXCOUNT 3
|
||||
|
||||
; *** Code ***
|
||||
|
||||
; Parse arguments at (HL) with specifiers at (DE) into (IX).
|
||||
;
|
||||
; Args specifiers are a series of flag for each arg:
|
||||
; Bit 0 - arg present: if unset, we stop parsing there
|
||||
; Bit 1 - is word: this arg is a word rather than a byte. Because our
|
||||
; destination are bytes anyway, this doesn't change much except
|
||||
; for whether we expect a space between the hex pairs. If set,
|
||||
; you still need to have a specifier for the second part of
|
||||
; the multibyte.
|
||||
; Bit 2 - optional: If set and not present during parsing, we don't error out
|
||||
; and write zero
|
||||
;
|
||||
; Bit 3 - String argument: If set, this argument is a string. A pointer to the
|
||||
; read string, null terminated (max 0x20 chars) will
|
||||
; be placed in the next two bytes. This has to be the
|
||||
; last argument of the list and it stops parsing.
|
||||
; Sets A to nonzero if there was an error during parsing, zero otherwise.
|
||||
parseArgs:
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
push ix
|
||||
|
||||
; init the arg value to a default 0
|
||||
xor a
|
||||
ld (ix), a
|
||||
ld (ix+1), a
|
||||
ld (ix+2), a
|
||||
ld b, PARSE_ARG_MAXCOUNT
|
||||
.loop:
|
||||
ld a, (hl)
|
||||
; is this the end of the line?
|
||||
or a ; cp 0
|
||||
jr z, .endofargs
|
||||
|
||||
; Get the specs
|
||||
ld a, (de)
|
||||
bit 0, a ; do we have an arg?
|
||||
jr z, .error ; not set? then we have too many args
|
||||
|
||||
ld c, a ; save the specs for multibyte check later
|
||||
bit 3, a ; is our arg a string?
|
||||
jr z, .notAString
|
||||
; our arg is a string. Let's place HL in our next two bytes and call
|
||||
; it a day. Little endian, remember
|
||||
ld (ix), l
|
||||
ld (ix+1), h
|
||||
jr .success ; directly to success: skip endofargs checks
|
||||
|
||||
.notAString:
|
||||
call parseHexPair
|
||||
jr c, .error
|
||||
|
||||
; we have a good arg and we need to write A in (IX).
|
||||
ld (ix), a
|
||||
|
||||
; Good! increase counters
|
||||
inc de
|
||||
inc ix
|
||||
inc hl ; get to following char (generally a space)
|
||||
|
||||
; Our arg is parsed, our pointers are increased. Normally, HL should
|
||||
; point to a space *unless* our argspec indicates a multibyte arg.
|
||||
bit 1, c
|
||||
jr nz, .nospacecheck ; bit set? no space check
|
||||
; do we have a proper space char (or null char)?
|
||||
ld a, (hl)
|
||||
or a
|
||||
jr z, .endofargs
|
||||
cp ' '
|
||||
jr nz, .error
|
||||
inc hl
|
||||
.nospacecheck:
|
||||
djnz .loop
|
||||
; If we get here, it means that our next char *has* to be a null char
|
||||
ld a, (hl)
|
||||
or a ; cp 0
|
||||
jr z, .success ; zero? great!
|
||||
jr .error
|
||||
|
||||
.endofargs:
|
||||
; We encountered our null char. Let's verify that we either have no
|
||||
; more args or that they are optional
|
||||
ld a, (de)
|
||||
or a
|
||||
jr z, .success ; no arg? success
|
||||
bit 2, a
|
||||
jr z, .error ; if unset, arg is not optional. error
|
||||
; success
|
||||
.success:
|
||||
xor a
|
||||
jr .end
|
||||
.error:
|
||||
inc a
|
||||
.end:
|
||||
pop ix
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
ret
|
||||
|
@ -22,42 +22,6 @@ parseHex:
|
||||
ret
|
||||
|
||||
|
||||
; Parses 2 characters of the string pointed to by HL and returns the numerical
|
||||
; value in A. If the second character is a "special" character (<0x21) we don't
|
||||
; error out: the result will be the one from the first char only.
|
||||
; HL is set to point to the last char of the pair.
|
||||
;
|
||||
; On success, the carry flag is reset. On error, it is set.
|
||||
parseHexPair:
|
||||
push bc
|
||||
|
||||
ld a, (hl)
|
||||
call parseHex
|
||||
jr c, .end ; error? goto end, keeping the C flag on
|
||||
rla \ rla \ rla \ rla ; let's push this in MSB
|
||||
ld b, a
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
cp 0x21
|
||||
jr c, .single ; special char? single digit
|
||||
call parseHex
|
||||
jr c, .end ; error?
|
||||
or b ; join left-shifted + new. we're done!
|
||||
; C flag was set on parseHex and is necessarily clear at this point
|
||||
jr .end
|
||||
|
||||
.single:
|
||||
; If we have a single digit, our result is already stored in B, but
|
||||
; we have to right-shift it back.
|
||||
ld a, b
|
||||
and 0xf0
|
||||
rra \ rra \ rra \ rra
|
||||
dec hl
|
||||
|
||||
.end:
|
||||
pop bc
|
||||
ret
|
||||
|
||||
; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
|
||||
; result in A.
|
||||
;
|
||||
@ -140,71 +104,45 @@ parseDecimal:
|
||||
pop hl ; <-- lvl 1, orig
|
||||
jp unsetZ
|
||||
|
||||
; Parse string at (HL) as a hexadecimal value and return value in DE under the
|
||||
; same conditions as parseLiteral.
|
||||
; Parse string at (HL) as a hexadecimal value without the "0x" prefix and
|
||||
; return value in DE.
|
||||
; HL is advanced to the character following the last successfully read char.
|
||||
; Sets Z on success.
|
||||
parseHexadecimal:
|
||||
call hasHexPrefix
|
||||
ret nz
|
||||
push hl
|
||||
ld d, 0
|
||||
inc hl ; get rid of "0x"
|
||||
inc hl
|
||||
call strlen
|
||||
cp 3
|
||||
jr c, .single
|
||||
cp 4
|
||||
jr c, .doubleShort ; 0x123
|
||||
cp 5
|
||||
jr c, .double ; 0x1234
|
||||
; too long, error
|
||||
jr .error
|
||||
.double:
|
||||
call parseHexPair
|
||||
jr c, .error
|
||||
inc hl ; now HL is on first char of next pair
|
||||
ld d, a
|
||||
jr .single
|
||||
.doubleShort:
|
||||
ld a, (hl)
|
||||
call parseHex
|
||||
jr c, .error
|
||||
inc hl ; now HL is on first char of next pair
|
||||
ld d, a
|
||||
.single:
|
||||
call parseHexPair
|
||||
jr c, .error
|
||||
jp c, unsetZ ; we need at least one char
|
||||
push bc
|
||||
ld de, 0
|
||||
ld b, 0
|
||||
.loop:
|
||||
; we push to B to verify overflow
|
||||
rl e \ rl d \ rl b
|
||||
rl e \ rl d \ rl b
|
||||
rl e \ rl d \ rl b
|
||||
rl e \ rl d \ rl b
|
||||
or e
|
||||
ld e, a
|
||||
cp a ; ensure Z
|
||||
jr .end
|
||||
.error:
|
||||
call unsetZ
|
||||
.end:
|
||||
pop hl
|
||||
ret
|
||||
|
||||
; Sets Z if (HL) has a '0x' prefix.
|
||||
hasHexPrefix:
|
||||
ld a, (hl)
|
||||
cp '0'
|
||||
ret nz
|
||||
push hl
|
||||
; did we overflow?
|
||||
ld a, b
|
||||
or a
|
||||
jr nz, .end ; overflow, NZ already set
|
||||
; next char
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
cp 'x'
|
||||
pop hl
|
||||
call parseHex
|
||||
jr nc, .loop
|
||||
cp a ; ensure Z
|
||||
.end:
|
||||
pop bc
|
||||
ret
|
||||
|
||||
; Parse string at (HL) as a binary value (0b010101) and return value in E.
|
||||
; D is always zero.
|
||||
; Parse string at (HL) as a binary value (010101) without the "0b" prefix and
|
||||
; return value in E. D is always zero.
|
||||
; Sets Z on success.
|
||||
parseBinaryLiteral:
|
||||
call hasBinPrefix
|
||||
ret nz
|
||||
push bc
|
||||
push hl
|
||||
ld d, 0
|
||||
inc hl ; get rid of "0b"
|
||||
inc hl
|
||||
call strlen
|
||||
or a
|
||||
jr z, .error ; empty, error
|
||||
@ -237,49 +175,6 @@ parseBinaryLiteral:
|
||||
pop bc
|
||||
ret
|
||||
|
||||
; Sets Z if (HL) has a '0b' prefix.
|
||||
hasBinPrefix:
|
||||
ld a, (hl)
|
||||
cp '0'
|
||||
ret nz
|
||||
push hl
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
cp 'b'
|
||||
pop hl
|
||||
ret
|
||||
|
||||
; Parse string at (HL) and, if it is a char literal, sets Z and return
|
||||
; corresponding value in E. D is always zero.
|
||||
;
|
||||
; A valid char literal starts with ', ends with ' and has one character in the
|
||||
; middle. No escape sequence are accepted, but ''' will return the apostrophe
|
||||
; character.
|
||||
parseCharLiteral:
|
||||
ld a, 0x27 ; apostrophe (') char
|
||||
cp (hl)
|
||||
ret nz
|
||||
|
||||
push hl
|
||||
inc hl
|
||||
inc hl
|
||||
cp (hl)
|
||||
jr nz, .end ; not ending with an apostrophe
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
or a ; cp 0
|
||||
jr nz, .end ; string has to end there
|
||||
; Valid char, good
|
||||
ld d, a ; A is zero, take advantage of that
|
||||
dec hl
|
||||
dec hl
|
||||
ld a, (hl)
|
||||
ld e, a
|
||||
cp a ; ensure Z
|
||||
.end:
|
||||
pop hl
|
||||
ret
|
||||
|
||||
; Parses the string at (HL) and returns the 16-bit value in DE. The string
|
||||
; can be a decimal literal (1234), a hexadecimal literal (0x1234) or a char
|
||||
; literal ('X').
|
||||
@ -287,11 +182,59 @@ parseCharLiteral:
|
||||
; As soon as the number doesn't fit 16-bit any more, parsing stops and the
|
||||
; number is invalid. If the number is valid, Z is set, otherwise, unset.
|
||||
parseLiteral:
|
||||
call parseCharLiteral
|
||||
ret z
|
||||
call parseHexadecimal
|
||||
ret z
|
||||
call parseBinaryLiteral
|
||||
ret z
|
||||
ld de, 0 ; pre-fill
|
||||
ld a, (hl)
|
||||
cp 0x27 ; apostrophe
|
||||
jr z, .char
|
||||
cp '0'
|
||||
jr z, .hexOrBin
|
||||
jp parseDecimal
|
||||
|
||||
; Parse string at (HL) and, if it is a char literal, sets Z and return
|
||||
; corresponding value in E. D is always zero.
|
||||
;
|
||||
; A valid char literal starts with ', ends with ' and has one character in the
|
||||
; middle. No escape sequence are accepted, but ''' will return the apostrophe
|
||||
; character.
|
||||
.char:
|
||||
push hl
|
||||
inc hl
|
||||
inc hl
|
||||
cp (hl)
|
||||
jr nz, .charEnd ; not ending with an apostrophe
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
or a ; cp 0
|
||||
jr nz, .charEnd ; string has to end there
|
||||
; Valid char, good
|
||||
dec hl
|
||||
dec hl
|
||||
ld e, (hl)
|
||||
cp a ; ensure Z
|
||||
.charEnd:
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.hexOrBin:
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
inc hl ; already place it for hex or bin
|
||||
cp 'x'
|
||||
jr z, .hex
|
||||
cp 'b'
|
||||
jr z, .bin
|
||||
; special case: single '0'. set Z if we hit have null terminating.
|
||||
or a
|
||||
.hexOrBinEnd:
|
||||
dec hl \ dec hl ; replace HL
|
||||
ret ; Z already set
|
||||
|
||||
.hex:
|
||||
push hl
|
||||
call parseHexadecimal
|
||||
pop hl
|
||||
jr .hexOrBinEnd
|
||||
|
||||
.bin:
|
||||
call parseBinaryLiteral
|
||||
jr .hexOrBinEnd
|
||||
|
@ -5,6 +5,31 @@ isWS:
|
||||
cp 0x09
|
||||
ret
|
||||
|
||||
; Advance HL to next WS.
|
||||
; Set Z if WS found, unset if end-of-string.
|
||||
toWS:
|
||||
ld a, (hl)
|
||||
call isWS
|
||||
ret z
|
||||
or a
|
||||
jp z, unsetZ
|
||||
inc hl
|
||||
jr toWS
|
||||
|
||||
; Consume following whitespaces in HL until a non-WS is hit.
|
||||
; Set Z if non-WS found, unset if end-of-string.
|
||||
rdWS:
|
||||
ld a, (hl)
|
||||
call isWS
|
||||
jr nz, .ok
|
||||
or a
|
||||
jp z, unsetZ
|
||||
inc hl
|
||||
jr rdWS
|
||||
.ok:
|
||||
cp a ; ensure Z
|
||||
ret
|
||||
|
||||
; Copy string from (HL) in (DE), that is, copy bytes until a null char is
|
||||
; encountered. The null char is also copied.
|
||||
; HL and DE point to the char right after the null char.
|
||||
|
@ -68,7 +68,6 @@ jp zasmMain
|
||||
.inc "lib/util.asm"
|
||||
.inc "lib/ari.asm"
|
||||
.inc "lib/parse.asm"
|
||||
.inc "lib/args.asm"
|
||||
.inc "zasm/util.asm"
|
||||
.equ IO_RAMSTART USER_RAMSTART
|
||||
.inc "zasm/io.asm"
|
||||
|
@ -25,7 +25,6 @@ jp zasmMain
|
||||
.inc "lib/util.asm"
|
||||
.inc "lib/ari.asm"
|
||||
.inc "lib/parse.asm"
|
||||
.inc "lib/args.asm"
|
||||
.inc "zasm/util.asm"
|
||||
.equ IO_RAMSTART USER_RAMSTART
|
||||
.inc "zasm/io.asm"
|
||||
|
@ -23,34 +23,34 @@
|
||||
; HL is set to the last lineno to be read.
|
||||
; Sets Z on success, unset on error. On error, A contains an error code (ERR_*)
|
||||
zasmMain:
|
||||
; Parse args. HL points to string already
|
||||
; We don't allocate memory just to hold this. Because this happens
|
||||
; before initialization, we don't really care where those args are
|
||||
; parsed. That's why we borrow zasm's RAMSTART for a little while.
|
||||
ld de, .argspecs
|
||||
ld ix, ZASM_RAMSTART
|
||||
call parseArgs
|
||||
jr z, .goodargs
|
||||
; bad args
|
||||
ld hl, 0
|
||||
ld de, 0
|
||||
ld a, SHELL_ERR_BAD_ARGS
|
||||
ret
|
||||
|
||||
.goodargs:
|
||||
; HL now points to parsed args
|
||||
; Init I/O
|
||||
ld a, (ZASM_RAMSTART) ; blkdev in ID
|
||||
; Parse args in (HL)
|
||||
; blkdev in
|
||||
call parseHexadecimal ; --> DE
|
||||
jr nz, .badargs
|
||||
ld a, e
|
||||
ld de, IO_IN_BLK
|
||||
call blkSel
|
||||
ld a, (ZASM_RAMSTART+1) ; blkdev out ID
|
||||
|
||||
; blkdev in
|
||||
call rdWS
|
||||
jr nz, .badargs
|
||||
call parseHexadecimal ; --> DE
|
||||
jr nz, .badargs
|
||||
ld a, e
|
||||
ld de, IO_OUT_BLK
|
||||
call blkSel
|
||||
|
||||
; Init .org
|
||||
; This is the 3rd argument, optional, will be zero if not given.
|
||||
; .org high byte
|
||||
ld e, 0 ; in case we .skipOrgSet
|
||||
call rdWS
|
||||
jr nz, .skipOrgSet ; no org argument
|
||||
call parseHexadecimal ; --> DE
|
||||
jr nz, .badargs
|
||||
|
||||
.skipOrgSet:
|
||||
; Init .org with value of E
|
||||
; Save in "@" too
|
||||
ld a, (ZASM_RAMSTART+2)
|
||||
ld a, e
|
||||
ld (ZASM_ORG+1), a ; high byte of .org
|
||||
ld (DIREC_LASTVAL+1), a
|
||||
xor a
|
||||
@ -82,8 +82,11 @@ zasmMain:
|
||||
.end:
|
||||
jp ioLineNo ; --> HL, --> DE, returns
|
||||
|
||||
.argspecs:
|
||||
.db 0b001, 0b001, 0b101
|
||||
.badargs:
|
||||
; bad args
|
||||
ld a, SHELL_ERR_BAD_ARGS
|
||||
ret
|
||||
|
||||
.sFirstPass:
|
||||
.db "First pass", 0
|
||||
.sSecondPass:
|
||||
|
@ -16,7 +16,6 @@
|
||||
jp upcase
|
||||
jp findchar
|
||||
jp parseHex
|
||||
jp parseHexPair
|
||||
jp blkSel
|
||||
jp blkSet
|
||||
jp fsFindFN
|
||||
@ -145,9 +144,9 @@ basFindCmdExtra:
|
||||
jp basPgmHook
|
||||
.mycmds:
|
||||
.db "ed", 0
|
||||
.dw 0x1e00
|
||||
.dw 0x1f00
|
||||
.db "zasm", 0
|
||||
.dw 0x2300
|
||||
.dw 0x2400
|
||||
.db 0xff
|
||||
|
||||
f0GetB:
|
||||
@ -166,13 +165,13 @@ f1PutB:
|
||||
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
||||
jp fsPutB
|
||||
|
||||
; last time I checked, PC at this point was 0x1df8. Let's give us a nice margin
|
||||
; last time I checked, PC at this point was 0x1e92. Let's give us a nice margin
|
||||
; for the start of ed.
|
||||
.fill 0x1e00-$
|
||||
.fill 0x1f00-$
|
||||
.bin "ed.bin"
|
||||
|
||||
; Last check: 0x22dd
|
||||
.fill 0x2300-$
|
||||
; Last check: 0x23b0
|
||||
.fill 0x2400-$
|
||||
.bin "zasm.bin"
|
||||
|
||||
.fill 0x7ff0-$
|
||||
|
@ -14,7 +14,6 @@
|
||||
.equ upcase @+3
|
||||
.equ findchar @+3
|
||||
.equ parseHex @+3
|
||||
.equ parseHexPair @+3
|
||||
.equ blkSel @+3
|
||||
.equ blkSet @+3
|
||||
.equ fsFindFN @+3
|
||||
|
85
tools/tests/unit/test_lib_parse.asm
Normal file
85
tools/tests/unit/test_lib_parse.asm
Normal file
@ -0,0 +1,85 @@
|
||||
jp test
|
||||
|
||||
.inc "core.asm"
|
||||
.inc "lib/util.asm"
|
||||
.inc "lib/parse.asm"
|
||||
|
||||
zasmGetPC:
|
||||
ret
|
||||
|
||||
testNum: .db 1
|
||||
|
||||
test:
|
||||
ld sp, 0xffff
|
||||
|
||||
call testParseHex
|
||||
call testParseHexadecimal
|
||||
|
||||
; success
|
||||
xor a
|
||||
halt
|
||||
|
||||
testParseHex:
|
||||
ld a, '8'
|
||||
call parseHex
|
||||
jp c, fail
|
||||
cp 8
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld a, 'e'
|
||||
call parseHex
|
||||
jp c, fail
|
||||
cp 0xe
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld a, 'x'
|
||||
call parseHex
|
||||
jp nc, fail
|
||||
call nexttest
|
||||
ret
|
||||
|
||||
testParseHexadecimal:
|
||||
ld hl, .s99
|
||||
call parseHexadecimal
|
||||
jp nz, fail
|
||||
ld a, e
|
||||
cp 0x99
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld hl, .saB
|
||||
call parseHexadecimal
|
||||
jp nz, fail
|
||||
ld a, e
|
||||
cp 0xab
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
; The string "Foo" will not cause a failure. We will parse up to "o"
|
||||
; and then stop.
|
||||
ld hl, .sFoo
|
||||
call parseHexadecimal
|
||||
jp nz, fail
|
||||
ld a, e
|
||||
cp 0xf
|
||||
call nexttest
|
||||
ret
|
||||
|
||||
.sFoo: .db "Foo", 0
|
||||
.saB: .db "aB", 0
|
||||
.s99: .db "99", 0
|
||||
|
||||
nexttest:
|
||||
ld a, (testNum)
|
||||
inc a
|
||||
ld (testNum), a
|
||||
ret
|
||||
|
||||
fail:
|
||||
ld a, (testNum)
|
||||
halt
|
||||
|
||||
; used as RAM
|
||||
sandbox:
|
@ -1,136 +0,0 @@
|
||||
jp test
|
||||
|
||||
.inc "core.asm"
|
||||
.inc "lib/util.asm"
|
||||
.inc "lib/parse.asm"
|
||||
.inc "lib/args.asm"
|
||||
|
||||
zasmGetPC:
|
||||
ret
|
||||
|
||||
testNum: .db 1
|
||||
|
||||
test:
|
||||
ld hl, 0xffff
|
||||
ld sp, hl
|
||||
|
||||
call testParseHex
|
||||
call testParseHexPair
|
||||
call testParseArgs
|
||||
|
||||
; success
|
||||
xor a
|
||||
halt
|
||||
|
||||
testParseHex:
|
||||
ld a, '8'
|
||||
call parseHex
|
||||
jp c, fail
|
||||
cp 8
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld a, 'e'
|
||||
call parseHex
|
||||
jp c, fail
|
||||
cp 0xe
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld a, 'x'
|
||||
call parseHex
|
||||
jp nc, fail
|
||||
call nexttest
|
||||
ret
|
||||
|
||||
testParseHexPair:
|
||||
ld hl, .s99
|
||||
call parseHexPair
|
||||
jp c, fail
|
||||
cp 0x99
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld hl, .saB
|
||||
call parseHexPair
|
||||
jp c, fail
|
||||
cp 0xab
|
||||
jp nz, fail
|
||||
call nexttest
|
||||
|
||||
ld hl, .sFoo
|
||||
call parseHexPair
|
||||
jp nc, fail
|
||||
call nexttest
|
||||
ret
|
||||
|
||||
.sFoo: .db "Foo", 0
|
||||
.saB: .db "aB", 0
|
||||
.s99: .db "99", 0
|
||||
|
||||
|
||||
testParseArgs:
|
||||
ld hl, .t1+6
|
||||
ld de, .t1
|
||||
ld iy, .t1+3
|
||||
call .testargs
|
||||
|
||||
ld hl, .t2+6
|
||||
ld de, .t2
|
||||
ld iy, .t2+3
|
||||
call .testargs
|
||||
|
||||
ld hl, .t3+6
|
||||
ld de, .t3
|
||||
ld iy, .t3+3
|
||||
call .testargs
|
||||
ret
|
||||
|
||||
; HL and DE must be set, and IY must point to expected results in IX
|
||||
.testargs:
|
||||
ld ix, sandbox
|
||||
call parseArgs
|
||||
jp nz, fail
|
||||
ld a, (ix)
|
||||
cp (iy)
|
||||
jp nz, fail
|
||||
ld a, (ix+1)
|
||||
cp (iy+1)
|
||||
jp nz, fail
|
||||
ld a, (ix+2)
|
||||
cp (iy+2)
|
||||
jp nz, fail
|
||||
jp nexttest
|
||||
|
||||
; Test data format: 3 bytes specs, 3 bytes expected (IX), then the arg string.
|
||||
|
||||
; Empty args with empty specs
|
||||
.t1:
|
||||
.db 0b0000, 0b0000, 0b0000
|
||||
.db 0, 0, 0
|
||||
.db 0
|
||||
|
||||
; One arg, one byte spec
|
||||
.t2:
|
||||
.db 0b0001, 0b0000, 0b0000
|
||||
.db 0xe4, 0, 0
|
||||
.db "e4", 0
|
||||
|
||||
; 3 args, 3 bytes spec
|
||||
.t3:
|
||||
.db 0b0001, 0b0001, 0b0001
|
||||
.db 0xe4, 0xab, 0x99
|
||||
.db "e4 ab 99", 0
|
||||
|
||||
nexttest:
|
||||
ld a, (testNum)
|
||||
inc a
|
||||
ld (testNum), a
|
||||
ret
|
||||
|
||||
fail:
|
||||
ld a, (testNum)
|
||||
halt
|
||||
|
||||
; used as RAM
|
||||
sandbox:
|
Loading…
Reference in New Issue
Block a user