basic: allow multiple args in print

This commit is contained in:
Virgil Dupras 2019-11-20 20:58:26 -05:00
parent 9c400ca642
commit 3f3dd9141e
7 changed files with 87 additions and 45 deletions

View File

@ -9,6 +9,10 @@
jp basStart
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD USER_RAMSTART
.inc "core.asm"
.inc "lib/util.asm"
.inc "lib/ari.asm"
@ -17,7 +21,7 @@
.equ EXPR_PARSE parseLiteralOrVar
.inc "lib/expr.asm"
.inc "basic/tok.asm"
.equ VAR_RAMSTART USER_RAMSTART
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
.inc "basic/var.asm"
.equ BUF_RAMSTART VAR_RAMEND
.inc "basic/buf.asm"

View File

@ -1,5 +1,3 @@
; *** Constants ***
.equ BAS_SCRATCHPAD_SIZE 0x20
; *** Variables ***
; Value of `SP` when basic was first invoked. This is where SP is going back to
; on restarts.
@ -9,8 +7,7 @@
; Important note: this is **not** a line number, it's a pointer to a line index
; in buffer. If it's not zero, its a valid pointer.
.equ BAS_PNEXTLN @+2
.equ BAS_SCRATCHPAD @+2
.equ BAS_RAMEND @+BAS_SCRATCHPAD_SIZE
.equ BAS_RAMEND @+2
; *** Code ***
basStart:
@ -18,11 +15,11 @@ basStart:
call varInit
call bufInit
xor a
ld (BAS_PNEXTLN), a
ld (BAS_PNEXTLN+1), a
ld hl, .welcome
call printstr
call printcrlf
ld hl, 0 ; points to a zero word
ld (BAS_PNEXTLN), hl
jr basLoop
.welcome:
@ -43,8 +40,8 @@ basLoop:
jr basLoop
.number:
push ix \ pop de
call toWS
call rdWS
call toSep
call rdSep
call bufAdd
jp nz, basERR
jr basLoop
@ -55,16 +52,7 @@ 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:
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!
@ -95,17 +83,13 @@ basCallCmd:
ex de, hl
ld a, b ; cmd's length
call addHL
call rdWS
call rdSep
jp (ix)
basPrintLn:
call printstr
jp printcrlf
basERR:
ld hl, .sErr
jr basPrintLn
call printstr
jp printcrlf
.sErr:
.db "ERR", 0
@ -118,7 +102,8 @@ basERR:
; Commands are expected to set Z on success.
basBYE:
ld hl, .sBye
call basPrintLn
call printstr
call printcrlf
; To quit the loop, let's return the stack to its initial value and
; then return.
xor a
@ -133,7 +118,7 @@ basLIST:
.loop:
ld e, (ix)
ld d, (ix+1)
ld hl, BAS_SCRATCHPAD
ld hl, SCRATCHPAD
call fmtDecimal
call printstr
ld a, ' '
@ -169,7 +154,7 @@ basRUN:
; Print line number, then return NZ (which will print ERR)
ld e, (ix)
ld d, (ix+1)
ld hl, BAS_SCRATCHPAD
ld hl, SCRATCHPAD
call fmtDecimal
call printstr
ld a, ' '
@ -191,15 +176,33 @@ basRUN:
ret
basPRINT:
ld de, SCRATCHPAD
call rdWord
push hl ; --> lvl 1
ex de, hl
call parseExpr
ret nz
push ix \ pop de
ld hl, BAS_SCRATCHPAD
ld hl, SCRATCHPAD
call fmtDecimal
call printstr
pop hl ; <-- lvl 1
; Do we have another arg?
call rdSep
jr z, .another
; no, we can stop here
cp a ; ensure Z
jp basPrintLn
jp printcrlf
.another:
; Before we jump to basPRINT, let's print a space
ld a, ' '
call stdioPutC
jr basPRINT
basGOTO:
ld de, SCRATCHPAD
call rdWord
ex de, hl
call parseExpr
ret nz
push ix \ pop de

View File

@ -1,3 +1,12 @@
; Sets Z is A is ' ' or '\t' (whitespace), or ',' (arg sep)
isSep:
cp ' '
ret z
cp 0x09
ret z
cp ','
ret
; Expect at least one whitespace (0x20, 0x09) at (HL), and then advance HL
; until a non-whitespace character is met.
; HL is advanced to the first non-whitespace char.
@ -5,7 +14,7 @@
; Failure is either not having a first whitespace or reaching the end of the
; string.
; Sets Z if we found a non-whitespace char, unset if we found the end of string.
rdWS:
rdSep:
ld a, (hl)
call isSep
ret nz ; failure
@ -47,10 +56,32 @@ fnWSIdx:
pop hl
ret
; Advance HL to the next whitespace or to the end of string.
toWS:
; Advance HL to the next separator or to the end of string.
toSep:
ld a, (hl)
call isSep
ret z
inc hl
jr toWS
jr toSep
; Read (HL) until the next separator and copy it in (DE)
; DE is preserved, but HL is advanced to the end of the read word.
rdWord:
push af
push de
.loop:
ld a, (hl)
call isSep
jr z, .stop
or a
jr z, .stop
ld (de), a
inc hl
inc de
jr .loop
.stop:
xor a
ld (de), a
pop de
pop af
ret

View File

@ -44,29 +44,33 @@ varTryAssign:
; 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
push de ; --> lvl 3
push af ; --> lvl 4. save for later
; Let's put that expression to read in scratchpad
inc hl \ inc hl
ld de, SCRATCHPAD
call rdWord
ex de, hl
; Now, evaluate that expression now in (HL)
call parseExpr ; --> number in IX
jr nz, .exprErr
pop af ; <-- lvl 3
pop af ; <-- lvl 4
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 de ; <-- lvl 3
pop hl ; <-- lvl 2
pop ix ; <-- lvl 1
ret
.exprErr:
pop af ; <-- lvl 3
pop af ; <-- lvl 4
jr .end
; Check if value at (HL) is a variable. If yes, returns its associated value.

View File

@ -132,7 +132,7 @@ parseDecimal:
pop hl
ret z
; A is not 0? Ok, but if it's a space, we're happy too.
jp isSep
jp isWS
.error:
pop hl
jp unsetZ

View File

@ -1,5 +1,5 @@
; Sets Z is A is ' ' or '\t'
isSep:
; Sets Z is A is ' ' or '\t' (whitespace)
isWS:
cp ' '
ret z
cp 0x09

View File

@ -31,7 +31,7 @@ isLineEnd:
; Sets Z is A is ' ', ',', ';', CR, LF, or null.
isSepOrLineEnd:
call isSep
call isWS
ret z
jr isLineEndOrComment
@ -68,7 +68,7 @@ isLabel:
; read char in A
_eatWhitespace:
call ioGetB
call isSep
call isWS
ret nz
jr _eatWhitespace