comparison src/lwbasic.s @ 76:eb2681108660

Split some code into separate files for easier management (4) 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 four of the split.
author William Astle <lost@l-w.ca>
date Sun, 06 Aug 2023 00:51:22 -0600
parents 5f8f0b0781e8
children bb50ac9fdf37
comparison
equal deleted inserted replaced
75:5f8f0b0781e8 76:eb2681108660
45 include interp.s 45 include interp.s
46 include progctrl.s 46 include progctrl.s
47 include print.s 47 include print.s
48 include error.s 48 include error.s
49 include expr.s 49 include expr.s
50 50 include number.s
51 include token.s
51 include miscdata.s 52 include miscdata.s
53 include keywords.s
52 *pragmapop list 54 *pragmapop list
53 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
54 ; Set carry if upper/lower case alpha
55 setcifalpha cmpa #'z+1 ; is it above lower case Z?
56 bhs setcifalpha0 ; brif so, C clear
57 suba #'a ; set C if >= lower case A
58 suba #-'a
59 bcs setcifalpha0 ; brif lower case alpha
60 setcifualpha cmpa #'Z+1 ; is it above upper case Z?
61 bhs setcifalpha0 ; brif so, C clear
62 suba #'A ; set C if >= upper case A
63 suba #-'A
64 setcifalpha0 rts
65 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
66 ; Set carry if digit
67 setcifdigit cmpa #'9+1 ; is it above digit 9?
68 bhs setcifdigit0 ; brif so, C clear
69 suba #'0 ; set C if >= digit 0
70 suba #-'0
71 setcifdigit0 rts
72 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
73 ; Operator handling routines
74 ;
75 ; binary plus: addition and concatenation
76 oper_plus ldb val.type,x ; get type of the left operand
77 cmpb valtype_string ; is it string?
78 bne oper_plus0 ; brif not
79 cmpb val.type,u ; is right operand also string?
80 lbeq SNERROR ; brif so - do string concatenation
81 oper_plus0 bsr val_matchtypes ; go match data types
82 jmp val_add ; go add the values
83 ; binary minus: subtraction
84 oper_minus bsr val_matchtypes ; go match data types
85 jmp val_sub ; do subtraction
86 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87 ; Arithmetic package
88 ;
89 ; This section contains routines that handle floating point and integer arithmetic.
90 ;
91 ; Most routines take a pointer to a value accumulator in X. Some take two pointers with the second in U.
92 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
93 ; Match operands for a numeric calculation. This works as follows:
94 ;
95 ; * If both operands are the same, ensure the type is numeric and return
96 ; * If one operand is floating point, convert the other to floating point, as long as it is numeric
97 ; * If one or both oeprands are not numeric, raise a type mismatch
98 ; The operands are in (X) and (U)
99 val_matchtypes ldb val.type,x ; get the type of first argument
100 cmpb #valtype_int ; is it integer?
101 beq val_matchtypes0 ; brif so
102 cmpb #valtype_float ; is it floating point?
103 beq val_matchtypes1 ; brif so
104 TMERROR ldb #err_tm ; raise a type mismatch
105 jmp ERROR
106 val_matchtypes0 ldb val.type,u ; get type of second operand
107 cmpb #valtype_int ; is it integer?
108 bne val_matchtypes2 ; brif not
109 val_matchtypes3 rts
110 val_matchtypes2 cmpb #valtype_float ; is it floating point?
111 bne TMERROR ; brif not - raise error
112 pshs u ; save pointer to second operand
113 bsr val_int32tofp ; convert first argument to floating point
114 puls u,pc ; restore second operand pointer and return
115 val_matchtypes1 ldb val.type,u ; get second argument type
116 cmpb #valtype_float ; is it floating point?
117 beq val_matchtypes3 ; brif so - we're good
118 cmpb #valtype_int ; is it integer?
119 bne TMERROR ; brif not - invalid type combination
120 pshs x,u ; save value pointers
121 leax ,u ; convert (U) to floating point
122 bsr val_int32tofp
123 puls x,u,pc ; restore argument pointers and return
124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125 ; Negate the 32 bit integer (for fp mantissa) at (X)
126 val_negint32 ldd zero ; subtract integer value from zero
127 subd val.int+2,x
128 std val.int+2,x
129 ldd zero
130 sbcb val.int+1,x
131 sbca val.int,x
132 std val.int,x
133 rts
134 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
135 ; Convert integer value at (X) to floating point value at (X). Enter at val_uint32tofp to treat the 32 bit value as
136 ; unsigned. Otherwise enter at val_int32tofp to treat it as signed.
137 val_uint32tofp clr val.fpsign,x ; for positive sign
138 bra val_int32tofpp ; go process as positive
139 val_int32tofp ldb val.int,x ; get sign to A
140 sex
141 sta val.fpsign,x ; set sign of result
142 bpl val_int32tofpp ; brif positive - don't need to do a two's complement adjustment
143 bsr val_negint32 ; negate the integer value
144 val_int32tofpp ldb valtype_float ; set result to floating point
145 stb val.type,x
146 ldb #0xa0 ; exponent to have binary point to the right of the mantissa
147 stb val.fpexp,x ; set the exponent
148 clrb ; clear out extra precision bits
149 ; fall through to normalize the value at (X)
150 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
151 ; Normalize floating point value at (X); this will shift the mantissa until there is a one in the leftmost
152 ; bit of the mantissa. The algorithm is as follows:
153 ;
154 ; 1. Shift the mantissa left until a 1 bit is found in the high bit of the mantissa.
155 ; 1a. If more than 40 bits of left shifts occur, determine that the value is zero and return
156 ; 2. Adjust exponent based on number of shifts
157 ; 2a. If new exponent went below -127, then underflow occurred and zero out value
158 ; 2b. If new exponent went above +127, raise an overflow
159 ; 3. If bit 7 of the extra precision byte is clear, return the resulting value
160 ; 4. Add one to the mantissa
161 ; 5. If a carry in (4) occurred, then set high bit of mantissa and bump exponent
162 ; 6. If new exponent carries, then raise overflow
163 ; 7. Return result.
164 ;
165 ; Note that if we carried in (4), the only possible result is that the mantissa
166 ; rolled over to all zeroes so there is no need to shift the entire mantissa right
167 ; nor is there any reason to check for additional rounding.
168 ;
169 ; The above algorithm has some optimizations in the code sequence below.
170 fp_normalize pshs b ; save extra bits
171 clrb ; set shift counter/exponent adjustment
172 fp_normalize0 lda val.fpmant,x ; set flags on high word of mantissa
173 bne fp_normalize2 ; brif we don't have a full byte to shift
174 addb #8 ; account for a while byte of shifts
175 ldu val.fpmant+1,x ; shift mantissa left 8 bits
176 stu val.fpmant,x
177 lda val.fpmant+3,x
178 sta val.fpmant+2,x
179 lda ,s ; and include extra bits
180 sta val.fpmant+3,x
181 clr ,s ; and blank extra bits
182 cmpb #40 ; have we shifted 40 bits?
183 blo fp_normalize0 ; brif not - keep shifting
184 bra fp_normalize7 ; go zero out the value
185 fp_normalize1 incb ; account for one bit of shifting
186 lsl ,s ; shift mantissa and extra bits left (will not be more than 7 shifts)
187 rol val.fpmant+3,x
188 rol val.fpmant+2,x
189 rol val.fpmant+1,x
190 rol val.fpmant,x
191 fp_normalize2 bpl fp_normalize1 ; brif we have to do a bit shift
192 pshs b ; apply exponent counter to exponent
193 lda val.fpexp,x
194 suba ,s+
195 bls fp_normalize6 ; brif we underflowed to zero
196 bcc fp_normalize3 ; brif we did not overflow
197 OVERROR2 jmp OVERROR ; raise overflow
198 fp_normalize3 lsl ,s+ ; set C if the high bit of extra precision is set
199 bcs fp_normalize5 ; brif bit set - we have to do rounding
200 fp_normalize4 rts ; return if no rounding
201 fp_normalize5 ldu val.fpmant+2,x ; add one to mantissa
202 leau 1,u
203 stu val.fpmant+2,x
204 bne fp_normalize4 ; brif low word doesn't carry
205 ldu val.fpmant,x
206 leau 1,u
207 stu val.fpmant,x
208 bne fp_normalize4 ; brif high word doesn't carry
209 ror val.fpmant,x ; shift right C in to high bit of mantissa (already set to get here)
210 inc val.fpexp,x ; bump exponent for a right shift
211 beq OVERROR2 ; brif it overflows (> +127)
212 rts ; return result (only possible result was mantissa wrapped to zero)
213 fp_normalize6 clr val.fpmant,x ; clear mantissa
214 clr val.fpmant+1,x
215 clr val.fpmant+2,x
216 clr val.fpmant+3,x
217 fp_normalize7 clr val.fpexp,x ; clear exponent and sign
218 clr val.fpsign,x
219 puls b,pc ; clean up stack and return
220 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
221 ; Addition and subtraction of values; must enter with values of matching types
222 ;
223 ; Calculates (X) + (U) -> (Y) (addition)
224 ; Calculates (X) - (U) -> (Y) (subtraction)
225 val_add ldb val.type,x ; get type of left operand
226 stb val.type,y ; set result type
227 cmpb #valtype_float ; is it float?
228 beq fp_add ; brif so
229 ldd val.int+2,x ; do the addition
230 addd val.int+2,u
231 std val.int+2,y
232 ldd val.int,x
233 adcb val.int+1,u
234 adca val.int,u
235 std val.int,y
236 lbvs OVERROR ; brif calculation overflowed
237 rts
238 val_sub ldb val.type,x ; get type of left operand
239 stb val.type,y ; set result type
240 cmpb #valtype_float ; floating point?
241 beq fp_sub ; brif so
242 ldd val.int+2,x ; do the subtraction
243 subd val.int+2,u
244 std val.int+2,y
245 ldd val.int,x
246 sbcb val.int+1,u
247 sbca val.int,u
248 std val.int,y
249 lbvs OVERROR ; brif overflow
250 rts
251 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
252 ; FP subtraction: just invert the sign of the second operand and add; operands must be writable and they should be
253 ; considered to be clobbered
254 fp_sub com val.fpsign,u ; negate right operand
255 ; fall through to addition
256 ; FP addition: this requires that *both operands* are writable and they may be clobbered
257 fp_add ldb val.fpexp,u ; is the second operand zero?
258 beq fp_add0 ; brif so - it's a no-op - copy the left operand to the output
259 lda val.fpexp,x ; is left operand zero?
260 bne fp_add1 ; brif not - we have to do the add
261 leau ,x ; copy the right operand to the output
262 fp_add0 ldd ,u ; copy the value across
263 std ,y
264 ldd 2,u
265 std 2,y
266 ldd 4,u
267 std 4,y
268 rts
269 fp_add1 subb val.fpexp,x ; get difference in exponents
270 beq fp_add6 ; brif they're the same - no denormalizing is needed
271 bhi fp_add2 ; brif second one is bigger, need to right-shift the mantissa of first
272 exg x,u ; swap the operands (we can do that for addition)l second is now biggest
273 negb ; invert the shift count
274 fp_add2 cmpb #32 ; are we shifting more than 32 bits?
275 blo fp_add0 ; brif so - we're effectively adding zero so bail out
276 fp_add3 cmpb #8 ; have 8 bits to move?
277 bhs fp_add5 ; brif not
278 lda val.fpmant+2,x ; shift 8 bits right
279 sta val.fpmant+3,x
280 lda val.fpmant+1,x
281 sta val.fpmant+2,x
282 lda val.fpmant,x
283 sta val.fpmant+1,x
284 clr val.fpmant,x
285 subb #8 ; account for 8 shifts
286 bra fp_add3 ; see if we have a whole byte to shift
287 fp_add4 lsr val.fpmant,x ; shift right one bit
288 ror val.fpmant+1,x
289 ror val.fpmant+2,x
290 ror val.fpmant+3,x
291 fp_add5 decb ; done all shifts?
292 bmi fp_add4 ; brif not - do a shift
293 fp_add6 ldb val.fpexp,u ; set exponent of result
294 stb val.fpexp,y
295 ldb val.fpsign,u ; fetch sign of larger value
296 stb val.fpsign,y ; set result sign
297 cmpb val.fpsign,x
298 bne fp_add8 ; brif not - need to subtract the operands
299 ldd val.fpmant+2,u ; add the mantissas
300 addd val.fpmant+2,x
301 std val.fpmant+2,y
302 ldd val.fpmant,u
303 adcb val.fpmant+1,x
304 adca val.fpmant,x
305 std val.fpmant,y
306 clrb ; clear extra precision bits
307 bcc fp_add7 ; brif no carry
308 ror val.fpmant,y ; shift carry into mantissa
309 ror val.fpmant+1,y
310 ror val.fpmant+2,y
311 ror val.fpmant+3,y
312 rorb ; keep bits for founding
313 inc val.fpexp,y ; bump exponent to account for shift
314 lbeq OVERROR ; brif it overflowed
315 fp_add7 leax ,y ; point to result
316 jmp fp_normalize ; go normalize the result
317 fp_add8 ldd val.fpmant+2,u ; subtract operands
318 subd val.fpmant+2,x
319 std val.fpmant+2,y
320 ldd val.fpmant,u
321 sbcb val.fpmant+1,x
322 sbca val.fpmant,x
323 std val.fpmant,y
324 bcc fp_add7 ; brif we didn't carry - no need to fix up
325 ldd zero ; negate the mantissa bits since we use sign+magnitude
326 subd val.fpmant+2,y
327 std val.fpmant+2,y
328 ldd zero
329 sbcb val.fpmant+1,y
330 sbca val.fpmant,y
331 std val.fpmant,y
332 neg val.fpsign,y ; invert sign of result since we went past zero
333 clrb ; clear extra precision bits
334 bra fp_add7 ; go normalize the result and return
335 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
336 ; Pack a floating point value at (X)
337 fp_packval ldb val.fpsign,x ; get sign
338 bmi fp_packval ; brif negative - the default 1 bit will do
339 ldb val.fpmant,x ; clear high bit of mantissa for positive
340 andb #0x7f
341 stb val.fpmant,x
342 fp_packval0 rts
343 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
344 ; Unpack a floating point value at (X)
345 fp_unpackval0 ldb val.fpmant,x ; get high byte of mantissa
346 sex ; now A is value for sign byte
347 sta val.fpsign,x ; set sign
348 orb #0x80 ; set high bit of mantissa
349 stb val.fpmant,x
350 rts
351 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
352 ; The LIST command.
353 ;
354 ; Syntax:
355 ; LIST
356 ; LIST <line>
357 ; LIST <line>-
358 ; LIST -<line>
359 ; LIST <start>-<end>
360 cmd_list bne cmd_list1 ; brif we have arguments
361 ldx progtext ; point to start of program
362 cmd_list0 ldd #65535 ; set last line to list to max line number
363 std binval
364 bra cmd_list2 ; go do the listing
365 cmd_list1 jsr parse_lineno ; parse starting line number (will default to 0)
366 jsr prog_findline ; find the line or the one after where it would be
367 jsr curchar ; are we at the end of the command?
368 beq cmd_list2 ; brif so - we have a single line (binval will have the start line #)
369 ldb #tok_minus ; insist on a - for a range if more than one line number
370 jsr syncheckb
371 beq cmd_list0 ; brif open ended ending - set to max line number
372 jsr parse_lineno ; parse ending of range
373 cmd_list2 ldd ,x ; are we at the end of the program?
374 bne cmd_list4 ; brif not
375 cmd_list3 rts
376 cmd_list4 ldd 2,x ; get line number
377 cmpd binval ; have we reached the end of the range?
378 bhi cmd_list3 ; brif so - we're done
379 jsr print_uint16d ; print out line number
380 lda #0x20 ; and a space
381 jsr writechr
382 pshs x ; save start of this line (in case detokenizing exits early)
383 leax 4,x ; move past line header
384 bsr detokenize ; detokenize line to current output stream
385 ldx [,s++] ; point to next line using saved pointer and clear it from the stack
386 ; need to add a break check here
387 bra cmd_list2 ; go handle another line
388 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
389 ; Detokenize a line to the current output stream
390 detokenize lda ,x+ ; get character from tokenized line
391 bmi detokenize1 ; brif it's a keyword token
392 lbeq writecondnl ; do a newline if needed and return
393 cmpa #': ; is it a colon?
394 bne detokenize0 ; brif not
395 ldb ,x ; fetch subsequent character
396 cmpb #tok_apos ; apostrophe version of REM?
397 beq detokenize ; brif so - skip the colon
398 cmpb #tok_else ; ELSE?
399 beq detokenize ; brif so - skip the colon
400 detokenize0 jsr writechr ; output it unmolested
401 bra detokenize ; go handle another character
402 detokenize1 ldu #primarydict ; point to primary dictionary table
403 cmpa #0xff ; is it a secondary token?
404 bne detokenize3 ; brif not
405 ldu #secondarydict ; point to secondary dictionary table
406 lda ,x+ ; get secondary token value
407 bne detokenize3 ; brif not end of line
408 leax -1,x ; don't consume the NUL
409 detokenize2 lda #'! ; invalid token flag
410 bra detokenize0 ; output it and continue
411 detokenize3 anda #0x7f ; lose the high bit
412 beq detokenize6 ; brif already at the right place
413 detokenize4 ldb ,u ; end of dictionary table?
414 beq detokenize2 ; brif so - show invalid tokenf lag
415 detokenize5 ldb ,u+ ; fetch character in this keyboard
416 bpl detokenize5 ; brif not end of keyword (high bit set)
417 deca ; at the right token?
418 bne detokenize4 ; brif not - skip another
419 detokenize6 lda ,u+ ; get keyword character
420 bmi detokenize7 ; brif end of keyword
421 jsr writechr ; output it
422 bra detokenize6 ; go fetch another
423 detokenize7 anda #0x7f ; lose the high bit
424 bra detokenize0 ; write it and move on with the input
425 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
426 ; Canonicalize certain sequences; ALL the rewrite sequences must make the result shorter or keep it the same size
427 makecanontab fcb tok_less,2
428 fcb tok_greater,tok_notequal
429 fcb tok_equal,tok_lessequal
430 fcb tok_greater,2
431 fcb tok_less,tok_notequal
432 fcb tok_equal,tok_greaterequal
433 fcb tok_equal,2
434 fcb tok_greater,tok_greaterequal
435 fcb tok_less,tok_lessequal
436 fcb 0
437 makecanon leay ,x ; point output to start of the buffer
438 makecanon0 lda ,x+ ; get current byte
439 sta ,y+ ; save in output
440 bne makecanon1 ; brif not end of line
441 rts
442 makecanon1 bpl makecanon0 ; brif not a token
443 cmpa #0xff ; is it secondary?
444 bne makecanon2 ; brif not
445 leax 1,x ; move past second half
446 bra makecanon0 ; go handle next byte
447 makecanon2 ldu #makecanontab ; point to replacement table
448 makecanon3 cmpa ,u+ ; is it this entry?
449 beq makecanon4 ; brif so
450 ldb ,u+ ; get number of entries
451 lslb ; 2 bytes per
452 leau b,u ; move past entry
453 ldb ,u ; end of table?
454 bne makecanon3 ; brif not
455 bra makecanon0 ; no substitutions found
456 makecanon4 pshs x ; save original source pointer
457 makecanon5 lda ,x+ ; get next character
458 cmpa #0x20 ; is it space?
459 beq makecanon5 ; brif so - skip it
460 ldb ,u+ ; get number of replacement candidates
461 makecanon6 cmpa ,u++ ; does it match?
462 beq makecanon7 ; brif so
463 decb ; seen all of them?
464 bne makecanon6 ; brif not
465 puls x ; restore input pointer
466 bra makecanon0 ; go handle next input
467 makecanon7 leas 2,s ; clear saved input pointer
468 lda -1,u ; get replacement token
469 sta -1,y ; put it in the output
470 bra makecanon0 ; go handle more input
471 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
472 ; Tokenize line to tokebuff
473 ;
474 ; Enter with X pointing to the text to tokenize.
475 ; Exit with X pointing to the start of the tokenized line and D holding the length of the tokenized line.
476 tokenize clr tok_skipkw ; clear "not token" flag
477 clr tok_skipdt ; clear the "in data" flag
478 ldy #tokebuff ; point to destination buffer
479 pshs y ; set return value
480 tokenize0 lda ,x+ ; get input character
481 bne tokenize3 ; brif not end of input
482 tokenize1 sta ,y+ ; blank out final byte in result
483 tokenize2 ldx #tokebuff ; point to start of tokenized line
484 bsr makecanon ; canonicalize certain sequences
485 tfr y,d ; get end address to accumulator
486 subd #tokebuff ; subtract out start; gives length of result
487 puls x,pc ; set return pointer and return
488 tokenize3 tst tok_skipkw ; are we in the middle of a "not token"?
489 beq tokenize6 ; brif not
490 jsr setcifalpha ; is it alpha
491 bcs tokenize4 ; brif so - store it and continue
492 jsr setcifdigit ; is it numeric?
493 bcc tokenize5 ; brif not
494 tokenize4 sta ,y+ ; save output character
495 bra tokenize0 ; check for another
496 tokenize5 clr tok_skipkw ; clear the "not token" flag
497 tokenize6 cmpa #'" ; is it a string?
498 bne tokenize8 ; brif not
499 sta ,y+ ; save string delimiter
500 tokenize7 lda ,x+ ; get input character
501 beq tokenize1 ; brif end of input
502 sta ,y+ ; save it in output
503 cmpa #'" ; end of string?
504 bne tokenize7 ; brif not
505 bra tokenize0 ; brif
506 tokenize8 cmpa #': ; end of statement?
507 bne tokenize9 ; brif not
508 clr tok_skipdt ; reset "in data" flag
509 bra tokenize4 ; stash it and continue
510 tokenize9 cmpa #0x20 ; is it a space?
511 beq tokenize4 ; brif so - stash it unmodified
512 tst tok_skipdt ; are we "in data"?
513 bne tokenize4 ; brif so - don't tokenize it
514 cmpa #'? ; PRINT shortcut?
515 bne tokenize10 ; brif not
516 lda #tok_print ; load token for PRINT
517 bra tokenize4 ; move stash it and move on
518 tokenize10 cmpa #'' ; ' shortcut for remark?
519 bne tokenize12 ; brif not
520 ldd #':*256+tok_apos ; put token for ' and an implied colon
521 std ,y++ ; stash it
522 tokenize11 lda ,x+ ; fetch byte from input
523 sta ,y+ ; stash in output
524 bne tokenize11 ; brif not end of input
525 bra tokenize2 ; go finish up
526 tokenize12 jsr setcifdigit ; is it a digit?
527 bcs tokenize4 ; brif so - pass it through
528 tsta ; is the high bit set?
529 bmi tokenize0 ; ignore it if so
530 ldu #primarydict ; point to keyword table
531 leax -1,x ; back up input to start of potential token
532 clr tok_kwtype ; set secondary table flag to primary table
533 clr tok_kwmatch ; clear the matched token
534 clr tok_kwmatch+1
535 clr tok_kwmatchl ; set length matched
536 pshs x ; save start of input token
537 tokenize13 clr tok_kwnum ; clear keyword number
538 tokenize14 ldb ,u ; are we at the end of the table?
539 bne tokenize16 ; brif not
540 ldu #secondarydict ; point to secondary token dictionary
541 com tok_kwtype ; flip to secondary token flag
542 bne tokenize13 ; brif we haven't already done the secondaries
543 puls x ; get back input pointer
544 ldb tok_kwmatchl ; get length of best match
545 beq tokenize15 ; brif we don't have a match
546 abx ; move input pointer past matched token
547 ldd tok_kwmatch ; get matched token number
548 tsta ; is it a primary?
549 beq tokenize24 ; brif so
550 bra tokenize23 ; go stash two byte token
551 tokenize15 com tok_skipkw ; set "not token flag"
552 lda ,x+ ; get character
553 bra tokenize4 ; stash it and continue
554 tokenize16 ldx ,s ; get back start of input token
555 clra ; initalize match length counter
556 tokenize17 inca ; bump length counter
557 ldb ,x+ ; get input character
558 cmpb #'z ; is it above lower case Z?
559 bhi tokenize18 ; brif so
560 cmpb #'a ; is it below lower case A?
561 blo tokenize18 ; brif so
562 subb #0x20 ; convert to upper case
563 tokenize18 subb ,u+ ; does it match?
564 beq tokenize17 ; brif so - check another
565 cmpb #0x80 ; did it match with high bit set?
566 beq tokenize21 ; brif so - exact match
567 leau -1,u ; back up to current test character
568 tokenize19 ldb ,u+ ; end of token?
569 bpl tokenize19 ; brif not
570 tokenize20 inc tok_kwnum ; bump token counter
571 bra tokenize14 ; go check another one
572 tokenize21 cmpa tok_kwmatchl ; is it a longer match?
573 bls tokenize20 ; brif not, ignore it
574 sta tok_kwmatchl ; save new match length
575 ldd tok_kwtype ; get the matched token count
576 orb #0x80 ; set token flag
577 std tok_kwmatch ; save matched token
578 bra tokenize20 ; keep looking through the tables
579 tokenize22 lda #': ; for putting implied colons in
580 tokenize23 std ,y++ ; put output into buffer
581 jmp tokenize0 ; go handle more input
582 tokenize24 cmpb #tok_else ; is it ELSE?
583 beq tokenize22 ; brif so - stash it with colon
584 cmpb #tok_data ; is it DATA?
585 bne tokenize26 ; brif not
586 stb tok_skipdt ; set "in data" flag
587 tokenize25 stb ,y+ ; stash token
588 jmp tokenize0 ; go handle more
589 tokenize26 cmpb #tok_rem ; is it REM?
590 beq tokenize28 ; brif so
591 cmpb #tok_apos ; apostrophe REM?
592 bne tokenize25 ; brif not - stash token and continue
593 lda #': ; stash the implied colon
594 sta ,y+
595 bra tokenize28
596 tokenize27 ldb ,x+ ; fetch next input character
597 tokenize28 stb ,y+ ; stash the character
598 bne tokenize27 ; brif not end of input - do another
599 jmp tokenize2 ; stash end of buffer and handle cleanup
600 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
601 ; Special tokenization handling
602 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
603 ; Keyword dictionaries and jump tables. These are defined by several macros which ensure that each command or function
604 ; entry has an associated jump table entry. These macros are:
605 ;
606 ; defcmd string,symbase
607 ; deffunc string,symbase,flags
608 ; cmdtab
609 ; functab
610 ; cmdjump
611 ; funcjump
612 ; defcmd and deffunc will add an entry into the relevant dictionary table as well as adding one to the relevant jump
613 ; tables. The cmdtab, functab, cmdjump, and funcjump will output the table definitions.
614 *pragmapush list
615 *pragma nolist
616 __cmdnum set 0x80
617 __funcnum set 0x80
618 defcmd macro noexpand
619 setstr __cmdtab="%(__cmdtab)\tfcs {1}\n"
620 ifstr ne,"{3}",""
621 setstr __cmdjump="%(__cmdjump)\tfdb {3}\n"
622 else
623 setstr __cmdjump="%(__cmdjump)\tfdb cmd_{2}\n"
624 endc
625 tok_{2} equ __cmdnum
626 __cmdnum set __cmdnum+1
627 endm
628 deffunc macro noexpand
629 setstr __functab="%(__functab)\tfcs {1}\n"
630 ifstr ne,"{4}",""
631 setstr __funcjump="%(__funcjump)\tfcb {3}\n\tfdb {4}\n"
632 else
633 setstr __funcjump="%(__funcjump)\tfcb {3}\n\tfdb func_{2}\n"
634 endc
635 tok_{2} equ __funcnum
636 __funcnum set __funcnum+1
637 endm
638 cmdtab macro
639 *pragmapush list
640 *pragma nolist
641 includestr "%(__cmdtab)"
642 *pragmapop list
643 fcb 0 ; flag end of table
644 endm
645 functab macro
646 *pragmapush list
647 *pragma nolist
648 includestr "%(__functab)"
649 *pragmapop list
650 fcb 0 ; flag end of table
651 endm
652 cmdjump macro
653 *pragmapush nolist
654 *pragma nolist
655 includestr "%(__cmdjump)"
656 *pragmapop list
657 endm
658 funcjump macro
659 *pragmapush nolist
660 *pragma nolist
661 includestr "%(__funcjump)"
662 *pragmapop list
663 endm
664 *pragmapop list
665 defcmd 'REM',rem
666 defcmd /'/,apos
667 defcmd 'DATA',data
668 defcmd 'ELSE',else
669 defcmd 'END',end
670 defcmd 'STOP',stop
671 defcmd 'LET',let
672 defcmd 'NEW',new
673 defcmd 'PRINT',print
674 defcmd 'LIST',list
675 defcmd 'RUN',run
676 defcmd 'GOTO',goto
677 defcmd 'GOSUB',gosub
678 defcmd 'RETURN',return
679 defcmd 'POP',pop
680 defcmd '+',plus,SNERROR ; IMPORTANT: the operators from + to OR MUST stay in this exact sequence
681 defcmd '-',minus,SNERROR ; with no gaps because a secondary lookup table is used for operator
682 defcmd '*',times,SNERROR ; handling during binary operator handling.
683 defcmd '/',divide,SNERROR
684 defcmd '^',power,SNERROR
685 defcmd '<',less,SNERROR
686 defcmd '>',greater,SNERROR
687 defcmd '=',equal,SNERROR
688 defcmd '<=',lessequal,SNERROR
689 defcmd '>=',greaterequal,SNERROR
690 defcmd '<>',notequal,SNERROR
691 defcmd 'AND',and,SNERROR
692 defcmd 'OR',or,SNERROR
693 defcmd 'NOT',not,SNERROR
694 primarydict cmdtab
695 secondarydict functab
696 primaryjump cmdjump
697 secondaryjump funcjump
698 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 55 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
699 ; Need to ensure the vectors are at 0xbff2 56 ; Need to ensure the vectors are at 0xbff2
700 zmb 0xbff2-* ; pad ROM up to the vector point 57 zmb 0xbff2-* ; pad ROM up to the vector point
701 fdb SW3VEC ; SWI3 vector 58 fdb SW3VEC ; SWI3 vector
702 fdb SW2VEC ; SWI2 vector 59 fdb SW2VEC ; SWI2 vector