basic: add variables

Things are getting cereal...
This commit is contained in:
Virgil Dupras 2019-11-20 15:10:00 -05:00
parent 9c9484fb88
commit 9d6cbe577c
3 changed files with 115 additions and 3 deletions

View File

@ -14,10 +14,12 @@
.inc "lib/ari.asm"
.inc "lib/parse.asm"
.inc "lib/fmt.asm"
.equ EXPR_PARSE parseLiteral
.equ EXPR_PARSE parseLiteralOrVar
.inc "lib/expr.asm"
.inc "basic/tok.asm"
.equ BUF_RAMSTART USER_RAMSTART
.equ VAR_RAMSTART USER_RAMSTART
.inc "basic/var.asm"
.equ BUF_RAMSTART VAR_RAMEND
.inc "basic/buf.asm"
.equ BAS_RAMSTART BUF_RAMEND
.inc "basic/main.asm"

View File

@ -12,6 +12,7 @@
; *** Code ***
basStart:
ld (BAS_INITSP), sp
call varInit
call bufInit
xor a
ld hl, .welcome
@ -51,8 +52,20 @@ basLoop:
; If found, jump to it. If not found, unset Z. We expect commands to set Z
; on success. Therefore, when calling basCallCmd results in NZ, we're not sure
; where the error come from, but well...
; Before being evaluated, (HL) is copied in BAS_SCRATCHPAD because some
; evaluation routines (such as parseExpr) mutate the string it evaluates.
; TODO: straighten this situation up. Mutating a string like this breaks
; expectations.
basCallCmd:
; First, get cmd length
push de ; --> lvl 1
ld de, BAS_SCRATCHPAD
call strcpy
ex de, hl ; HL now points to scratchpad
pop de ; <-- lvl 1
; let's see if it's a variable assignment.
call varTryAssign
ret z ; Done!
; Second, get cmd length
call fnWSIdx
cp 7
jp nc, unsetZ ; Too long, can't possibly fit anything.

97
apps/basic/var.asm Normal file
View File

@ -0,0 +1,97 @@
; *** Variables ***
; A list of words for each member of the A-Z range.
.equ VAR_TBL VAR_RAMSTART
.equ VAR_RAMEND @+52
; *** Code ***
varInit:
ld b, VAR_RAMEND-VAR_RAMSTART
ld hl, VAR_RAMSTART
xor a
.loop:
ld (hl), a
inc hl
djnz .loop
ret
; Check if A is a valid variable letter (a-z or A-Z). If it is, set A to a
; valid VAR_TBL index and set Z. Otherwise, unset Z (and A is destroyed)
varChk:
call upcase
sub 'A'
ret c ; Z unset
cp 27 ; 'Z' + 1
jr c, .isVar
; A > 'Z'
dec a ; unset Z
ret
.isVar:
cp a ; set Z
ret
; Try to interpret line at (HL) and see if it's a variable assignment. If it
; is, proceed with the assignment and set Z. Otherwise, NZ.
varTryAssign:
inc hl
ld a, (hl)
dec hl
cp '='
ret nz
ld a, (hl)
call varChk
ret nz
; We have a variable! Its table index is currently in A.
push ix ; --> lvl 1
push hl ; --> lvl 2
push af ; --> lvl 3. save for later
; Let's start by evaluating that expression
inc hl \ inc hl
call parseExpr ; --> number in IX
jr nz, .exprErr
pop af ; <-- lvl 3
add a, a ; * 2 because each element is a word
ld hl, VAR_TBL
call addHL
; HL placed, write number
push de ; --> lvl 3
push ix \ pop de
ld (hl), e
inc hl
ld (hl), d
pop de ; <-- lvl 3
xor a ; ensure Z
.end:
pop hl ; <-- lvl 2
pop ix ; <-- lvl 1
ret
.exprErr:
pop af ; <-- lvl 3
jr .end
; Check if value at (HL) is a variable. If yes, returns its associated value.
; Otherwise, jump to parseLiteral.
parseLiteralOrVar:
inc hl
ld a, (hl)
dec hl
or a
; if more than one in length, it can't be a variable
jp nz, parseLiteral
ld a, (hl)
call varChk
jp nz, parseLiteral
; It's a variable, resolve!
add a, a ; * 2 because each element is a word
push hl ; --> lvl 1
ld hl, VAR_TBL
call addHL
push de ; --> lvl 2
ld e, (hl)
inc hl
ld d, (hl)
push de \ pop ix
pop de ; <-- lvl 2
pop hl ; <-- lvl 1
cp a ; ensure Z
ret