1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-23 16:38:06 +11:00

basic: begin implementing a line buffer

This commit is contained in:
Virgil Dupras 2019-11-19 15:14:04 -05:00
parent f5b04fc02f
commit 4c6de413df
6 changed files with 167 additions and 6 deletions

15
CODE.md
View File

@ -51,6 +51,21 @@ Therefore, shadow registers should only be used in code that doesn't call
routines or that call a routine that explicitly states that it preserves
shadow registers.
## Z for success
The vast majority of routines use the Z flag to indicate success. When Z is set,
it indicates success. When Z is unset, it indicates error. This follows the
tradition of a zero indicating success and a nonzero indicating error.
Important note: only Z indicate success. Many routines return a meaningful
nonzero value in A and still set Z to indicate success.
In error conditions, however, most of the time A is set to an error code.
In many routines, this is specified verbosely, but it's repeated so often that
I started writing it in short form, "Z for success", which means what is
described here.
## Stack management
Keeping the stack "balanced" is a big challenge when writing assembler code.

View File

@ -14,3 +14,17 @@ writing from scratch, so here I am, writing from scratch again...
The biggest challenge here is to extract code from zasm, adapt it to fit BASIC,
not break anything, and have the wisdom to see when copy/pasting is a better
idea.
## Design goal
The reason for including a BASIC dialect in Collapse OS is to supply some form
of system administration swiss knife. zasm, ed and the shell can do
theoretically anything, but some tasks (which are difficult to predict) can
possibly be overly tedious. One can think, for example, about hardware
debugging. Poking and peeking around when not sure what we're looking for can
be a lot more effective with the help of variables, conditions and for-loops in
an interpreter.
Because the goal is not to provide a foundation for complex programs, I'm
planning on intentionally crippling this BASIC dialect for the sake of
simplicity.

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

@ -0,0 +1,97 @@
; *** Consts ***
.equ BUF_POOLSIZE 0x1000
; *** Variables ***
; A pointer to free space in the pool.
.equ BUF_FREE BUF_RAMSTART
; The line pool. Each line consists of a two bytes binary number followed by
; a one byte length followed by the command string, which doesn't include its
; line number (example "10 print 123" becomes "print 123"), but which is null
; terminated. The one byte length includes null termination. For example, if
; we have a line record starting at 0x1000 and that its length field indicates
; 0x42, this means that the next line starts at 0x1045 (0x42+2+1).
.equ BUF_POOL @+2
.equ BUF_RAMEND @+BUF_POOLSIZE
bufInit:
ld hl, BUF_POOL
ld (BUF_FREE), hl
ret
; Add line at (HL) with line number DE to the pool. The string at (HL) should
; not contain the line number prefix or the whitespace between the line number
; and the comment.
; Note that an empty string is *not* an error. It will be saved as a line.
; Don't send strings that are more than 0xfe in length. It won't work well.
; Z for success.
; The only error condition that is handled is when there is not enough space
; left in the pool to add a string of (HL)'s size. In that case, nothing will
; be done and Z will be unset.
;
; DESTROYED REGISTER: DE. Too much pushpopping around to keep it. Not worth it.
bufAdd:
push hl ; --> lvl 1
push de ; --> lvl 2
; First step: see if we're within the pool's bounds
call strlen
inc a ; strlen doesn't include line termination
ld hl, (BUF_FREE)
call addHL
; add overhead (3b)
inc hl \ inc hl \ inc hl
ld de, BUF_RAMEND
sbc hl, de
; no carry? HL >= BUF_RAMEND, error. Z already unset
jr nc, .error
; We have enough space, proceed
ld hl, (BUF_FREE)
pop de ; <-- lvl 2
ld (hl), e
inc hl
ld (hl), d
inc hl
; A has been untouched since that strlen call. Let's use it as-is.
ld (hl), a
inc hl ; HL now points to dest for our string.
ex de, hl
pop hl \ push hl ; <--> lvl 1. recall orig, but also preserve
call strcpyM
; Copying done. Let's update the free zone marker.
ld (BUF_FREE), de
xor a ; set Z
pop hl ; <-- lvl 1
ret
.error:
pop de
pop hl
ret
; Set IX to point to the first valid line we have in the pool.
; Error if the pool is empty.
; Z for success.
bufFirst:
ld a, (BUF_POOL+2)
or a
jp z, unsetZ
ld ix, BUF_POOL
xor a ; set Z
ret
; Given a valid line record in IX, move IX to the next valid line.
; This routine doesn't check that IX is valid. Ensure IX validity before
; calling. This routine also doesn't check that the next line is within the
; bounds of the pool because this check is done during bufAdd.
; The only possible error is if there is no next line.
; Z for success.
bufNext:
push de ; --> lvl 1
ld d, 0
ld e, (ix+2)
add ix, de
inc ix \ inc ix \ inc ix
pop de ; <-- lvl 1
ld a, (ix+2)
or a
jp z, unsetZ
xor a ; set Z
ret

View File

@ -17,6 +17,8 @@
.equ EXPR_PARSE parseLiteral
.inc "lib/expr.asm"
.inc "basic/tok.asm"
.equ BAS_RAMSTART USER_RAMSTART
.equ BUF_RAMSTART USER_RAMSTART
.inc "basic/buf.asm"
.equ BAS_RAMSTART BUF_RAMEND
.inc "basic/main.asm"
USER_RAMSTART:

View File

@ -12,6 +12,7 @@
; *** Code ***
basStart:
ld (BAS_INITSP), sp
call bufInit
xor a
ld hl, .welcome
call printstr
@ -32,12 +33,13 @@ basPrompt:
call basDirect
jr basPrompt
.number:
; do nothing for now, we only support direct mode.
ld hl, .sNumber
call basPrintLn
push ix \ pop de
call toWS
call rdWS
call bufAdd
jp nz, basERR
call printcrlf
jr basPrompt
.sNumber:
.db "A number!", 0
.sPrompt:
.db "> ", 0
@ -104,6 +106,27 @@ basBYE:
.sBye:
.db "Goodbye!", 0
basLIST:
call printcrlf
call bufFirst
ret nz
.loop:
ld e, (ix)
ld d, (ix+1)
ld hl, BAS_SCRATCHPAD
call fmtDecimal
call printstr
ld a, ' '
call stdioPutC
push ix \ pop hl
inc hl \ inc hl \ inc hl
call printstr
call printcrlf
call bufNext
jr z, .loop
ret
basPRINT:
call parseExpr
jp nz, basERR
@ -116,6 +139,8 @@ basPRINT:
basCmds1:
.dw basBYE
.db "bye", 0, 0, 0
.dw basLIST
.db "list", 0, 0
; statements
basCmds2:
.dw basPRINT

View File

@ -46,3 +46,11 @@ fnWSIdx:
pop bc
pop hl
ret
; Advance HL to the next whitespace or to the end of string.
toWS:
ld a, (hl)
call isSep
ret z
inc hl
jr toWS