comparison src/interp.s @ 74:e74d00ac6b79

Split some code into separate files for easier management (2) Because the source for lwbasic is so large, split it into several different files to make it easier to navigate and modify. This is part two of the split. Also includes fix for dependency tracking related to the split in the make file.
author William Astle <lost@l-w.ca>
date Sun, 06 Aug 2023 00:36:48 -0600
parents
children 5f8f0b0781e8
comparison
equal deleted inserted replaced
73:2d52cd154ed1 74:e74d00ac6b79
1 *pragmapush list
2 *pragma list
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ; Fetch next input character, skip spaces. This is structured the way it is to avoid burning any register except A
5 ; which is used for the returned value. Z will be set if the input character is NUL or a colon. C will be set if the
6 ; input character is an ASCII digit. This allows testing Z to identify the end of a command due to either a colon or
7 ; the end of a line.
8 ;
9 ; Compared to Color Basic, the instruction sequence only varies in the handling of the LDA. In Color Basic, the sequence
10 ; is an LDA extended followed by a JMP extended. This totals to 9 cycles (5 for LDA, 4 for JMP). In LWBasic, an LDA
11 ; with extended indirect addressing is used. This also totals 9 cycles. The only other difference is when a space is
12 ; detected where the branch can be direct to the nextchar code instead of having to branch around a direct page JUMP
13 ; which saves 3 cycles for the case where a space is detected. In other words, this is only slower by virtue of the
14 ; fact that it is called with an extended JSR instead of a direct JSR which causes one extra cycle to be used there
15 ; and one extra byte for each call to nextchar or curchar.
16 ;
17 ; On 6309, native move saves an extra cycle in the LDA sequence using the LDA extended followed by JMP extended
18 ; sequence.
19 ;
20 ; This whole thing could be sped up by keeping the input pointer in a register. However, retaining the ability to
21 ; use Y without having to save it first is likely more beneficial.
22 nextchar inc inputptr+1 ; bump LSB of input pointer
23 bne curchar ; brif no carry
24 inc inputptr ; bump MSB
25 curchar lda [inputptr] ; read the byte
26 cmpa #'9+1 ; clear C if above ASCII digits, Z if colon
27 bhs curchar0 ; brif above the ASCII digits
28 cmpa #0x20 ; is it a space?
29 beq nextchar ; brif so - skip over it
30 suba #'0 ; clever way to set C if >= ASCII 0, Z if zero
31 suba #-'0
32 curchar0 rts
33 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 ; This is exactly the same as nextchar except it doesn't skip spaces. Unfortunately, for efficiency purposes, we need
35 ; to actually duplicate code here.
36 nextcharraw inc inputptr+1 ; bump LSB of input pointer
37 bne curchar ; brif no carry
38 inc inputptr ; bump MSB
39 curcharraw lda [inputptr] ; fetch the byte
40 cmpa #'9+1 ; clear C if above digits, set Z if colon
41 bhs curcharraw0 ; brif above digits
42 suba #'0 ; clever way to set C if >= ASCII 0, Z if zero
43 suba #-'0
44 curcharraw0 rts
45 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46 ; The error handler
47 ;
48 ; Enter with the error number in B. This routine will do some cleanup and handle any ON ERROR GOTO handler that
49 ; may be active.
50 ;
51 ; Note the error message lookup does not need to be efficient which is why the lookup just runs through the list
52 ; of error messages in sequence looking for NUL terminators. The specific handling of B (error number) below avoids
53 ; issues if there happen to be error codes above 128.
54 ERROR clr filenum ; reset display device to console
55 jsr writecondnl ; do a newline if needed (will preserve B)
56 ldx #errormsg ; point to error message list
57 incb ; account for decb below
58 bra ERROR1 ; go search for correct message
59 ERROR0 lda ,x+ ; end of message?
60 bne ERROR0 ; brif not end of message
61 ERROR1 decb ; at the correct one?
62 bne ERROR0 ; brif not - skip to next one
63 ERROR2 jsr writestrconduc ; output error message
64 ldu curline ; are we in immediate mode?
65 beq ERROR3 ; brif so
66 ldx #inmsg ; point to " in "
67 jsr writestrconduc ; output " in "
68 ldd 2,u ; get line number
69 jsr print_uint16d ; display the line number
70 ERROR3 lds freetop ; reset the stack pointer (error routine could be called anywhere)
71 clr ,-s ; reset the call stack
72 sts stackptr
73 ; fall through to immediate mode intentional
74 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
75 ; Immediate mode handler
76 immediate jsr writecondnl ; do newline if required
77 ldx #prompt ; point to prompt string
78 jsr console_outstrn
79 immediate0 jsr readline ; read input line
80 bcs immediate0 ; brif ended with BREAK
81 ldx #linebuff ; point to start of line input buffer
82 stx inputptr ; set input pointer
83 jsr curchar ; skip spaces and set flags
84 bcs immediate1 ; brif there's a line number
85 tsta ; is there anything there at all (end of line)?
86 beq immediate0 ; brif not - read another line
87 ldx inputptr ; get the modified input pointer processing above
88 jsr tokenize ; tokenize the line at inputptr, return with result at tokebuff and X
89 jsr interpretline ; go interpret the tokenized line
90 bra immediate ; go handle another line
91 immediate1 bsr parse_lineno ; parse the line number
92 bsr prog_findline ; go see if the line is in the program
93 bne immediate3 ; brif not - no need to delete it
94 ldu ,x ; get next line pointer which is where we start the copy from
95 leay ,x ; use temp pointer for copying
96 immediate2 lda ,u+ ; get source byte
97 sta ,y+ ; stash it
98 cmpu vartab ; did we reach the end of the program text?
99 blo immediate2 ; brif not
100 sty vartab ; save new end of program
101 immediate3 jsr curchar ; skip any spaces after line number
102 tsta ; is it the end of input (don't test for colon)
103 beq immediate6 ; brif so - we don't need to insert a line
104 pshs x ; save program insert location and line number
105 ldx inputptr ; point to line text
106 jsr tokenize ; tokenize line, get length to D
107 leay ,x ; save tokenized line pointer
108 addd #4 ; account for next line pointer and line number
109 ldx vartab ; get start of copy location
110 leau d,x ; set destination copy location D bytes further up
111 stu vartab ; save new end of program
112 immediate4 lda ,-x ; get byte from program
113 sta ,-u ; stash it above the empty space
114 cmpx ,s ; did we reach the insertion point?
115 bne immediate4 ; brif not - keep going
116 leas 2,s ; clear insertion location
117 stu ,x++ ; set next line pointer to not null
118 ldd binval ; set the line number for the program
119 std ,x++
120 immediate5 lda ,y+ ; get byte from tokenized line
121 sta ,x+ ; stash it in the program
122 bne immediate5 ; brif not at end of tokenized line (see note for fixlineptrs)
123 immediate6 bsr prog_fixlineptrs ; fix up line pointers (all of them)
124 ldx vartab ; clear out variables
125 stx objecttab
126 stx freestart
127 bra immediate0 ; go handle more input
128 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
129 ; Fix up next line pointers. Enter at prog_fixlineptrs to do the entire program. Enter at prog_fixlineptrsx to start
130 ; at the line pointered to by X, which MUST NOT point to the end of the program.
131 ;
132 ; Works by simply scanning for a NUL in the program text after a line header (pointer to next line and line number)
133 ; and uses that as the new next line pointer. A NULL next line pointer flags the end of the program.
134 ;
135 ; Observation: if the program text format is changed such that it can include NULs embedded within a line, this routine
136 ; will need to be updated to grok that.
137 prog_fixlineptrs
138 ldx progtext ; point to start of program
139 prog_fixlineptrsx
140 ldu ,x ; are we at the end of the program?
141 beq prog_findline2 ; brif not (borrow RTS from findline)
142 leau 4,x ; point to line text (past pointer and line number)
143 prog_fixlineptrs1
144 lda ,u+ ; are we at the end of this line?
145 bne prog_fixlineptrs1 ; brif not
146 stu ,x ; set the next pointer for the previous line
147 leax ,u ; move to the next line
148 bra prog_fixlineptrsx ; go handle the next line
149 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
150 ; Find a line in the program. Returns with C set and Z clear if no match and C clear and Z set if a match is found. X
151 ; will point to either the exact matched line *or* the line that would be immediately after the desired line number if
152 ; the line had been present, which could be the end of the program. D and U are clobbered. Enter at prog_findlinex to
153 ; start searching at the line pointed to by X. Enter at prog_findline to start at the beginning of the program. Enter
154 ; with the desired line number in binval.
155 prog_findlinecl ldx curline ; get current line pointer
156 beq prog_findline ; brif immediate mode
157 ldd binval ; get desired line number
158 cmpd 2,x ; is the desired line number >= current line?
159 beq prog_findline2 ; brif this is the right line (optimizes goto self)
160 bhi prog_findlinex ; brif desired line higher: start here instead of program start
161 prog_findline ldx progtext ; point to start of program
162 prog_findlinex ldu binval ; get line number to search for
163 prog_findline0 ldd ,x ; end of program?
164 beq prog_findline1 ; brif not
165 cmpu 2,x ; does line number match? Z set if so, clear if not; C set not found
166 bls prog_findline2
167 ldx ,x ; move to next line
168 bra prog_findline0 ; see if we found the line yet
169 prog_findline1 coma ; set carry for not found; also clears Z because D is zero from above
170 prog_findline2 rts
171 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172 ; Parse a line number and return it in binval; raise syntax error if the line number overflows 16 bits unsigned.
173 ; Preserves; registers except D. This will accept the entire 16 bit unsigned number range which is why there is
174 ; a BCS after every shift or add. Enter with the input pointer pointing to the number to parse.
175 parse_lineno ldd zero ; clear out accumlator but preserve carry flag
176 std binval
177 jsr curchar ; set flags on current character; skip spaces
178 bcc parse_lineno1 ; brif first character wasn't a digit - default to zero
179 parse_lineno0 suba #0x30 ; adjust to binary digit
180 pshs a ; save digit so we can add it later
181 ldd binval ; get accumulated number
182 lslb ; multiply accumulator by 10
183 rola ; times 2
184 bcs SNERROR ; brif overflow
185 lslb
186 rola ; times 4
187 bcs SNERROR ; brif overflow
188 addd binval ; times 5 (add orignal value to times 4)
189 bcs SNERROR ; brif overflow
190 lslb
191 rola ; times 10
192 bcs SNERROR ; brif overflow
193 addb ,s+ ; add in accumulated digit
194 adca #0
195 bcs SNERROR ; brif overflow
196 std binval ; save accumulated number
197 jsr nextcharraw ; get next input character; DO NOT skip spaces
198 bcs parse_lineno0 ; brif it's also a digit
199 parse_lineno1 rts
200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201 ; Main interpretation loop
202 ;
203 ; Enter at interpret with inputptr pointing to the code stream to interpret.
204 ; Enter at interpretline with X pointing to the command stream to interpret which will return to the caller one the
205 ; command stream has completed. STOP or BREAK will return with carry set while END or falling off the end of the
206 ; code will return with carry clear. In the event of an error, the usual error processing will be done and control
207 ; will return to immediate mode with the stack reset.
208 interpret jsr breakcheck ; check for BREAK
209 bcs cmd_stop0 ; brif BREAK detected - go stop the program
210 ldx inputptr ; get interpration address
211 stx curstmt ; save address of the current statement (needed for some stuff)
212 lda ,x+ ; are we at the end of the line?
213 beq interpret0 ; brif so
214 cmpa #': ; end of statement?
215 beq interpret3 ; brif so - do a statement
216 SNERROR ldb #err_sn ; raise a syntax error
217 jmp ERROR
218 interpret0 sta endflag ; flag the program exit state as "END" (will be zero)
219 ldd curline ; were we in immediate mode?
220 bne interpret1 ; brif not
221 clra ; clear carry to indicate normal exit
222 rts ; return to caller
223 interpret1 ldd ,x ; are we at the end of the program?
224 beq interpret4 ; brif so - bail out
225 stx curline ; save pointer to current line
226 leax 3,x ; set input pointer one before the start of the line text
227 interpret2 stx inputptr
228 interpret3 jsr nextchar ; fetch first character of next statement
229 beq interpret ; brif end of statement - do the next statement dance
230 tsta ; set flags properly for token
231 lbpl cmd_let ; brif no command - do assignment (LET command is optional)
232 ldx #primaryjump ; point to jump table
233 anda #0x7f ; lose bit 7
234 leax a,x ; get half way to the correct offset
235 ldx a,x ; get the address the other half of the way from here
236 jsr nextchar ; skip past token and set flags
237 jsr ,x ; call the routine
238 bra interpret ; go handle the next statement dance
239 interpret4 bsr cmd_stop1 ; make sure stack is aligned correctly (will not return)
240 interpretline clr curline ; blank out current line pointer (for immediate mode)
241 clr curline+1
242 leax -1,x ; move back before start of code stream
243 bra interpret2 ; go interpret this statement and then continue with stuff
244 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
245 ; Check for character in B and raise a syntax error if not found at current input pointer. If it is found, fetch the
246 ; next input character.
247 syncheckb cmpb [inputptr] ; do we have a syntax match?
248 bne SNERROR ; brif not
249 jmp nextchar ; return next input character
250 *pragmapop list