collapseos/apps/basic/parse.asm

143 lines
3.0 KiB
NASM

; Parse an expression yielding a truth value from (HL) and set A accordingly.
; 0 for False, nonzero for True.
; How it evaluates truth is that it looks for =, <, >, >= or <= in (HL) and,
; if it finds it, evaluate left and right expressions separately. Then it
; compares both sides and set A accordingly.
; If comparison operators aren't found, the whole string is sent to parseExpr
; and zero means False, nonzero means True.
; **This routine mutates (HL).**
; Z for success.
parseTruth:
push ix
push de
ld a, '='
call .maybeFind
jr z, .foundEQ
ld a, '<'
call .maybeFind
jr z, .foundLT
ld a, '>'
call .maybeFind
jr z, .foundGT
jr .simple
.success:
cp a ; ensure Z
.end:
pop de
pop ix
ret
.maybeFind:
push hl ; --> lvl 1
call findchar
jr nz, .notFound
; found! We want to keep new HL around. Let's pop old HL in DE
pop de ; <-- lvl 1
ret
.notFound:
; not found, restore HL
pop hl ; <-- lvl 1
ret
.simple:
call parseExpr
jr nz, .end
ld a, d
or e
jr .success
.foundEQ:
; we found an '=' char and HL is pointing to it. DE is pointing to the
; beginning of our string. Let's separate those two strings.
; But before we do that, to we have a '<' or a '>' at the left of (HL)?
dec hl
ld a, (hl)
cp '<'
jr z, .foundLTE
cp '>'
jr z, .foundGTE
inc hl
; Ok, we are a straight '='. Proceed.
call .splitLR
; HL now point to right-hand, DE to left-hand
call .parseLeftRight
jr nz, .end ; error, stop
xor a ; clear carry and prepare value for False
sbc hl, de
jr nz, .success ; NZ? equality not met. A already 0, return.
; Z? equality met, make A=1, set Z
inc a
jr .success
.foundLTE:
; Almost the same as '<', but we have two sep chars
call .splitLR
inc hl ; skip the '=' char
call .parseLeftRight
jr nz, .end
ld a, 1 ; prepare for True
sbc hl, de
jr nc, .success ; Left <= Right, True
; Left > Right, False
dec a
jr .success
.foundGTE:
; Almost the same as '<='
call .splitLR
inc hl ; skip the '=' char
call .parseLeftRight
jr nz, .end
ld a, 1 ; prepare for True
sbc hl, de
jr z, .success ; Left == Right, True
jr c, .success ; Left > Right, True
; Left < Right, False
dec a
jr .success
.foundLT:
; Same thing as EQ, but for '<'
call .splitLR
call .parseLeftRight
jr nz, .end
xor a
sbc hl, de
jr z, .success ; Left == Right, False
jr c, .success ; Left > Right, False
; Left < Right, True
inc a
jr .success
.foundGT:
; Same thing as EQ, but for '>'
call .splitLR
call .parseLeftRight
jr nz, .end
xor a
sbc hl, de
jr nc, .success ; Left <= Right, False
; Left > Right, True
inc a
jr .success
.splitLR:
xor a
ld (hl), a
inc hl
ret
; Given string pointers in (HL) and (DE), evaluate those two expressions and
; place their corresponding values in HL and DE.
.parseLeftRight:
; let's start with HL
push de ; --> lvl 1
call parseExpr
pop hl ; <-- lvl 1, orig DE
ret nz
push de ; --> lvl 1. save HL value in stack.
; Now, for DE. (DE) is now in HL
call parseExpr ; DE in place
pop hl ; <-- lvl 1. restore saved HL
ret