2019-11-18 15:52:07 -05:00
|
|
|
; *** Requirements ***
|
|
|
|
; findchar
|
|
|
|
; multDEBC
|
|
|
|
;
|
|
|
|
; *** Defines ***
|
|
|
|
;
|
|
|
|
; EXPR_PARSE: routine to call to parse literals or symbols that are part of
|
|
|
|
; the expression. Routine's signature:
|
|
|
|
; String in (HL), returns its parsed value to IX. Z for success.
|
|
|
|
;
|
|
|
|
; *** Code ***
|
|
|
|
;
|
2019-05-14 15:26:29 -04:00
|
|
|
; Parse expression in string at (HL) and returns the result in IX.
|
2019-11-21 16:06:14 -05:00
|
|
|
; **This routine mutates (HL).**
|
2019-05-14 15:26:29 -04:00
|
|
|
; We expect (HL) to be disposable: we mutate it to avoid having to make a copy.
|
|
|
|
; Sets Z on success, unset on error.
|
|
|
|
parseExpr:
|
2019-05-14 16:38:19 -04:00
|
|
|
push de
|
2019-05-14 15:26:29 -04:00
|
|
|
push hl
|
2019-05-17 22:22:10 -04:00
|
|
|
call _parseExpr
|
2019-05-14 16:38:19 -04:00
|
|
|
pop hl
|
2019-05-17 22:22:10 -04:00
|
|
|
pop de
|
|
|
|
ret
|
|
|
|
|
|
|
|
_parseExpr:
|
2019-11-22 14:45:12 -05:00
|
|
|
ld de, exprTbl
|
|
|
|
.loop:
|
|
|
|
ld a, (de)
|
|
|
|
or a
|
|
|
|
jp z, EXPR_PARSE ; no operator, just parse the literal
|
|
|
|
push de ; --> lvl 1. save operator row
|
2019-05-17 22:22:10 -04:00
|
|
|
call _findAndSplit
|
2019-11-22 14:45:12 -05:00
|
|
|
jr z, .found
|
|
|
|
pop de ; <-- lvl 1
|
|
|
|
inc de \ inc de \ inc de
|
|
|
|
jr .loop
|
|
|
|
.found:
|
|
|
|
; Operator found, string splitted. Left in (HL), right in (DE)
|
|
|
|
call _resolveLeftAndRight
|
|
|
|
; Whether _resolveLeftAndRight was a success, we pop our lvl 1 stack
|
|
|
|
; out, which contains our operator row. We pop it in HL because we
|
|
|
|
; don't need our string anymore. L-R numbers are parsed, and in DE and
|
|
|
|
; IX.
|
|
|
|
pop hl ; <-- lvl 1
|
|
|
|
ret nz
|
|
|
|
; Resolving left and right succeeded, proceed!
|
|
|
|
inc hl ; point to routine pointer
|
|
|
|
call intoHL
|
|
|
|
jp (hl)
|
2019-05-17 22:22:10 -04:00
|
|
|
|
|
|
|
; Given a string in (HL) and a separator char in A, return a splitted string,
|
|
|
|
; that is, the same (HL) string but with the found A char replaced by a null
|
|
|
|
; char. DE points to the second part of the split.
|
|
|
|
; Sets Z if found, unset if not found.
|
|
|
|
_findAndSplit:
|
|
|
|
push hl
|
2019-05-20 10:46:27 -04:00
|
|
|
call .skipCharLiteral
|
2019-05-17 09:50:11 -04:00
|
|
|
call findchar
|
2019-05-17 22:22:10 -04:00
|
|
|
jr nz, .end ; nothing found
|
|
|
|
; Alright, we have our char and we're pointing at it. Let's replace it
|
|
|
|
; with a null char.
|
2019-05-14 15:26:29 -04:00
|
|
|
xor a
|
|
|
|
ld (hl), a ; + changed to \0
|
|
|
|
inc hl
|
2019-05-17 22:22:10 -04:00
|
|
|
ex de, hl ; DE now points to the second part of the split
|
|
|
|
cp a ; ensure Z
|
|
|
|
.end:
|
|
|
|
pop hl ; HL is back to the start
|
2019-05-14 16:38:19 -04:00
|
|
|
ret
|
|
|
|
|
2019-05-20 10:46:27 -04:00
|
|
|
.skipCharLiteral:
|
|
|
|
; special case: if our first char is ', skip the first 3 characters
|
|
|
|
; so that we don't mistake a literal for an iterator
|
|
|
|
push af
|
|
|
|
ld a, (hl)
|
|
|
|
cp 0x27 ; '
|
|
|
|
jr nz, .skipCharLiteralEnd ; not a '
|
|
|
|
xor a ; check for null char during skipping
|
|
|
|
; skip 3
|
|
|
|
inc hl
|
|
|
|
cp (hl)
|
|
|
|
jr z, .skipCharLiteralEnd
|
|
|
|
inc hl
|
|
|
|
cp (hl)
|
|
|
|
jr z, .skipCharLiteralEnd
|
|
|
|
inc hl
|
|
|
|
.skipCharLiteralEnd:
|
|
|
|
pop af
|
|
|
|
ret
|
|
|
|
.find:
|
|
|
|
|
2019-05-17 22:22:10 -04:00
|
|
|
; parse expression on the left (HL) and the right (DE) and put the results in
|
|
|
|
; DE (left) and IX (right)
|
|
|
|
_resolveLeftAndRight:
|
2019-05-14 16:38:19 -04:00
|
|
|
call parseExpr
|
2019-05-14 15:26:29 -04:00
|
|
|
ret nz ; return immediately if error
|
2019-05-17 22:22:10 -04:00
|
|
|
; Now we have parsed everything to the left and we have its result in
|
|
|
|
; IX. What we need to do now is the same thing on (DE) and then apply
|
|
|
|
; the + operator. Let's save IX somewhere and parse this.
|
2019-05-19 10:45:11 -04:00
|
|
|
ex de, hl ; right expr now in HL
|
2019-05-14 16:38:19 -04:00
|
|
|
push ix
|
2019-05-17 22:22:10 -04:00
|
|
|
pop de ; numeric left expr result in DE
|
|
|
|
jp parseExpr
|
|
|
|
|
2019-11-22 14:45:12 -05:00
|
|
|
; Routines in here all have the same signature: they take two numbers, DE (left)
|
|
|
|
; and IX (right), apply the operator and put the resulting number in IX.
|
|
|
|
; The table has 3 bytes per row: 1 byte for operator and 2 bytes for routine
|
|
|
|
; pointer.
|
|
|
|
exprTbl:
|
|
|
|
.db '+'
|
|
|
|
.dw .plus
|
|
|
|
.db '-'
|
|
|
|
.dw .minus
|
|
|
|
.db '*'
|
|
|
|
.dw .mult
|
2019-11-22 15:03:16 -05:00
|
|
|
.db '/'
|
|
|
|
.dw .div
|
|
|
|
.db '%'
|
|
|
|
.dw .mod
|
2019-11-22 17:16:51 -05:00
|
|
|
.db '&'
|
|
|
|
.dw .and
|
|
|
|
.db 0x7c ; '|'
|
|
|
|
.dw .or
|
|
|
|
.db '^'
|
|
|
|
.dw .xor
|
2019-11-22 14:45:12 -05:00
|
|
|
.db 0 ; end of table
|
|
|
|
|
|
|
|
.plus:
|
2019-05-14 15:26:29 -04:00
|
|
|
add ix, de
|
2019-05-17 22:22:10 -04:00
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
|
|
|
|
2019-11-22 14:45:12 -05:00
|
|
|
.minus:
|
2019-05-14 16:38:19 -04:00
|
|
|
push ix
|
|
|
|
pop hl
|
2019-05-17 22:22:10 -04:00
|
|
|
ex de, hl
|
2019-05-18 15:17:56 -04:00
|
|
|
scf \ ccf
|
2019-05-14 16:38:19 -04:00
|
|
|
sbc hl, de
|
|
|
|
push hl
|
|
|
|
pop ix
|
2019-05-17 22:22:10 -04:00
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
|
|
|
|
2019-11-22 14:45:12 -05:00
|
|
|
.mult:
|
2019-05-17 22:22:10 -04:00
|
|
|
push ix \ pop bc
|
|
|
|
call multDEBC
|
|
|
|
push hl \ pop ix
|
2019-05-14 16:38:19 -04:00
|
|
|
cp a ; ensure Z
|
2019-05-14 15:26:29 -04:00
|
|
|
ret
|
2019-11-22 15:03:16 -05:00
|
|
|
|
|
|
|
.div:
|
|
|
|
; divide takes HL/DE
|
|
|
|
push bc
|
|
|
|
ex de, hl
|
|
|
|
push ix \ pop de
|
|
|
|
call divide
|
|
|
|
push bc \ pop ix
|
|
|
|
pop bc
|
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
|
|
|
|
|
|
|
.mod:
|
|
|
|
call .div
|
2019-11-22 17:16:51 -05:00
|
|
|
push hl \ pop ix
|
|
|
|
ret
|
|
|
|
|
|
|
|
.and:
|
|
|
|
push ix \ pop hl
|
|
|
|
ld a, h
|
|
|
|
and d
|
|
|
|
ld h, a
|
|
|
|
ld a, l
|
|
|
|
and e
|
|
|
|
ld l, a
|
|
|
|
push hl \ pop ix
|
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
|
|
|
.or:
|
|
|
|
push ix \ pop hl
|
|
|
|
ld a, h
|
|
|
|
or d
|
|
|
|
ld h, a
|
|
|
|
ld a, l
|
|
|
|
or e
|
|
|
|
ld l, a
|
|
|
|
push hl \ pop ix
|
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
|
|
|
|
|
|
|
.xor:
|
|
|
|
push ix \ pop hl
|
|
|
|
ld a, h
|
|
|
|
xor d
|
|
|
|
ld h, a
|
|
|
|
ld a, l
|
|
|
|
xor e
|
|
|
|
ld l, a
|
|
|
|
push hl \ pop ix
|
|
|
|
cp a ; ensure Z
|
2019-11-22 15:03:16 -05:00
|
|
|
ret
|