Initial revision
[ssr] / StraySrc / Libraries / Sapphire / sail / _s / express
1 ;
2 ; express.s
3 ;
4 ; Evaluation of BASIC expressions
5 ;
6 ; © 1995 Straylight
7 ;
8
9 ;----- Standard header ------------------------------------------------------
10
11 GET libs:header
12 GET libs:swis
13
14 GET libs:stream
15
16 ;----- External dependencies ------------------------------------------------
17
18 GET sh.anchor
19 GET sh.ctrl
20 GET sh.divide
21 GET sh.errNum
22 GET sh.error
23 GET sh.getToken
24 GET sh.stracc
25 GET sh.termite
26 GET sh.termScript
27 GET sh.tokenise
28 GET sh.tokens
29 GET sh.upcalls
30 GET sh.mem
31 GET sh.var
32
33 ;----- Macros ---------------------------------------------------------------
34
35 MACRO
36 $label GETOP $r,$prec,$branch,$cc
37 ALIGN
38 $label
39 MOV$cc $r,#($prec)<<24
40 ORR$cc $r,$r,#($branch-exp__bTable)>>2
41 MEND
42
43 ;----- Main code ------------------------------------------------------------
44
45 AREA |TermScript$$Code|,CODE,READONLY
46
47 ;----- Stack handling -------------------------------------------------------
48
49 ; --- exp__pushOp ---
50 ;
51 ; On entry: R0 == operator thing to push
52 ;
53 ; On exit: R0-R4 corrupted
54 ;
55 ; Use: Pushes an operator onto the stack.
56
57 exp__pushOp ROUT
58
59 STMFD R13!,{R14}
60 MOV R3,R0 ;Look after thing to push
61 ADR R1,tsc_opStack ;Point to some stack data
62 LDMIA R1,{R0-R2} ;Load it out
63
64 ADD R4,R1,#4 ;New used size
65 CMP R4,R2 ;Do we need more stack?
66 BGT %10exp__pushOp ;Yes -- jump ahead
67 00exp__pushOp STR R4,tsc_opStkPtr ;Store back new size
68 LDR R0,[R0] ;Point to the stack
69 ADD R0,R0,R4 ;Address to put next thing on
70 STR R3,[R0,#-4] ;Store the new operator
71 LDMFD R13!,{PC}^
72
73 10exp__pushOp ADD R1,R4,#255 ;Align to next size thing
74 BIC R1,R1,#255 ;Finish the align
75 BL mem_realloc ;Yes -- get more space then
76 STR R1,tsc_opStkSize ;Store new size maybe
77 B %00exp__pushOp ;Branch back agin
78
79 LTORG
80
81 ; --- exp__popOp ---
82 ;
83 ; On entry: --
84 ;
85 ; On exit: R0 == value popped off
86 ; R1-R4 corrupted
87 ;
88 ; Use: Pops an operator from the stack.
89
90 exp__popOp ROUT
91
92 STMFD R13!,{R14}
93 ADR R1,tsc_opStack ;Point to some stack data
94 LDMIA R1,{R0-R2} ;Load it out
95
96 SUB R4,R1,#4 ;The new size
97 ADD R1,R4,#255 ;Align up again
98 BIC R1,R1,#255 ;Aligned down
99 ADD R1,R1,#256 ;At least this much
100 CMP R1,R2 ;Has this size changed?
101 BLLT mem_realloc ;Yes -- reduce memory reqs.
102 STRLT R1,tsc_opStkSize ;Store new size maybe
103 STR R4,tsc_opStkPtr ;Store back new size
104 LDR R0,[R0] ;Point to the stack
105 LDR R0,[R0,R4] ;Load the value off the stack
106 LDMFD R13!,{PC}^ ;Return to caller
107
108 LTORG
109
110 ; --- exp__pushVal ---
111 ;
112 ; On entry: R0 == operator thing to push
113 ; R1 == type of thing to push
114 ;
115 ; On exit: R0-R5 corrupted
116 ;
117 ; Use: Pushes an value onto the stack.
118
119 exp__pushVal ROUT
120
121 STMFD R13!,{R5,R14}
122 MOV R3,R0 ;Look after thing to push
123 MOV R4,R1
124 ADR R1,tsc_calcStack ;Point to some stack data
125 LDMIA R1,{R0-R2} ;Load it out
126
127 ADD R5,R1,#8 ;New used size
128 CMP R5,R2
129 BGT %10exp__pushVal
130 00exp__pushVal STR R5,tsc_calcStkPtr ;Store back new size
131 LDR R0,[R0] ;Point to the stack
132 ADD R0,R0,R5 ;Address to put next thing on
133 STMDB R0,{R3,R4} ;Store the thing
134 LDMFD R13!,{R5,PC}^
135
136 10exp__pushVal ADD R1,R5,#255 ;Align to next size thing
137 BIC R1,R1,#255 ;Finish the align
138 BL mem_realloc ;Yes -- get more space then
139 STR R1,tsc_calcStkSize ;Store new size maybe
140 B %00exp__pushVal
141
142 LTORG
143
144 ; --- exp__popVal ---
145 ;
146 ; On entry: --
147 ;
148 ; On exit: R0,R1 == value popped off
149 ; R2-R4 corrupted
150 ;
151 ; Use: Pops a value from the stack.
152
153 exp__popVal ROUT
154
155 STMFD R13!,{R14}
156 ADR R1,tsc_calcStack ;Point to some stack data
157 LDMIA R1,{R0-R2} ;Load it out
158
159 SUB R4,R1,#8 ;The new size
160 ADD R1,R4,#255 ;Align up again
161 BIC R1,R1,#255 ;Aligned down
162 ADD R1,R1,#256 ;At least this much please
163 CMP R1,R2 ;Has this size changed?
164 BLLT mem_realloc ;Yes -- reduce memory reqs.
165 STRLT R1,tsc_calcStkSize ;Store new size maybe
166 STR R4,tsc_calcStkPtr ;Store back new size
167 LDR R0,[R0] ;Point to the stack
168 ADD R0,R0,R4 ;Point into the stack
169 LDMIA R0,{R0,R1} ;Load values from the stack
170 LDMFD R13!,{PC}^ ;Return to caller
171
172 LTORG
173
174 ; --- exp__popTwoVals ---
175 ;
176 ; On entry: --
177 ;
178 ; On exit: R0-R3 == values popped off
179 ; R4 corrupted
180 ;
181 ; Use: Pops two values from the stack.
182
183 exp__popTwoVals ROUT
184
185 STMFD R13!,{R14}
186 ADR R1,tsc_calcStack ;Point to some stack data
187 LDMIA R1,{R0-R2} ;Load it out
188
189 SUB R4,R1,#16 ;The new size
190 ADD R1,R4,#255 ;Align up again
191 BIC R1,R1,#255 ;Aligned down
192 ADD R1,R1,#256 ;At least his much
193 CMP R1,R2 ;Has this size changed?
194 BLLT mem_realloc ;Yes -- reduce memory reqs.
195 STRLT R1,tsc_calcStkSize ;Store new size maybe
196 STR R4,tsc_calcStkPtr ;Store back new size
197 LDR R0,[R0] ;Point to the stack
198 ADD R0,R0,R4 ;Point into the stack
199 LDMIA R0,{R0-R3} ;Load values from the stack
200 LDMFD R13!,{PC}^ ;Return to caller
201
202 LTORG
203
204 ; --- express_pop ---
205 ;
206 ; On entry: --
207 ;
208 ; On exit: R0,R1 == value popped off
209 ;
210 ; Use: Pops a value from the stack.
211
212 EXPORT express_pop
213 express_pop ROUT
214
215 STMFD R13!,{R2-R4,R14} ;Stack registers
216 BL exp__popVal ;Get the value
217 LDMFD R13!,{R2-R4,PC}^ ;Return to caller
218
219 LTORG
220
221 ; --- express_popTwo ---
222 ;
223 ; On entry: --
224 ;
225 ; On exit: R0-R3 == two values popped from the stack
226 ;
227 ; Use: Pops two values from the stack.
228
229 EXPORT express_popTwo
230 express_popTwo ROUT
231
232 STMFD R13!,{R4,R14} ;Stack registers
233 BL exp__popTwoVals ;Pop the values
234 LDMFD R13!,{R4,PC}^ ;And return to caller
235
236 LTORG
237
238 ; --- express_push ---
239 ;
240 ; On entry: R0,R1 == l/rvalue to push
241 ;
242 ; On exit: --
243 ;
244 ; Use: Pushes a value onto the expression stack.
245
246 EXPORT express_push
247 express_push ROUT
248
249 STMFD R13!,{R0-R4,R14} ;Save some registers
250 BL exp__pushVal ;Do the pushing
251 LDMFD R13!,{R0-R4,PC}^ ;And return to caller
252
253 LTORG
254
255 ;----- Space-saving type checking routines ----------------------------------
256
257 ; --- exp__chkTwoInts ---
258 ;
259 ; On entry: R1,R3 == types of variable
260 ;
261 ; On exit: --
262 ;
263 ; Use: Ensures that R1 and R3 are both of type integer, and
264 ; complains otherwise.
265
266 exp__chkTwoInts ROUT
267
268 CMP R3,#vType_integer ;Is second an integer?
269 MOVNE R1,R3 ;No -- fiddle the first then
270
271 ; Drop through here (yuk)
272
273 ; --- exp__chkInt ---
274 ;
275 ; On entry: R1 == type of a variable
276 ;
277 ; On exit: --
278 ;
279 ; Use: Ensures that R1 is of type integer, and complains otherwise.
280
281 exp__chkInt ROUT
282
283 CMP R1,#vType_integer ;Is it an integer
284 MOVEQS PC,R14 ;Yes -- all OK -- return
285 MOV R0,#err_numNeeded ;No -- get the error
286 B error_report ;And complain at the user
287
288 LTORG
289
290 ; --- exp__popInt ---
291 ;
292 ; On entry: --
293 ;
294 ; On exit: R0,R1 == value popped from the stack
295 ; R2-R4 corrupted
296 ;
297 ; Use: Pops a value from the stack and ensures that it is an
298 ; integer.
299
300 exp__popInt STMFD R13!,{R14} ;Save the link for a bit
301 BL exp__popVal ;Pop a value from stack
302 LDMFD R13!,{R14} ;Restore link register
303 B exp__chkInt ;And check the value
304
305 LTORG
306
307 ; --- exp__popTwoInts ---
308 ;
309 ; On entry: --
310 ;
311 ; On exit: R0,R1,R2,R3 == two integers popped from the calc stack
312 ; R4 corrupted
313 ;
314 ; Use: Pops two values from the stack and ensures that they are
315 ; integers.
316
317 exp__popTwoInts ROUT
318
319 STMFD R13!,{R14} ;Save the link for a bit
320 BL exp__popTwoVals ;Pop two values from stack
321 LDMFD R13!,{R14} ;Restore link register
322 B exp__chkTwoInts ;And check the values
323
324 LTORG
325
326 ; --- exp__chkTwoStrs ---
327 ;
328 ; On entry: R1,R3 == types of variable
329 ;
330 ; On exit: --
331 ;
332 ; Use: Ensures that R1 and R3 are both of type string, and
333 ; complains otherwise.
334
335 exp__chkTwoStrs ROUT
336
337 CMP R3,#vType_string ;Is second an integer?
338 MOVNE R1,R3 ;No -- fiddle the first then
339
340 ; Drop through here (yuk)
341
342 ; --- exp__chkStr ---
343 ;
344 ; On entry: R1 == type of a variable
345 ;
346 ; On exit: --
347 ;
348 ; Use: Ensures that R1 is of type string, and complains otherwise.
349
350 exp__chkStr ROUT
351
352 CMP R1,#vType_string ;Is it an integer
353 MOVEQS PC,R14 ;Yes -- all OK -- return
354 MOV R0,#err_strNeeded ;No -- get the error
355 B error_report ;And complain at the user
356
357 LTORG
358
359 ; --- exp__popStr ---
360 ;
361 ; On entry: --
362 ;
363 ; On exit: R0,R1 == value popped from the stack
364 ; R2-R4 corrupted
365 ;
366 ; Use: Pops a value from the stack and ensures that it is an
367 ; integer.
368
369 exp__popStr STMFD R13!,{R14} ;Save the link for a bit
370 BL exp__popVal ;Pop a value from stack
371 LDMFD R13!,{R14} ;Restore link register
372 B exp__chkStr ;And check the value
373
374 LTORG
375
376 ; --- exp__popTwoStrs ---
377 ;
378 ; On entry: --
379 ;
380 ; On exit: R0,R1,R2,R3 == two integers popped from the calc stack
381 ; R4 corrupted
382 ;
383 ; Use: Pops two values from the stack and ensures that they are
384 ; integers.
385
386 exp__popTwoStrs ROUT
387
388 STMFD R13!,{R14} ;Save the link for a bit
389 BL exp__popTwoVals ;Pop two values from stack
390 LDMFD R13!,{R14} ;Restore link register
391 B exp__chkTwoStrs ;And check the values
392
393 LTORG
394
395 ;----- Expression evaluation routines ---------------------------------------
396
397 ; --- express_fnCont ---
398 ;
399 ; On entry: Involved
400 ;
401 ; On exit: Similarly involved.
402 ;
403 ; Use: We continue here after executing a function.
404
405 EXPORT express_fnCont
406
407 ; --- express_read ---
408 ;
409 ; On entry: R0 == 1 to read an lvalue, 2 to read ident, 0 otherwise
410 ; R7, R8, R9 == lookahead token
411 ; R10 == pointer into tokenised buffer
412 ; R11 == evaluation stack pointer
413 ; R12 == anchor pointer
414 ;
415 ; On exit: R0,R1 == value of expression
416 ; R7, R8, R9 == lookahead token
417 ; R0, R1 == result of expression
418 ; R10 == moved on to first char after expression
419 ;
420 ; Use: Reads an expression for the current position in the
421 ; tokenised file.
422
423 EXPORT express_read
424 express_read ROUT
425
426 STMFD R13!,{R0-R6,R14} ;Stack registers
427 MOV R6,#0 ;Current flags word
428 CMP R0,#1 ;Reading an lvalue?
429 ORREQ R6,R6,#eFlag__lval ;Yes -- set the flag then
430 CMP R0,#2 ;Reading an ident?
431 ORREQ R6,R6,#eFlag__parseLval ;Yes -- parse as lval then
432
433 GETOP R0,255,exp__bExpEnd ;Push a sentinel operand
434 BL exp__pushOp ;To separate this expression
435
436 exp__mainLoop
437 express_fnCont
438 10express_read TST R6,#eFlag__done ;Have we finished this?
439 BNE %70express_read ;Yes -- jump ahead
440 TST R6,#eFlag__op ;Are we reading an op?
441 BNE %50express_read ;Yes -- jump ahead
442
443 ; --- Read an operand then ---
444
445 SUBS R4,R9,#'_' ;Is it an underscore?
446 SUBNE R4,R9,#'A' ;Or a capital letter?
447 CMP R4,#26
448 SUBCS R4,R9,#'a' ;Or a lowercase letter?
449 CMPCS R4,#26
450 BCC exp__readIdent ;Read an identifier
451
452 CMP R9,#'!' ;Is it an indirection op?
453 CMPNE R9,#'?'
454 CMPNE R9,#'$'
455 BEQ exp__indir ;Yes -- jump ahead
456
457 TST R6,#eFlag__lval ;Are we reading an lvalue?
458 MOVNE R0,#err_syntax ;Yes -- get the error number
459 BNE error_report ;...and report the error
460
461 CMP R9,#'"' ;Is it a quote?
462 BEQ exp__string ;Yes -- read string then
463
464 CMP R9,#'(' ;Is it a bracket?
465 BEQ exp__par ;Yes -- jump ahead
466
467 CMP R9,#tok_fn ;Is it a function call?
468 BEQ exp__userFn ;Yes -- handle that then
469
470 CMP R9,#tok_rnd ;Is this the RND fn?
471 BLEQ getToken ;Yes -- gobble that
472 BEQ exp__doRnd ;And deal with it then
473
474 CMP R9,#'+' ;Is it a unary '+'?
475 BLEQ getToken ;...get another token
476 BEQ %10express_read ;...keep going around again
477 CMP R9,#'-' ;Is it a unary '-'?
478 BEQ exp__uMinus ;Yes -- jump ahead then
479
480 CMP R7,#tClass_pseud ;Is this a pseudovariable?
481 BEQ exp__pseud ;Yes -- deal with it
482
483 CMP R7,#tClass_fn ;Is it a function then?
484 BEQ exp__fn ;Yes -- deal with that
485
486 CMP R7,#tClass_streamOp ;Also check for stream ops
487 BEQ exp__streamOp ;Just for luck
488
489 CMP R7,#tClass_multArg ;Multiple parameter thing?
490 BEQ exp__multArg ;Yes -- deal with it then
491
492 CMP R9,#'&' ;Start a hex number?
493 BEQ exp__readHex ;Yes -- jump ahead
494 CMP R9,#'%' ;Start of a binary number?
495 BEQ exp__readBin ;Yes -- jump ahead
496 SUB R14,R9,#'0' ;Set up for a range check
497 CMP R14,#10 ;Is it a number?
498 BCC exp__readDec ;Read a decimal number
499
500 MOV R0,#err_unknown ;Get all-encompassing error
501 B error_report ;And report the error
502
503 LTORG
504
505 ; --- Handle a string ---
506
507 exp__string BL stracc_ensure ;Ensure stracc is big enough
508 MOV R2,#0 ;The initial length
509 00 BL getToken ;Read the next token
510 CMP R9,#&0a ;Is this a line end?
511 CMPNE R9,#&ff ;Or an end of file?
512 MOVEQ R0,#err_expQuote ;Yes -- get error number
513 BEQ error_report ;And report it
514 CMP R9,#'"' ;Is it a quote?
515 BEQ %f05 ;Yes -- branch ahead
516 03 STRB R9,[R0],#1 ;No -- store the byte
517 ADDS R2,R2,#1<<24 ;...increment the length
518 BCC %b00 ;Keep looping for more
519 MOVCS R0,#err_strTooLong ;Get error message
520 BCS error_report ;and report it nicely
521
522 05 BL getToken ;Get another token
523 CMP R9,#'"' ;Is this a quote too?
524 BEQ %b03 ;Yes -- jump back upwards
525
526 ORR R0,R1,R2,LSR #24 ;Get the rvalue word
527 MOV R1,#vType_string ;This is a string
528 BL stracc_added ;Tell stracc about this
529 BL exp__pushVal ;Push the value
530 ORR R6,R6,#eFlag__op ;Read an operator now
531 B %10express_read ;And jump with glee
532
533 ; --- Handle a function call ---
534
535 exp__userFn ORR R6,R6,#eFlag__op ;Expect operand next
536 BL getToken ;Gobble the token
537 B ctrl_fn ;And handle it elsewhere
538
539 ; --- Handle an open bracket ---
540
541 exp__par GETOP R0,253,exp__bPar ;Do a bracket like thing
542 BL exp__pushOp ;Push that onto the stack
543 ADD R6,R6,#1<<8 ;Bump the paren count
544 BL getToken ;Get another token
545 B %10express_read ;And read the first operand
546
547 ; --- Handle a unary minus ---
548
549 exp__uMinus GETOP R0,1,exp__bUMinus ;Do a unary minus
550 BL exp__pushOp ;Push that onto the stack
551 BL getToken ;Get another token
552 B %10express_read ;And read the first operand
553
554 ; --- Handle a pseudovariable ---
555
556 exp__pseud MOV R0,R8 ;Look after token index
557 BL getToken ;Move on to next token
558 ORR R6,R6,#eFlag__op ;Now expecting an operator
559 MOV R14,PC ;Set up return address
560 ADD PC,PC,R0,LSL #2 ;Dispatch on token index
561 B %10express_read ;And return to the top
562
563 B exp__doFalse ;Return 0
564 B exp__doTime ;Get the current time
565 B exp__doTimeS ;Read time as a string (ouch)
566 B exp__doTrue ;Return -1
567
568 ; --- Handle unary functions ---
569
570 exp__fn MOV R0,#(exp__fns-exp__bTable)>>2
571 ADD R0,R0,R8 ;Add on the token index
572 ORR R0,R0,#1<<24 ;Use normal unary precedence
573 CMP R9,#tok_strS ;Is this STR$?
574 BLNE exp__pushOp ;Put that on the stack
575 BLNE getToken ;Get the next token
576 BNE %10express_read ;And go back up top
577
578 BL getToken ;Get another token
579 CMP R9,#'~' ;Hex conversion?
580 ORREQ R0,R0,#1<<16 ;Set a useful flag
581 BLEQ getToken ;And get another token
582 BL exp__pushOp ;Put that on the stack
583 B %10express_read ;And go back up top
584
585 ; --- Handle stream operations with irritating #s ---
586
587 exp__streamOp MOV R1,R8 ;Look after token index
588 BL getToken ;Get the next token
589 CMP R9,#'#' ;Is next char a hash?
590 MOVNE R0,#err_expHash ;No -- complain then
591 BNE error_report ;And report an error
592 BL getToken ;Get the next token
593 MOV R0,#(exp__streamOps-exp__bTable)>>2
594 ADD R0,R0,R1 ;Add on the token index
595 ORR R0,R0,#1<<24 ;Use normal unary precedence
596 BL exp__pushOp ;Put that on the stack
597 B %10express_read ;And go back up top
598
599 ; --- Deal with multiple parameter commands ---
600
601 exp__multArg MOV R0,#(exp__multArgs-exp__bTable)>>2
602 ADD R0,R0,R8 ;Add on the token index
603 ORR R0,R0,#1<<24 ;Use normal unary precedence
604 BL exp__pushOp ;Put that on the stack
605 BL getToken ;Get the next token
606
607 GETOP R0,254,exp__bMultArg ;Get the operator value
608 TST R6,#eFlag__commaOk ;Are we allowing commas?
609 ORRNE R0,R0,#1<<16 ;Yes -- set the flag then
610 BL exp__pushOp ;Put that on there
611 ORR R6,R6,#eFlag__commaOk ;Allow commas for a while
612 ADD R6,R6,#1<<8 ;Increment the paren count
613
614 B %10express_read ;And go back up top
615
616 ; --- Deal with an indirection operator ---
617
618 exp__indir MOV R0,#0 ;Prepare a zero base
619 TST R6,#eFlag__lval ;Are we reading an lvalue?
620 MOVEQ R1,#vType_integer ;No -- call it an integer
621 MOVNE R1,#vType_lvInt ;Yes -- call it an int lval
622 BICNE R6,R6,#eFlag__lval ;Clear lvalue flag too
623 ORRNE R6,R6,#eFlag__parseLval ;But carry on parsing one!
624 BL exp__pushVal ;Push that on the calc stack
625 CMP R9,#'$' ;Is this a dollar?
626 MOVLT R0,#(exp__bPling-exp__bTable)>>2
627 MOVEQ R0,#(exp__bDollar-exp__bTable)>>2
628 MOVGT R0,#(exp__bQuery-exp__bTable)>>2
629 ORR R0,R0,#1<<24 ;Make it precedence 1
630 BL exp__pushOp ;Stick that on the op stack
631 BL getToken ;Get another token
632 B %10express_read ;And read the operand
633
634 ; --- Read a hexadecimal number ---
635
636 exp__readHex MOV R0,#0 ;Initial value is zero
637 BL getToken ;Get a first token
638 SUB R14,R9,#'A' ;Is this a letter
639 CMP R14,#6 ;If so, make sure it's OK
640 ADDCC R14,R14,#10 ;And move on to 10-15
641 SUBCS R14,R9,#'0' ;Otherwise check for digit
642 CMPCS R14,#10 ;Make sure that's in range
643 MOVCS R0,#err_badHex ;If not, make an error
644 BCS error_report ;And stop doing this
645
646 00express_read ADD R0,R14,R0,LSL #4 ;Accumulate a result
647 BL getToken ;Get another token
648 SUB R14,R9,#'A' ;Is this a letter
649 CMP R14,#6 ;If so, make sure it's OK
650 ADDCC R14,R14,#10 ;And move on to 10-15
651 SUBCS R14,R9,#'0' ;Otherwise check for digit
652 CMPCS R14,#10 ;Make sure that's in range
653 BCC %b00express_read ;If it was OK, go round more
654
655 MOV R1,#vType_integer ;Call it an integer
656 BL exp__pushVal ;Stick that on the val stack
657 TST R6,#eFlag__parseLval ;Parsing an lvalue?
658 ORRNE R6,R6,#eFlag__done ;Yes -- we're finished
659 ORR R6,R6,#eFlag__op ;Now look for binary operator
660 B %10express_read ;And read the operator
661
662 ; --- Read a binary number ---
663
664 exp__readBin MOV R0,#0 ;Initial value is zero
665 BL getToken ;Get a first token
666 SUB R14,R9,#'0' ;Otherwise check for digit
667 CMP R14,#1 ;Make sure that's in range
668 MOVHI R0,#err_badHex ;If not, make an error
669 BHI error_report ;And stop doing this
670
671 00express_read ADC R0,R0,R0 ;Accumulate a result
672 BL getToken ;Get another token
673 SUB R14,R9,#'0' ;Otherwise check for digit
674 CMP R14,#1 ;Make sure that's in range
675 BLS %b00express_read ;If it was OK, go round more
676
677 MOV R1,#vType_integer ;Call it an integer
678 BL exp__pushVal ;Stick that on the val stack
679 TST R6,#eFlag__parseLval ;Parsing an lvalue?
680 ORRNE R6,R6,#eFlag__done ;Yes -- we're finished
681 ORR R6,R6,#eFlag__op ;Now look for binary operator
682 B %10express_read ;And read the operator
683
684 ; --- Read a decimal number ---
685
686 exp__readDec MOV R0,#0 ;Initial value is zero
687
688 00express_read ADD R0,R0,R0,LSL #2 ;Multiply accumulator by 5
689 ADD R0,R14,R0,LSL #1 ;Accumulate the result
690
691 BL getToken ;Get another token
692 SUB R14,R9,#'0' ;Otherwise check for digit
693 CMP R14,#10 ;Make sure that's in range
694 BCC %b00express_read ;If it was OK, go round more
695
696 MOV R1,#vType_integer ;Call it an integer
697 BL exp__pushVal ;Stick that on the val stack
698 TST R6,#eFlag__parseLval ;Parsing an lvalue?
699 ORRNE R6,R6,#eFlag__done ;Yes -- we're finished
700 ORR R6,R6,#eFlag__op ;Now look for binary operator
701 B %10express_read ;And read the operator
702
703 ; --- Read an identifier ---
704
705 exp__readIdent ADR R1,tsc_misc ;Point to a nice block
706 MOV R2,#vType_integer ;The current variable type
707
708 00express_read SUBS R4,R9,#'_' ;Is it an underscore?
709 SUBNE R4,R9,#'0' ;Or a number?
710 CMP R4,#10
711 SUBCS R4,R9,#'A' ;Or a capital letter?
712 CMPCS R4,#26
713 SUBCS R4,R9,#'a' ;Or a lowercase letter?
714 CMPCS R4,#26
715 STRCCB R9,[R1],#1 ;Yes -- store it away
716 BLCC getToken ;Read the next byte
717 MOVCS R0,#err_unknown ;Don't know this -- error!
718 BCS error_report ;So give a bogus error msg
719
720 CMP R9,#'$' ;Is it a dollar sign?
721 MOVEQ R2,#vType_string ;It's a string now
722 CMPNE R9,#'%' ;Or a percentage?
723 STREQB R9,[R1],#1 ;Yes -- store it then
724 CMPNE R9,#' ' ;Just check for a space
725
726 BNE %b00express_read ;Go round for more
727
728 MOV R14,#0 ;The terminator
729 STRB R14,[R1],#0 ;Store that in the var name
730 BL getToken ;Read the next token ready
731
732 ; --- Check for arrays ---
733
734 CMP R9,#'(' ;Is this an array?
735 BNE %f05 ;No -- skip on then
736 BL getToken ;Get another token
737 ADD R2,R2,#vType_dimInt-vType_integer
738 MOV R0,R2 ;Put that in R2
739 ADR R1,tsc_misc ;Point to variable name
740 BL var_find ;Find the variable
741 LDR R14,tsc_varTree ;Find var tree anchor
742 LDR R14,[R14,#0] ;Grrr...
743 SUB R3,R0,R14 ;Convert this to an offset
744 TST R6,#eFlag__lval ;Reading an lvalue?
745 ADDNE R2,R2,#vType_lvIntArr-vType_dimInt
746
747 CMP R9,#')' ;Is it a whole array?
748 BEQ %f00 ;Yes -- deal with that
749
750 ; --- Set up for subscripting the array ---
751
752 STMFD R13!,{R2} ;Save some registers
753 MOV R0,R3 ;Get the array's offset
754 BL exp__pushOp ;Stuff that on op stack (!)
755 LDMFD R13!,{R0} ;And get its type
756 BL exp__pushOp ;Stuff that on op stack too
757
758 GETOP R0,254,exp__bSubscript ;Get the operator value
759 TST R6,#eFlag__commaOk ;Are we allowing commas?
760 ORRNE R0,R0,#1<<16 ;Yes -- set the flag then
761 TST R6,#eFlag__lval ;Are we reading an value?
762 ORRNE R0,R0,#1<<17 ;Yes -- set that flag
763 BL exp__pushOp ;Put that on there
764 ORR R6,R6,#eFlag__commaOk ;Allow commas for a while
765 BIC R6,R6,#eFlag__lval ;Don't read as lvalues
766 ADD R6,R6,#1<<8 ;Increment the paren count
767 B %10express_read ;Now read the subscripts
768
769 ; --- Just store the array lvalue ---
770
771 00 BL getToken ;Skip over the bracket
772 MOV R1,R2 ;Get the type
773 MOV R0,R3 ;And the tree offset
774 BL exp__pushVal ;Stash it on the stack
775 ORR R6,R6,#eFlag__op ;Expect an operator
776 B %10express_read ;And go read that
777
778 ; --- Handle strings and things ---
779
780 05 TST R6,#eFlag__lval ;Are we reading an lvalue?
781 BNE %f20express_read ;Yes -- jump ahead
782
783 TST R6,#eFlag__parseLval ;Parsing an lvalue?
784 ORRNE R6,R6,#eFlag__done ;Yes -- we're finished
785
786 ADR R1,tsc_misc ;Point to variable name
787 MOV R0,R2 ;Get the variable type too
788 BL var_find ;Try to find the variable
789
790 ; --- Do wildly different things with strings ---
791
792 CMP R2,#vType_string ;Is this a string
793 BNE %f00 ;No -- jump ahead then
794 LDR R14,tsc_varTree ;Load base of variable tree
795 LDR R14,[R14]
796 SUB R0,R0,R14 ;Get the offset of node
797 ADD R0,R0,#4 ;Point to the actual word
798 MOV R1,#vType_lvString ;The variable type
799 BL ctrl_load ;Load the string into stracc
800 MOV R0,R2 ;Put rvalue into R0,R1
801 MOV R1,R3
802 BL exp__pushVal ;Stack that nicely
803 ORR R6,R6,#eFlag__op ;Expect an operator
804 B %10express_read ;And keep on looking
805
806 00express_read MOV R1,R2 ;Get the operand type
807 LDR R0,[R0,#4] ;Load the integer value
808 BL exp__pushVal ;Stack that nicely
809
810 ; --- Now try to cope with indirection ---
811
812 CMP R9,#'!' ;Is this an indirection op?
813 CMPNE R9,#'?' ;Or maybe a different one
814 ORRNE R6,R6,#eFlag__op ;No -- expect an operator
815 BNE %10express_read ;And go for that then
816
817 CMP R9,#'?' ;Is this a '?' ?
818 MOVEQ R0,#(exp__bQuery-exp__bTable)>>2
819 MOVNE R0,#(exp__bPling-exp__bTable)>>2
820 ORR R0,R0,#1<<24 ;Use unary op precedence
821 BL exp__pushOp ;Stick that on the stack
822 BL getToken ;Get another token
823 B %10express_read ;Return, still expecting val
824
825 ; --- We are reading an lvalue ---
826 ;
827 ; We only need to create the variable if there is not an
828 ; indirection operator following.
829
830 20express_read CMP R9,#'!' ;Is this an indirection op?
831 CMPNE R9,#'?' ;Or maybe a different one
832 ORRNE R6,R6,#eFlag__done ;Yes -- we're finished
833 BIC R6,R6,#eFlag__lval ;Clear lvalue flag too
834 ORR R6,R6,#eFlag__parseLval ;Parse an lvalue-ish now
835
836 ADR R1,tsc_misc ;Point to variable name
837 MOV R0,R2 ;Get the variable type too
838 BLNE var_create ;Create the variable maybe
839 BLEQ var_find ;Or maybe we just find it
840
841 ADR R14,exp__indirTran ;Point to the translation
842 LDRB R1,[R14,R2] ;Get the new type
843 LDRNE R14,tsc_varTree ;Get the tree address
844 LDRNE R14,[R14] ;Wimp_Extension is shitty
845 SUBNE R0,R0,R14 ;Find the offset
846 ADDNE R0,R0,#4 ;Point to the actual value
847 LDREQ R0,[R0,#4] ;If indirect op, load value
848 BL exp__pushVal ;Push on the new value
849
850 CMP R9,#'?' ;Is this a '?' ?
851 MOVEQ R0,#(exp__bQuery-exp__bTable)>>2
852 MOVNE R0,#(exp__bPling-exp__bTable)>>2
853 CMPNE R9,#'!' ;Or a '!' ?
854 ORREQ R0,R0,#1<<24 ;Use unary op precedence
855 BLEQ exp__pushOp ;Stick that on the stack
856 BLEQ getToken ;Get a token if we need to
857
858 B %10express_read ;Return, still expecting val
859
860 ; --- Try reading an operator ---
861
862 50express_read CMP R9,#')' ;Is this a close bracket?
863 BEQ exp__en ;Yes -- deal with that then
864
865 CMP R9,#',' ;Is it a comma?
866 BEQ exp__comma ;Yes -- deal with that
867
868 ADRL R5,exp__opTable ;Point to the op table
869 LDR R0,[R5,R7,LSL #3]! ;Load the precedence
870 CMP R0,#0 ;Is this reasonable?
871 ORREQ R6,R6,#eFlag__done ;No -- stop then
872 BEQ %10express_read ;Let things tidy up nicely
873
874 BL exp__eval ;Evaluate things on the stack
875 LDR R5,[R5,#4] ;Load the branch table offset
876 ORR R0,R5,R0,LSL #24 ;Build the op stack entry
877 ADD R0,R0,R8 ;Add on the op index
878 BL exp__pushOp ;Stick that on the stack
879 BL getToken ;Get another token
880 BIC R6,R6,#eFlag__op ;Expect another operand
881 B %10express_read ;And go round again
882
883 ; --- Handle a closing bracket ---
884
885 exp__en SUBS R6,R6,#1<<8 ;Decrement paren counter
886 ORRLT R6,R6,#eFlag__done ;If no parens, then stop
887 BLT %10express_read ;It was someone else's `)'
888 BL getToken ;Get another token
889 MOV R0,#252 ;Stop at the dummy `(' op
890 BL exp__eval ;Force evaluation of that lot
891 BL exp__popOp ;Pop the dummy operator
892
893 ; --- Check for comma-separated pseudo-ops ---
894
895 MOV R14,R0,LSR #24 ;Get the op precedence
896 CMP R14,#254 ;Is it a cs-pseudo-op?
897 BNE %10express_read ;No -- keep going then
898
899 ; --- Reset the flags from the operator ---
900
901 BIC R6,R6,#eFlag__lval+eFlag__commaOk
902 TST R0,#1<<16 ;Is the comma-ok flag set?
903 ORRNE R6,R6,#eFlag__commaOk ;Yes -- then set it in R6
904 TST R0,#1<<17 ;Is the lvalue flag set?
905 ORRNE R6,R6,#eFlag__done+eFlag__lval
906
907 ; --- Now do the required processing ---
908
909 MOV R5,R0,LSR #8 ;Get the number of arguments
910 ADD R5,R5,#1 ;One less comman than subs
911 AND R5,R5,#&FF ;Clear the other bits
912 AND R0,R0,#&FF ;Also find jump entry
913 ADRL R14,exp__bTable ;Find the op table
914 ADD PC,R14,R0,LSL #2 ;And dispatch
915
916 ; --- Handle a comma ---
917
918 exp__comma TST R6,#eFlag__commaOk ;Expecting a comma here?
919 ORREQ R6,R6,#eFlag__done ;No -- must be someone else's
920 BEQ %10express_read ;So let them handle it
921 BL getToken ;Gobble the comma char
922 MOV R0,#253 ;Evaluate up to pseudoop
923 BL exp__eval ;Do lots of evaluating
924 BL exp__popOp ;Pop the pseudoop
925 ADD R0,R0,#1<<8 ;Bump the argument count
926 BL exp__pushOp ;Put the pseudoop back again
927 BIC R6,R6,#eFlag__op ;Read another operand
928 B %10express_read ;Now continue doing things
929
930 ; --- We have finished reading the expression ---
931
932 70express_read MOV R0,#254 ;Choose a suitable prec.
933 BL exp__eval ;Do rest of evaluations
934 BL exp__popOp ;Pop of the expression
935
936 ; --- See if this was an evaluated string ---
937
938 AND R14,R0,#&FF ;Get the branch table offset
939 CMP R14,#(exp__bEvalOp-exp__bTable)>>2
940 BEQ exp__endEval ;Yes -- continue doing that
941
942 LDMFD R13!,{R0-R6,PC}^ ;Load some registers
943
944 exp__indirTran DCB vType_lvInt
945 DCB vType_lvString
946 DCB vType_lvIntArr
947 DCB vType_lvStrArr
948
949 LTORG
950
951 ; --- exp__eval ---
952 ;
953 ; On entry: R0 == precedence to look for
954 ; R7, R8, R9 == lookahead token
955 ; R10 == pointer into tokenised buffer
956 ; R11 == evaluation stack pointer
957 ; R12 == anchor pointer
958 ;
959 ; On exit: R1-R4 corrupted
960 ;
961 ; Use: Performs things
962
963 exp__eval ROUT
964
965 STMFD R13!,{R0,R14} ;Stack some registers
966 00exp__eval BL exp__popOp ;Pop an operator
967 LDR R1,[R13,#0] ;Load back thing
968 CMP R1,R0,LSR #24 ;Compare the prec things
969 BLT %10exp__eval ;It's GE so jump ahead
970 MOV R2,R0 ;Put op thing in R2
971 AND R0,R0,#&FF ;Get the branch offset
972 ADR R1,exp__bTable ;Point to the table
973 ADD PC,R1,R0,LSL #2 ;Branch to the do it routine
974 exp__evalRet BL exp__pushVal ;Push the returned value
975 B %00exp__eval ;And keep on going
976
977 10exp__eval BL exp__pushOp ;Push it back on again
978 LDMFD R13!,{R0,PC}^ ;Return to caller
979
980 LTORG
981
982 ; --- exp__doMultArg ---
983 ;
984 ; On entry: R5 == number of subscripts provided
985 ; R6 == flags
986 ; R7, R8, R9 == lookahead token
987 ; R10 == pointer into tokenised buffer
988 ; R11 == upcall block pointer
989 ; R12 == anchor pointer
990 ;
991 ; On exit: R0-R3 corrupted
992 ;
993 ; Use: Subscripts an array of things to find just one of them.
994
995 exp__doMultArg ROUT
996
997 BL exp__popOp ;Pop off the function
998 AND R0,R0,#&FF ;Get the branch offset
999 ADR R1,exp__bTable ;Point to the table
1000 MOV R14,PC ;Set up return address
1001 ADD PC,R1,R0,LSL #2 ;Branch to the do it routine
1002 BL exp__pushVal ;Push the returned value
1003 B exp__mainLoop ;Go back to main loop
1004
1005 LTORG
1006
1007 ; --- A nice precedance table ----
1008
1009 exp__opTable DCD 0,0
1010 DCD 25,(exp__andOps-exp__bTable)>>2
1011 DCD 0,0
1012 DCD 0,0
1013 DCD 0,0
1014 DCD 0,0
1015 DCD 0,0
1016 DCD 10,(exp__multOps-exp__bTable)>>2
1017 DCD 30,(exp__orOps-exp__bTable)>>2
1018 DCD 0,0
1019 DCD 0,0
1020 DCD 0,0
1021 DCD 20,(exp__relOps-exp__bTable)>>2
1022 DCD 15,(exp__addOps-exp__bTable)>>2
1023 DCD 0,0
1024 DCD 5,(exp__powOps-exp__bTable)>>2
1025
1026 ; --- The main dispatch table ---
1027
1028 exp__bTable
1029
1030 exp__andOps B exp__doAnd
1031
1032 exp__multOps B exp__doDiv
1033 B exp__doMod
1034 B exp__doDiv
1035 B exp__doMult
1036
1037 exp__orOps B exp__doXor
1038 B exp__doOr
1039
1040 exp__relOps B exp__doEqual
1041 B exp__doLess
1042 B exp__doLessEq
1043 B exp__doNotEq
1044 B exp__doMore
1045 B exp__doMoreEq
1046 B exp__doLSL
1047 B exp__doASR
1048 B exp__doLSR
1049
1050 exp__addOps B exp__doAdd
1051 B exp__doSub
1052
1053 exp__fns B exp__doAbs
1054 B exp__doAsc
1055 B exp__doChrS
1056 B exp__doEval
1057 B exp__doLen
1058 B exp__doNot
1059 B exp__doOpenin
1060 B exp__doOpenout
1061 B exp__doOpenup
1062 B exp__doSgn
1063 B exp__doStrS
1064 B exp__doVal
1065
1066 exp__streamOps B exp__doBget
1067 B exp__doEof
1068 B exp__doExt
1069 B exp__doGetS
1070 B exp__doPtr
1071
1072 exp__multArgs B exp__doInstr
1073 B exp__doLeftS
1074 B exp__doMidS
1075 B exp__doRightS
1076 B exp__doStringS
1077
1078 exp__powOps B exp__doPow
1079
1080 exp__bUMinus B exp__doUMinus
1081 exp__bPar B exp__doParen
1082 exp__bExpEnd B exp__doEndEval
1083 exp__bEvalOp B exp__doEndEval
1084 exp__bPling B exp__doPling
1085 exp__bQuery B exp__doQuery
1086 exp__bDollar B exp__doDollar
1087
1088 exp__bSubscript B exp__doSubscript
1089
1090 exp__bMultArg B exp__doMultArg
1091
1092 ; --- exp__doAdd ---
1093 ;
1094 ; On entry: R7, R8, R9 == lookahead token
1095 ; R10 == pointer into tokenised buffer
1096 ; R11 == evaluation stack pointer
1097 ; R12 == anchor pointer
1098 ;
1099 ; On exit: R0-R3 corrupted
1100 ;
1101 ; Use: Adds two things.
1102
1103 exp__doAdd ROUT
1104
1105 BL exp__popTwoVals ;Get two values
1106 CMP R1,#vType_integer ;Is this an integer?
1107 BNE %10exp__doAdd ;No -- onwards ho
1108
1109 CMP R3,#vType_integer ;Is this a integer too?
1110 MOVNE R0,#err_numNeeded ;No -- get error number
1111 BNE error_report ;...and report the error
1112 ADD R0,R0,R2 ;Add the numbers together
1113 B exp__evalRet ;Jump back into eval loop
1114
1115 ; --- Concatenate strings ---
1116
1117 10exp__doAdd CMP R1,#vType_string ;This is a string I hope
1118 MOVNE R0,#err_arrayBad ;Arrays are bad
1119 BNE error_report ;So says my mum
1120 CMP R3,#vType_string ;Is this a string too?
1121 MOVNE R0,#err_strNeeded ;No -- get error number
1122 BNE error_report ;...and report the error
1123
1124 MOV R14,R2,LSL #24 ;Get the second string len
1125 CMN R14,R0,LSL #24 ;Is the string short enough?
1126 ADDCC R0,R0,R14,LSR #24 ;Add on second length
1127 BCC exp__evalRet ;Finished -- return
1128
1129 MOV R0,#err_strTooLong ;String is too long
1130 B error_report
1131
1132 LTORG
1133
1134 ; --- exp__doSub ---
1135 ;
1136 ; On entry: R7, R8, R9 == lookahead token
1137 ; R10 == pointer into tokenised buffer
1138 ; R11 == evaluation stack pointer
1139 ; R12 == anchor pointer
1140 ;
1141 ; On exit: R0-R3 corrupted
1142 ;
1143 ; Use: Subtracts one thing from another thing.
1144
1145 exp__doSub ROUT
1146
1147 BL exp__popTwoInts ;Get two integers
1148 SUB R0,R0,R2 ;Subtract the things
1149 B exp__evalRet ;Jump back into eval loop
1150
1151 LTORG
1152
1153 ; --- exp__doMult ---
1154 ;
1155 ; On entry: R7, R8, R9 == lookahead token
1156 ; R10 == pointer into tokenised buffer
1157 ; R11 == evaluation stack pointer
1158 ; R12 == anchor pointer
1159 ;
1160 ; On exit: R0-R3 corrupted
1161 ;
1162 ; Use: Multiplies two things together.
1163
1164 exp__doMult ROUT
1165
1166 BL exp__popTwoInts ;Get two integers
1167 MUL R0,R2,R0 ;Multiply the things
1168 B exp__evalRet ;Jump back into eval loop
1169
1170 LTORG
1171
1172 ; --- exp__doDiv ---
1173 ;
1174 ; On entry: R7, R8, R9 == lookahead token
1175 ; R10 == pointer into tokenised buffer
1176 ; R11 == evaluation stack pointer
1177 ; R12 == anchor pointer
1178 ;
1179 ; On exit: R0-R3 corrupted
1180 ;
1181 ; Use: Divides one thing by another thing.
1182
1183 exp__doDiv ROUT
1184
1185 BL exp__popTwoInts ;Get two integers
1186 MOV R1,R2 ;Get the other thing to do
1187 BL divide ;Divide the things
1188 MOV R1,#vType_integer ;Set the return type
1189 B exp__evalRet ;Jump back into eval loop
1190
1191 LTORG
1192
1193 ; --- exp__doMod ---
1194 ;
1195 ; On entry: R7, R8, R9 == lookahead token
1196 ; R10 == pointer into tokenised buffer
1197 ; R11 == evaluation stack pointer
1198 ; R12 == anchor pointer
1199 ;
1200 ; On exit: R0-R3 corrupted
1201 ;
1202 ; Use: Gives the remainder when one thing is divided by another
1203 ; thing.
1204
1205 exp__doMod ROUT
1206
1207 BL exp__popTwoInts ;Get two integers
1208 MOV R1,R2 ;Get the dividend ready
1209 BL divide ;Divide the things
1210 MOV R0,R1 ;Get the remainder
1211 MOV R1,#vType_integer ;Get the type of the thing
1212 B exp__evalRet ;Jump back into eval loop
1213
1214 LTORG
1215
1216 ; --- exp__doPow ---
1217 ;
1218 ; On entry: R7, R8, R9 == lookahead token
1219 ; R10 == pointer into tokenised buffer
1220 ; R11 == evaluation stack pointer
1221 ; R12 == anchor pointer
1222 ;
1223 ; On exit: R0-R3 corrupted
1224 ;
1225 ; Use: Raises one thing to the power of another thing.
1226
1227 exp__doPow ROUT
1228
1229 BL exp__popTwoInts ;Get two integers
1230
1231 ; --- Check for some special cases ---
1232
1233 CMP R0,#1 ;Raising 1 ^ anything...
1234 CMPNE R2,#0 ;And raising anything ^ 0...
1235 MOVEQ R0,#1 ;Gives you 1
1236 BEQ exp__evalRet ;And return to eval loop
1237
1238 CMP R2,#0 ;Is the exponent negative?
1239 MOVLT R0,#0 ;Yes -- result is fractional
1240 BLT exp__evalRet ;And return to eval loop
1241
1242 ; --- Now we use a cunning loop to make this quick ---
1243 ;
1244 ; Basically, we note that x^2y == (x^2)^y
1245
1246 MOV R3,R0 ;Look after the x value
1247 MOV R0,#1 ;An initial multiplier
1248
1249 10exp__doPow MOVS R2,R2,LSR #1 ;Get bottom bit
1250 MULCS R0,R3,R0 ;If set, do multiply
1251 MUL R14,R3,R3 ;Square thing to raise
1252 MOV R3,R14 ;Can't do in one instr :-(
1253 BNE %10exp__doPow ;If not finished, continue
1254
1255 B exp__evalRet ;Go back to eval loop
1256
1257 LTORG
1258
1259 ; --- exp__doAnd ---
1260 ;
1261 ; On entry: R7, R8, R9 == lookahead token
1262 ; R10 == pointer into tokenised buffer
1263 ; R11 == evaluation stack pointer
1264 ; R12 == anchor pointer
1265 ;
1266 ; On exit: R0-R3 corrupted
1267 ;
1268 ; Use: ANDs two things.
1269
1270 exp__doAnd ROUT
1271
1272 BL exp__popTwoInts ;Get two integers
1273 AND R0,R0,R2 ;Do the AND op
1274 B exp__evalRet ;Jump back into eval loop
1275
1276 LTORG
1277
1278 ; --- exp__doOr ---
1279 ;
1280 ; On entry: R7, R8, R9 == lookahead token
1281 ; R10 == pointer into tokenised buffer
1282 ; R11 == evaluation stack pointer
1283 ; R12 == anchor pointer
1284 ;
1285 ; On exit: R0-R3 corrupted
1286 ;
1287 ; Use: ORs two things.
1288
1289 exp__doOr ROUT
1290
1291 BL exp__popTwoInts ;Get two integers
1292 ORR R0,R0,R2 ;Do the OR op
1293 B exp__evalRet ;Jump back into eval loop
1294
1295 LTORG
1296
1297 ; --- exp__doXor ---
1298 ;
1299 ; On entry: R7, R8, R9 == lookahead token
1300 ; R10 == pointer into tokenised buffer
1301 ; R11 == evaluation stack pointer
1302 ; R12 == anchor pointer
1303 ;
1304 ; On exit: R0-R3 corrupted
1305 ;
1306 ; Use: XORs two things.
1307
1308 exp__doXor ROUT
1309
1310 BL exp__popTwoInts ;Get two integers
1311 EOR R0,R0,R2 ;Do the XOR op
1312 B exp__evalRet ;Jump back into eval loop
1313
1314 LTORG
1315
1316 ; --- exp__doPling ---
1317 ;
1318 ; On entry: R7, R8, R9 == lookahead token
1319 ; R10 == pointer into tokenised buffer
1320 ; R11 == evaluation stack pointer
1321 ; R12 == anchor pointer
1322 ;
1323 ; On exit: R0-R3 corrupted
1324 ;
1325 ; Use: Reads a word from a memory address.
1326
1327 exp__doPling ROUT
1328
1329 BL exp__popTwoVals ;Get next two values
1330 CMP R1,#vType_lvInt ;We can cope with lvalues
1331 BEQ %50exp__doPling ;If this is the case, be odd
1332 BL exp__chkTwoInts ;Make sure we have integers
1333 LDR R0,[R0,R2] ;Load the word
1334 B exp__evalRet ;Jump back into eval loop
1335
1336 50exp__doPling CMP R3,#vType_integer ;Make sure other val is int
1337 MOVNE R0,#err_numNeeded ;If not, moan at the user
1338 BNE error_report ;That's that done then
1339 ADD R0,R0,R2 ;Calculate the address
1340 MOV R1,#vType_lvWord ;This is a word lvalue
1341 B exp__evalRet ;Jump back into eval loop
1342
1343 LTORG
1344
1345 ; --- exp__doQuery ---
1346 ;
1347 ; On entry: R7, R8, R9 == lookahead token
1348 ; R10 == pointer into tokenised buffer
1349 ; R11 == evaluation stack pointer
1350 ; R12 == anchor pointer
1351 ;
1352 ; On exit: R0-R3 corrupted
1353 ;
1354 ; Use: Reads a byte from a memory address.
1355
1356 exp__doQuery ROUT
1357
1358 BL exp__popTwoVals ;Get next two values
1359 CMP R1,#vType_lvInt ;We can cope with lvalues
1360 BEQ %50exp__doQuery ;If this is the case, be odd
1361 BL exp__chkTwoInts ;Make sure we have integers
1362 LDRB R0,[R0,R2] ;Load the byte
1363 B exp__evalRet ;Jump back into eval loop
1364
1365 50exp__doQuery CMP R3,#vType_integer ;Make sure other val is int
1366 MOVNE R0,#err_numNeeded ;If not, moan at the user
1367 BNE error_report ;That's that done then
1368 ADD R0,R0,R2 ;Calculate the address
1369 MOV R1,#vType_lvByte ;This is a byte lvalue
1370 B exp__evalRet ;Jump back into eval loop
1371
1372 LTORG
1373
1374 ; --- exp__doDollar ---
1375 ;
1376 ; On entry: R7, R8, R9 == lookahead token
1377 ; R10 == pointer into tokenised buffer
1378 ; R11 == evaluation stack pointer
1379 ; R12 == anchor pointer
1380 ;
1381 ; On exit: R0-R3 corrupted
1382 ;
1383 ; Use: Reads a word from a memory address.
1384
1385 exp__doDollar ROUT
1386
1387 BL exp__popTwoVals ;Get next two values
1388 CMP R1,#vType_lvInt ;We can cope with lvalues
1389 BEQ %50exp__doDollar ;If this is the case, be odd
1390 BL exp__chkTwoInts ;Make sure we have integers
1391
1392 ADD R2,R0,R2 ;Point to the string
1393 BL stracc_ensure ;Make sure there is room
1394 MOV R3,#0 ;Number so far
1395 00 LDRB R14,[R2],#1 ;Load a byte
1396 CMP R14,#13 ;Is this the terminator?
1397 BEQ %10exp__doDollar ;Yes -- jump ahead
1398 STRB R14,[R0],#1 ;No -- save it away
1399 ADD R3,R3,#1 ;Increment the length
1400 CMP R3,#255 ;Are we at the maximum?
1401 BLT %b00 ;No -- branch back then
1402
1403 10 ORR R0,R1,R3 ;Set up the lvalue
1404 MOV R1,#vType_string ;This is a string
1405 B exp__evalRet ;Jump back into eval loop
1406
1407 ; --- The lvalue form ---
1408
1409 50exp__doDollar CMP R3,#vType_integer ;Make sure other val is int
1410 MOVNE R0,#err_numNeeded ;If not, moan at the user
1411 BNE error_report ;That's that done then
1412 ADD R0,R0,R2 ;Calculate the address
1413 MOV R1,#vType_lvBytes ;This is a bytes lvalue
1414 B exp__evalRet ;Jump back into eval loop
1415
1416 LTORG
1417
1418 ; --- RND ---
1419
1420 exp__doRnd ROUT
1421
1422 CMP R9,#'(' ;Do we have a bracket here?
1423 MOVNE R0,#-1 ;No -- range here then
1424 BLNE exp__rng ;And generate random number
1425 ORRNE R6,R6,#eFlag__op ;Read operator next
1426 BNE exp__mainLoop ;And go back up top
1427 BL getToken ;Gobble the bracket
1428
1429 ; --- Start scanning for an RND multi-op ---
1430
1431 GETOP R0,1,exp__rndArg ;Get the operator value
1432 BL exp__pushOp ;Put that on the stack
1433
1434 GETOP R0,254,exp__bMultArg ;Get the operator value
1435 TST R6,#eFlag__commaOk ;Are we allowing commas?
1436 ORRNE R0,R0,#1<<16 ;Yes -- set the flag then
1437 BL exp__pushOp ;Put that on there
1438 BIC R6,R6,#eFlag__commaOk ;Disallow commas for a while
1439 ADD R6,R6,#1<<8 ;Increment the paren count
1440 B exp__mainLoop ;And go back up top
1441
1442 LTORG
1443
1444 ; --- RND(arg) ---
1445
1446 exp__rndArg ROUT
1447
1448 STMFD R13!,{R14} ;Save a register
1449 BL exp__popInt ;Pop off the argument
1450 CMP R0,#0 ;Is the value negative?
1451 BLT %50exp__rndArg ;Yes -- deal with that
1452 CMPNE R0,#1 ;Is it one then?
1453 BEQ %60exp__rndArg ;Yes -- be odd then
1454 BL exp__rng ;And generate random number
1455 BL exp__popVal ;Pop the value off
1456 LDMFD R13!,{PC}^ ;Return to caller
1457
1458 ; --- Store a seed ---
1459
1460 50exp__rndArg STR R0,tsc_rndSeed ;Store the new seed
1461 MOV R14,#0 ;Clear the top bit
1462 STR R14,tsc_rndSeed+4 ;Store that too
1463 LDMFD R13!,{PC}^ ;And return to caller
1464
1465 ; --- Request for FP random number ---
1466
1467 60exp__rndArg STMFD R13!,{R5} ;Save another register
1468 MOV R0,#0 ;Return zero here
1469 MOV R1,#vType_integer ;Say this is an integer
1470 LDMFD R13!,{R5,PC}^ ;And return
1471
1472 LTORG
1473
1474 ; --- exp__rng ---
1475 ;
1476 ; On entry: R0 == maximum value for random number
1477 ;
1478 ; On exit: --
1479 ;
1480 ; Use: Stacks a random number between 1 and R0.
1481
1482 exp__rng ROUT
1483
1484 STMFD R13!,{R0-R5,R14} ;Save lots of registers
1485 MOV R3,R0 ;Look after this
1486 ADR R14,tsc_rndSeed ;Find the random seed
1487 LDMIA R14,{R0,R1} ;Load that out
1488 TST R1,R1,LSR #1 ;Top bit into carry
1489 MOVS R2,R0,RRX ;33-bit rotate right
1490 ADC R1,R1,R1 ;Carry into LSB of Rb
1491 EOR R2,R2,R0,LSL #12 ;(Involved!)
1492 EOR R0,R2,R2,LSR #20 ;(Similarly involved!)
1493 STMIA R14,{R0,R1} ;Store new seed back
1494 MOV R1,R3 ;Get maximum value again
1495 BL div_unsigned ;Do the division we need
1496 ADD R0,R1,#1 ;Fit it into range
1497 MOV R1,#vType_integer ;This is an integer
1498 BL exp__pushVal ;Push it onto the stack
1499 LDMFD R13!,{R0-R5,PC}^ ;And return to caller
1500
1501 LTORG
1502
1503 ; --- Relational operators (and shifts) ---
1504 ;
1505 ; On entry: R7, R8, R9 == lookahead token
1506 ; R10 == pointer into tokenised buffer
1507 ; R11 == evaluation stack pointer
1508 ; R12 == anchor pointer
1509 ;
1510 ; On exit: R0-R3 corrupted
1511 ;
1512 ; Use: Does comparing. Or shifting. Depending.
1513
1514 exp__doLess ROUT
1515
1516 BL exp__popTwoVals ;Get two values
1517 BL ctrl_compare ;Compare them
1518 MOVLT R0,#-1 ;It's less -- that's true
1519 MOVGE R0,#0 ;It's more or equal, -- false
1520 MOV R1,#vType_integer ;We are returning an integer
1521 B exp__evalRet ;Jump back into eval loop
1522
1523 LTORG
1524
1525 exp__doMore ROUT
1526
1527 BL exp__popTwoVals ;Get two values
1528 BL ctrl_compare ;Compare them
1529 MOVGT R0,#-1 ;It's more -- that's true
1530 MOVLE R0,#0 ;It's less or equal, -- false
1531 MOV R1,#vType_integer ;We are returning an integer
1532 B exp__evalRet ;Jump back into eval loop
1533
1534 LTORG
1535
1536 exp__doLessEq ROUT
1537
1538 BL exp__popTwoVals ;Get two values
1539 BL ctrl_compare ;Compare them
1540 MOVLE R0,#-1 ;It's less or equal -- true
1541 MOVGT R0,#0 ;It's more -- that's false
1542 MOV R1,#vType_integer ;We are returning an integer
1543 B exp__evalRet ;Jump back into eval loop
1544
1545 LTORG
1546
1547 exp__doMoreEq ROUT
1548
1549 BL exp__popTwoVals ;Get two values
1550 BL ctrl_compare ;Compare them
1551 MOVGE R0,#-1 ;It's more or equal -- true
1552 MOVLT R0,#0 ;It's less -- that's false
1553 MOV R1,#vType_integer ;We are returning an integer
1554 B exp__evalRet ;Jump back into eval loop
1555
1556 LTORG
1557
1558 exp__doEqual ROUT
1559
1560 BL exp__popTwoVals ;Get two values
1561 BL ctrl_compare ;Compare them
1562 MOVEQ R0,#-1 ;If equal, return TRUE
1563 MOVNE R0,#0 ;Otherwise return FALSE
1564 MOV R1,#vType_integer ;We are returning an integer
1565 B exp__evalRet ;Jump back into eval loop
1566
1567 LTORG
1568
1569 exp__doNotEq ROUT
1570
1571 BL exp__popTwoVals ;Get two values
1572 BL ctrl_compare ;Compare them
1573 MOVNE R0,#-1 ;If nonzero, return TRUE
1574 MOVEQ R0,#0 ;Otherwise return FALSE
1575 MOV R1,#vType_integer ;We are returning an integer
1576 B exp__evalRet ;Jump back into eval loop
1577
1578 LTORG
1579
1580 exp__doLSL ROUT
1581
1582 BL exp__popTwoInts ;Get two integers
1583 MOV R0,R0,LSL R2 ;Do the shift
1584 B exp__evalRet ;Jump back into eval loop
1585
1586 LTORG
1587
1588 exp__doLSR ROUT
1589
1590 BL exp__popTwoInts ;Get two integers
1591 MOV R0,R0,LSR R2 ;Do the shift
1592 B exp__evalRet ;Jump back into eval loop
1593
1594 LTORG
1595
1596 exp__doASR ROUT
1597
1598 BL exp__popTwoInts ;Get two integers
1599 MOV R0,R0,ASR R2 ;Do the shift
1600 B exp__evalRet ;Jump back into eval loop
1601
1602 LTORG
1603
1604 ; --- exp__doUMinus ---
1605 ;
1606 ; On entry: R7, R8, R9 == lookahead token
1607 ; R10 == pointer into tokenised buffer
1608 ; R11 == evaluation stack pointer
1609 ; R12 == anchor pointer
1610 ;
1611 ; On exit: R0-R3 corrupted
1612 ;
1613 ; Use: Negates a thing.
1614
1615 exp__doUMinus ROUT
1616
1617 BL exp__popInt ;Pop a val
1618 RSB R0,R0,#0 ;Negate the thing
1619 B exp__evalRet ;Jump back into eval loop
1620
1621 LTORG
1622
1623 ; --- exp__doSubscript ---
1624 ;
1625 ; On entry: R5 == number of subscripts provided
1626 ; R6 == flags
1627 ; R7, R8, R9 == lookahead token
1628 ; R10 == pointer into tokenised buffer
1629 ; R11 == upcall block pointer
1630 ; R12 == anchor pointer
1631 ;
1632 ; On exit: R0-R3 corrupted
1633 ;
1634 ; Use: Subscripts an array of things to find just one of them.
1635
1636 exp__doSubscript ROUT
1637
1638 BL exp__popOp ;Read the array's type
1639 STMFD R13!,{R0} ;Save that away
1640 BL exp__popOp ;Now find the offset too
1641 LDMFD R13!,{R2} ;Restore the type word
1642 LDR R14,tsc_varTree ;Find the variable tree
1643 LDR R14,[R14,#0] ;Grrr...
1644 ADD R3,R0,R14 ;Find the actual array
1645
1646 ; --- Do some preliminary checking ---
1647
1648 LDR R14,[R3,#4] ;Find number of subscripts
1649 CMP R14,R5 ;Do they match up?
1650 MOVNE R0,#err_numSubs ;No -- get an error
1651 BNE error_report ;And report it
1652
1653 ; --- Now actually find the element ---
1654
1655 STMFD R13!,{R2,R7-R10} ;Save some more registers
1656 ADD R10,R3,#12 ;Point to subscripts
1657 ADD R10,R10,R5,LSL #2 ;Find topmost subscript
1658 MOV R9,R10 ;Do this again
1659 MOV R8,#0 ;Current element is 0
1660 MOV R7,R5 ;Get the number of subscripts
1661
1662 00 BL exp__popInt ;Read the next integer
1663 LDR R14,[R9,#-4]! ;And load subscript size
1664 CMP R0,R14 ;How does this compare?
1665 MOVCS R0,#err_subRange ;Out of range -- get error
1666 BCS error_report ;And report it
1667 MLA R8,R14,R8,R0 ;Accumulate subscript
1668 SUBS R7,R7,#1 ;Decrement my counter
1669 BGT %b00 ;If more to go, keep on
1670
1671 ; --- Finally get an rvalue or lvalue as required ---
1672
1673 ADD R0,R10,R8,LSL #2 ;Find the lvalue
1674 LDMFD R13!,{R1,R7-R10} ;Restore system registers
1675 LDR R14,tsc_varTree ;Find the variable tree
1676 LDR R14,[R14,#0] ;Grrr...
1677 SUB R0,R0,R14 ;Yes -- turn into offset
1678 TST R6,#eFlag__lval ;Reading an lvalue?
1679 SUBNE R1,R1,#vType_lvIntArr-vType_lvInt
1680 SUBEQ R1,R1,#vType_dimInt-vType_lvInt
1681 BLEQ ctrl_load ;No -- load rvalue then
1682 MOVEQ R0,R2 ;And shift results around
1683 MOVEQ R1,R3 ;Because of strangeness
1684 BL exp__pushVal ;Push the result
1685 B exp__mainLoop ;Go back to main loop
1686
1687 LTORG
1688
1689 ; --- exp__doParen ---
1690 ;
1691 ; On entry: R7, R8, R9 == lookahead token
1692 ; R10 == pointer into tokenised buffer
1693 ; R11 == evaluation stack pointer
1694 ; R12 == anchor pointer
1695 ;
1696 ; On exit: R0-R3 corrupted
1697 ;
1698 ; Use: Complains.
1699
1700 exp__doParen ROUT
1701
1702 MOV R0,#err_expBracket ;Get the error message
1703 B error_report ;And complain bitterly
1704
1705 LTORG
1706
1707 ; --- exp__doEndEval ---
1708 ;
1709 ; On entry: R7, R8, R9 == lookahead token
1710 ; R10 == pointer into tokenised buffer
1711 ; R11 == evaluation stack pointer
1712 ; R12 == anchor pointer
1713 ;
1714 ; On exit: R0-R3 corrupted
1715 ;
1716 ; Use: Complains.
1717
1718 exp__doEndEval ROUT
1719
1720 MOV R0,#err_erk ;Get the error message
1721 B error_report ;And complain bitterly
1722
1723 LTORG
1724
1725 ; --- exp__getString ---
1726 ;
1727 ; On entry: R0 == buffer for string
1728 ; R7, R8, R9 == lookahead token
1729 ; R10 == pointer into tokenised buffer
1730 ; R11 == evaluation stack pointer
1731 ; R12 == anchor pointer
1732 ;
1733 ; On exit: R0 == length of string
1734 ;
1735 ; Use: Reads a string argument, and copies it into tsc_misc.
1736
1737 exp__getString ROUT
1738
1739 STMFD R13!,{R1-R5,R14} ;Stack some register
1740 MOV R5,R0 ;Look after address
1741 BL exp__popStr ;Get a string
1742 LDR R1,tsc_stracc ;Get the stracc address
1743 LDR R1,[R1]
1744 ADD R1,R1,R0,LSR #8 ;Point to the string
1745 AND R2,R0,#&FF ;Get the length
1746 MOV R3,R0 ;Look after the rvalue
1747 MOV R0,R5 ;Point to a buffer
1748 BL termite_copyString ;Copy the string over
1749 MOV R0,R3 ;Put the rvalue back
1750 BL stracc_free ;Won't need it any more
1751 MOV R0,R2 ;Put the length in R0
1752 LDMFD R13!,{R1-R5,PC}^ ;Return to caller
1753
1754 LTORG
1755
1756 ;----- Pseudovariables ------------------------------------------------------
1757
1758 ; --- TIME ---
1759
1760 exp__doTime STMFD R13!,{R14}
1761 SWI OS_ReadMonotonicTime
1762 LDR R1,tsc_timeOff
1763 SUB R0,R0,R1
1764 MOV R1,#vType_integer
1765 BL exp__pushVal
1766 LDMFD R13!,{PC}^
1767
1768 ; --- TIME$ ---
1769
1770 exp__doTimeS STMFD R13!,{R14} ;Save some registers
1771
1772 ; --- First, read the system clock ---
1773
1774 SUB R13,R13,#8 ;Get a nice block
1775 MOV R0,#14 ;Read the system clock
1776 MOV R1,R13 ;Point to the block
1777 MOV R14,#3 ;Get the reason code
1778 STRB R14,[R1,#0] ;Store in block
1779 SWI OS_Word ;Read the time then
1780
1781 ; -- Now put it into stracc ---
1782
1783 BL stracc_ensure ;Make sure we have room
1784 MOV R4,R1 ;Remember the index
1785 MOV R1,R0 ;Put the address in R1
1786 MOV R0,R13 ;Point to time block
1787 MOV R2,#255 ;Size of the buffer
1788 ADR R3,exp__timeFormat ;Point to the format
1789 SWI OS_ConvertDateAndTime ;Convert the date and time
1790 ORR R0,R4,#24 ;Set up the rvalue
1791 MOV R1,#vType_string ;This is a string
1792 BL stracc_added ;Tell stracc about this
1793 ADD R13,R13,#8 ;Reclaim my stack
1794 BL exp__pushVal ;Push on my value
1795 LDMFD R13!,{PC}^ ;Return the caller
1796
1797 exp__timeFormat DCB "%W3,%DY %M3 %CE%YR.%24:%MI:%SE",0
1798
1799 ; --- FALSE ---
1800
1801 exp__doFalse MOV R0,#0
1802 MOV R1,#vType_integer
1803 B exp__pushVal
1804
1805 ; --- TRUE ---
1806
1807 exp__doTrue MOV R0,#-1
1808 MOV R1,#vType_integer
1809 B exp__pushVal
1810
1811 ;----- Functions ------------------------------------------------------------
1812
1813 ; --- EVAL ---
1814
1815 exp__doEval ROUT
1816
1817 ; --- Hack the stack ---
1818 ;
1819 ; We're called from exp__eval, which has stacked R0 and R14.
1820 ; We pop these off the stack, and stuff them onto the op
1821 ; stack instead. Yukmeister.
1822
1823 LDMFD R13!,{R0} ;Get R0 off the stack
1824 BL exp__pushOp ;Push that onto op stack
1825 LDMFD R13!,{R0} ;And R14 off too
1826 BL exp__pushOp ;Push that onto op stack
1827 MOV R0,R5 ;We need to corrupt R5
1828 BL exp__pushOp ;Push that onto op stack
1829
1830 ; --- Tokenise the string to evaluate ---
1831
1832 BL stracc_ensure ;Make space for tokenised
1833 STMFD R13!,{R0,R1} ;Save the address away
1834 BL exp__popStr ;Pop the string
1835 LDR R14,tsc_stracc ;Load stracc anchor address
1836 LDR R14,[R14,#0] ;Grrr....
1837 MOV R5,R0 ;Remember this for a while
1838 AND R1,R0,#&FF ;Get the string length
1839 ADD R0,R14,R0,LSR #8 ;Work out string address
1840 LDMFD R13!,{R2} ;Load the address out
1841 MOV R3,#0 ;Just tokenise the expression
1842 BL tokenise ;Go and do that then
1843 LDMFD R13!,{R0} ;Load the stracc rvalue
1844 ADD R0,R0,#&FF ;Say it's very long
1845 BL stracc_added ;And record that
1846
1847 ; --- Now save state on the op stack ---
1848
1849 STMFD R13!,{R2} ;Save the address again
1850 MOV R0,R5 ;Save the stracc offset
1851 BL exp__pushOp ;Stack that
1852 MOV R0,R6 ;Save the eval flags
1853 BL exp__pushOp ;Stack that
1854 LDR R0,tsc_oldAnchor ;Load the old anchor
1855 BL exp__pushOp ;Push that away too
1856 LDR R0,tsc_currAnchor ;Load current file anchor
1857 STR R0,tsc_oldAnchor ;This is now the old one
1858 LDR R0,[R0,#0] ;Load the actual pointer
1859 SUB R0,R10,R0 ;Find the file offset
1860 BL exp__pushOp ;Push that away too
1861 LDR R14,tsc_stracc ;Input is now in stracc
1862 STR R14,tsc_currAnchor ;This is the new anchor
1863 LDMFD R13!,{R10} ;Load the new address
1864 GETOP R0,255,exp__bEvalOp ;Create a pseudoop
1865 BL exp__pushOp ;Stuff that on the stack
1866 MOV R6,#0 ;Just read an expression
1867 MOV R9,#-1 ;Make getToken happy
1868 BL getToken ;Prime the first token
1869 B exp__mainLoop ;And resume the main loop
1870
1871 LTORG
1872
1873 ; --- exp__endEval ---
1874
1875 exp__endEval ROUT
1876
1877 BL exp__popOp ;Pop the file offset
1878 MOV R10,R0 ;Look after this
1879 LDR R14,tsc_oldAnchor ;Load the previous anchor
1880 STR R14,tsc_currAnchor ;This is now the current one
1881 LDR R14,[R14,#0] ;Bodge for wimpextension
1882 ADD R10,R14,R10 ;Relocate the output pointer
1883 BL exp__popOp ;And the anchor pointer
1884 STR R0,tsc_oldAnchor ;Remember this now
1885 SUB R10,R10,#1 ;Quick hack now
1886 MOV R9,#-1 ;Make getToken happy
1887 BL getToken ;Prime lookahead token
1888 BL exp__popOp ;Pop the express_read flags
1889 MOV R6,R0 ;Re-instate them
1890 BL exp__popOp ;Get the stracc offset
1891 BL stracc_free ;Free *both* the strings
1892 BL exp__popOp ;Get preserved R5 value
1893 MOV R5,R0 ;Put that back nicely
1894 BL exp__popOp ;Get stacked R14 value
1895 STMFD R13!,{R0} ;Push that back on the stack
1896 BL exp__popOp ;Get stacked R0 value
1897 STMFD R13!,{R0} ;Push that back on the stack
1898 BL exp__popVal ;Pop the result (odd)
1899 B exp__evalRet ;Now leap back into routine
1900
1901 LTORG
1902
1903 ; --- VAL ---
1904
1905 exp__doVal ROUT
1906
1907 ADR R0,tsc_misc ;Point to a buffer
1908 BL exp__getString ;Get a string
1909 ADR R1,tsc_misc ;Point to the string
1910
1911 ; --- Scan the string ---
1912 ;
1913 ; We skip spaces, and stop at the first non space.
1914 ; If that happens to be a minus sign, we remember that.
1915
1916 00 LDRB R14,[R1],#1 ;Read the character
1917 CMP R14,#0 ;Are we at the end?
1918 MOVEQ R0,#0 ;Yes -- get the rvalue
1919 BEQ %20exp__doVal ;And jump ahead a bit
1920 CMP R14,#32 ;Is this a space
1921 BEQ %b00 ;Yes -- go round for more
1922 CMP R14,#'-' ;Is it a minus sign?
1923 SUBNE R1,R1,#1 ;No -- backtrack then
1924 MOV R0,#10 ;Read as base 10 by default
1925 SWI XOS_ReadUnsigned ;Read the value
1926 RSBEQ R0,R2,#0 ;Negate if we should
1927 MOVNE R0,R2 ;Otherwise don't bother
1928 MOVVS R0,#0 ;Return 0 on an error
1929 20 MOV R1,#vType_integer ;This is an integer
1930 B exp__evalRet ;Return to eval loop
1931
1932 LTORG
1933
1934 ;----- Arithmetic routine ---------------------------------------------------
1935
1936 ; --- ABS ---
1937
1938 exp__doAbs ROUT
1939
1940 BL exp__popInt ;Get an integer
1941 CMP R0,#0 ;Is the argument <0?
1942 RSBLT R0,R0,#0 ;Yes -- negate it then
1943 B exp__evalRet ;Return to eval loop
1944
1945 LTORG
1946
1947 ; --- NOT ---
1948
1949 exp__doNot ROUT
1950
1951 BL exp__popInt ;Get an integer
1952 MVN R0,R0 ;Invert the operand
1953 B exp__evalRet ;Return to eval loop
1954
1955 LTORG
1956
1957 ; --- SGN ---
1958
1959 exp__doSgn ROUT
1960
1961 BL exp__popInt ;Get an integer
1962 CMP R0,#0 ;Compare argument with 0
1963 MOVGT R0,#1 ;If bigger return 1
1964 MOVLT R0,#-1 ;If smaller, return -1
1965 B exp__evalRet ;Return to eval loop
1966
1967 LTORG
1968
1969 ;----- String associated routines -------------------------------------------
1970
1971 ; --- ASC ---
1972
1973 exp__doAsc ROUT
1974
1975 BL exp__popStr ;Get a string
1976 BL stracc_free ;Won't need it any more
1977 MOV R1,#vType_integer ;We will return an int
1978 TST R0,#&FF ;Is this a NULL string?
1979 MOVEQ R0,#-1 ;Yes -- return -1 then
1980 BEQ exp__evalRet
1981
1982 LDR R14,tsc_stracc ;Loacte stracc
1983 LDR R14,[R14]
1984 ADD R14,R14,R0,LSR #8 ;Point to the string
1985 LDRB R0,[R14,#0] ;Load a byte
1986 B exp__evalRet ;Return this to caller
1987
1988 ; --- CHR$ ---
1989
1990 exp__doChrS ROUT
1991
1992 BL exp__popInt ;Pop an integer
1993 MOV R2,R0 ;Look after the value
1994 BL stracc_ensure ;Make sure there's space
1995 MOVS R14,R2,LSR #8 ;Check the value's OK
1996 STREQB R2,[R0,#0] ;If so, store it
1997 ORREQ R1,R1,#1 ;And set length one
1998 MOV R0,R1 ;Get the rvalue
1999 MOV R1,#vType_string ;Say it's a string
2000 BL stracc_added ;Say I've added it
2001 B exp__evalRet ;And return to eval loop
2002
2003
2004 ; --- LEN ---
2005
2006 exp__doLen ROUT
2007
2008 BL exp__popStr ;Get a string
2009 BL stracc_free ;Won't need it any more
2010 AND R0,R0,#&FF ;Get the length
2011 MOV R1,#vType_integer ;This is an integer
2012 B exp__evalRet ;Return to eval loop
2013
2014 ; --- STR$ ---
2015
2016 exp__doStrS ROUT
2017
2018 TST R2,#(1<<16) ;Is this a hex conversion?
2019 BL exp__popInt ;Pop an integer
2020 MOV R3,R0 ;Put it in R3
2021 BL stracc_ensure ;Make sure we have room
2022 MOV R4,R1 ;Look after the offset
2023 BNE %10exp__doStrS ;If hex -- jump ahead
2024
2025
2026 MOV R1,R0 ;Write result to here
2027 MOV R2,#255 ;Buffer is big
2028 MOVS R0,R3 ;Put the number in here
2029 RSBLT R0,R0,#0 ;If -ve, mak positive
2030 MOVLT R14,#'-' ;...get a minus ready
2031 STRLTB R14,[R1],#1 ;Store in the buffer
2032 SWI OS_ConvertInteger4 ;Convert to a string
2033 SUB R14,R1,R0 ;Get the string length
2034 ADDLT R14,R14,#1 ;There may be a minus
2035 ORR R0,R4,R14 ;Get the rvalue
2036 MOV R1,#vType_string ;This is a string
2037 BL stracc_added ;Tell stracc about it
2038 B exp__evalRet ;Return to eval loop
2039
2040 ; --- We need to output as hex ---
2041
2042 10exp__doStrS ADR R1,tsc_misc ;Point to a nice buffer
2043 00 AND R2,R3,#&F ;Get teh remainder
2044 MOV R3,R3,LSR #4 ;Divide number by 16
2045 ADD R14,R2,#'0' ;Turn into a digit
2046 CMP R14,#'9'+1 ;Is it too big for this?
2047 ADDCS R14,R14,#'A'-'9'-1 ;Yes -- turn into a letter
2048 STRB R14,[R1],#1 ;Save the next byte
2049 CMP R3,#0 ;Have we finished now?
2050 BNE %b00 ;Yes -- jump back then
2051
2052 ; --- Copy the digits over ---
2053 ;
2054 ; The characters are now in the buffer in reverse order
2055
2056 ADR R2,tsc_misc ;Point to the buffer
2057 SUBS R2,R1,R2 ;Get the number of chars
2058 ORR R4,R4,R2 ;Put that in the index
2059 00 LDRGTB R14,[R1,#-1]! ;Load out byte
2060 STRGTB R14,[R0],#1 ;Store that in the buffer
2061 SUBS R2,R2,#1 ;Reduce the number count
2062 BGT %b00 ;And keep on doing this
2063
2064 MOV R0,R4 ;Get the rvalue
2065 MOV R1,#vType_string ;This is a string
2066 BL stracc_added ;Tell stracc about it
2067 B exp__evalRet ;Return to eval loop
2068
2069 LTORG
2070
2071 ;----- File operations ------------------------------------------------------
2072
2073 ; --- OPENOUT ---
2074
2075 exp__doOpenout ADR R0,tsc_misc ;Point to a buffer
2076 BL exp__getString ;Get the string argument
2077
2078 MOV R0,#&81 ;The flags to open with
2079 ADR R1,tsc_misc ;Point to the name
2080 SWI XOS_Find ;Try to open the file
2081 BVS error_reportReal ;Return possible error
2082 BL exp__opened ;Remember we opened the file
2083
2084 MOV R1,#vType_integer ;We will return an int
2085 B exp__evalRet ;Return this to caller
2086
2087 LTORG
2088
2089 ; --- OPENUP ---
2090
2091 exp__doOpenup ADR R0,tsc_misc ;Point to a buffer
2092 BL exp__getString ;Get the string argument
2093
2094 MOV R0,#&C7 ;The flags to open with
2095 ADR R1,tsc_misc ;Point to the name
2096 SWI XOS_Find ;Try to open the file
2097 BVS error_reportReal ;Return possible error
2098 BL exp__opened ;Remember we opened the file
2099
2100 MOV R1,#vType_integer ;We will return an int
2101 B exp__evalRet ;Return this to caller
2102
2103 LTORG
2104
2105 ; --- OPENIN ---
2106
2107 exp__doOpenin ADR R0,tsc_misc ;Point to a buffer
2108 BL exp__getString ;Get the string argument
2109
2110 MOV R0,#&47 ;The flags to open with
2111 ADR R1,tsc_misc ;Point to the name
2112 SWI XOS_Find ;Try to open the file
2113 BVS error_reportReal ;Return possible error
2114 BL exp__opened ;Remember we opened the file
2115
2116 MOV R1,#vType_integer ;We will return an int
2117 B exp__evalRet ;Return this to caller
2118
2119 LTORG
2120
2121 ; --- exp__opened ---
2122 ;
2123 ; On entry: R0 == file handle
2124 ;
2125 ; On exit: --
2126 ;
2127 ; Use: Remembers that a file has been opened. (Bit bashing code
2128 ; courtesy of the RISC OS 3.5 Keyboard Drivers, duplicated
2129 ; without permission.)
2130
2131 exp__opened ROUT
2132
2133 STMFD R13!,{R0-R2,R14} ;Save some registers
2134 ADR R1,tsc_files ;Find file bit-array
2135 MOV R14,R0,LSR #5 ;Get word index
2136 LDR R14,[R1,R14,LSL #2]! ;Load the word I want
2137 MOV R2,#(1<<31) ;Set the top bit here
2138 ORR R14,R14,R2,ROR R0 ;Set the correct bit
2139 STR R14,[R1,#0] ;Save the word back again
2140 LDMFD R13!,{R0-R2,PC}^ ;And return to caller
2141
2142 LTORG
2143
2144 ;----- Stream operations ----------------------------------------------------
2145
2146 ; --- BGET ---
2147
2148 exp__doBget ROUT
2149
2150 BL exp__popInt ;Get an integer
2151 MOV R1,R0 ;Put it in R1
2152 SWI XOS_BGet ;Get a byte from the file
2153 BVS error_reportReal
2154 MOV R1,#vType_integer ;It's an integer Jim
2155 B exp__evalRet ;Return to eval loop
2156
2157 LTORG
2158
2159 ; --- EOF ---
2160
2161 exp__doEof ROUT
2162
2163 BL exp__popInt ;Get an integer
2164 MOV R1,R0 ;Put it in R1
2165 MOV R0,#5 ;Read EOF status
2166 SWI XOS_Args ;Read it then
2167 BVS error_reportReal
2168 MOVS R0,R2 ;Put result in R0
2169 MOVNE R0,#-1 ;Make it -1 if TRUE
2170 MOV R1,#vType_integer ;It's an integer Jim
2171 B exp__evalRet ;Return to eval loop
2172
2173 LTORG
2174
2175 ; --- EXT ---
2176
2177 exp__doExt ROUT
2178
2179 BL exp__popInt ;Get an integer
2180 MOV R1,R0 ;Put it in R1
2181 MOV R0,#2 ;Read EOF status
2182 SWI XOS_Args ;Read it then
2183 BVS error_reportReal
2184 MOV R0,R2 ;Put result in R0
2185 MOV R1,#vType_integer ;It's an integer Jim
2186 B exp__evalRet ;Return to eval loop
2187
2188 LTORG
2189
2190 ; --- GET$ ---
2191
2192 exp__doGetS ROUT
2193
2194 BL exp__popInt ;Get an integer
2195 MOV R4,R0 ;Put it in R4
2196 BL stracc_ensure ;Ensure there is enough space
2197 MOV R2,R0 ;Remember the address
2198 MOV R3,R1 ;And the offset
2199 MOV R1,R4 ;Put file handle in R1
2200 MOV R4,#0 ;The length so far
2201 00 SWI XOS_BGet ;Geta byte
2202 BVS error_reportReal ;Report possible error
2203 BCS %10exp__doGetS ;Undefined -- dropout
2204 CMP R0,#10 ;Have we reached the end?
2205 CMPNE R0,#13
2206 CMPNE R0,#0
2207 BEQ %10exp__doGetS ;Yes -- drop out
2208 STRB R0,[R2],#1 ;No -- store the byte
2209 ADD R4,R4,#1 ;And increment the count
2210 CMP R4,#255 ;Have we read the maximum?
2211 BLT %b00 ;No -- keep getting them
2212
2213 10exp__doGetS ORR R0,R3,R4 ;Get the rvalue
2214 MOV R1,#vType_string ;This is a string
2215 BL stracc_added ;Tell stracc about this
2216 B exp__evalRet ;Return to eval loop
2217
2218 ; --- PTR ---
2219
2220 exp__doPtr ROUT
2221
2222 BL exp__popInt ;Get an integer
2223 MOV R1,R0 ;Put it in R1
2224 MOV R0,#0 ;Read EOF status
2225 SWI XOS_Args ;Read it then
2226 BVS error_reportReal
2227 MOV R0,R2 ;Put result in R0
2228 MOV R1,#vType_integer ;It's an integer Jim
2229 B exp__evalRet ;Return to eval loop
2230
2231 LTORG
2232
2233 ;---- Multiple argument things ----------------------------------------------
2234
2235 ; --- exp__midString ---
2236 ;
2237 ; On entry: R1 == index into string
2238 ; R2 == number of chars needed
2239 ; String is in tsc_misc
2240 ;
2241 ; On exit: R0, R1 == value to push
2242 ;
2243 ; Use: Performs a string extraction on the string
2244
2245 exp__midString ROUT
2246
2247 STMFD R13!,{R14} ;Stack the link
2248 ADR R0,tsc_misc ;Point to the string
2249 ADD R3,R0,R1 ;Copy from here
2250 MOV R4,R2 ;Remember the length
2251 BL stracc_ensure ;Make sure we have room
2252 CMP R2,#0 ;Anything to copy?
2253 00 LDRGTB R14,[R3],#1 ;Load a byte
2254 STRGTB R14,[R0],#1 ;Store it
2255 SUBS R2,R2,#1 ;Decrement the count
2256 BGT %b00 ;Go round for more
2257 ORR R0,R1,R4 ;Get the rvalue
2258 MOV R1,#vType_string ;This is a string
2259 BL stracc_added ;Tell stracc about this
2260 LDMFD R13!,{PC}^ ;Return to caller
2261
2262 LTORG
2263
2264 ; --- LEFT$ ---
2265
2266 exp__doLeftS ROUT
2267
2268 STMFD R13!,{R2-R6,R14} ;Stack registers
2269 CMP R5,#2 ;Two of them?
2270 MOVNE R0,#err_leftSArgs ;No -- get the error number
2271 BNE error_report ;And report the error
2272
2273 BL exp__popInt ;Get the number of chars
2274 MOV R2,R0 ;Put that in R2
2275 MOV R1,#0 ;From the beginning
2276 ADR R0,tsc_misc ;Point to a buffer
2277 BL exp__getString ;Get then string
2278 CMP R2,R0 ;Are we getting too many?
2279 MOVCS R2,R0 ;Yes -- get this many
2280 BL exp__midString ;Do the mid$
2281 LDMFD R13!,{R2-R6,PC}^ ;Return to caller
2282
2283 LTORG
2284
2285 ; --- MID$ ---
2286
2287 exp__doMidS ROUT
2288
2289 STMFD R13!,{R2-R6,R14} ;Stack registers
2290 CMP R5,#2 ;Two of them?
2291 CMPNE R5,#3 ;Or maybe 3?
2292 MOVNE R0,#err_midSArgs ;No -- get the error number
2293 BNE error_report ;And report the error
2294
2295 CMP R5,#2 ;Just two args?
2296 BEQ %10exp__doMidS ;Yes -- jump ahead
2297
2298 BL exp__popTwoInts ;Get the number of chars
2299 SUBS R1,R0,#1 ;Put index in R1
2300 MOVLT R1,#0 ;Put it in range
2301 ADR R0,tsc_misc ;Point to a buffer
2302 BL exp__getString ;Get then string
2303 CMP R1,R0 ;Is the index in range?
2304 MOVGT R1,R0 ;No -- put it in range
2305 SUB R14,R0,R1 ;Get number of chars left
2306 CMP R2,R14 ;Are we getting too many?
2307 MOVCS R2,R14 ;Yes -- get this many
2308 BL exp__midString ;Do the mid$
2309 LDMFD R13!,{R2-R6,PC}^ ;Return to caller
2310
2311 ; --- Deal with 2 arg variation ---
2312
2313 10exp__doMidS BL exp__popInt ;Get the index
2314 SUB R1,R0,#1 ;Put it in R1
2315 ADR R0,tsc_misc ;Point to a buffer
2316 BL exp__getString ;Get the string
2317 CMP R1,R0 ;Are we in range?
2318 MOVCS R1,R0 ;No -- we are now
2319 SUB R2,R0,R1 ;Get the number to get
2320 BL exp__midString ;Do the mid$
2321 LDMFD R13!,{R2-R6,PC}^ ;Return to caller
2322
2323 LTORG
2324
2325 ; --- RIGHT$ ---
2326
2327 exp__doRightS ROUT
2328
2329 STMFD R13!,{R2-R6,R14} ;Stack registers
2330 CMP R5,#2 ;Two of them?
2331 MOVNE R0,#err_rightSArgs ;No -- get the error number
2332 BNE error_report ;And report the error
2333
2334 BL exp__popInt ;Get the number
2335 MOV R2,R0 ;Put it in R2
2336 ADR R0,tsc_misc ;Point to the buffer
2337 BL exp__getString ;Get the string
2338 SUBS R1,R0,R2 ;Work out the index
2339 MOVLT R1,#0 ;If getting too many, reduce
2340 MOVLT R2,R0
2341 BL exp__midString ;Do the mid$
2342 LDMFD R13!,{R2-R6,PC}^ ;Return to caller
2343
2344 LTORG
2345
2346 ; --- STRING$ ---
2347
2348 exp__doStringS ROUT
2349
2350 ; --- Make sure we have the right number of arguments ---
2351
2352 STMFD R13!,{R2-R6,R14} ;Stack registers
2353 CMP R5,#2 ;Two of them?
2354 MOVNE R0,#err_stringSArgs ;No -- get the error number
2355 BNE error_report ;And report the error
2356
2357 ADR R0,tsc_misc ;Point to a buffer
2358 BL exp__getString ;Copy the string into buffer
2359 MOV R5,R0 ;Put length in R2
2360 BL exp__popInt ;Pop an integer
2361 MOV R3,R0 ;Put number in R3
2362 MUL R6,R5,R0 ;Get the overall length
2363 CMP R6,#255 ;Is it too big?
2364 MOVGT R0,#err_strTooLong ;Yes -- get error number
2365 BGT error_report ;And report it happily
2366
2367 ; --- Now copy the string ---
2368
2369 CMP R5,#0 ;Is this a 0 length string?
2370 MOVEQ R0,#0 ;Yes -- get rvalue
2371 BEQ %10exp__doStringS ;And jump ahead
2372
2373 BL stracc_ensure ;Make sure we have room
2374 MOV R4,R1 ;Look after the offset
2375 MOV R2,R5 ;Keep copy of length
2376
2377 00 ADR R1,tsc_misc ;Point to the string
2378 05 LDRB R14,[R1],#1 ;Load a byte
2379 STRB R14,[R0],#1 ;Store it
2380 SUBS R2,R2,#1 ;Decrement the string length
2381 BGT %b05 ;And go round for more
2382 MOV R2,R5 ;Get the length back
2383 SUBS R3,R3,#1 ;Decrment other counter
2384 BGT %b00 ;And go round for more
2385
2386 ORR R0,R4,R6 ;Get the rvalue
2387 10 MOV R1,#vType_string ;This is a string
2388 BL stracc_added ;Tell stracc about it
2389 LDMFD R13!,{R2-R6,PC}^ ;Return to caller
2390
2391 LTORG
2392
2393 ; --- INSTR ---
2394
2395 exp__doInstr ROUT
2396
2397 STMFD R13!,{R5,R14} ;Stack registers
2398 CMP R5,#2 ;Two of them?
2399 CMPNE R5,#3 ;Or maybe 3?
2400 MOVNE R0,#err_instrSArgs ;No -- get the error number
2401 BNE error_report ;And report the error
2402
2403 CMP R5,#3 ;Are there 3 args?
2404 BLEQ exp__popInt ;Yes -- get it then
2405 SUBEQ R5,R0,#1 ;And reduce by 1
2406 MOVNE R5,#0 ;Otherwise use 0
2407
2408 BL exp__popTwoStrs ;Get two strings
2409 STMFD R13!,{R0,R6-R9} ;Stack nice stracc position
2410 LDR R14,tsc_stracc ;Get the stracc anchor
2411 LDR R14,[R14]
2412 AND R1,R0,#&FF ;Get a string length
2413 ADD R0,R14,R0,LSR #8 ;Point at the strings
2414 AND R3,R2,#&FF ;Do this for...
2415 ADD R2,R14,R2,LSR #8 ;...both of them
2416
2417 SUB R1,R1,R5 ;Get len of remaining string
2418 05 CMP R1,R3 ;Enough string for a match?
2419 BLT %90exp__doInstr ;No match -- jump onwards
2420 ADD R6,R0,R5 ;Look after values
2421 MOV R7,R2
2422 MOV R9,R3 ;Remember the length too
2423 00 SUBS R9,R9,#1 ;Reduce length count
2424 BLT %95exp__doInstr ;We have a match :-)
2425 LDRB R8,[R6],#1 ;Load a byte
2426 LDRB R14,[R7],#1 ;From both strings
2427 CMP R8,R14 ;Do the bytes match?
2428 BEQ %b00 ;Yes -- keep on comparing
2429 ADD R5,R5,#1 ;Increment the position
2430 SUB R1,R1,#1 ;Reduce length
2431 B %b05 ;And keep on going
2432
2433 ; --- We return failure ---
2434
2435 90 LDMFD R13!,{R0,R6-R9} ;Load back registers
2436 BL stracc_free ;Free my strings
2437 MOV R0,#0 ;No match
2438 MOV R1,#vType_integer ;Return a string please
2439 LDMFD R13!,{R5,PC}^ ;Return to caller
2440
2441 ; --- Return success then ---
2442
2443 95 LDMFD R13!,{R0,R6-R9} ;Load back registers
2444 BL stracc_free ;Free my strings
2445 ADD R0,R5,#1 ;No match
2446 MOV R1,#vType_integer ;Return a string please
2447 LDMFD R13!,{R5,PC}^ ;Return to caller
2448
2449 LTORG
2450
2451 ;----- Flags and things -----------------------------------------------------
2452
2453 eFlag__commaOk EQU (1<<0) ;We can cope with commas here
2454 eFlag__op EQU (1<<1) ;We are reading an operator
2455 eFlag__done EQU (1<<2) ;Finished reading expression
2456 eFlag__lval EQU (1<<3) ;Reading an lvalue
2457 eFlag__parseLval EQU (1<<4) ;We are parsing an lvalue
2458
2459 ;----- That's all, folks ----------------------------------------------------
2460
2461 END