mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 18:20:55 +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`).
|
parsed as a decimal. Hexadecimal literals must be prefixed with `0x` (`0xf4`).
|
||||||
Binary must be prefixed with `0b` (`0b01100110`).
|
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
|
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,
|
a word, you don't need to prefix them with zeroes. Watch out for overflow,
|
||||||
however.
|
however.
|
||||||
|
@ -22,6 +22,5 @@ jp at28wMain
|
|||||||
.inc "core.asm"
|
.inc "core.asm"
|
||||||
.inc "lib/util.asm"
|
.inc "lib/util.asm"
|
||||||
.inc "lib/parse.asm"
|
.inc "lib/parse.asm"
|
||||||
.inc "lib/args.asm"
|
|
||||||
.inc "at28w/main.asm"
|
.inc "at28w/main.asm"
|
||||||
USER_RAMSTART:
|
USER_RAMSTART:
|
||||||
|
@ -11,15 +11,15 @@
|
|||||||
; *** Code ***
|
; *** Code ***
|
||||||
|
|
||||||
at28wMain:
|
at28wMain:
|
||||||
ld de, .argspecs
|
ld de, AT28W_MAXBYTES
|
||||||
ld ix, AT28W_MAXBYTES
|
ld a, (hl)
|
||||||
call parseArgs
|
or a
|
||||||
|
jr z, at28wInner ; no arg
|
||||||
|
call parseHexadecimal ; --> DE
|
||||||
jr z, at28wInner
|
jr z, at28wInner
|
||||||
; bad args
|
; bad args
|
||||||
ld a, SHELL_ERR_BAD_ARGS
|
ld a, SHELL_ERR_BAD_ARGS
|
||||||
ret
|
ret
|
||||||
.argspecs:
|
|
||||||
.db 0b111, 0b101, 0
|
|
||||||
|
|
||||||
at28wInner:
|
at28wInner:
|
||||||
; Reminder: words in parseArgs aren't little endian. High byte is first.
|
; 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
|
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
|
; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
|
||||||
; result in A.
|
; result in A.
|
||||||
;
|
;
|
||||||
@ -140,71 +104,45 @@ parseDecimal:
|
|||||||
pop hl ; <-- lvl 1, orig
|
pop hl ; <-- lvl 1, orig
|
||||||
jp unsetZ
|
jp unsetZ
|
||||||
|
|
||||||
; Parse string at (HL) as a hexadecimal value and return value in DE under the
|
; Parse string at (HL) as a hexadecimal value without the "0x" prefix and
|
||||||
; same conditions as parseLiteral.
|
; return value in DE.
|
||||||
|
; HL is advanced to the character following the last successfully read char.
|
||||||
|
; Sets Z on success.
|
||||||
parseHexadecimal:
|
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)
|
ld a, (hl)
|
||||||
call parseHex
|
call parseHex
|
||||||
jr c, .error
|
jp c, unsetZ ; we need at least one char
|
||||||
inc hl ; now HL is on first char of next pair
|
push bc
|
||||||
ld d, a
|
ld de, 0
|
||||||
.single:
|
ld b, 0
|
||||||
call parseHexPair
|
.loop:
|
||||||
jr c, .error
|
; 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
|
ld e, a
|
||||||
cp a ; ensure Z
|
; did we overflow?
|
||||||
jr .end
|
ld a, b
|
||||||
.error:
|
or a
|
||||||
call unsetZ
|
jr nz, .end ; overflow, NZ already set
|
||||||
.end:
|
; next char
|
||||||
pop hl
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Sets Z if (HL) has a '0x' prefix.
|
|
||||||
hasHexPrefix:
|
|
||||||
ld a, (hl)
|
|
||||||
cp '0'
|
|
||||||
ret nz
|
|
||||||
push hl
|
|
||||||
inc hl
|
inc hl
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
cp 'x'
|
call parseHex
|
||||||
pop hl
|
jr nc, .loop
|
||||||
|
cp a ; ensure Z
|
||||||
|
.end:
|
||||||
|
pop bc
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Parse string at (HL) as a binary value (0b010101) and return value in E.
|
; Parse string at (HL) as a binary value (010101) without the "0b" prefix and
|
||||||
; D is always zero.
|
; return value in E. D is always zero.
|
||||||
; Sets Z on success.
|
; Sets Z on success.
|
||||||
parseBinaryLiteral:
|
parseBinaryLiteral:
|
||||||
call hasBinPrefix
|
|
||||||
ret nz
|
|
||||||
push bc
|
push bc
|
||||||
push hl
|
push hl
|
||||||
ld d, 0
|
|
||||||
inc hl ; get rid of "0b"
|
|
||||||
inc hl
|
|
||||||
call strlen
|
call strlen
|
||||||
or a
|
or a
|
||||||
jr z, .error ; empty, error
|
jr z, .error ; empty, error
|
||||||
@ -237,49 +175,6 @@ parseBinaryLiteral:
|
|||||||
pop bc
|
pop bc
|
||||||
ret
|
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
|
; 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
|
; can be a decimal literal (1234), a hexadecimal literal (0x1234) or a char
|
||||||
; literal ('X').
|
; literal ('X').
|
||||||
@ -287,11 +182,59 @@ parseCharLiteral:
|
|||||||
; As soon as the number doesn't fit 16-bit any more, parsing stops and the
|
; 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.
|
; number is invalid. If the number is valid, Z is set, otherwise, unset.
|
||||||
parseLiteral:
|
parseLiteral:
|
||||||
call parseCharLiteral
|
ld de, 0 ; pre-fill
|
||||||
ret z
|
ld a, (hl)
|
||||||
call parseHexadecimal
|
cp 0x27 ; apostrophe
|
||||||
ret z
|
jr z, .char
|
||||||
call parseBinaryLiteral
|
cp '0'
|
||||||
ret z
|
jr z, .hexOrBin
|
||||||
jp parseDecimal
|
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
|
cp 0x09
|
||||||
ret
|
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
|
; Copy string from (HL) in (DE), that is, copy bytes until a null char is
|
||||||
; encountered. The null char is also copied.
|
; encountered. The null char is also copied.
|
||||||
; HL and DE point to the char right after the null char.
|
; HL and DE point to the char right after the null char.
|
||||||
|
@ -68,7 +68,6 @@ jp zasmMain
|
|||||||
.inc "lib/util.asm"
|
.inc "lib/util.asm"
|
||||||
.inc "lib/ari.asm"
|
.inc "lib/ari.asm"
|
||||||
.inc "lib/parse.asm"
|
.inc "lib/parse.asm"
|
||||||
.inc "lib/args.asm"
|
|
||||||
.inc "zasm/util.asm"
|
.inc "zasm/util.asm"
|
||||||
.equ IO_RAMSTART USER_RAMSTART
|
.equ IO_RAMSTART USER_RAMSTART
|
||||||
.inc "zasm/io.asm"
|
.inc "zasm/io.asm"
|
||||||
|
@ -25,7 +25,6 @@ jp zasmMain
|
|||||||
.inc "lib/util.asm"
|
.inc "lib/util.asm"
|
||||||
.inc "lib/ari.asm"
|
.inc "lib/ari.asm"
|
||||||
.inc "lib/parse.asm"
|
.inc "lib/parse.asm"
|
||||||
.inc "lib/args.asm"
|
|
||||||
.inc "zasm/util.asm"
|
.inc "zasm/util.asm"
|
||||||
.equ IO_RAMSTART USER_RAMSTART
|
.equ IO_RAMSTART USER_RAMSTART
|
||||||
.inc "zasm/io.asm"
|
.inc "zasm/io.asm"
|
||||||
|
@ -23,34 +23,34 @@
|
|||||||
; HL is set to the last lineno to be read.
|
; 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_*)
|
; Sets Z on success, unset on error. On error, A contains an error code (ERR_*)
|
||||||
zasmMain:
|
zasmMain:
|
||||||
; Parse args. HL points to string already
|
; Parse args in (HL)
|
||||||
; We don't allocate memory just to hold this. Because this happens
|
; blkdev in
|
||||||
; before initialization, we don't really care where those args are
|
call parseHexadecimal ; --> DE
|
||||||
; parsed. That's why we borrow zasm's RAMSTART for a little while.
|
jr nz, .badargs
|
||||||
ld de, .argspecs
|
ld a, e
|
||||||
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
|
|
||||||
ld de, IO_IN_BLK
|
ld de, IO_IN_BLK
|
||||||
call blkSel
|
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
|
ld de, IO_OUT_BLK
|
||||||
call blkSel
|
call blkSel
|
||||||
|
|
||||||
; Init .org
|
; .org high byte
|
||||||
; This is the 3rd argument, optional, will be zero if not given.
|
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
|
; Save in "@" too
|
||||||
ld a, (ZASM_RAMSTART+2)
|
ld a, e
|
||||||
ld (ZASM_ORG+1), a ; high byte of .org
|
ld (ZASM_ORG+1), a ; high byte of .org
|
||||||
ld (DIREC_LASTVAL+1), a
|
ld (DIREC_LASTVAL+1), a
|
||||||
xor a
|
xor a
|
||||||
@ -82,8 +82,11 @@ zasmMain:
|
|||||||
.end:
|
.end:
|
||||||
jp ioLineNo ; --> HL, --> DE, returns
|
jp ioLineNo ; --> HL, --> DE, returns
|
||||||
|
|
||||||
.argspecs:
|
.badargs:
|
||||||
.db 0b001, 0b001, 0b101
|
; bad args
|
||||||
|
ld a, SHELL_ERR_BAD_ARGS
|
||||||
|
ret
|
||||||
|
|
||||||
.sFirstPass:
|
.sFirstPass:
|
||||||
.db "First pass", 0
|
.db "First pass", 0
|
||||||
.sSecondPass:
|
.sSecondPass:
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
jp upcase
|
jp upcase
|
||||||
jp findchar
|
jp findchar
|
||||||
jp parseHex
|
jp parseHex
|
||||||
jp parseHexPair
|
|
||||||
jp blkSel
|
jp blkSel
|
||||||
jp blkSet
|
jp blkSet
|
||||||
jp fsFindFN
|
jp fsFindFN
|
||||||
@ -145,9 +144,9 @@ basFindCmdExtra:
|
|||||||
jp basPgmHook
|
jp basPgmHook
|
||||||
.mycmds:
|
.mycmds:
|
||||||
.db "ed", 0
|
.db "ed", 0
|
||||||
.dw 0x1e00
|
.dw 0x1f00
|
||||||
.db "zasm", 0
|
.db "zasm", 0
|
||||||
.dw 0x2300
|
.dw 0x2400
|
||||||
.db 0xff
|
.db 0xff
|
||||||
|
|
||||||
f0GetB:
|
f0GetB:
|
||||||
@ -166,13 +165,13 @@ f1PutB:
|
|||||||
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
||||||
jp fsPutB
|
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.
|
; for the start of ed.
|
||||||
.fill 0x1e00-$
|
.fill 0x1f00-$
|
||||||
.bin "ed.bin"
|
.bin "ed.bin"
|
||||||
|
|
||||||
; Last check: 0x22dd
|
; Last check: 0x23b0
|
||||||
.fill 0x2300-$
|
.fill 0x2400-$
|
||||||
.bin "zasm.bin"
|
.bin "zasm.bin"
|
||||||
|
|
||||||
.fill 0x7ff0-$
|
.fill 0x7ff0-$
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
.equ upcase @+3
|
.equ upcase @+3
|
||||||
.equ findchar @+3
|
.equ findchar @+3
|
||||||
.equ parseHex @+3
|
.equ parseHex @+3
|
||||||
.equ parseHexPair @+3
|
|
||||||
.equ blkSel @+3
|
.equ blkSel @+3
|
||||||
.equ blkSet @+3
|
.equ blkSet @+3
|
||||||
.equ fsFindFN @+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