collapseos/apps/zasm/parse.asm

262 lines
4.8 KiB
NASM
Raw Normal View History

2019-05-10 21:19:34 -04:00
; 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.
parseDecimalDigit:
; First, let's see if we have an easy 0-9 case
cp '0'
ret c ; if < '0', we have a problem
2019-05-18 19:59:58 -04:00
sub '0' ; our value now is valid if it's < 10
2019-05-10 21:19:34 -04:00
cp 10 ; on success, C is set, which is the opposite
; of what we want
ccf ; invert C flag
ret
2019-05-09 15:55:29 -04:00
2019-05-10 21:19:34 -04:00
; Parse string at (HL) as a decimal value and return value in IX under the
2019-05-14 13:53:12 -04:00
; same conditions as parseLiteral.
2019-05-10 21:19:34 -04:00
parseDecimal:
push hl
push de
push bc
2019-05-10 21:19:34 -04:00
ld ix, 0
.loop:
ld a, (hl)
2019-05-18 19:59:58 -04:00
or a
2019-05-10 21:19:34 -04:00
jr z, .end ; success!
call parseDecimalDigit
jr c, .error
2019-05-10 21:19:34 -04:00
; Now, let's add A to IX. First, multiply by 10.
2019-05-18 19:59:58 -04:00
push ix \ pop de
2019-05-10 21:19:34 -04:00
add ix, ix ; x2
2019-05-18 19:59:58 -04:00
jr c, .error
2019-05-10 21:19:34 -04:00
add ix, ix ; x4
2019-05-18 19:59:58 -04:00
jr c, .error
2019-05-10 21:19:34 -04:00
add ix, ix ; x8
2019-05-18 19:59:58 -04:00
jr c, .error
2019-05-10 21:19:34 -04:00
add ix, de ; x9
2019-05-18 19:59:58 -04:00
jr c, .error
2019-05-10 21:19:34 -04:00
add ix, de ; x10
2019-05-18 19:59:58 -04:00
jr c, .error
ld d, 0
ld e, a
add ix, de
jr c, .error
2019-05-10 21:19:34 -04:00
inc hl
jr .loop
.error:
call unsetZ
2019-05-10 21:19:34 -04:00
.end:
pop bc
pop de
pop hl
ret
2019-05-10 21:19:34 -04:00
; Parse string at (HL) as a hexadecimal value and return value in IX under the
2019-05-14 13:53:12 -04:00
; same conditions as parseLiteral.
2019-05-10 21:19:34 -04:00
parseHexadecimal:
2019-05-14 13:53:12 -04:00
call hasHexPrefix
ret nz
2019-05-09 21:21:08 -04:00
push hl
2019-05-18 19:59:58 -04:00
push de
ld d, 0
2019-05-10 21:19:34 -04:00
inc hl ; get rid of "0x"
2019-05-09 21:21:08 -04:00
inc hl
2019-05-10 21:19:34 -04:00
call strlen
cp 3
jr c, .single
2019-05-17 23:00:57 -04:00
cp 4
jr c, .doubleShort ; 0x123
2019-05-10 21:19:34 -04:00
cp 5
2019-05-17 23:00:57 -04:00
jr c, .double ; 0x1234
2019-05-10 21:19:34 -04:00
; too long, error
jr .error
.double:
2019-05-17 23:00:57 -04:00
call parseHexPair
jr c, .error
inc hl ; now HL is on first char of next pair
2019-05-18 19:59:58 -04:00
ld d, a
2019-05-17 23:00:57 -04:00
jr .single
.doubleShort:
ld a, (hl)
call parseHex
2019-05-10 21:19:34 -04:00
jr c, .error
inc hl ; now HL is on first char of next pair
2019-05-18 19:59:58 -04:00
ld d, a
2019-05-10 21:19:34 -04:00
.single:
call parseHexPair
2019-05-10 21:19:34 -04:00
jr c, .error
2019-05-18 19:59:58 -04:00
ld e, a
2019-05-10 21:19:34 -04:00
cp a ; ensure Z
2019-05-09 21:21:08 -04:00
jr .end
2019-05-10 21:19:34 -04:00
.error:
call unsetZ
2019-05-09 21:21:08 -04:00
.end:
2019-05-18 19:59:58 -04:00
push de \ pop ix
pop de
2019-05-09 21:21:08 -04:00
pop hl
ret
2019-05-17 10:34:01 -04:00
; Sets Z if (HL) has a '0x' prefix.
2019-05-10 21:19:34 -04:00
hasHexPrefix:
ld a, (hl)
2019-05-10 21:19:34 -04:00
cp '0'
ret nz
push hl
inc hl
ld a, (hl)
2019-05-10 21:19:34 -04:00
cp 'x'
2019-05-09 15:55:29 -04:00
pop hl
ret
2019-05-10 21:19:34 -04:00
2019-05-18 19:59:58 -04:00
; Parse string at (HL) as a binary value (0b010101) and return value in IX.
; High IX byte is always clear.
2019-05-17 10:34:01 -04:00
; Sets Z on success.
parseBinaryLiteral:
call hasBinPrefix
ret nz
push bc
push hl
2019-05-18 19:59:58 -04:00
push de
ld d, 0
inc hl ; get rid of "0b"
2019-05-17 10:34:01 -04:00
inc hl
call strlen
or a
jr z, .error ; empty, error
cp 9
jr nc, .error ; >= 9, too long
; We have a string of 8 or less chars. What we'll do is that for each
; char, we rotate left and set the LSB according to whether we have '0'
; or '1'. Error out on anything else. C is our stored result.
ld b, a ; we loop for "strlen" times
ld c, 0 ; our stored result
.loop:
rlc c
ld a, (hl)
inc hl
cp '0'
jr z, .nobit ; no bit to set
cp '1'
jr nz, .error ; not 0 or 1
; We have a bit to set
inc c
.nobit:
djnz .loop
2019-05-18 19:59:58 -04:00
ld e, c
2019-05-17 10:34:01 -04:00
cp a ; ensure Z
jr .end
.error:
call unsetZ
.end:
2019-05-18 19:59:58 -04:00
push de \ pop ix
pop de
2019-05-17 10:34:01 -04:00
pop hl
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
2019-05-14 13:53:12 -04:00
; Parse string at (HL) and, if it is a char literal, sets Z and return
2019-05-18 19:59:58 -04:00
; corresponding value in IX. High IX byte is always clear.
2019-05-14 13:53:12 -04:00
;
; 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
2019-05-18 19:59:58 -04:00
push de
2019-05-14 13:53:12 -04:00
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
2019-05-18 19:59:58 -04:00
ld d, a ; A is zero, take advantage of that
2019-05-14 13:53:12 -04:00
dec hl
dec hl
ld a, (hl)
2019-05-18 19:59:58 -04:00
ld e, a
2019-05-14 13:53:12 -04:00
cp a ; ensure Z
.end:
2019-05-18 19:59:58 -04:00
push de \ pop ix
pop de
2019-05-14 13:53:12 -04:00
pop hl
ret
; Parses the string at (HL) and returns the 16-bit value in IX. The string
; can be a decimal literal (1234), a hexadecimal literal (0x1234) or a char
; literal ('X').
;
2019-05-10 21:19:34 -04:00
; 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.
2019-05-14 13:53:12 -04:00
parseLiteral:
call parseCharLiteral
ret z
call parseHexadecimal
ret z
2019-05-17 10:34:01 -04:00
call parseBinaryLiteral
ret z
2019-05-14 13:53:12 -04:00
jp parseDecimal
2019-05-10 21:19:34 -04:00
; Parse string in (HL) and return its numerical value whether its a number
; literal or a symbol. Returns value in IX.
; Sets Z if number or symbol is valid, unset otherwise.
parseNumberOrSymbol:
2019-05-14 13:53:12 -04:00
call parseLiteral
2019-05-10 21:19:34 -04:00
ret z
; Not a number. Try PC
push de
ld de, .sDollar
call strcmp
pop de
jr z, .returnPC
; Not PC either, try symbol
2019-05-15 20:07:21 -04:00
call symSelect
call symFind
2019-05-19 13:22:14 -04:00
jr nz, .notfound
; Found! let's fetch value
2019-05-10 21:19:34 -04:00
push de
call symGetVal
; value in DE. We need it in IX
2019-05-18 19:59:58 -04:00
push de \ pop ix
2019-05-10 21:19:34 -04:00
pop de
cp a ; ensure Z
2019-05-09 15:55:29 -04:00
ret
2019-05-19 13:22:14 -04:00
.notfound:
; If not found, check if we're in first pass. If we are, it doesn't
; matter that we didn't find our symbol. Return success anyhow.
; Otherwise return error. Z is already unset, so in fact, this is the
; same as jumping to zasmIsFirstPass
jp zasmIsFirstPass
.returnPC:
push hl
call zasmGetPC
push hl \ pop ix
pop hl
ret
.sDollar:
.db '$', 0