LOAD/SAVE of BASIC files

This commit is contained in:
Kilian committed 2026-09-28 22:53:04 +02:00
1 parent e6a2af6f8a
commit 33faa4fac2
9 files changed
+352 -2886

No files matched your search

File diff suppressed because it is too large. Load diff
+24
View File
@@ -0,0 +1,24 @@
10 REM ENDLESS RULE 30
20 W=78
30 DIM A(79),B(79)
40 FOR I=1 TO W
50 A(I)=INT(RND(1)*2)
60 NEXT I
70 E$=CHR$(27)
80 PRINT E$;"[2J";E$;"[H";
90 A(0)=A(W)
100 A(W+1)=A(1)
110 FOR I=1 TO W
120 POKE 48128,32+10*A(I)
130 B(I)=ABS(A(I-1)-(A(I) OR A(I+1)))
140 NEXT I
150 POKE 48128,10
160 FOR I=1 TO W
170 A(I)=B(I)
180 NEXT I
190 GOTO 90
-1
View File
@@ -1 +0,0 @@
tmp/
+1
View File
@@ -9,6 +9,7 @@ PR_WRITTEN_BY:
COLD_START: COLD_START:
lda #$00 lda #$00
sta CURDVC sta CURDVC
sta LOAD_ACTIVE
ldx #$FF ldx #$FF
stx CURLIN+1 stx CURLIN+1
ldx #$FB ldx #$FB
+318 -1
View File
@@ -1,3 +1,320 @@
.segment "CODE" .segment "CODE"
; None yet LOADSAVE_LFN = $FF
; ============================================================================
; COPY STRING EXPRESSION TO FILE_NAME_BUFFER
;
; Entry:
; TXTPTR points at string expression
;
; Exit:
; FILE_NAME_BUFFER contains NUL-terminated filename
;
; Clobbers:
; A,X,Y,INDEX,STRNG2
; ============================================================================
PARSE_LOADSAVE_FILENAME:
jsr FRMEVL
jsr CHKSTR
jsr FREFAC
; FREFAC:
; A = length
; INDEX = string address
sta STRNG2
ldy #$00
@copy:
cpy STRNG2
beq @done
lda (INDEX),y
sta FILE_NAME_BUFFER,y
iny
bne @copy
@done:
lda #$00
sta FILE_NAME_BUFFER,y
rts
; ============================================================================
; SET UP THE COMMON FILE ARGUMENTS
; ============================================================================
LOADSAVE_SET_FILE:
lda #LOADSAVE_LFN
sta IO_FILE_DESCRIPTOR
lda #<FILE_NAME_BUFFER
sta IO_FILE_DATA
lda #>FILE_NAME_BUFFER
sta IO_FILE_DATA+1
rts
; ============================================================================
; WAIT FOR FILE COMMAND COMPLETION
;
; Jumps to IQERR on host-side failure.
; ============================================================================
LOADSAVE_WAIT:
lda IO_FILE_STATUS
and #FILE_STATUS_READY
beq LOADSAVE_WAIT
lda IO_FILE_STATUS
and #FILE_STATUS_ERROR
beq @ok
jmp IQERR
@ok:
rts
; ============================================================================
; OPEN FOR READING
; ============================================================================
LOADSAVE_OPEN_R:
jsr LOADSAVE_SET_FILE
lda #IO_COMMAND_OPEN_R
sta IO_FILE_COMMAND
jmp LOADSAVE_WAIT
; ============================================================================
; OPEN FOR WRITING / TRUNCATE
; ============================================================================
LOADSAVE_OPEN_W:
jsr LOADSAVE_SET_FILE
lda #IO_COMMAND_OPEN_W
sta IO_FILE_COMMAND
jmp LOADSAVE_WAIT
; ============================================================================
; CLOSE INTERNAL LOAD/SAVE FILE
; ============================================================================
LOADSAVE_CLOSE:
lda #LOADSAVE_LFN
sta IO_FILE_DESCRIPTOR
lda #IO_COMMAND_CLOSE
sta IO_FILE_COMMAND
jsr LOADSAVE_WAIT
jsr CLRCH
rts
; ============================================================================
; SAVE "filename"
;
; Saves plain ASCII BASIC source, equivalent to LIST output.
; ============================================================================
SAVE:
jsr PARSE_LOADSAVE_FILENAME
jsr LOADSAVE_OPEN_W
; Route OUTDO/CHROUT to our internal file.
ldx #LOADSAVE_LFN
jsr CHKOUT
stx CURDVC
; Start with first BASIC line.
lda TXTTAB
sta LOWTRX
lda TXTTAB+1
sta LOWTRX+1
SAVE_NEXT_LINE:
; The high byte of the forward link is zero at end of program.
ldy #$01
lda (LOWTRX),y
beq SAVE_DONE
; ------------------------------------------------------------
; Print line number.
;
; record:
; +0/+1 = next line
; +2/+3 = line number
; +4... = tokenized body
; ------------------------------------------------------------
iny ; Y=2
lda (LOWTRX),y
tax
iny ; Y=3
lda (LOWTRX),y
jsr LINPRT
lda #' '
jsr OUTDO
; DATAFLG follows LIST's quoting/token rules.
lda #$01
sta DATAFLG
ldy #$04
SAVE_LINE_CHAR:
lda (LOWTRX),y
beq SAVE_LINE_DONE
; Test whether it's plain ASCII/token BEFORE doing CMPs
bpl SAVE_PLAIN_CHAR
cmp #$FF
beq SAVE_PLAIN_CHAR
bit DATAFLG
bmi SAVE_PLAIN_CHAR
; Token
sec
sbc #$7F
tax
sty FORPNT
ldy #$FF
SAVE_FIND_TOKEN:
dex
beq SAVE_TOKEN_FOUND
SAVE_SKIP_TOKEN:
iny
lda TOKEN_NAME_TABLE,y
bpl SAVE_SKIP_TOKEN
bmi SAVE_FIND_TOKEN
SAVE_TOKEN_FOUND:
iny
lda TOKEN_NAME_TABLE,y
bmi SAVE_TOKEN_LAST
jsr OUTDO
bne SAVE_TOKEN_FOUND
SAVE_TOKEN_LAST:
and #$7F
jsr OUTDO
ldy FORPNT
iny
jmp SAVE_LINE_CHAR
SAVE_PLAIN_CHAR:
and #$7F
jsr OUTDO
; Quote state must be updated AFTER output/test.
cmp #$22
bne SAVE_PLAIN_DONE
lda DATAFLG
eor #$FF
sta DATAFLG
SAVE_PLAIN_DONE:
iny
jmp SAVE_LINE_CHAR
SAVE_LINE_DONE:
; Every saved source line ends in LF.
jsr LFDO
; Follow next-line pointer.
ldy #$00
lda (LOWTRX),y
tax
iny
lda (LOWTRX),y
stx LOWTRX
sta LOWTRX+1
jmp SAVE_NEXT_LINE
SAVE_DONE:
jsr LOADSAVE_CLOSE
rts
; ============================================================================
; LOAD "filename"
;
; Replaces current program.
; Reads ASCII source one line at a time, tokenizes through the normal
; BASIC parser, and inserts using NUMBERED_LINE.
;
; IMPORTANT:
; NUMBERED_LINE eventually reaches FIX_LINKS -> SETPTRS -> STKINI, which
; resets the hardware stack. Therefore LOAD cannot expect NUMBERED_LINE to
; return with RTS. FIX_LINKS jumps back to LOAD_NEXT_LINE while LOAD_ACTIVE
; is set.
; ============================================================================
LOAD:
; Copy the filename before SCRTCH destroys temporary strings.
jsr PARSE_LOADSAVE_FILENAME
jsr LOADSAVE_OPEN_R
; Delete current program.
jsr SCRTCH
; Route CHRIN to the file.
ldx #LOADSAVE_LFN
jsr CHKIN
stx CURDVC
; Tell FIX_LINKS that program insertion belongs to LOAD.
lda #$01
sta LOAD_ACTIVE
; ----------------------------------------------------------------------------
; Entry point used both initially and by FIX_LINKS after inserting each line.
; Must be a globally visible label if FIX_LINKS lives in another source file.
; ----------------------------------------------------------------------------
LOAD_NEXT_LINE:
ldx #$00
; ----------------------------------------------------------------------------
; Read one physical source line into INPUTBUFFER.
;
; "10 PRINT 1\n" -> normal line
; "10 PRINT 1"<EOF> -> final line still accepted
; EOF with X=0 -> done loading
; ----------------------------------------------------------------------------
@read_char:
jsr CHRIN
; If host says EOF, A is not considered valid data.
pha
lda IO_FILE_STATUS
and #FILE_STATUS_EOF
bne @eof
pla
; LF terminates a source line.
cmp #LF
beq @line_complete
; Accept CRLF files too.
cmp #$0D
beq @read_char
; Same practical line limit as interactive INLIN.
cpx #$47
bcs @line_too_long
sta INPUTBUFFER,x
inx
jmp @read_char
@eof:
pla
; EOF with no accumulated characters means real end of file.
cpx #$00
beq @load_done
; Otherwise process the unterminated final line.
@line_complete:
lda #$00
sta INPUTBUFFER,x
; Point CHRGET at INPUTBUFFER-1, exactly like INLIN returns.
lda #<(INPUTBUFFER-1)
sta TXTPTR
lda #>(INPUTBUFFER-1)
sta TXTPTR+1
jsr CHRGET
; Ignore empty physical lines.
beq LOAD_NEXT_LINE
; A source file must consist of numbered program lines.
;
; CHRGET leaves carry clear for a leading decimal digit,
; exactly like the normal RESTART path.
bcc @numbered
jmp @syntax_error
@numbered:
; NUMBERED_LINE performs:
;
; LINGET
; PARSE_INPUT_LINE
; FNDLIN
; PUT_NEW_LINE
; FIX_LINKS
;
; DO NOT JSR here.
;
; FIX_LINKS eventually calls SETPTRS/STKINI, which resets the
; hardware stack. FIX_LINKS will detect LOAD_ACTIVE and jump back
; to LOAD_NEXT_LINE.
jmp NUMBERED_LINE
@line_too_long:
@syntax_error:
lda #$00
sta LOAD_ACTIVE
jsr CLRCH
jsr LOADSAVE_CLOSE
jmp SYNERR
@load_done:
lda #$00
sta LOAD_ACTIVE
jsr CLRCH
jsr LOADSAVE_CLOSE
; Do NOT JSR SETPTRS here.
;
; Every successfully inserted line already passed through
; FIX_LINKS -> SETPTRS -> LE33D.
;
; Also do not RTS: SETPTRS/STKINI during loading may have destroyed
; the original LOAD command's return frame.
jmp RESTART
-1
View File
@@ -6,7 +6,6 @@
.include "defines.s" .include "defines.s"
.include "macros.s" .include "macros.s"
.include "zeropage.s" .include "zeropage.s"
.include "header.s" .include "header.s"
.include "token.s" .include "token.s"
.include "error.s" .include "error.s"
+4
View File
@@ -168,6 +168,10 @@ L23E6:
FIX_LINKS: FIX_LINKS:
jsr SETPTRS jsr SETPTRS
jsr LE33D jsr LE33D
lda LOAD_ACTIVE
beq :+
jmp LOAD_NEXT_LINE
:
jmp L2351 jmp L2351
LE33D: LE33D:
lda TXTTAB lda TXTTAB
+3 -1
View File
@@ -1,6 +1,6 @@
init_token_tables init_token_tables
keyword_rts "WOZMON", RESET keyword_rts "WOZ", RESET
keyword_rts "END", END keyword_rts "END", END
keyword_rts "FOR", FOR keyword_rts "FOR", FOR
@@ -21,6 +21,8 @@
keyword_rts "STOP", STOP keyword_rts "STOP", STOP
keyword_rts "ON", ON keyword_rts "ON", ON
keyword_rts "WAIT", WAIT keyword_rts "WAIT", WAIT
keyword_rts "LOAD", LOAD
keyword_rts "SAVE", SAVE
keyword_rts "DEF", DEF keyword_rts "DEF", DEF
keyword_rts "POKE", POKE keyword_rts "POKE", POKE
keyword_rts "PRINT#", PRINTH keyword_rts "PRINT#", PRINTH
+2
View File
@@ -151,6 +151,8 @@ STRNG2:
.res 2 .res 2
CURDVC: CURDVC:
.res 1 .res 1
LOAD_ACTIVE:
.res 1
FILE_NAME_BUFFER = $0300 FILE_NAME_BUFFER = $0300
CHRGET: CHRGET:
TXTPTR = <(GENERIC_TXTPTR-GENERIC_CHRGET + CHRGET) TXTPTR = <(GENERIC_TXTPTR-GENERIC_CHRGET + CHRGET)