chiark / gitweb /
Create readable text `.bas' for each tokenized BASIC `,ffb' file.
[ssr] / StraySrc / Libraries / Sapphire / sail / s / ctrl
1 ;
2 ; ctrl.s
3 ;
4 ; Control flow handling
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.divide
20                 GET     sh.errNum
21                 GET     sh.error
22                 GET     sh.express
23                 GET     sh.getToken
24                 GET     sh.interp
25                 GET     sh.mem
26                 GET     sh.stracc
27                 GET     sh.strBucket
28                 GET     sh.termite
29                 GET     sh.termscript
30                 GET     sh.tokens
31                 GET     sh.tree
32                 GET     sh.var
33
34 ;----- Main code ------------------------------------------------------------
35
36                 AREA    |TermScript$$Code|,CODE,READONLY
37
38 ;----- Execution stack handling ---------------------------------------------
39
40 ; --- ctrl__pushFrame ---
41 ;
42 ; On entry:     R0 == type of frame to create
43 ;
44 ; On exit:      R0 == address of frame data to fill in
45 ;
46 ; Use:          Creates a new frame of the given type on the execution stack.
47
48 ctrl__pushFrame ROUT
49
50                 STMFD   R13!,{R1-R5,R14}        ;Save some registers
51                 MOV     R3,R0                   ;Look after thing to push
52                 ADR     R14,ctrl__frSize        ;Point to frame size table
53                 LDRB    R4,[R14,R3]             ;Load the frame size
54                 ADR     R1,sail_execStack       ;Point to some stack data
55                 LDMIA   R1,{R0-R2}              ;Load it out
56
57                 ADD     R5,R1,R4                ;New used size
58                 ADD     R1,R5,#255              ;Align to next size thing
59                 BIC     R1,R1,#255              ;Finish the align
60                 CMP     R1,R2                   ;Has it got too big?
61                 BLGT    mem_realloc             ;Yes -- get more space then
62                 STRGT   R1,sail_execStkSize     ;Store new size maybe
63                 STR     R5,sail_execStkPtr      ;Store back new size
64                 LDR     R0,[R0]                 ;Point to the stack
65                 ADD     R0,R0,R5                ;Address to put next thing on
66                 STR     R3,[R0,#-4]             ;Store the new frame type
67                 SUB     R0,R0,R4                ;And return frame base addr
68                 LDMFD   R13!,{R1-R5,PC}^        ;And return to caller
69
70                 LTORG
71
72 ; --- ctrl__peekFrame ---
73 ;
74 ; On entry:     --
75 ;
76 ; On exit:      R0 == type of topmost frame
77 ;               R1 == base address of frame
78 ;
79 ; Use:          Returns the type of the topmost frame, so a routine can
80 ;               work out if it needs to be removed.
81
82 ctrl__peekFrame ROUT
83
84                 STMFD   R13!,{R14}              ;Save a register
85                 ADR     R0,sail_execStack       ;Point to stack info block
86                 LDMIA   R0,{R0,R1}              ;Load anchor addr and sp
87                 LDR     R0,[R0]                 ;WimpExt_Heap's oddness again
88                 ADD     R14,R0,R1               ;Find top of the stack
89                 LDR     R0,[R14,#-4]            ;Load the frame type
90                 ADR     R1,ctrl__frSize         ;Find the frame size table
91                 LDRB    R1,[R1,R0]              ;Load the size of this entry
92                 SUB     R1,R14,R1               ;Find base of this frame
93                 LDMFD   R13!,{PC}^              ;And return to caller
94
95                 LTORG
96
97 ; --- ctrl__popFrame ---
98 ;
99 ; On entry:     --
100 ;
101 ; On exit:      R0 == frame type
102 ;               R1 == base address of frame
103 ;
104 ; Use:          Pops the top stack frame off the execution stack.  A pointer
105 ;               to the frame's data is returned; this data is *still on
106 ;               the stack*, so be careful about pushing more on.
107
108 ctrl__popFrame  ROUT
109
110                 STMFD   R13!,{R2-R5,R14}        ;Save some registers
111                 ADR     R1,sail_execStack       ;Point to some stack data
112                 LDMIA   R1,{R0-R2}              ;Load it out
113                 LDR     R14,[R0]                ;Load the actual base address
114                 ADD     R14,R14,R1              ;Find the top of the stack
115                 LDR     R3,[R14,#-4]            ;Load type of top frame
116                 ADR     R14,ctrl__frSize        ;Point to frame size table
117                 LDRB    R5,[R14,R3]             ;And get the frame size
118
119                 SUB     R4,R1,R5                ;The new size
120                 ADD     R1,R4,#255              ;Align up again
121                 BIC     R1,R1,#255              ;Aligned down
122                 ADD     R1,R1,#256              ;At more than we need
123                 CMP     R1,R2                   ;Has this size changed?
124                 BLLT    mem_realloc             ;Yes -- reduce memory reqs.
125                 STRLT   R1,sail_execStkSize     ;Store new size maybe
126                 STR     R4,sail_execStkPtr      ;Store back new size
127                 LDR     R0,[R0]                 ;Point to the stack
128                 ADD     R1,R0,R4                ;Find the frame base address
129                 MOV     R0,R3                   ;And get the frame type
130                 LDMFD   R13!,{R2-R5,PC}^        ;And return to caller
131
132                 LTORG
133
134 ctrl__frSize    DCB     cFor__size+4
135                 DCB     cWhile__size+4
136                 DCB     cRepeat__size+4
137
138                 DCB     cGosub__size+4
139                 DCB     cLocal__size+4
140                 DCB     cReturn__size+4
141                 DCB     cProc__size+4
142                 DCB     cFn__size+4
143                 DCB     cDead__size+4
144
145 ;----- Command handlers -----------------------------------------------------
146
147 ; --- ctrl_let ---
148
149                 EXPORT  ctrl_let
150 ctrl_let        ROUT
151
152                 MOV     R0,#1                   ;Read an lvalue
153                 BL      express_read            ;Leave that on the stack
154                 CMP     R9,#'='                 ;Is this an assignment op?
155                 BNE     %10ctrl_let             ;No -- maybe more complex
156                 BL      getToken                ;Get another token
157                 MOV     R0,#0                   ;Read a general expression
158                 BL      express_read            ;Read that nicely
159
160                 BL      express_popTwo          ;Pop two values off the stack
161                 BL      ctrl_store              ;Stuff one into the other
162                 B       interp_next             ;Move on to next instruction
163
164                 ; --- Try other assignment ops then ---
165
166 10              CMP     R7,#tClass_assign       ;Is it an assign op?
167                 MOVNE   R0,#err_mistake         ;No -- that's a mistake
168                 BNE     error_report            ;So complain at someone
169
170                 ; --- Read the rvalue ---
171
172                 MOV     R6,R8                   ;Look after the index
173                 BL      getToken                ;Get another token
174                 BL      express_pop             ;Pop off the lvalue
175                 BL      ctrl_load               ;Load it's value
176                 STMFD   R13!,{R0,R1}            ;Look after the lvalue
177                 MOV     R0,#0                   ;Read a general expression
178                 BL      express_read            ;Read that nicely
179                 BL      express_pop             ;Pop the rvalue
180                 MOV     R4,R0                   ;Look after rvalue
181                 MOV     R5,R1
182                 LDMFD   R13!,{R0,R1}            ;Load the lvalue back
183
184                 ADD     PC,PC,R6,LSL #2         ;Jump to the right routine
185                 DCB     "TMA!"
186
187                 B       %20ctrl_let             ;+=
188                 B       %30ctrl_let             ;-=
189                 B       %40ctrl_let             ;*=
190                 B       %50ctrl_let             ;/=
191
192                 ; --- The operations ---
193                 ;
194                 ; Addition.
195
196 20              CMP     R3,#vType_string
197                 BEQ     %25ctrl_let
198                 CMP     R3,#vType_integer
199                 MOVNE   R0,#err_arrayBad
200                 BNE     error_report
201                 CMP     R5,#vType_integer
202                 MOVNE   R0,#err_numNeeded
203                 BNE     error_report
204                 ADD     R2,R2,R4
205                 BL      ctrl_store
206                 B       interp_next
207
208 25              CMP     R5,#vType_string        ;This is a string I hope
209                 MOVNE   R0,#err_strNeeded       ;No -- get error number
210                 BNE     error_report            ;...and report the error
211
212                 MOV     R14,R4,LSL #24          ;Get the second string len
213                 CMN     R14,R2,LSL #24          ;Is the string short enough?
214                 ADDCC   R2,R2,R14,LSR #24       ;Add on second length
215                 BLCC    ctrl_store
216                 BCC     interp_next
217
218                 MOV     R0,#err_strTooLong      ;String is too long
219                 B       error_report
220
221                 ; --- Subtraction ---
222
223 30              CMP     R3,#vType_integer
224                 CMPEQ   R5,#vType_integer
225                 MOVNE   R0,#err_numNeeded
226                 BNE     error_report
227                 SUB     R2,R2,R4
228                 BL      ctrl_store
229                 B       interp_next
230
231                 ; --- Multiplication ---
232
233 40              CMP     R3,#vType_integer
234                 CMPEQ   R5,#vType_integer
235                 MOVNE   R0,#err_numNeeded
236                 BNE     error_report
237                 MUL     R2,R4,R2
238                 BL      ctrl_store
239                 B       interp_next
240
241                 ; --- Division ---
242
243 50              CMP     R3,#vType_integer
244                 CMPEQ   R5,#vType_integer
245                 MOVNE   R0,#err_numNeeded
246                 BNE     error_report
247                 STMFD   R13!,{R0,R1}
248                 MOV     R0,R2
249                 MOV     R1,R4
250                 BL      divide
251                 MOV     R2,R0
252                 LDMFD   R13!,{R0,R1}
253                 BL      ctrl_store
254                 B       interp_next
255
256                 LTORG
257
258 ; --- ctrl_timeEq ---
259
260                 EXPORT  ctrl_timeEq
261 ctrl_timeEq     ROUT
262
263                 CMP     R9,#'='                 ;Next char must be `='
264                 MOVNE   R0,#err_expEq           ;If it isn't, moan
265                 BNE     error_report
266                 BL      getToken                ;Skip past the equals sign
267                 MOV     R0,#0                   ;Read the expression
268                 BL      express_read
269                 BL      express_pop             ;Pop the result
270                 CMP     R1,#vType_integer       ;It must be an integer
271                 BNE     ctrl__notAnInt          ;So if it isn't, complain
272                 MOV     R1,R0                   ;Look after this result
273                 SWI     OS_ReadMonotonicTime    ;Find the current real time
274                 SUB     R0,R0,R1                ;Work out the correct offset
275                 STR     R0,sail_timeOff         ;Store it away nicely
276                 B       interp_next             ;And read another instruction
277
278                 LTORG
279
280 ; --- ctrl_for ---
281
282                 EXPORT  ctrl_for
283 ctrl_for        ROUT
284
285                 MOV     R0,#1                   ;Read an lvalue
286                 BL      express_read            ;Leave that on the stack
287                 CMP     R9,#'='                 ;We now need an equals
288                 MOVNE   R0,#err_eqInFor         ;If we don't have it, moan
289                 BNE     error_report
290                 BL      getToken                ;Skip over the equals sign
291                 MOV     R0,#0                   ;Read the base value
292                 BL      express_read
293                 CMP     R9,#tok_to              ;Make sure we have a TO
294                 MOVNE   R0,#err_expTo           ;If we don't have it, moan
295                 BNE     error_report
296                 BL      getToken                ;Skip over the TO token
297                 MOV     R0,#0                   ;Read the end value
298                 BL      express_read
299                 CMP     R9,#tok_step            ;Is there a STEP?
300                 BLEQ    getToken                ;Yes -- get another token
301                 MOVEQ   R0,#0                   ;...read another rvalue
302                 BLEQ    express_read
303                 BLEQ    express_pop             ;...and get this value
304                 MOVNE   R0,#1                   ;Otherwise use sensible value
305                 MOVNE   R1,#vType_integer
306
307                 ; --- Create the stack frame ---
308
309                 STMFD   R13!,{R0,R1}            ;Save step again for a bit
310                 MOV     R0,#cFrame__for         ;Create a FOR loop frame
311                 BL      ctrl__pushFrame         ;Stick that on the stack
312                 MOV     R4,R0                   ;Look after the frame pointer
313                 LDMFD   R13!,{R0,R1}            ;Load the step value again
314                 CMP     R1,#vType_integer       ;Check it's an integer
315                 BNE     ctrl__notAnInt          ;If not, complain
316                 STR     R0,[R4,#cFor__step]     ;Save the step away
317
318                 BL      express_pop             ;Find the end marker
319                 CMP     R1,#vType_integer       ;Check it's an integer
320                 BNE     ctrl__notAnInt          ;If not, complain
321                 STR     R0,[R4,#cFor__end]      ;Stuff that in the end pos
322
323                 BL      express_popTwo          ;Get ctrl var and start pos
324                 CMP     R1,#vType_lvInt         ;Ensure lvalue is integral
325                 CMPNE   R1,#vType_lvWord
326                 CMPNE   R1,#vType_lvByte
327                 MOVNE   R0,#err_badForVar       ;If not, find suitable error
328                 BNE     error_report            ;And tell the user
329                 BL      ctrl_store              ;Initialise it nicely
330                 ADD     R14,R4,#cFor__lval      ;Find the lvalue position
331                 STMIA   R14,{R0,R1}             ;Save that away too
332
333                 ADD     R14,R4,#cFor__resume    ;Point to resume buffer
334                 LDR     R1,sail_tokAnchor       ;Find anchor of script buff
335                 SUB     R1,R10,R1               ;Work out current offset
336                 LDR     R0,sail_line            ;Get the current line number
337                 STMIA   R14,{R0,R1}             ;Save these in the frame
338
339                 B       interp_next             ;Move on to next instruction
340
341                 LTORG
342
343 ; --- ctrl_next ---
344
345                 EXPORT  ctrl_next
346 ctrl_next       ROUT
347
348                 ; --- First check for identifier ---
349                 ;
350                 ; If there is one, we need to search for a specific FOR
351                 ; frame.  Otherwise any old one will do.
352
353                 SUBS    R14,R9,#'_'             ;Is this an identifier?
354                 SUBNE   R14,R9,#'A'             ;No -- check for uppercase
355                 CMP     R14,#26
356                 SUBCS   R14,R9,#'a'             ;No -- check for lowercase
357                 CMPCS   R14,#26
358
359                 ; --- Read the lvalue given ---
360
361                 MOVCC   R0,#1                   ;Read an lvalue
362                 BLCC    express_read            ;And put it on the stack
363                 BLCC    express_pop             ;Get it in registers
364                 MOVCS   R1,#-1                  ;Otherwise get bogus value
365                 MOV     R2,R0                   ;Look after the lvalue
366                 MOV     R3,R1                   ;And the type
367 10              MOV     R0,#cFrame__for         ;Look for a FOR frame
368                 BL      ctrl__findFrame         ;Try to find the frame
369                 MOVCC   R0,#err_noFor           ;Complain if we hit routine
370                 BCC     error_report
371                 ADD     R14,R1,#cFor__lval      ;Find the lvalue
372                 LDMIA   R1,{R4,R5}              ;Load them out nicely
373                 CMP     R2,R4                   ;Now check for a match
374                 CMPEQ   R3,R5                   ;Check the type too
375                 CMPNE   R3,#-1                  ;Or maybe we don't care
376                 BLNE    ctrl__popFrame          ;No match -- discard frame
377                 BNE     %10ctrl_next            ;And loop back round
378
379                 ; --- Now step the variable ---
380
381                 MOV     R6,R1                   ;Look after frame base
382                 MOV     R0,R4                   ;Get the original lvalue back
383                 MOV     R1,R5                   ;And its type
384                 BL      ctrl_load               ;Load the current value
385                 LDR     R4,[R6,#cFor__step]     ;Load the step size
386                 ADD     R2,R2,R4                ;Bump the loop counter
387                 BL      ctrl_store              ;Save the modified counter
388                 LDR     R14,[R6,#cFor__end]     ;Find the end limit
389                 CMP     R4,#0                   ;Are we going backwards?
390                 SUBGT   R14,R2,R14              ;Yes -- subtract this way
391                 SUBLT   R14,R14,R2              ;Otherwise the other way
392                 CMP     R14,#0                  ;Now which way do we go?
393                 BGT     %50ctrl_next            ;Finished the loop -- stop
394
395                 ; --- Now resume from the FOR loop ---
396
397                 ADD     R14,R6,#cFor__resume    ;Find the resume point
398                 LDMIA   R14,{R0,R1}             ;Load the line and offset
399                 STR     R0,sail_line            ;Save the line counter
400                 LDR     R14,sail_tokAnchor      ;Find the anchor of the file
401                 ADD     R10,R14,R1              ;Get the new offset
402                 SUB     R10,R10,#1              ;Backtrack to read prev token
403                 MOV     R9,#0                   ;Give bogus current token
404                 BL      getToken                ;Read this token
405                 B       interp_next             ;And continue merrily
406
407                 ; --- Now see if there's more loops to close ---
408
409 50ctrl_next     BL      ctrl__popFrame          ;Remove defunct FOR frame
410                 CMP     R9,#','                 ;Do we have more loops?
411                 BLEQ    getToken                ;Yes -- skip the comma
412                 BEQ     ctrl_next               ;And close them too
413
414                 B       interp_next             ;Finished this instruction
415
416                 LTORG
417
418 ; --- ctrl_repeat ---
419
420                 EXPORT  ctrl_repeat
421 ctrl_repeat     ROUT
422
423                 MOV     R0,#cFrame__repeat      ;Create a REPEAT frame
424                 BL      ctrl__pushFrame         ;Stick that on the stack
425                 LDR     R2,sail_tokAnchor       ;Find anchor of script buff
426                 SUB     R2,R10,R2               ;Work out current offset
427                 LDR     R1,sail_line            ;Get the current line number
428                 STMIA   R0,{R1,R2}              ;Save these in the frame
429                 B       interp_exec             ;Get the next instruction
430
431                 LTORG
432
433 ; --- ctrl_until ---
434
435                 EXPORT  ctrl_until
436 ctrl_until      ROUT
437
438                 MOV     R0,#0                   ;Read an rvalue
439                 BL      express_read            ;Read an expression
440                 BL      express_pop             ;Read it then
441                 CMP     R1,#vType_integer       ;Is it an integer?
442                 BNE     ctrl__notAnInt          ;No -- complain then
443                 MOV     R2,R0                   ;Look after the result
444
445                 ; --- Find the REPEAT frame ---
446
447                 MOV     R0,#cFrame__repeat      ;Look for a REPEAT frame
448                 BL      ctrl__findFrame         ;Try to find the frame
449                 MOVCC   R0,#err_noRepeat        ;Complain if we hit routine
450                 BCC     error_report
451
452                 CMP     R2,#0                   ;Should we REPEAT?
453                 BLNE    ctrl__popFrame          ;No -- pop the repeat frame
454                 BNE     interp_next             ;No -- just continue then
455
456                 ; --- Go back to the REPEAT ---
457
458                 LDMIA   R1,{R0,R1}              ;Load the line and offset
459                 STR     R0,sail_line            ;Save the line counter
460                 LDR     R14,sail_tokAnchor      ;Find the anchor of the file
461                 ADD     R10,R14,R1              ;Get the new offset
462                 SUB     R10,R10,#1              ;Backtrack to read prev token
463                 MOV     R9,#-1                  ;Give bogus current token
464                 BL      getToken                ;Read this token
465                 B       interp_exec             ;And continue merrily
466
467                 LTORG
468
469 ; --- ctrl_while ---
470
471                 EXPORT  ctrl_while
472 ctrl_while      ROUT
473
474                 ; --- Push a while frame on the stack ---
475
476                 MOV     R0,#cFrame__while       ;Create a REPEAT frame
477                 BL      ctrl__pushFrame         ;Stick that on the stack
478                 LDR     R2,sail_tokAnchor       ;Find anchor of script buff
479                 SUB     R2,R10,R2               ;Work out current offset
480                 LDR     R1,sail_line            ;Get the current line number
481                 STMIA   R0,{R1,R2}              ;Save these in the frame
482
483                 ; --- Read the expression ---
484
485                 MOV     R0,#0                   ;Read an expression
486                 BL      express_read            ;Read it ithen
487                 BL      express_pop             ;Pop the resut
488                 CMP     R1,#vType_integer       ;Is it an integer?
489                 BNE     ctrl__notAnInt          ;No -- that's bad then
490                 CMP     R0,#0                   ;Is is FALSE?
491                 BNE     interp_exec             ;No -- continue then
492
493                 ; --- Scan for the first ENDWHILE then ---
494
495                 MOV     R2,#0                   ;Keep a nesting count
496                 LDR     R4,sail_line            ;Get current line number
497 10ctrl_while    BL      getToken                ;Get another token
498                 CMP     R9,#&FF                 ;Reached the end yet?
499                 BEQ     %90ctrl_while           ;If so, moan about ENDWHILE
500                 CMP     R9,#tok_while           ;Is it a WHILE token?
501                 ADDEQ   R2,R2,#1                ;Yes -- bump nesting count
502
503                 CMP     R9,#tok_endwhile        ;Yes -- check for ENDWHILE
504                 SUBEQ   R2,R2,#1                ;Yes -- decrement nesting
505                 CMP     R2,#0                   ;Have we dropped out?
506                 BGE     %10ctrl_while           ;No -- loop
507
508                 ; --- We found the ENDWHILE ---
509
510                 BL      getToken                ;Get the next token
511                 BL      ctrl__popFrame          ;Get rid of my WHILE frame
512                 B       interp_next             ;And execute from here
513
514                 ; --- We fell off the end -- oops ---
515
516 90ctrl_while    STR     R4,sail_line            ;Save bogus line back
517                 MOV     R0,#err_expEndwhile     ;Hmm... should have had an...
518                 B       error_report            ;ENDWHILE somewhere
519
520                 LTORG
521
522 ; --- ctrl_endwhile ---
523
524                 EXPORT  ctrl_endwhile
525 ctrl_endwhile   ROUT
526
527                 ; --- Find the ENDWHILE frame ---
528
529                 MOV     R0,#cFrame__while       ;Look for a REPEAT frame
530                 BL      ctrl__findFrame         ;Try to find the frame
531                 MOVCC   R0,#err_noWhile         ;Complain if we hit routine
532                 BCC     error_report
533
534                 ; --- Remember where we are ---
535
536                 LDR     R2,sail_line            ;Get the line number
537                 MOV     R3,R10                  ;And our position
538
539                 ; --- Go back to the WHILE ---
540
541                 LDMIA   R1,{R0,R1}              ;Load the line and offset
542                 STR     R0,sail_line            ;Save the line counter
543                 LDR     R14,sail_tokAnchor      ;Find the anchor of the file
544                 ADD     R10,R14,R1              ;Get the new offset
545                 SUB     R10,R10,#1              ;Backtrack to read prev token
546                 MOV     R9,#-1                  ;Give bogus current token
547                 BL      getToken                ;Read this token
548
549                 ; --- Now read the expression ---
550
551                 MOV     R0,#0                   ;Read an rvalue
552                 BL      express_read            ;Read it then
553                 BL      express_pop             ;Get the value
554                 CMP     R0,#0                   ;Should we go from here?
555                 BNE     interp_exec             ;Yes -- execute then
556
557                 ; --- Execute from the ENDWHILE ---
558
559                 BL      ctrl__popFrame          ;Pop the WHILE frame
560                 SUB     R10,R3,#1               ;Set R10 up
561                 STR     R2,sail_line            ;Store the line number
562                 MOV     R9,#-1                  ;Make getToken happy
563                 BL      getToken                ;Get a token then
564                 B       interp_next             ;And execute happily
565
566                 LTORG
567
568 ; --- ctrl__readLabel ---
569 ;
570 ; On entry:     --
571 ;
572 ; On exit:      CS if there was a label and,
573 ;                 R0 == pointer to the label node
574 ;                 R1, R2 corrupted
575 ;               CC otherwise
576 ;
577 ; Use:          Reads a label fromthe current position, and looks it
578 ;               up inthe symbol table.
579
580 ctrl__readLabel ROUT
581
582                 STMFD   R13!,{R14}              ;Stack the link
583
584                 ADR     R2,sail_misc            ;Point to a nice buffer
585                 SUBS    R14,R9,#'_'             ;Is it a valid characer?
586                 SUBNE   R14,R9,#'A'
587                 CMP     R14,#26
588                 SUBCS   R14,R9,#'a'
589                 CMPCS   R14,#26
590                 SUBCS   R14,R9,#'0'
591                 CMPCS   R14,#10
592                 BCS     %90ctrl__readLabel      ;No -- bark then
593                 STRB    R9,[R2],#1              ;And store in the buffer
594
595 10              BL      getToken                ;Get the next character
596                 SUBS    R14,R9,#'_'             ;Is it a valid characer?
597                 SUBNE   R14,R9,#'A'
598                 CMP     R14,#26
599                 SUBCS   R14,R9,#'a'
600                 CMPCS   R14,#26
601                 SUBCS   R14,R9,#'0'
602                 CMPCS   R14,#10
603                 STRCCB  R9,[R2],#1              ;Yes -- store in the buffer
604                 BCC     %10ctrl__readLabel      ;...and keep on looping
605
606                 MOV     R14,#0
607                 STRB    R14,[R2],#1
608
609                 ; --- Now find the node ---
610
611                 MOV     R0,#vType_label         ;This is a label
612                 ADR     R1,sail_misc            ;Point at the name
613                 BL      tree_find               ;Try to find it
614                 MOVCC   R0,#err_noLabel         ;Not there -- complain
615                 BCC     error_report
616
617                 LDMFD   R13!,{R14}              ;Load the link back
618                 ORRS    PC,R14,#C_flag          ;Return 'label here'
619
620                 ; --- The label was bad --
621
622 90              LDMFD   R13!,{R14}              ;Load the link back
623                 BICS    PC,R14,#C_flag          ;Return 'no label'
624
625                 LTORG
626
627 ; --- ctrl_gosub ---
628
629                 EXPORT  ctrl_gosub
630 ctrl_gosub      ROUT
631
632                 ; --- Read the label ---
633
634                 BL      ctrl__readLabel         ;Read a label
635                 BCC     %90ctrl_gosub           ;No there -- barf
636                 MOV     R3,R0                   ;Look after node address
637
638                 ; --- Push a GOSUB frame ---
639
640                 MOV     R0,#cFrame__gosub       ;Create a REPEAT frame
641                 BL      ctrl__pushFrame         ;Stick that on the stack
642                 LDR     R2,sail_tokAnchor       ;Find anchor of script buff
643                 SUB     R2,R10,R2               ;Work out current offset
644                 LDR     R1,sail_line            ;Get the current line number
645                 STMIA   R0,{R1,R2}              ;Save these in the frame
646
647                 ; --- Branch off somewhere ---
648
649                 LDMIB   R3,{R0,R1}              ;Load out address/line
650                 STR     R1,sail_line            ;Store the line number
651                 LDR     R1,sail_tokAnchor       ;Load anchor address
652                 MOV     R9,#-1                  ;Don't confuse getToken
653                 ADD     R10,R0,R1               ;This is where we are
654                 BL      getToken                ;Prime the lookahead token
655                 LDR     R14,sail_flags          ;Load the flags word
656                 BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
657                 STR     R14,sail_flags          ;Store the flasg back
658                 B       interp_exec             ;Execute from here!
659
660 90ctrl_gosub    MOV     R0,#err_expLabel        ;Get the error number
661                 B       error_report            ;Report the error
662
663                 LTORG
664
665 ; --- ctrl_return ---
666
667                 EXPORT  ctrl_return
668 ctrl_return     ROUT
669
670                 MOV     R0,#cFrame__gosub       ;Look for a GOSUB frame
671                 BL      ctrl__findFrame         ;Try to find the frame
672                 MOVCC   R0,#err_notInSub        ;Complain if not a GOSUB
673                 BCC     error_report
674                 BL      ctrl__popFrame          ;Pop off the frame
675                 LDMIA   R1,{R0,R1}              ;Load the line and offset
676                 STR     R0,sail_line            ;Save the line counter
677                 LDR     R14,sail_tokAnchor      ;Find the anchor of the file
678                 ADD     R10,R14,R1              ;Get the new offset
679                 SUB     R10,R10,#1              ;Backtrac a little
680                 MOV     R9,#-1                  ;Give bogus current token
681                 BL      getToken                ;Read this token
682                 B       interp_next             ;And continue merrily
683
684 ; --- ctrl_if ---
685
686                 EXPORT  ctrl_if
687 ctrl_if         ROUT
688
689                 LDR     R14,sail_flags          ;Load the flags word
690                 BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
691                 STR     R14,sail_flags          ;Store the flasg back
692
693                 MOV     R0,#0                   ;Read an rvalue
694                 BL      express_read
695                 BL      express_pop             ;Get that value
696                 CMP     R1,#vType_integer       ;It must be an integer
697                 MOVNE   R0,#err_numNeeded       ;Isn't -- get error
698                 BNE     error_report            ;And report the error
699                 CMP     R0,#0                   ;Should we execute this?
700                 BEQ     %10ctrl_if              ;No -- look for the else
701
702                 CMP     R9,#tok_then            ;Is there a THEN here?
703                 BLEQ    getToken                ;Yes -- skip over it then
704                 B       interp_exec             ;And just execute from here
705
706                 ; --- Look for an ELSE statement ---
707
708 10ctrl_if       CMP     R9,#tok_then            ;Do we have a THEN then?
709                 BNE     %30ctrl_if              ;No -- search line for else
710
711                 BL      getToken                ;Get another token
712                 CMP     R9,#&0a                 ;Is this a return?
713                 BNE     %30ctrl_if              ;No -- search line then
714
715                 ; --- Now look for ELSE ... ENDIF structure ---
716
717                 MOV     R3,#0                   ;My counter thing
718                 LDR     R4,sail_line            ;Get the current line
719
720 20ctrl_if       MOV     R2,R9                   ;Remmber the previous char
721                 BL      getToken                ;Skip over the return
722                 CMP     R9,#&FF                 ;Is this the end of file?
723                 BEQ     %50ctrl_if              ;Yes -- jump ahead
724                 CMP     R2,#&0a                 ;Was prev a newline?
725                 CMPNE   R9,#&0a                 ;Or even this one?
726                 BNE     %20ctrl_if              ;Neither -- keep looping
727
728                 CMP     R2,#tok_then            ;Did we just read a then
729                 ADDEQ   R3,R3,#1                ;Yes -- increment the count
730                 BEQ     %20ctrl_if              ;And keep on looping
731
732                 CMP     R9,#tok_else            ;Or an else?
733                 CMPEQ   R3,#0                   ;Yes -- at bottom level?
734                 CMPNE   R9,#tok_endif           ;Is this an endif?
735                 SUBEQ   R3,R3,#1                ;Yes -- decrement the count
736                 CMP     R3,#0                   ;Are we ready to execute?
737                 BGE     %20ctrl_if              ;No -- loop then
738
739                 BL      getToken                ;Get the next token
740                 B       interp_next             ;Execute from here!
741
742                 ; --- Search on the same line ---
743
744 30ctrl_if       MOV     R0,R9                   ;Look after this char
745                 CMP     R9,#&FF                 ;At end of file?
746                 BLNE    getToken                ;No -- read next token
747                 CMPNE   R0,#tok_else            ;Stop at ELSE tokens
748                 CMPNE   R0,#&0a                 ;And at line end
749                 BNE     %30ctrl_if              ;If not, loop back again
750                 B       interp_exec             ;And carry on going
751
752                 ; -- Missing ENDIF ---
753
754 50ctrl_if       STR     R4,sail_line            ;Store original line number
755                 MOV     R0,#err_expEndif        ;Get the error number
756                 B       error_report            ;And report the error
757
758                 LTORG
759
760 ; --- ctrl_else ---
761
762                 EXPORT  ctrl_else
763 ctrl_else       ROUT
764
765                 LDR     R0,sail_flags           ;Load the flags word
766                 TST     R0,#tscFlag_nl          ;Have we just had a newline?
767                 BNE     %20ctrl_else            ;Yes -- look for an ENDIF
768
769                 ; --- Search for the line end ---
770
771 10ctrl_else     MOV     R0,R9                   ;Look after old token
772                 CMP     R9,#&FF                 ;Is this the EOF
773                 BLNE    getToken                ;No - get a token
774                 CMP     R0,#&0a                 ;Was it the line end?
775                 BNE     %10ctrl_else            ;No -- keep on looking
776                 B       interp_next             ;Execute from here
777
778                 ; --- Look for an ENDIF ---
779
780 20ctrl_else     MOV     R3,#0                   ;My counter thing
781                 LDR     R4,sail_line            ;Get the current line
782                 MOV     R2,#0                   ;Dummy previous char
783                 B       %45ctrl_else
784
785 40ctrl_else     MOV     R2,R9                   ;Remember the previous token
786                 BL      getToken                ;Get a new one
787 45ctrl_else     CMP     R9,#&FF                 ;Is this the end of file?
788                 BEQ     %50ctrl_else            ;Yes -- jump ahead
789                 CMP     R2,#&0a                 ;Was prev a newline?
790                 CMPNE   R9,#&0a                 ;Or even this one?
791                 BNE     %40ctrl_else            ;Neither -- keep looping
792
793                 CMP     R2,#tok_then            ;Did we just read a then
794                 ADDEQ   R3,R3,#1                ;Yes -- increment the count
795                 BEQ     %40ctrl_else            ;And keep on looping
796
797                 CMP     R9,#tok_endif           ;Is this an endif?
798                 SUBEQ   R3,R3,#1                ;Yes -- decrement the count
799                 CMP     R3,#0                   ;Are we ready to execute?
800                 BGE     %40ctrl_else            ;No -- loop then
801
802                 BL      getToken                ;Get the next token
803                 B       interp_next             ;Execute from here!
804
805                 ; -- Missing ENDIF ---
806
807 50ctrl_else     STR     R4,sail_line            ;Store original line number
808                 MOV     R0,#err_expEndif        ;Get the error number
809                 B       error_report            ;And report the error
810
811                 LTORG
812
813 ; --- ctrl_goto ---
814
815                 EXPORT  ctrl_goto
816 ctrl_goto       ROUT
817
818                 BL      ctrl__readLabel         ;Read the label
819                 BCC     %90ctrl_goto            ;Not there -- barf
820
821                 LDMIB   R0,{R0,R1}              ;Load out address/line
822                 STR     R1,sail_line            ;Store the line number
823                 LDR     R1,sail_tokAnchor       ;Load anchor address
824                 MOV     R9,#-1                  ;Don't confuse getToken
825                 ADD     R10,R0,R1               ;This is where we are
826                 BL      getToken                ;Prime the lookahead token
827                 LDR     R14,sail_flags          ;Load the flags word
828                 BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
829                 STR     R14,sail_flags          ;Store the flasg back
830                 B       interp_exec             ;Execute from here!
831
832 90ctrl_goto     MOV     R0,#err_expLabel        ;Get the error number
833                 B       error_report            ;Report the error
834
835                 LTORG
836
837 ; --- ctrl_case ---
838
839                 EXPORT  ctrl_case
840 ctrl_case       ROUT
841
842                 MOV     R0,#0                   ;Read the comparand
843                 BL      express_read
844                 BL      express_pop             ;Read the value of that
845                 CMP     R1,#vType_integer       ;Is it an integer?
846                 CMPNE   R1,#vType_string        ;Or a string?
847                 MOVNE   R0,#err_arrayBad        ;No -- then point to error
848                 BNE     error_report            ;And report the error
849                 MOV     R2,R0                   ;Look after compare value
850                 MOV     R3,R1                   ;And the type too, please
851
852                 CMP     R9,#tok_of              ;We pointlessly expect `OF'
853                 MOVNE   R0,#err_expOf           ;If not there, complain
854                 BNE     error_report
855                 BL      getToken                ;Get the next token
856                 CMP     R9,#&0A                 ;This must be the line end
857                 MOVNE   R0,#err_afterCase       ;If not, complain annoyingly
858                 BNE     error_report
859
860                 ; --- Now keep an eye out for WHENs and OTHERWISEs ---
861
862                 MOV     R5,#0                   ;Keep a nesting count
863                 LDR     R6,sail_line            ;Get current line number
864 10ctrl_case     MOV     R4,R9                   ;Look after previous char
865                 BL      getToken                ;Get another token
866                 CMP     R9,#&FF                 ;Reached the end yet?
867                 BEQ     %90ctrl_case            ;If so, moan about ENDCASE
868                 CMP     R9,#tok_case            ;Is it a CASE token?
869                 ADDEQ   R5,R5,#1                ;Yes -- bump nesting count
870                 CMP     R4,#&0A                 ;Was previous newline?
871                 BNE     %10ctrl_case            ;No -- nothing doing here
872
873                 CMP     R5,#0                   ;At bottom nesting level?
874                 CMPEQ   R9,#tok_otherwise       ;Yes -- check for OTHERWISE
875                 CMPNE   R9,#tok_endcase         ;Or maybe an ENDCASE?
876                 SUBEQ   R5,R5,#1                ;Yes -- decrement nesting
877                 CMP     R5,#0                   ;Have we dropped out?
878                 BLLT    getToken                ;Yes -- get the next token
879                 BLT     %80ctrl_case            ;Yes -- start executing
880                 CMPEQ   R9,#tok_when            ;Now check for a W
881                 BNE     %10ctrl_case            ;No -- loop
882                 BL      getToken                ;Get another token
883
884                 ; --- Found a WHEN -- check for a match ---
885
886 11ctrl_case     MOV     R0,#0                   ;Read an rvalue
887                 BL      express_read
888                 BL      express_pop             ;Get result from the stack
889                 BL      ctrl_compare            ;Compare the values
890                 BEQ     %15ctrl_case            ;Match -- skip other exprs
891                 CMP     R1,#vType_string        ;Did we load a string?
892                 BLEQ    stracc_free             ;Yes -- reomve the string
893                 CMP     R9,#','                 ;Comma next?
894                 BLEQ    getToken                ;Yes -- skip it
895                 BEQ     %11ctrl_case            ;And try next expression
896                 B       %10ctrl_case            ;Otherwise hope we get lucky
897
898                 ; --- Skip other expressions ---
899                 ;
900                 ; BASIC allows extreme bogosity here, and so shall we.
901
902 15ctrl_case     CMP     R1,#vType_string        ;Did we load a string?
903                 BLEQ    stracc_free             ;Yes -- reomve the string
904 00              CMP     R5,#0                   ;Are we quoted?
905                 CMPEQ   R9,#':'                 ;No -- check for colon
906                 CMPNE   R9,#&0A                 ;Newline?
907                 BEQ     %80ctrl_case            ;Yes -- let it rip
908                 CMP     R9,#'""'                ;Is this a quote?
909                 EOREQ   R5,R5,#1                ;Yes -- toggle quoted bit
910                 BL      getToken                ;Get another token
911                 B       %b00                    ;And keep going
912
913                 ; --- Return to interp_next, removing str from stracc ---
914
915 80ctrl_case     CMP     R3,#vType_string        ;Were we dealing with a str?
916                 MOVEQ   R0,R2                   ;Yes -- put it in R0
917                 BLEQ    stracc_free             ;...and remove it from stracc
918                 B       interp_next             ;Keep on interpreting
919
920                 ; --- We fell off the end -- oops ---
921
922 90ctrl_case     STR     R6,sail_line            ;Save bogus line back
923                 MOV     R0,#err_expEndcase      ;Hmm... should have had an...
924                 B       error_report            ;ENDCASE somewhere
925
926                 LTORG
927
928 ; --- ctrl_when ---
929
930                 EXPORT  ctrl_when
931
932 ; --- ctrl_otherwise ---
933
934                 EXPORT  ctrl_otherwise
935
936 ctrl_when       ROUT
937 ctrl_otherwise
938
939                 MOV     R3,#0                   ;My counter thing
940                 LDR     R4,sail_line            ;Get the current line
941                 MOV     R2,#0                   ;Dummy previous char
942                 B       %45ctrl_when
943
944 40ctrl_when     MOV     R2,R9                   ;Remember the previous token
945                 BL      getToken                ;Get a new one
946 45ctrl_when     CMP     R9,#&FF                 ;Is this the end of file?
947                 BEQ     %50ctrl_when            ;Yes -- jump ahead
948                 CMP     R9,#tok_case            ;Did we just read a CASE
949                 ADDEQ   R3,R3,#1                ;Yes -- increment the count
950                 BEQ     %40ctrl_when            ;And keep on looping
951                 CMP     R2,#&0a                 ;Was prev a newline?
952                 CMPEQ   R9,#tok_endcase         ;Is this an endcase?
953                 SUBEQ   R3,R3,#1                ;Yes -- decrement the count
954                 CMP     R3,#0                   ;Are we ready to execute?
955                 BGE     %40ctrl_when            ;No -- loop then
956
957                 BL      getToken                ;Get the next token
958                 B       interp_next             ;Execute from here!
959
960                 ; -- Missing ENDCASE ---
961
962 50ctrl_when     STR     R4,sail_line            ;Store original line number
963                 MOV     R0,#err_expEndcase      ;Get the error number
964                 B       error_report            ;And report the error
965
966                 LTORG
967
968 ; --- ctrl_end ---
969
970                 EXPORT  ctrl_end
971 ctrl_end        ROUT
972
973                 MOV     R0,#0
974                 B       sail_end
975
976                 LTORG
977
978 ; --- ctrl_swap ---
979
980                 EXPORT  ctrl_swap
981 ctrl_swap       ROUT
982
983                 MOV     R0,#1                   ;Read an lvalue
984                 BL      express_read
985                 CMP     R9,#','                 ;Do we have a comma?
986                 MOVNE   R0,#err_expComma        ;No -- get the error number
987                 BNE     error_report            ;And report the error
988                 BL      getToken                ;Skip over the comma
989                 MOV     R0,#1                   ;Read another lvalue
990                 BL      express_read
991                 BL      express_popTwo          ;Pop off the two lvalues
992
993                 ; --- Swap the contents of the lvalues ---
994
995 10ctrl_swap     MOV     R4,R2                   ;Look after parm 2
996                 MOV     R5,R3
997                 BL      ctrl_load               ;Load the parameter
998                 STMFD   R13!,{R2,R3}            ;Store rvalue
999                 STMFD   R13!,{R0,R1}            ;And lvalue
1000                 MOV     R0,R4                   ;Get the second one
1001                 MOV     R1,R5
1002                 BL      ctrl_load               ;Load it's value too
1003                 LDMFD   R13!,{R0,R1}            ;Get back lvalue
1004                 BL      ctrl_store              ;Store rvalue in lvalue
1005                 MOV     R0,R4                   ;Get the second one
1006                 MOV     R1,R5
1007                 LDMFD   R13!,{R2,R3}            ;Load rvalue
1008                 BL      ctrl_store              ;Complete the swap
1009                 B       interp_next             ;All over and happy
1010
1011                 LTORG
1012
1013 ; --- ctrl_ptr ---
1014
1015                 EXPORT  ctrl_ptr
1016 ctrl_ptr        ROUT
1017
1018                 MOV     R0,#2                   ;Read an rvalue ident
1019                 BL      express_read            ;Read it then
1020                 BL      express_pop             ;And get it off the stack
1021                 CMP     R1,#vType_integer       ;Is this a string?
1022                 BNE     ctrl__notAnInt          ;So if it isn't, complain
1023                 MOV     R3,R0                   ;Remember file handle
1024
1025                 CMP     R9,#'='                 ;Next char must be `='
1026                 MOVNE   R0,#err_expEq           ;If it isn't, moan
1027                 BNE     error_report
1028                 BL      getToken                ;Skip past the equals sign
1029                 MOV     R0,#0                   ;Read the expression
1030                 BL      express_read
1031                 BL      express_pop             ;Pop the result
1032                 CMP     R1,#vType_integer       ;It must be an integer
1033                 BNE     ctrl__notAnInt          ;So if it isn't, complain
1034
1035                 MOV     R2,R0                   ;Put pointer in R2
1036                 MOV     R1,R3                   ;And handle in R1
1037                 MOV     R0,#1                   ;Write pointer
1038                 SWI     XOS_Args                ;Write the pointer
1039                 BVS     sail_error              ;Report possible error
1040
1041                 B       interp_next             ;And read another instruction
1042
1043                 LTORG
1044
1045 ; --- ctrl_ext ---
1046
1047                 EXPORT  ctrl_ext
1048 ctrl_ext        ROUT
1049
1050                 MOV     R0,#2                   ;Read an rvalue ident
1051                 BL      express_read            ;Read it then
1052                 BL      express_pop             ;And get it off the stack
1053                 CMP     R1,#vType_integer       ;Is this a string?
1054                 BNE     ctrl__notAnInt          ;So if it isn't, complain
1055                 MOV     R3,R0                   ;Remember file handle
1056
1057                 CMP     R9,#'='                 ;Next char must be `='
1058                 MOVNE   R0,#err_expEq           ;If it isn't, moan
1059                 BNE     error_report
1060                 BL      getToken                ;Skip past the equals sign
1061                 MOV     R0,#0                   ;Read the expression
1062                 BL      express_read
1063                 BL      express_pop             ;Pop the result
1064                 CMP     R1,#vType_integer       ;It must be an integer
1065                 BNE     ctrl__notAnInt          ;So if it isn't, complain
1066
1067                 MOV     R2,R0                   ;Put extent in R2
1068                 MOV     R1,R3                   ;And handle in R1
1069                 MOV     R0,#3                   ;Write pointer
1070                 SWI     XOS_Args                ;Write the extent
1071                 BVS     sail_error              ;Report possible error
1072
1073                 B       interp_next             ;And read another instruction
1074
1075                 LTORG
1076
1077 ; --- ctrl_close ---
1078
1079                 EXPORT  ctrl_close
1080 ctrl_close      ROUT
1081
1082                 MOV     R0,#2                   ;Read an rvalue ident
1083                 BL      express_read            ;Read it then
1084                 BL      express_pop             ;And get it off the stack
1085                 CMP     R1,#vType_integer       ;Is this a string?
1086                 BNE     ctrl__notAnInt          ;So if it isn't, complain
1087                 MOV     R1,R0                   ;Remember file handle
1088                 MOV     R0,#0                   ;Close file
1089                 SWI     XOS_Find                ;Close it then
1090                 BVS     interp_next             ;And read another instr
1091
1092                 AND     R0,R0,#&FF              ;Make sure this is a byte
1093                 ADR     R1,sail_files           ;Find file bit-array
1094                 MOV     R14,R0,LSR #5           ;Get word index
1095                 LDR     R14,[R1,R14,LSL #2]!    ;Load the word I want
1096                 MOV     R2,#(1<<31)             ;Set the top bit here
1097                 BIC     R14,R14,R2,ROR R0       ;Clear the correct bit
1098                 STR     R14,[R1,#0]             ;Save the word back again
1099                 B       interp_next             ;And read another instr
1100
1101                 LTORG
1102
1103 ; --- ctrl_bput ---
1104
1105                 EXPORT  ctrl_bput
1106 ctrl_bput       ROUT
1107
1108                 ; --- First, make sure we have a hash ---
1109
1110                 CMP     R9,#'#'                 ;We must have a hash
1111                 MOVNE   R0,#err_expHash         ;No -- complain then
1112                 BNE     error_report            ;And report an error
1113                 BL      getToken                ;Get the next token
1114
1115                 ; --- Now read the channel number ---
1116
1117                 MOV     R0,#2                   ;Read an rvalue ident
1118                 BL      express_read            ;Read it then
1119                 BL      express_pop             ;And get it off the stack
1120                 CMP     R1,#vType_integer       ;Is this a string?
1121                 BNE     ctrl__notAnInt          ;So if it isn't, complain
1122                 MOV     R3,R0                   ;Remember file handle
1123
1124                 ; --- Skip over the comma ---
1125
1126                 CMP     R9,#','                 ;Next char must be `,'
1127                 MOVNE   R0,#err_expComma        ;If it isn't, moan
1128                 BNE     error_report
1129                 BL      getToken                ;Skip past the comma
1130
1131                 ; --- Now we read an expression ---
1132
1133                 MOV     R0,#0                   ;Read the expression
1134                 BL      express_read
1135                 BL      express_pop             ;Pop the result
1136                 CMP     R1,#vType_integer       ;Is it an integer?
1137                 BEQ     %10ctrl_bput            ;Yes -- jump ahead
1138                 CMP     R1,#vType_string        ;Make sure it is a string
1139                 MOVNE   R0,#err_arrayBad        ;Nope -- get error message
1140                 BNE     error_report            ;So if it isn't, complain
1141
1142                 ; --- Write a string to the file ---
1143
1144                 MOV     R5,R0                   ;Look after the value
1145                 LDR     R1,sail_stracc          ;Get the stracc address
1146                 LDR     R1,[R1]
1147                 ADD     R4,R1,R0,LSR #8         ;Point to the string
1148                 AND     R2,R0,#&FF              ;Get the length
1149
1150                 MOV     R1,R3                   ;Get the file handle
1151                 CMP     R2,#0                   ;Is this a short string?
1152 00              LDRGTB  R0,[R4],#1              ;Load a character
1153                 SWIGT   XOS_BPut                ;Put the byte
1154                 BVS     error_reportReal        ;Report possible error
1155                 SUBS    R2,R2,#1                ;Reduce the count
1156                 BGT     %b00                    ;And keep on goin'
1157
1158                 MOV     R0,R5                   ;Put the string in R0
1159                 BL      stracc_free             ;Free it from stracc
1160
1161                 CMP     R9,#';'                 ;Is there a semicolon now?
1162                 BLEQ    getToken                ;Yes -- get a token
1163                 MOVNE   R0,#10                  ;Get a terminator
1164                 SWINE   XOS_BPut                ;Put the byte
1165                 B       interp_next             ;And read another instruction
1166
1167                 ; --- Just write a character ---
1168
1169 10              MOV     R1,R3                   ;Get the file handle
1170                 SWI     XOS_BPut                ;Put the byte
1171                 BVS     error_reportReal        ;Report possible error
1172                 B       interp_next             ;And read another instruction
1173
1174                 LTORG
1175
1176 ;----- Odds and sods --------------------------------------------------------
1177
1178 ; --- ctrl_error ---
1179
1180                 EXPORT  ctrl_error
1181 ctrl_error      ROUT
1182
1183                 ; --- Read a parameter ---
1184
1185                 MOV     R0,#0                   ;Read an rvalue
1186                 BL      express_read            ;Read it then
1187                 BL      express_pop             ;And get it off the stack
1188                 CMP     R1,#vType_string        ;Is this a string?
1189                 MOVNE   R0,#err_strNeeded       ;Nope -- get error number
1190                 BNE     error_report            ;...and report the error
1191
1192                 LDR     R1,sail_stracc          ;Get the stracc address
1193                 LDR     R1,[R1]
1194                 ADD     R1,R1,R0,LSR #8         ;Point to the string
1195                 AND     R2,R0,#&FF              ;Get the length
1196
1197                 MOV     R5,R0                   ;look after the rvalue
1198                 ADR     R0,sail_misc            ;Point to the misc buffer
1199                 MOV     R14,#1                  ;A sillu error number
1200                 STR     R14,[R0],#4             ;Store that
1201                 BL      ctrl_copyString         ;Copy the string over
1202                 ADR     R0,sail_misc            ;Point to the misc buffer
1203                 B       sail_error              ;Return the error
1204
1205                 LTORG
1206
1207 ; --- ctrl_oscli ---
1208
1209                 EXPORT  ctrl_oscli
1210 ctrl_oscli      ROUT
1211
1212                 ; --- Read a parameter ---
1213
1214                 MOV     R0,#0                   ;Read an rvalue
1215                 BL      express_read            ;Read it then
1216                 BL      express_pop             ;And get it off the stack
1217                 CMP     R1,#vType_string        ;Is this a string?
1218                 MOVNE   R0,#err_strNeeded       ;Nope -- get error number
1219                 BNE     error_report            ;...and report the error
1220
1221                 LDR     R1,sail_stracc          ;Get the stracc address
1222                 LDR     R1,[R1]
1223                 ADD     R1,R1,R0,LSR #8         ;Point to the string
1224                 AND     R2,R0,#&FF              ;Get the length
1225
1226                 MOV     R5,R0                   ;look after the rvalue
1227                 ADR     R0,sail_misc            ;Point to the misc buffer
1228                 BL      ctrl_copyString         ;Copy the string over
1229                 SWI     OS_CLI                  ;Do the command
1230                 MOV     R0,R5                   ;Get the rvalue back
1231                 BL      stracc_free             ;Free the string from stracc
1232                 B       interp_next             ;Continue happily
1233
1234                 LTORG
1235
1236
1237
1238 ;----- DATA and the like ----------------------------------------------------
1239
1240 ; --- ctrl__findDATA ---
1241 ;
1242 ; On entry:     All the normal things
1243 ;
1244 ; On exit:      R0 == *address* in file of next DATA
1245 ;
1246 ; Use:          Sets the internal data pointer to the first DATA statement
1247 ;               fromthe current position.
1248
1249                 EXPORT  ctrl_findDATA
1250 ctrl_findDATA   ROUT
1251
1252                 STMFD   R13!,{R1,R2,R14}        ;Save some registers
1253                 LDR     R0,sail_dataPtr         ;Load the current position
1254                 LDR     R1,sail_tokAnchor       ;Load the anchor
1255                 ADD     R0,R1,R0                ;Point into the file
1256                 LDR     R2,sail_dataLine        ;Line number of DATA
1257
1258                 ; --- Search the file for DATA, or EOF ---
1259
1260 00              LDRB    R14,[R0],#1             ;Load a byte
1261                 CMP     R14,#10                 ;Are we at a return?
1262                 ADDEQ   R2,R2,#1                ;Yes -- inc line number
1263                 CMP     R14,#&FF                ;Is this the EOF?
1264                 SUBEQ   R0,R0,#1                ;Yes -- point to it
1265                 CMPNE   R14,#tok_data           ;Did we read a DATA?
1266                 BNE     %b00                    ;No -- keep on looking
1267
1268 90              SUB     R1,R0,R1                ;Get it as an offset
1269                 STR     R1,sail_dataPtr         ;Save this away then
1270                 STR     R2,sail_dataLine                ;And the line number
1271                 LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
1272
1273                 LTORG
1274
1275 ; --- ctrl_read ---
1276
1277                 EXPORT  ctrl_read
1278 ctrl_read       ROUT
1279
1280                 ; --- Point at the current position ---
1281
1282                 LDR     R4,sail_dataPtr         ;Load the current position
1283                 LDR     R5,sail_tokAnchor       ;Load the anchor
1284                 ADD     R4,R5,R4                ;Point into the file
1285
1286 00ctrl_read     LDRB    R14,[R4,#0]             ;Load the byte there
1287                 CMP     R14,#&FF                ;Is it the EOF?
1288                 MOVEQ   R0,#err_outOfDATA       ;Yes -- get error num
1289                 BEQ     error_report            ;And report the error
1290                 CMP     R14,#10                 ;Are we at the line end?
1291                 BLEQ    ctrl_findDATA           ;Yes -- find next data
1292                 MOVEQ   R4,R0                   ;...put ptr in R0
1293                 BEQ     %00ctrl_read            ;...and start again
1294                 CMP     R14,#','                ;Is it a comma?
1295                 ADDEQ   R4,R4,#1                ;Yes -- skip over it
1296
1297                 ; --- Read an rvalue from this position ---
1298
1299                 LDR     R6,sail_line            ;Load the line number
1300                 STMFD   R13!,{R6-R10}           ;Stack position details
1301                 MOV     R10,R4                  ;Point just before data
1302                 LDR     R14,sail_dataLine       ;Get the line number
1303                 STR     R14,sail_line           ;Store as actual line
1304                 MOV     R9,#-1                  ;Make getToken happy
1305                 BL      getToken                ;Get a token
1306                 MOV     R0,#0                   ;Read an rvalue
1307                 BL      express_read            ;Read it then
1308                 BL      express_pop             ;Get it off the stack
1309                 LDR     R14,sail_line           ;Get line number
1310                 STR     R14,sail_dataLine       ;Store as DATA line number
1311                 SUB     R4,R10,#1               ;Restore data pointer
1312                 LDMFD   R13!,{R6-R10}           ;Load back position
1313                 STR     R6,sail_line            ;Restore line number
1314                 MOV     R2,R0                   ;Put rvalue in R2,R3
1315                 MOV     R3,R1
1316
1317                 ; --- We are hopefully pointing at some data ---
1318
1319                 MOV     R0,#1                   ;Prepare to read an lvalue
1320                 BL      express_read            ;Read one then
1321                 BL      express_pop             ;Get it off the stack
1322                 BL      ctrl_store              ;Store the rvalue
1323
1324                 SUB     R14,R4,R5               ;Get data pointer as offset
1325                 STR     R14,sail_dataPtr                ;Store this away
1326                 CMP     R9,#','                 ;Should we read more?
1327                 BLEQ    getToken                ;Yes -- skip over the comma
1328                 BEQ     %00ctrl_read            ;..and loop back again
1329
1330                 B       interp_next             ;Do next instruction
1331
1332                 LTORG
1333
1334 ; --- ctrl_restore ---
1335
1336                 EXPORT  ctrl_restore
1337 ctrl_restore    ROUT
1338
1339                 BL      ctrl__readLabel         ;Read the label
1340                 MOVCC   R0,#0                   ;Not there -- offset is 0
1341                 MOVCC   R1,#1                   ;Line is 1
1342                 LDMCSIB R0,{R0,R1}              ;Load out address/line
1343
1344                 STR     R0,sail_dataPtr         ;Save the data pointer
1345                 STR     R1,sail_dataLine                ;And the line number
1346                 BL      ctrl_findDATA           ;Find the DATA
1347                 B       interp_next             ;And do the next instruction
1348
1349                 LTORG
1350
1351 ;----- SYS and friends ------------------------------------------------------
1352
1353 ; --- ctrl_call ---
1354
1355                 EXPORT  ctrl_call
1356 ctrl_call       ROUT
1357
1358                 BL      ctrl_setUpRegs          ;Set up the regs then
1359
1360                 CMP     R10,#vType_integer      ;Is this an integer?
1361                 MOVNE   R0,#err_numNeeded       ;No -- get error number
1362                 BNE     error_report            ;...and report the error
1363
1364                 MOV     R14,PC                  ;Set up return address
1365                 MOV     PC,R9                   ;Execute the code
1366
1367                 ADRL    R9,ctrl__returned       ;Point to some space
1368                 STMIA   R9!,{R0-R8}             ;Store returned registers
1369                 MOV     R14,PC,LSR #28          ;Get the flags
1370                 STMIA   R9,{R14}                ;Strore the flags too
1371                 LDMFD   R13!,{R7-R12}           ;Load back position info
1372                 LDMFD   R13!,{R0}               ;Load stracc offset
1373                 BL      stracc_free             ;Free any strings I had
1374
1375                 ; --- We have now done the SWI instr ---
1376
1377                 ADRL    R0,ctrl__returned       ;Point to the returned regs
1378                 BL      ctrl_resolveRegs        ;Do the other half now
1379                 B       interp_next             ;If flags -- return
1380
1381                 LTORG
1382
1383 ; --- ctrl_sys ---
1384
1385                 EXPORT  ctrl_sys
1386 ctrl_sys        ROUT
1387
1388                 BL      ctrl_setUpRegs          ;Set up the registers
1389                 STMFD   R13!,{R0-R8}            ;Stack these registers
1390
1391                 CMP     R10,#vType_integer      ;Did user use an integer?
1392                 MOVEQ   R0,R9                   ;Yes -- use that then
1393                 BEQ     %10ctrl_sys             ;And jump ahead
1394
1395                 ; --- Convert the name to a number ---
1396
1397                 LDR     R1,sail_stracc          ;Load the stracc address
1398                 LDR     R1,[R1]
1399                 ADD     R1,R1,R9,LSR #8         ;Point to the name
1400                 SWI     XOS_SWINumberFromString ;Convert it then
1401                 BVS     error_reportReal        ;Report possible error
1402
1403                 ; --- We have the SWI number in R0 ---
1404                 ;
1405                 ; We build the following instructions on the stack:
1406                 ;
1407                 ;       SWI     <R0>
1408                 ;       MOV     PC,R14
1409
1410 10              ORR     R9,R0,#&EF000000        ;Build the SWI instruction
1411                 LDR     R10,=&E1A0F00E          ;Get the MOV instr too
1412                 LDMFD   R13!,{R0-R8}            ;Load the registers
1413                 SUB     R13,R13,#8              ;Make some room
1414                 STMIA   R13,{R9,R10}            ;Stack code
1415                 MOV     R14,PC                  ;Set up return address
1416                 MOV     PC,R13                  ;Call my code
1417
1418                 ADD     R13,R13,#8              ;Get rid of my code
1419                 ADR     R9,ctrl__returned       ;Point to some space
1420                 STMIA   R9!,{R0-R8}             ;Store returned registers
1421                 MOV     R14,PC,LSR #28          ;Get the flags
1422                 STMIA   R9,{R14}                ;Strore the flags too
1423                 LDMFD   R13!,{R7-R12}           ;Load back position info
1424                 LDMFD   R13!,{R0}               ;Load stracc offset
1425                 BL      stracc_free             ;Free any strings I had
1426
1427                 ; --- We have now done the SWI instr ---
1428
1429                 ADR     R0,ctrl__returned       ;Point to the returned regs
1430                 BL      ctrl_resolveRegs        ;Do the other half now
1431                 B       interp_next             ;Do the next instruction
1432
1433 ctrl__returned  DCD     0,0,0,0,0,0,0,0,0,0,0
1434
1435                 LTORG
1436
1437 ; --- ctrl_setUpRegs ---
1438 ;
1439 ; On entry:     R7-R10 == position info
1440 ;
1441 ; On exit:      R0-R8 set up for sys call
1442 ;               R9,R10 == rvalue of first parameter
1443 ;               On the stack:
1444 ;                 new position info, R7-R12
1445 ;                 place to stracc free
1446 ;
1447 ; Use:          Sets up all the registers as required by a SYS or SYSCALL
1448 ;               command.
1449
1450                 EXPORT  ctrl_setUpRegs
1451 ctrl_setUpRegs ROUT
1452
1453                 MOV     R3,R14                  ;Look after the link
1454                 BL      stracc_ensure           ;Get current stracc offset
1455                 STMFD   R13!,{R1}               ;Put it on the stack
1456                 MOV     R5,#0                   ;Might be useful
1457
1458                 ; --- Read the complusory argument ---
1459
1460                 MOV     R0,#0                   ;It's an rvalue
1461                 BL      express_read            ;Read the expression
1462                 BL      express_pop             ;Pop it
1463                 BL      express_push            ;Push it again
1464
1465                 CMP     R1,#vType_integer       ;Is it an integer?
1466                 BEQ     %f00                    ;Yes -- go round again then
1467                 CMP     R1,#vType_string        ;Was it a string?
1468                 MOVNE   R0,#err_arrayBad        ;No -- get error number
1469                 BNE     error_report            ;And report the error
1470                 BL      stracc_ensure           ;If it was -- ensure room
1471                 STRB    R5,[R0,#0]              ;...store a terminator
1472                 AND     R0,R0,#3                ;Get the alignment
1473                 RSB     R0,R0,#4
1474                 ORR     R0,R1,R0                ;...set up the rvalue
1475                 BL      stracc_added            ;Tell stracc about this
1476
1477                 ; --- Now read all other parameters ---
1478
1479 00              MOV     R2,#0                   ;Mask of regs read
1480                 MOV     R4,#0                   ;Number we have read
1481 00              CMP     R9,#','                 ;Do we have a comma?
1482                 BNE     %10ctrl_setUpRegs       ;No -- we have finshed then
1483 05              ADD     R4,R4,#1                ;Increment the counter
1484                 CMP     R4,#8                   ;Have we read 8?
1485                 MOVEQ   R0,#err_sysTooManyI     ;Yes -- get error number
1486                 BEQ     error_report            ;And report the error
1487                 BL      getToken                ;Skip over the comma
1488                 CMP     R9,#','                 ;Another comma?
1489                 MOVEQ   R2,R2,LSL #1            ;Yes -- shift R2 along
1490                 BEQ     %b05                    ;And go back for more
1491                 MOV     R0,#0                   ;Read an rvalue
1492                 BL      express_read            ;Read it then
1493                 MOV     R2,R2,LSL #1            ;Shift R2 along
1494                 ORR     R2,R2,#1                ;And set the bit
1495                 BL      express_pop             ;Get it off the stack
1496                 BL      express_push            ;Oh -- better not!
1497                 CMP     R1,#vType_integer       ;Is it an integer?
1498                 BEQ     %b00                    ;Yes -- go round again then
1499                 CMP     R1,#vType_string        ;Was it a string?
1500                 MOVNE   R0,#err_arrayBad        ;No -- get error number
1501                 BNE     error_report            ;And report the error
1502                 BL      stracc_ensure           ;If it was -- ensure room
1503                 STRB    R5,[R0]                 ;...store a terminator
1504                 AND     R0,R0,#3                ;Get the alignment
1505                 RSB     R0,R0,#4
1506                 ORR     R0,R1,R0                ;...set up the rvalue
1507                 BL      stracc_added            ;Tell stracc about this
1508                 B       %b00                    ;And go round for more
1509
1510                 ; --- We have read the input parameters ---
1511                 ;
1512                 ; We must put the position infor on the stack before
1513                 ; the link here, so that it remains on the stack at return
1514                 ; time.
1515
1516 10              STMFD   R13!,{R7-R12}           ;Stack position info
1517                 STMFD   R13!,{R3}               ;And then stack the link!
1518                 LDR     R9,sail_stracc          ;Load the stracc anchor
1519                 LDR     R9,[R9]                 ;Get it's address
1520                 MOV     R10,R2                  ;Put the mask in R10
1521
1522                 ; --- Now transfer the info to R0-R8 ---
1523                 ;
1524                 ; Each routine is padded to eight bytes, for niceness (?)
1525                 ; To start, we set everything to
1526
1527                 MOV     R14,R4                  ;Look after number of regs
1528                 MOV     R0,#0
1529                 MOV     R1,#0
1530                 MOV     R2,#0
1531                 MOV     R3,#0
1532                 MOV     R4,#0
1533                 MOV     R5,#0
1534                 MOV     R6,#0
1535                 MOV     R7,#0
1536                 MOV     R8,#0
1537
1538                 CMP     R14,#0                  ;Read no registers?
1539                 BEQ     %30ctrl_setUpRegs       ;Indeed -- jump ahead then
1540                 RSB     R14,R14,#9              ;Make R4 right
1541                 ADD     R14,R14,R14,LSL #1      ;Multiply by 3
1542                 ADDS    PC,PC,R14,LSL #3        ;Jump to the routine (*24)
1543                 DCB     "TMA!"                  ;Pad pad pad pad...
1544
1545 28              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1546                 BCC     %27ctrl_setUpRegs       ;No go -- jump ahead then
1547                 BL      express_pop             ;Get the rvalue
1548                 CMP     R1,#vType_string        ;Was it a string?
1549                 ADDEQ   R8,R9,R0,LSR #8         ;Yes -- point to string
1550                 MOVNE   R8,R0                   ;No -- it's an integer then
1551
1552 27              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1553                 BCC     %26ctrl_setUpRegs       ;No go -- jump ahead then
1554                 BL      express_pop             ;Get the rvalue
1555                 CMP     R1,#vType_string        ;Was it a string?
1556                 ADDEQ   R7,R9,R0,LSR #8         ;Yes -- point to string
1557                 MOVNE   R7,R0                   ;No -- it's an integer then
1558
1559 26              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1560                 BCC     %25ctrl_setUpRegs       ;No go -- jump ahead then
1561                 BL      express_pop             ;Get the rvalue
1562                 CMP     R1,#vType_string        ;Was it a string?
1563                 ADDEQ   R6,R9,R0,LSR #8         ;Yes -- point to string
1564                 MOVNE   R6,R0                   ;No -- it's an integer then
1565
1566 25              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1567                 BCC     %24ctrl_setUpRegs       ;No go -- jump ahead then
1568                 BL      express_pop             ;Get the rvalue
1569                 CMP     R1,#vType_string        ;Was it a string?
1570                 ADDEQ   R5,R9,R0,LSR #8         ;Yes -- point to string
1571                 MOVNE   R5,R0                   ;No -- it's an integer then
1572
1573 24              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1574                 BCC     %23ctrl_setUpRegs       ;No go -- jump ahead then
1575                 BL      express_pop             ;Get the rvalue
1576                 CMP     R1,#vType_string        ;Was it a string?
1577                 ADDEQ   R4,R9,R0,LSR #8         ;Yes -- point to string
1578                 MOVNE   R4,R0                   ;No -- it's an integer then
1579
1580 23              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1581                 BCC     %22ctrl_setUpRegs       ;No go -- jump ahead then
1582                 BL      express_pop             ;Get the rvalue
1583                 CMP     R1,#vType_string        ;Was it a string?
1584                 ADDEQ   R3,R9,R0,LSR #8         ;Yes -- point to string
1585                 MOVNE   R3,R0                   ;No -- it's an integer then
1586
1587 22              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1588                 BCC     %21ctrl_setUpRegs       ;No go -- jump ahead then
1589                 BL      express_pop             ;Get the rvalue
1590                 CMP     R1,#vType_string        ;Was it a string?
1591                 ADDEQ   R2,R9,R0,LSR #8         ;Yes -- point to string
1592                 MOVNE   R2,R0                   ;No -- it's an integer then
1593
1594 21              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1595                 BCC     %20ctrl_setUpRegs       ;No go -- jump ahead then
1596                 BL      express_pop             ;Get the rvalue
1597                 CMP     R1,#vType_string        ;Was it a string?
1598                 ADDEQ   R1,R9,R0,LSR #8         ;Yes -- point to string
1599                 MOVNE   R1,R0                   ;No -- it's an integer then
1600
1601 20              MOVS    R10,R10,LSR #1          ;Shift the mask down a little
1602                 BCC     %30ctrl_setUpRegs       ;No go -- jump ahead then
1603                 STMFD   R13!,{R1}               ;Stack R1
1604                 BL      express_pop             ;Get the rvalue
1605                 CMP     R1,#vType_string        ;Was it a string?
1606                 ADDEQ   R0,R9,R0,LSR #8         ;Yes -- point to string
1607                 LDMFD   R13!,{R1}               ;Restore R1
1608
1609                 ; --- All the registers are now set up, phew! ---
1610
1611 30              STMFD   R13!,{R0,R1}            ;Stack some registers
1612                 BL      express_pop             ;Get off first arg!
1613                 MOV     R9,R0                   ;Put rvalue in R9,R10
1614                 MOV     R10,R1
1615                 LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
1616
1617                 LTORG
1618
1619 ; --- ctrl_resolveRegs ---
1620 ;
1621 ; On entry:     R0 == pointer to register block
1622 ;
1623 ; On exit:      CS if flags were required, CC otherwise
1624 ;
1625 ; Use:          Resolves the registers returned from a SYS or SYSCALL
1626 ;               into the appropriate variables.  The code assumes that
1627 ;               we have possibly just read a TO command, and goes on
1628 ;               from there.
1629
1630                 EXPORT  ctrl_resolveRegs
1631 ctrl_resolveRegs ROUT
1632
1633                 ; --- See if we require register return ---
1634
1635                 CMP     R9,#tok_to              ;Do we have a TO?
1636                 MOVNES  PC,R14                  ;No -- return PDQ then
1637
1638                 STMFD   R13!,{R0-R6,R14}        ;Stack registers
1639                 BL      getToken                ;Skip over the TO
1640                 MOV     R4,R0                   ;Put the block in R4
1641                 MOV     R5,#0                   ;Number read so far
1642                 ADD     R6,R4,#9*4              ;Point tothe flags
1643
1644 00              CMP     R9,#':'                 ;Is this the end?
1645                 CMPNE   R9,#10
1646                 CMPNE   R9,#&FF
1647                 CMPNE   R9,#tok_else
1648                 BEQ     %90ctrl_resolveRegs     ;Yes -- return then
1649                 CMP     R9,#','                 ;Do we skip this one?
1650                 ADDEQ   R4,R4,#4                ;Yes -- go onto next reg
1651                 ADDEQ   R5,R5,#1                ;We have done this many
1652                 CMP     R5,#9                   ;Is this reg 9?
1653                 MOVEQ   R0,#err_sysTooManyO     ;Yes -- get error number
1654                 BEQ     error_report            ;And report then error
1655                 CMP     R9,#','                 ;Compare again with comma
1656                 BLEQ    getToken                ;Yes -- skip the comma
1657                 BEQ     %b00                    ;Keep on going
1658
1659                 ; --- We must read one then ---
1660                 ;
1661                 ; Actually, we may be reading the flags too.
1662
1663                 CMP     R9,#';'                 ;Do we have a semicolon?
1664                 BEQ     %30ctrl_resolveRegs     ;Yes -- deal with it then
1665
1666                 MOV     R0,#1                   ;We are reading an lvalue
1667                 BL      express_read            ;Read it
1668                 BL      express_pop             ;Pop it off the stack
1669                 BL      ctrl_load               ;Load the value
1670                 CMP     R3,#vType_integer       ;Is it an integer?
1671                 BEQ     %20ctrl_resolveRegs     ;Yes -- jump ahead
1672
1673                 CMP     R3,#vType_string        ;Is it a string then?
1674                 MOVNE   R0,#err_arrayBad        ;No -- get error number
1675                 BNE     error_report            ;And report the error
1676
1677                 ; --- We have to return a string ---
1678
1679                 STMFD   R13!,{R0,R1}            ;Look after the lvalue
1680                 MOV     R0,R2                   ;Put the rvalue in R0
1681                 BL      stracc_free             ;Free the string from stracc
1682
1683                 LDR     R2,[R4,#0]              ;Load the string address
1684                 BL      stracc_ensure           ;Make sure we have room
1685                 MOV     R3,#0                   ;Length so far
1686
1687 10              LDRB    R14,[R2],#1             ;Load a byte
1688                 CMP     R14,#0                  ;Is it 0?
1689                 STRNEB  R14,[R0],#1             ;No -- store it then
1690                 ADDNE   R3,R3,#1                ;...increment the length
1691                 BNE     %b10                    ;And go round for more
1692
1693                 ORR     R0,R1,R3                ;Create the rvalue
1694                 BL      stracc_added            ;Tell stracc about this
1695                 MOV     R2,R0                   ;Put rvalue in R2 too
1696                 MOV     R3,#vType_string        ;This is a string
1697                 LDMFD   R13!,{R0,R1}            ;Load the lvalue back
1698                 BL      ctrl_store              ;Store the new value
1699                 B       %b00                    ;Go round again
1700
1701                 ; --- It's just an integer then ---
1702
1703 20              LDR     R2,[R4,#0]              ;Load the integer
1704                 BL      ctrl_store              ;Store this result
1705                 B       %b00                    ;Go round again
1706
1707                 ; --- We must read the flags ---
1708
1709 30              BL      getToken                ;Skip over the ';'
1710                 MOV     R0,#1                   ;Read an lvalue
1711                 BL      express_read            ;Read it then
1712                 BL      express_pop             ;Get it off the stack
1713                 BL      ctrl_load               ;Load the current value
1714                 CMP     R3,#vType_integer       ;Is it an integer?
1715                 MOVNE   R0,#err_numNeeded       ;No -- get error number
1716                 BNE     error_report            ;And report the error
1717                 LDR     R2,[R6,#0]              ;Load the flags word
1718                 BL      ctrl_store              ;Store the new value
1719                 LDMFD   R13!,{R0-R6,R14}        ;Load back registers
1720                 ORRS    PC,R14,#C_flag          ;Return with C set
1721
1722 90              LDMFD   R13!,{R0-R6,R14}        ;Load back registers
1723                 BICS    PC,R14,#C_flag          ;Return with C clear
1724
1725                 LTORG
1726
1727 ;----- Function/Procedure call ----------------------------------------------
1728
1729 ; --- FN ---
1730 ;
1731 ; OK, maybe it shouldn't be here.  I don't really care.
1732 ;
1733 ; Hack warning: This is a hack.  We unwind express_read's stack and stuff
1734 ;               them away somewhere completely different.
1735
1736                 EXPORT  ctrl_fn
1737 ctrl_fn         ROUT
1738
1739                 ; --- First we need to make a FN frame ---
1740                 ;
1741                 ; This involves taking a copy of express_read's stack and
1742                 ; stuffing it into the frame so we can restore it afterwards.
1743                 ; This basically means that we can recurse mightily without
1744                 ; using any R13 stack space.  Huzzah!
1745
1746                 MOV     R0,#cFrame__fn          ;Get the frame type
1747                 BL      ctrl__pushFrame         ;Push the frame
1748                 LDR     R14,sail_oldAnchor      ;Load the old anchor address
1749                 STR     R14,[R0,#cFn__anchor]   ;Save it in the frame
1750                 STR     R6,[R0,#cFn__flags]     ;Save express_read's flags
1751                 STMFD   R13!,{R0}               ;Save some register
1752                 BL      stracc_ensure           ;Get current strac position
1753                 LDMFD   R13!,{R0}               ;Load registers back again
1754                 STR     R1,[R0,#cFn__stracc]    ;Save this away
1755                 ; Oh, bugger.  This doesn't work.
1756                 LDR     R14,sail_currAnchor     ;Load the current anchor
1757                 STR     R14,sail_oldAnchor      ;Save this as the old one
1758                 LDR     R14,sail_tokAnchor      ;Now we work from the file
1759                 STR     R14,sail_currAnchor     ;So set this as current one
1760
1761                 ADD     R14,R0,#cFn__stack+32   ;Find the stack copy bit
1762                 LDMFD   R13!,{R1-R4}            ;Load some registers
1763                 STMFD   R14!,{R1-R4}            ;Save them into the frame
1764                 LDMFD   R13!,{R1-R4}            ;Load some registers again
1765                 STMFD   R14!,{R1-R4}            ;Save them into the frame
1766
1767                 ; --- Now get on with the business of calling ---
1768
1769                 LDR     R1,sail_execStack       ;Load the stack anchor
1770                 LDR     R1,[R1,#0]              ;Tycho bops WimpExtension
1771                 SUB     R6,R0,R1                ;Turn into an offset
1772
1773                 ; --- Substitute the arguments ---
1774
1775                 MOV     R0,#vType_fn            ;This is a FN
1776                 BL      ctrl__subArgs           ;Substitute the args
1777
1778                 LDR     R0,sail_execStack       ;Load the stack anchor
1779                 LDR     R0,[R0,#0]              ;Tycho bops WimpExtension
1780                 ADD     R0,R0,R6                ;Point to my frame
1781                 STMIA   R0,{R3,R4}              ;Save the return point away
1782
1783                 B       interp_exec             ;Execute next instruction
1784
1785                 LTORG
1786
1787 ; --- = ---
1788
1789                 EXPORT  ctrl_equals
1790 ctrl_equals     ROUT
1791
1792                 ; --- First, evaluate the argument ---
1793
1794                 MOV     R0,#0                   ;Get an rvalue for it
1795                 BL      express_read            ;Read the expression
1796                 CMP     R9,#&0A                 ;Now at end of line?
1797                 CMPNE   R9,#':'                 ;Or end of statement (weird)
1798                 CMPNE   R9,#&FF                 ;Or end of file?
1799                 CMPNE   R9,#tok_else            ;Or an ElSE?
1800                 MOVNE   R0,#err_syntax          ;No -- that's a cock-up
1801                 BNE     error_report            ;So be righteous about it
1802
1803                 ; --- If the result is a string, copy it ---
1804
1805                 BL      express_pop             ;Pop off the result
1806                 MOV     R4,R0                   ;Put the rvalue in R4
1807                 MOV     R5,R1                   ;And the type in R5
1808                 CMP     R5,#vType_string        ;Is it a string?
1809                 BNE     %10ctrl_equals          ;No -- jump ahead
1810
1811                 ; --- Copy the string elsewhere ---
1812                 ;
1813                 ; We do this since there may be local strings that are
1814                 ; removed from stracc, underneath the result.
1815
1816                 LDR     R1,sail_stracc          ;Load stracc's anchor
1817                 LDR     R1,[R1]                 ;Load the address
1818                 ADD     R1,R1,R4,LSR #8         ;Point to the string
1819
1820                 ADR     R0,sail_misc            ;Point to a misc buffer
1821                 ANDS    R2,R4,#&FF              ;Get the length
1822                 BEQ     %10ctrl_equals          ;Nothin' doin', jump
1823
1824 00              LDRB    R14,[R1],#1             ;Load a byte
1825                 STRB    R14,[R0],#1             ;Store a byte
1826                 SUBS    R2,R2,#1                ;Reduce counter
1827                 BNE     %b00                    ;Do this lots
1828                 MOV     R0,R4                   ;Put the rvalue in R0
1829                 BL      stracc_free             ;Free the string
1830
1831                 ; --- Find the frame thing ---
1832
1833 10ctrl_equals   MOV     R0,#cFrame__fn          ;Search for a FN frame
1834                 BL      ctrl__unwind            ;Look for one of these then
1835                 MOVCC   R0,#err_notInFn         ;Get possible error num
1836                 BCC     error_report            ;And report the error
1837                 MOV     R6,R1                   ;Look after frame address
1838
1839                 ; --- Put stracc in the right place ---
1840
1841                 LDR     R0,[R6,#cFn__stracc]    ;Load the offset
1842                 BL      stracc_free             ;Okaydokey
1843
1844                 ; --- Reset other things ---
1845
1846                 LDMIA   R1,{R0,R1}              ;Load the line and offset
1847                 STR     R1,sail_line            ;Save the line counter
1848                 LDR     R14,sail_oldAnchor      ;Find the anchor of the file
1849                 STR     R14,sail_currAnchor     ;This is the current one
1850                 LDR     R1,[R6,#cFn__anchor]    ;Load the saved anchor
1851                 STR     R1,sail_oldAnchor       ;This is the old one
1852                 LDR     R14,[R14]               ;Pointless instruction
1853                 ADD     R10,R14,R0              ;Get the new offset
1854                 SUB     R10,R10,#1              ;Backtrack a little
1855                 MOV     R9,#-1                  ;Give bogus current token
1856                 BL      getToken                ;Read this token
1857
1858                 ; --- Put a string result back on stracc ---
1859
1860                 MOV     R0,R4                   ;Get the rvalue
1861                 MOV     R1,R5                   ;And the type
1862                 CMP     R1,#vType_string        ;Was it a string?
1863                 BNE     %20ctrl_equals          ;No -- jump ahead
1864
1865                 ; --- Copy the result back into stracc ---
1866
1867                 BL      stracc_ensure           ;Make sure we have room
1868                 ADR     R2,sail_misc            ;Point to our string
1869                 ANDS    R3,R4,#&FF              ;Get the length
1870                 BEQ     %15ctrl_equals          ;Very short -- jump
1871 00              LDRB    R14,[R2],#1             ;Load a byte
1872                 STRB    R14,[R0],#1             ;Store a byte
1873                 SUBS    R3,R3,#1                ;Reduce a counter
1874                 BNE     %b00                    ;Lots more please
1875
1876 15              ANDS    R3,R4,#&FF              ;Get the length again
1877                 ORR     R0,R1,R3                ;Put the rvalue in R0
1878                 MOV     R1,#vType_string        ;This is a string
1879                 BL      stracc_added            ;Tell stracc about this
1880 20              BL      express_push            ;Push this result
1881
1882                 ; --- Now we need to return to express_read ---
1883                 ;
1884                 ; Hack warning: This is a hack.
1885
1886                 ADD     R14,R6,#cFn__stack      ;Find stack contents
1887                 LDMFD   R14!,{R0-R3}            ;Load contents out
1888                 STMFD   R13!,{R0-R3}            ;Stuff them back on the stack
1889                 LDMFD   R14!,{R0-R3}
1890                 STMFD   R13!,{R0-R3}
1891                 LDR     R6,[R6,#cFn__flags]     ;Restore express_read's flags
1892                 B       express_fnCont          ;And resume horridly
1893
1894                 LTORG
1895
1896 ; --- PROC ---
1897
1898                 EXPORT  ctrl_proc
1899 ctrl_proc       ROUT
1900
1901                 ; --- First, we push a PROC frame onto the stack ---
1902
1903                 MOV     R0,#cFrame__proc        ;Push on this type
1904                 BL      ctrl__pushFrame         ;Push on the frame
1905                 LDR     R14,sail_oldAnchor      ;Get the old anchor
1906                 STR     R14,[R0,#cProc__anchor] ;Save it in the frame
1907                 LDR     R14,sail_tokAnchor      ;Args must be in the file
1908                 STR     R14,sail_oldAnchor      ;So read them from there
1909                 STMFD   R13!,{R0}               ;Save some register
1910                 BL      stracc_ensure           ;Get current strac position
1911                 LDMFD   R13!,{R0}               ;Load registers back again
1912                 STR     R1,[R0,#cProc__stracc]  ;Save this away
1913                 LDR     R1,sail_execStack       ;Load the stack anchor
1914                 LDR     R1,[R1,#0]              ;Tycho bops WimpExtension
1915                 SUB     R6,R0,R1                ;Turn into an offset
1916
1917                 ; --- Substitute the arguments ---
1918
1919                 MOV     R0,#vType_proc          ;This is a PROC
1920                 BL      ctrl__subArgs           ;Substitute the args
1921
1922                 LDR     R0,sail_execStack       ;Load the stack anchor
1923                 LDR     R0,[R0,#0]              ;Tycho bops WimpExtension
1924                 ADD     R0,R0,R6                ;Point to my frame
1925                 STMIA   R0,{R3,R4}              ;Save the return point away
1926                 LDR     R14,[R0,#cProc__anchor] ;Load anchor we saved above
1927                 STR     R14,sail_oldAnchor      ;Re-instate this again
1928
1929                 B       interp_exec             ;Execute next instruction
1930
1931                 LTORG
1932
1933 ; --- ENDPROC ---
1934
1935                 EXPORT  ctrl_endproc
1936 ctrl_endproc    ROUT
1937
1938                 MOV     R0,#cFrame__proc        ;Search for a PROC frame
1939                 BL      ctrl__unwind            ;Look for one of these then
1940                 MOVCC   R0,#err_notInProc       ;Get possible error num
1941                 BCC     error_report            ;And report the error
1942
1943                 LDR     R0,[R1,#cProc__stracc]  ;Load the offset
1944                 BL      stracc_free             ;Okaydokey
1945
1946                 LDMIA   R1,{R0,R1}              ;Load the line and offset
1947                 STR     R1,sail_line            ;Save the line counter
1948                 LDR     R14,sail_tokAnchor      ;Find the anchor of the file
1949                 LDR     R14,[R14]               ;Pointless instruction
1950                 ADD     R10,R14,R0              ;Get the new offset
1951                 SUB     R10,R10,#1              ;Backtrac a little
1952                 MOV     R9,#-1                  ;Give bogus current token
1953                 BL      getToken                ;Read this token
1954                 B       interp_next             ;And continue merrily
1955
1956                 LTORG
1957
1958 ; --- DATA ---
1959
1960                 EXPORT  ctrl_data
1961 ctrl_data
1962
1963 ; --- DEF  ---
1964
1965                 EXPORT  ctrl_def
1966
1967 ctrl_def        ROUT
1968
1969                 ; --- Simply search for a newline! ---
1970
1971 00              CMP     R9,#10                  ;Is this a newline?
1972                 CMPNE   R9,#&FF                 ;Or the EOF?
1973                 BNE     getToken                ;No -- get another token
1974                 BNE     %b00                    ;...get another one then
1975                 B       interp_next             ;And carry on as before
1976
1977                 LTORG
1978
1979 ; --- LOCAL ---
1980
1981                 EXPORT  ctrl_local
1982 ctrl_local      ROUT
1983
1984                 ; --- We read lots of lvalues, and create local frames ---
1985
1986 00              MOV     R0,#cFrame__local       ;We want a local frame
1987                 BL      ctrl__pushFrame         ;Create the frame then
1988                 MOV     R5,R0                   ;Look after the address
1989                 MOV     R0,#1                   ;Read an lvalue
1990                 BL      express_read            ;Go to it then
1991                 BL      express_pop             ;Pop it off
1992                 BL      ctrl_load               ;Load its value out
1993                 STMIA   R5,{R0-R3}              ;Store this in the frame
1994
1995                 CMP     R9,#','                 ;Do we have a comma now?
1996                 BLEQ    getToken                ;Yes -- gobble it up
1997                 BEQ     %b00                    ;...and do another one
1998
1999                 B       interp_next             ;Do the next instruction
2000
2001                 LTORG
2002
2003 ; --- ctrl__subArgs ---
2004 ;
2005 ; On entry:     R0 == type of routine to find
2006 ;
2007 ; On exit:      R3 == offset of return point
2008 ;               R4 == line number of return point
2009 ;               R0-R2, R5 corrupted
2010 ;
2011 ; Use:          Performs argument substitution.  The next token to read
2012 ;               should be the name of the routine to execute.  On exit,
2013 ;               the interpreter will begin execution of the routine.
2014
2015 ctrl__subArgs   ROUT
2016
2017                 ; --- A nasty macro ---
2018                 ;
2019                 ; Swap between the two states
2020
2021                 MACRO
2022                 READARG
2023                 LDR     R0,sail_oldAnchor
2024                 LDR     R0,[R0]
2025                 MOV     R14,R10
2026                 SUB     R10,R3,#1
2027                 ADD     R10,R10,R0
2028                 LDR     R0,sail_currAnchor
2029                 LDR     R0,[R0]
2030                 SUB     R3,R14,R0
2031                 LDR     R14,sail_line
2032                 STR     R4,sail_line
2033                 MOV     R4,R14
2034                 MOV     R9,#-1
2035                 BL      getToken
2036                 MEND
2037
2038                 MACRO
2039                 READDEF
2040                 LDR     R0,sail_currAnchor
2041                 LDR     R0,[R0]
2042                 MOV     R14,R10
2043                 SUB     R10,R3,#1
2044                 ADD     R10,R10,R0
2045                 LDR     R0,sail_oldAnchor
2046                 LDR     R0,[R0]
2047                 SUB     R3,R14,R0
2048                 LDR     R14,sail_line
2049                 STR     R4,sail_line
2050                 MOV     R4,R14
2051                 MOV     R9,#-1
2052                 BL      getToken
2053                 MEND
2054
2055                 ; --- Now get on with it ---
2056                 ;
2057                 ; We're calling express_read during the first part of this,
2058                 ; so we don't have the luxury of a stack...
2059
2060                 MOV     R5,R14                  ;Remember the return address
2061
2062                 ; --- First, get the PROC/FN name ---
2063
2064                 ADR     R2,sail_misc            ;Point to a nice buffer
2065                 SUBS    R14,R9,#'_'             ;Is it a valid characer?
2066                 SUBNE   R14,R9,#'A'
2067                 CMP     R14,#26
2068                 SUBCS   R14,R9,#'a'
2069                 CMPCS   R14,#26
2070                 SUBCS   R14,R9,#'0'
2071                 CMPCS   R14,#10
2072                 MOVCS   R0,#err_badCall         ;No -- get error then
2073                 BCS     error_report            ;And report it
2074                 STRB    R9,[R2],#1              ;And store in the buffer
2075
2076 00              BL      getToken                ;Get the next character
2077                 SUBS    R14,R9,#'_'             ;Is it a valid characer?
2078                 SUBNE   R14,R9,#'A'
2079                 CMP     R14,#26
2080                 SUBCS   R14,R9,#'a'
2081                 CMPCS   R14,#26
2082                 SUBCS   R14,R9,#'0'
2083                 CMPCS   R14,#10
2084                 STRCCB  R9,[R2],#1              ;Yes -- store in the buffer
2085                 BCC     %b00                    ;...and keep on looping
2086
2087                 MOV     R14,#0
2088                 STRB    R14,[R2],#1
2089
2090                 ; --- Now find the PROC/FN ---
2091
2092                 ADR     R1,sail_misc            ;Point to the name
2093                 BL      tree_find               ;Try to find the thing
2094                 MOVCC   R0,#err_noProc          ;Not there -- complain
2095                 BCC     error_report
2096                 LDMIB   R0,{R3,R4}              ;Load out address/line
2097                 ADD     R3,R3,#1                ;Skip past the proc
2098
2099                 ; --- First, see if we have an open banana ---
2100
2101                 SUBS    R1,R9,#'('              ;Do we have actual arguments?
2102                 BLEQ    getToken                ;Yes -- gobble the bracket
2103                 MOVNE   R1,#1                   ;No -- remember this then
2104                 READDEF                         ;Swap to the def
2105                 SUBS    R2,R9,#'('              ;Do we have formal args?
2106                 BLEQ    getToken                ;Yes -- gobble the bracket
2107                 MOVNE   R2,#1                   ;No -- remember this then
2108                 CMP     R1,R2                   ;Are both the same?
2109                 MOVNE   R0,#err_badArgs         ;No -- get an error
2110                 BNE     error_report            ;So report it then
2111                 CMP     R1,#0                   ;Any arguments?
2112                 BNE     %90ctrl__subArgs        ;No -- just tidy up then
2113
2114                 MOV     R2,#0                   ;No arguments read yet
2115
2116                 ; --- Stage 1: Read actual and formal arguments ---
2117                 ;
2118                 ; Here we will build 3 records on the val stack for each
2119                 ; argument:
2120                 ;
2121                 ;   If argument is RETURN, lvalue of actual arg, else 0
2122                 ;   rvalue of actual arg (read to avoid aliassing problems)
2123                 ;   lvalue of formal arg
2124
2125 10ctrl__subArgs CMP     R9,#tok_return          ;Is this a RETURN token?
2126                 BLEQ    getToken                ;If so, gobble it
2127                 READARG                         ;Swap back to the call
2128                 BNE     %f00                    ;No -- skip to read rvalue
2129
2130                 ; --- Read lvalue for actual arg ---
2131
2132                 MOV     R0,#1                   ;Read the lvalue here
2133                 BL      express_read            ;Read that please
2134                 STMFD   R13!,{R2,R3}            ;Save some registers
2135                 BL      express_pop             ;Pop the lvalue
2136                 BL      ctrl_load               ;Load the rvalue out
2137                 BL      express_push            ;Push the lvalue back
2138                 MOV     R0,R2                   ;Get the rvalue now
2139                 MOV     R1,R3                   ;And its type, please
2140                 BL      express_push            ;Push that too
2141                 LDMFD   R13!,{R2,R3}            ;Restore my registers
2142                 B       %f01                    ;Now skip to handling formal
2143
2144                 ; --- Read rvalue for actual arg ---
2145
2146 00              MOV     R1,#-1                  ;Mark a strange lvalue type
2147                 BL      express_push            ;Push that on
2148                 MOV     R0,#0                   ;Read an rvalue
2149                 BL      express_read            ;Do that then
2150
2151                 ; --- Now swap and read the formal argument ---
2152
2153 01              ADD     R2,R2,#1                ;Bump argument counter
2154                 CMP     R9,#')'                 ;Is this a close bracket?
2155                 CMPNE   R9,#','                 ;Or maybe a comma?
2156                 MOVNE   R0,#err_badCall         ;No -- that's an error
2157                 BNE     error_report            ;So complain about it
2158                 MOV     R1,R9                   ;Look after this token
2159                 BL      getToken                ;Gobble the token
2160
2161                 READDEF                         ;Swap back to the DEF
2162                 MOV     R0,#1                   ;Read an lvalue now
2163                 BL      express_read            ;Read the expression
2164
2165                 CMP     R9,#')'                 ;Is this a close bracket?
2166                 CMPNE   R9,#','                 ;Or maybe a comma?
2167                 MOVNE   R0,#err_expBracket      ;No -- error (odd BASIC one)
2168                 BNE     error_report            ;So complain about it
2169
2170                 CMP     R1,R9                   ;Do these match?
2171                 MOVNE   R0,#err_badArgs         ;No -- someone can't count
2172                 BNE     error_report            ;So report that
2173                 CMP     R9,#','                 ;Is there more to come?
2174                 BL      getToken                ;Get the next token
2175                 BEQ     %10ctrl__subArgs        ;Yes -- read the rest then
2176
2177                 ; --- Stage 2: Bind arguments, and queue value/returns ---
2178                 ;
2179                 ; Here, we build the LOCAL frames for the arguments, and
2180                 ; store the actual arguments into the formal ones.  We also
2181                 ; remember which ones are value/return so we can sort them
2182                 ; out later.  Fortunately we've now done all the messing
2183                 ; about with express_read that we need to, so we can stack
2184                 ; registers and seriously get down to business...
2185
2186                 STMFD   R13!,{R0-R10}           ;Save loads of registers
2187                 MOV     R10,R2                  ;Look after argument count
2188                 MOV     R9,#0                   ;Counter of valret args
2189
2190                 ; --- First, build the LOCAL frame for formal arg ---
2191
2192 00              MOV     R0,#cFrame__local       ;Create a local frame
2193                 BL      ctrl__pushFrame         ;Push that on the stack
2194                 MOV     R4,R0                   ;Look after the address
2195                 BL      express_pop             ;Pop a formal arg lvalue
2196                 BL      ctrl_load               ;Load the current value
2197                 STMIA   R4,{R0-R3}              ;Save all that lot away
2198
2199                 ; --- Now read the rvalue and lvalue of actual arg ---
2200
2201                 MOV     R4,R0                   ;Look after this lvalue
2202                 MOV     R5,R1                   ;Copy it away somewhere
2203                 BL      express_popTwo          ;Pop the lvalue and rvalue
2204                 CMP     R1,#-1                  ;Do we have an actual lvalue?
2205                 STMNEFD R13!,{R0,R1,R4,R5}      ;Yes -- stack that lot away
2206                 ADDNE   R9,R9,#1                ;And increment the counter
2207                 MOV     R0,R4                   ;Put formal lvalue in R0,R1
2208                 ORR     R1,R5,#(1<<31)          ;Don't remove strs from strc
2209                 BL      ctrl_store              ;And bind the argument
2210
2211                 SUBS    R10,R10,#1              ;Decrement arg counter
2212                 BGT     %b00                    ;And loop till all done
2213
2214                 ; --- Stage 3: Finally deal with value/return args ---
2215                 ;
2216                 ; We have to create the value/return frames now.  This is
2217                 ; complicated by the need to prevent LOCAL from over-
2218                 ; zealously restoring values.  We transform any LOCAL frames
2219                 ; which might do this into deadlocal ones, which won't.
2220
2221                 CMP     R9,#0                   ;Do I need to do any of this?
2222                 BEQ     %85ctrl__subArgs        ;No -- go away then
2223                 LDR     R8,sail_execStkPtr      ;Find ctrl stack pointer
2224                 LDR     R7,sail_execStack       ;And find the anchor
2225
2226                 ; --- Check for matching LOCAL frame ---
2227
2228 05              LDR     R0,[R13,#0]             ;Load the lvalue to match
2229                 LDR     R14,[R7,#0]             ;Load the stack anchor
2230                 ADD     R14,R14,R8              ;And find the stack top
2231 00              LDR     R1,[R14,#-4]            ;Load the frame type
2232                 CMP     R1,#cFrame__local       ;Is this a local frame?
2233                 CMPNE   R1,#cFrame__dead        ;Or one we nobbled earlier?
2234                 BNE     %f00                    ;No -- not there then
2235
2236                 LDR     R1,[R14,#-20]!          ;Load the lvalue from here
2237                 CMP     R1,R0                   ;Do these match?
2238                 BNE     %b00                    ;No -- keep looking then
2239                 MOV     R0,#cFrame__dead        ;Nobble this frame
2240                 STR     R0,[R14,#16]            ;Change the type to a dummy
2241
2242                 ; --- Now create a value/return frame ---
2243
2244 00              MOV     R0,#cFrame__return      ;Get the frame type
2245                 BL      ctrl__pushFrame         ;Push this frame
2246                 LDMFD   R13!,{R1-R4}            ;Load the lvalues out
2247                 STMIA   R0,{R1-R4}              ;Save that information away
2248                 SUBS    R9,R9,#1                ;One less of them to do
2249                 BGT     %b05                    ;If any more to do, do them
2250
2251                 ; --- We're done here -- return to caller ---
2252
2253 85              LDMFD   R13!,{R0-R10}           ;Restore registers
2254 90              MOVS    PC,R5                   ;And return (slurrrp)
2255
2256                 LTORG
2257
2258 ; --- ctrl__unwind ---
2259 ;
2260 ; On entry:     R0 == type of frame to find (PROC or FN)
2261 ;
2262 ; On exit:      CS and R1 == address of frame found, else
2263 ;               CC and R1 corrupted
2264 ;               R0 corrupted
2265 ;
2266 ; Use:          Pops frames off the stack, until it finds a frame which
2267 ;               matches the type specified. Looping constructs are ignored,
2268 ;               and locals, deadlocals and return locals are all dealt with.
2269 ;               It will stop at any other routine frame, and return CC.
2270
2271 ctrl__unwind    ROUT
2272
2273                 STMFD   R13!,{R2-R6,R14}        ;Stack registers
2274                 MOV     R4,R0                   ;Look after the routine type
2275                 MOV     R5,#0                   ;Number of return-frames now
2276 00              BL      ctrl__popFrame          ;Pop the frame off the stack
2277                 CMP     R0,#cFrame__routine     ;Is it a routine frame?
2278                 BLT     %b00                    ;Nope -- keep on looking then
2279
2280                 ; --- Now pop off routine frames ---
2281
2282                 CMP     R0,R4                   ;Have we found it?
2283                 BEQ     %90ctrl__unwind         ;Yes -- return success
2284
2285                 CMP     R0,#cFrame__local       ;Is this a local frame?
2286                 BNE     %10ctrl__unwind         ;No -- jump ahead
2287
2288                 ; --- Deal with local frames ---
2289
2290                 LDMIA   R1,{R0-R3}              ;Load lvalue/rvalue
2291                 ORR     R1,R1,#(1<<31)          ;Don't remove strings
2292                 BL      ctrl_store              ;Put it back to how it was
2293                 B       %b00                    ;And go round for more
2294
2295                 ; --- Check for dead frame ---
2296
2297 10              CMP     R0,#cFrame__dead        ;Is this frame dead?
2298                 BEQ     %b00                    ;Yes -- ignore it then
2299
2300 15              CMP     R0,#cFrame__return      ;A return frame?
2301                 BNE     %95ctrl__unwind         ;Nope -- return CC then
2302
2303                 ; --- We have a return frame ---
2304
2305                 MOV     R6,R1                   ;Look after frame address
2306                 ADD     R1,R1,#8                ;Point to formal lvalue
2307                 LDMIA   R1,{R0,R1}              ;Load that out
2308                 BL      ctrl_load               ;Get its value
2309                 LDMIA   R6,{R0,R1}              ;Load destination lvalue
2310                 STMFD   R13!,{R0-R3}            ;Store on the R13 stack
2311                 ADD     R5,R5,#1                ;Increment number so far
2312                 B       %b00                    ;Yes -- ignore it then
2313
2314                 ; --- We found what we were looking for ---
2315                 ;
2316                 ; Resolve all the value return types ---
2317
2318 90              MOV     R6,R1                   ;Look after frame address
2319                 CMP     R5,#0                   ;And value returns on stack?
2320 00              LDMNEFD R13!,{R0-R3}            ;Load lvalue/rvalue
2321                 BLNE    ctrl_store              ;Store the value away
2322                 SUBNES  R5,R5,#1                ;Decrement the counter
2323                 BNE     %b00                    ;And do this for all
2324
2325                 MOV     R1,R6                   ;Put address in R1
2326                 LDMFD   R13!,{R2-R6,R14}        ;Load registers
2327                 ORRS    PC,R14,#C_flag          ;Return success then
2328
2329                 ; --- We didn't find it :-( ---
2330
2331 95              LDMFD   R13!,{R2-R6,R14}        ;Load registers
2332                 BICS    PC,R14,#C_flag          ;Return failure
2333
2334                 LTORG
2335
2336 ;----- String manipulation --------------------------------------------------
2337
2338 ; --- ctrl__alterStr ---
2339 ;
2340 ; On entry:     R2 == rvalue of string to change
2341 ;               R3 == index to copy into
2342 ;               R4 == number of chars to copy
2343 ;               R5 = rvalue of string to copy from
2344 ;
2345 ; On exit:      --
2346
2347 ctrl__alterStr  ROUT
2348
2349                 STMFD   R13!,{R0-R5,R14}        ;Save some registers
2350                 MOV     R0,R5                   ;Remeber rvalue of string 2
2351                 LDR     R14,sail_stracc         ;Get the stracc address
2352                 LDR     R14,[R14]
2353                 ADD     R2,R14,R2,LSR #8        ;Point to the string
2354                 ADD     R2,R2,R3                ;Point into the string
2355                 ADD     R5,R14,R5,LSR #8        ;Point to second string
2356
2357                 CMP     R4,#0                   ;Anything to copy?
2358 00              LDRGTB  R14,[R5],#1             ;Load a byte
2359                 STRGTB  R14,[R2],#1             ;Store it again
2360                 SUBS    R4,R4,#1                ;Reduce the counter
2361                 BGT     %b00                    ;And keep on going
2362
2363                 MOV     R1,#vType_string        ;R0 is a string
2364                 BL      stracc_free             ;We don't need it now
2365                 LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
2366
2367 ; --- ctrl_leftS ---
2368
2369                 EXPORT  ctrl_leftS
2370 ctrl_leftS      ROUT
2371
2372                 ; --- First, read the string variable ---
2373
2374                 MOV     R0,#1                   ;Read an lvalue
2375                 BL      express_read            ;Read it then
2376                 BL      express_pop             ;Get the lvalue
2377                 BL      ctrl_load               ;Load the string into stracc
2378                 CMP     R3,#vType_string        ;Make sure we have a string
2379                 BNE     ctrl__notAString        ;And report the error
2380                 AND     R6,R2,#&FF              ;Get the length too
2381                 STMFD   R13!,{R0,R1}            ;Remember the lvalue
2382
2383                 ; --- We need a comma now ---
2384
2385                 CMP     R9,#','                 ;We need a comma now
2386                 MOVNE   R0,#err_expComma        ;If it isn't, moan
2387                 BNE     error_report
2388                 BL      getToken                ;Skip past the comma
2389
2390                 ; --- Read the number of characters ---
2391
2392                 MOV     R1,#0                   ;Read an rvalue
2393                 BL      express_read            ;Read it then
2394                 BL      express_pop             ;Pop off the value
2395                 CMP     R1,#vType_integer       ;Is it an integer?
2396                 BNE     ctrl__notAnInt          ;No -- barf then
2397                 CMP     R0,R6                   ;Reading too many?
2398                 MOVLE   R4,R0                   ;Put the number in R4
2399                 MOVGT   R4,R6                   ;Put it in range
2400                 MOV     R3,#0                   ;The index is 0
2401
2402                 ; --- Look for ')=' now ---
2403
2404                 CMP     R9,#')'                 ;We need a ')' now
2405                 MOVNE   R0,#err_expBracket      ;If it isn't, moan
2406                 BNE     error_report
2407                 BL      getToken                ;Skip past the comma
2408                 CMP     R9,#'='                 ;We need a '=' now
2409                 MOVNE   R0,#err_expEq           ;If it isn't, moan
2410                 BNE     error_report
2411                 BL      getToken                ;Skip past the comma
2412
2413                 ; --- Now we need a replacement string ---
2414
2415                 MOV     R0,#0                   ;Read another rvalue
2416                 BL      express_read            ;Read it then
2417                 BL      express_pop             ;Pop off the value
2418                 CMP     R1,#vType_string        ;Is it a string?
2419                 BNE     ctrl__notAString        ;And report the error
2420                 MOV     R5,R0                   ;Put the rvalue in R5
2421                 AND     R6,R0,#&FF              ;Get the length of that one
2422                 CMP     R4,R6                   ;Only copy enough
2423                 MOVGT   R4,R6                   ;To save embarrassment
2424
2425                 BL      ctrl__alterStr          ;Do the string transform
2426                 MOV     R3,#vType_string        ;It is a string
2427                 LDMFD   R13!,{R0,R1}            ;Get the lvalue back
2428                 BL      ctrl_store              ;Store back the new string
2429
2430                 B       interp_next             ;Do the next instruction
2431
2432                 LTORG
2433
2434 ; --- ctrl_midS ---
2435
2436                 EXPORT  ctrl_midS
2437 ctrl_midS       ROUT
2438
2439                 ; --- First, read the string variable ---
2440
2441                 MOV     R0,#1                   ;Read an lvalue
2442                 BL      express_read            ;Read it then
2443                 BL      express_pop             ;Get the lvalue
2444                 BL      ctrl_load               ;Load the string into stracc
2445                 CMP     R3,#vType_string        ;Make sure we have a string
2446                 BNE     ctrl__notAString        ;And report the error
2447                 AND     R6,R2,#&FF              ;Get the length too
2448                 STMFD   R13!,{R0,R1}            ;Remember the lvalue
2449
2450                 ; --- We need a comma now ---
2451
2452                 CMP     R9,#','                 ;We need a comma now
2453                 MOVNE   R0,#err_expComma        ;If it isn't, moan
2454                 BNE     error_report
2455                 BL      getToken                ;Skip past the comma
2456
2457                 ; --- Read the index ---
2458
2459                 MOV     R1,#0                   ;Read an rvalue
2460                 BL      express_read            ;Read it then
2461                 BL      express_pop             ;Pop off the value
2462                 CMP     R1,#vType_integer       ;Is it an integer?
2463                 BNE     ctrl__notAnInt          ;No -- barf then
2464                 SUBS    R3,R0,#1                ;Put it in R4
2465                 MOVLE   R3,#0                   ;Put it in range
2466                 CMP     R3,R6                   ;Is the index too high?
2467                 MOVGT   R3,R6                   ;Put it in range
2468                 SUB     R4,R6,R3                ;Get max to read
2469
2470                 ; --- We may have a comma now ---
2471
2472                 CMP     R9,#','                 ;We need a comma now
2473                 BNE     %10ctrl_midS            ;And jump ahead
2474
2475                 ; --- Read the number of characters ---
2476
2477                 BL      getToken                ;Skip past the comma
2478                 MOV     R1,#0                   ;Read an rvalue
2479                 BL      express_read            ;Read it then
2480                 BL      express_pop             ;Pop off the value
2481                 CMP     R1,#vType_integer       ;Is it an integer?
2482                 BNE     ctrl__notAnInt          ;No -- barf then
2483                 CMP     R0,R4                   ;Is the index too high?
2484                 MOVLE   R4,R0                   ;Put the number in R4
2485                 CMP     R4,#0                   ;Not below 0 either
2486                 MOVLT   R4,#0
2487
2488                 ; --- Look for ')=' now ---
2489
2490 10ctrl_midS     CMP     R9,#')'                 ;We need a ')' now
2491                 MOVNE   R0,#err_expBracket      ;If it isn't, moan
2492                 BNE     error_report
2493                 BL      getToken                ;Skip past the comma
2494                 CMP     R9,#'='                 ;We need a '=' now
2495                 MOVNE   R0,#err_expEq           ;If it isn't, moan
2496                 BNE     error_report
2497                 BL      getToken                ;Skip past the comma
2498
2499                 ; --- Now we need a replacement string ---
2500
2501                 MOV     R0,#0                   ;Read another rvalue
2502                 BL      express_read            ;Read it then
2503                 BL      express_pop             ;Pop off the value
2504                 CMP     R1,#vType_string        ;Is it a string?
2505                 BNE     ctrl__notAString        ;And report the error
2506                 MOV     R5,R0                   ;Put the rvalue in R5
2507                 AND     R6,R0,#&FF              ;Get the length of that one
2508                 CMP     R4,R6                   ;Only copy enough
2509                 MOVGT   R4,R6                   ;To save embarrassment
2510
2511                 BL      ctrl__alterStr          ;Do the string transform
2512                 MOV     R3,#vType_string        ;It is a string
2513                 LDMFD   R13!,{R0,R1}            ;Get the lvalue back
2514                 BL      ctrl_store              ;Store back the new string
2515
2516                 B       interp_next             ;Do the next instruction
2517
2518                 LTORG
2519
2520 ; --- ctrl_rightS ---
2521
2522                 EXPORT  ctrl_rightS
2523 ctrl_rightS     ROUT
2524
2525                 ; --- First, read the string variable ---
2526
2527                 MOV     R0,#1                   ;Read an lvalue
2528                 BL      express_read            ;Read it then
2529                 BL      express_pop             ;Get the lvalue
2530                 BL      ctrl_load               ;Load the string into stracc
2531                 CMP     R3,#vType_string        ;Make sure we have a string
2532                 BNE     ctrl__notAString        ;And report the error
2533                 AND     R6,R2,#&FF              ;Get the length too
2534                 STMFD   R13!,{R0,R1}            ;Remember the lvalue
2535
2536                 ; --- We need a comma now ---
2537
2538                 CMP     R9,#','                 ;We need a comma now
2539                 MOVNE   R0,#err_expComma        ;If it isn't, moan
2540                 BNE     error_report
2541                 BL      getToken                ;Skip past the comma
2542
2543                 ; --- Read the number of characters ---
2544
2545                 MOV     R1,#0                   ;Read an rvalue
2546                 BL      express_read            ;Read it then
2547                 BL      express_pop             ;Pop off the value
2548                 CMP     R1,#vType_integer       ;Is it an integer?
2549                 BNE     ctrl__notAnInt          ;No -- barf then
2550                 CMP     R0,R6                   ;Reading too many?
2551                 MOVLE   R4,R0                   ;Put the number in R4
2552                 MOVGT   R4,R6                   ;Put it in range
2553                 SUBS    R3,R6,R4                ;Work out the index
2554
2555                 ; --- Look for ')=' now ---
2556
2557                 CMP     R9,#')'                 ;We need a ')' now
2558                 MOVNE   R0,#err_expBracket      ;If it isn't, moan
2559                 BNE     error_report
2560                 BL      getToken                ;Skip past the comma
2561                 CMP     R9,#'='                 ;We need a '=' now
2562                 MOVNE   R0,#err_expEq           ;If it isn't, moan
2563                 BNE     error_report
2564                 BL      getToken                ;Skip past the comma
2565
2566                 ; --- Now we need a replacement string ---
2567
2568                 MOV     R0,#0                   ;Read another rvalue
2569                 BL      express_read            ;Read it then
2570                 BL      express_pop             ;Pop off the value
2571                 CMP     R1,#vType_string        ;Is it a string?
2572                 BNE     ctrl__notAString        ;And report the error
2573                 MOV     R5,R0                   ;Put the rvalue in R5
2574                 AND     R0,R0,#&FF              ;Get the length of that one
2575                 CMP     R4,R0                   ;Only copy enough
2576                 MOVGT   R4,R0                   ;To save embarrassment
2577                 SUBGT   R3,R6,R4
2578
2579                 BL      ctrl__alterStr          ;Do the string transform
2580                 MOV     R3,#vType_string        ;It is a string
2581                 LDMFD   R13!,{R0,R1}            ;Get the lvalue back
2582                 BL      ctrl_store              ;Store back the new string
2583
2584                 B       interp_next             ;Do the next instruction
2585
2586                 LTORG
2587
2588 ;----- Arrays ---------------------------------------------------------------
2589
2590 ; --- ctrl_dim ---
2591
2592                 EXPORT  ctrl_dim
2593 ctrl_dim        ROUT
2594
2595                 ; --- Stash current position ---
2596
2597                 LDR     R6,sail_line            ;Find the current line
2598                 STMFD   R13!,{R6-R10}           ;Save current position info
2599
2600                 ; --- Now try reading an identifier ---
2601
2602                 ADR     R1,sail_misc            ;Point to a buffer
2603                 MOV     R2,#vType_dimInt        ;Currently it's an int array
2604
2605                 SUBS    R14,R9,#'_'             ;Allow strange ident chars
2606                 SUBNE   R14,R9,#'A'             ;Check for uppercase letters
2607                 CMP     R14,#26                 ;In range?
2608                 SUBCS   R14,R9,#'a'             ;Check for lowercase letters
2609                 CMPCS   R14,#26                 ;In range?
2610                 MOVCS   R0,#err_badDim          ;No -- get an error
2611                 BCS     error_report            ;And kill the program
2612
2613 00              STRB    R9,[R1],#1              ;Store the character away
2614                 BL      getToken                ;Get another token
2615                 SUBS    R14,R9,#'_'             ;Allow strange ident chars
2616                 SUBNE   R14,R9,#'A'             ;Check for uppercase letters
2617                 CMP     R14,#26                 ;In range?
2618                 SUBCS   R14,R9,#'a'             ;Check for lowercase letters
2619                 CMPCS   R14,#26                 ;In range?
2620                 SUBCS   R14,R9,#'0'             ;Check for digits too now
2621                 CMPCS   R14,#10                 ;In range?
2622                 BCC     %b00                    ;We're OK here -- loop
2623
2624                 ; --- Found something which stopped us ---
2625
2626                 CMP     R9,#'$'                 ;Is it a dollar sign?
2627                 MOVEQ   R2,#vType_dimStr        ;It's a string array now
2628                 CMPNE   R9,#'%'                 ;Or a percentage?
2629                 STREQB  R9,[R1],#1              ;Yes -- store it then
2630                 CMPNE   R9,#' '                 ;Just check for a space
2631                 BLEQ    getToken                ;Valid terminator -- get tok
2632
2633                 ; --- Now see if this is an array ---
2634
2635                 CMP     R9,#'('                 ;Defining an array here?
2636                 BNE     %50ctrl_dim             ;No -- allocate a block then
2637                 ADD     R13,R13,#20             ;Lose positioning info
2638                 MOV     R14,#0                  ;Terminate the identifier
2639                 STRB    R14,[R1],#1             ;Store zero on the end
2640                 BL      getToken                ;Get the next token
2641
2642                 ; --- Ensure that the name isn't already used ---
2643
2644                 MOV     R0,R2                   ;Get the array type
2645                 ADR     R1,sail_misc            ;Point to the name
2646                 BL      tree_find               ;Is it there already?
2647                 MOVCS   R0,#err_reDim           ;Yes -- moan then
2648                 BCS     error_report            ;And kill things off
2649
2650                 ; --- Stuff the string on stracc ---
2651
2652                 BL      stracc_ensure           ;Make enough space for it
2653                 ADR     R3,sail_misc            ;Point to the misc buffer
2654 00              LDRB    R14,[R3],#1             ;Load the byte out
2655                 STRB    R14,[R0],#1             ;Store in the buffer
2656                 ADD     R1,R1,#1                ;And increment the length
2657                 CMP     R14,#0                  ;Finished yet?
2658                 BNE     %b00                    ;No -- then loop round
2659                 MOV     R0,R1                   ;Get the rvalue I made
2660                 BL      stracc_added            ;I've added this string
2661                 MOV     R5,R1                   ;Look after this value
2662
2663                 ; --- Now read the subscripts ---
2664                 ;
2665                 ; We use the stack to keep track of them all.  This is
2666                 ; fairly crufty, but I don't care.
2667
2668                 MOV     R3,#0                   ;No subscripts so far
2669                 MOV     R4,#1                   ;Number of items we need
2670 00              MOV     R0,#0                   ;Read an rvalue
2671                 BL      express_read            ;Evaluate an expression
2672                 BL      express_pop             ;Pop the rvalue
2673                 CMP     R1,#vType_integer       ;Ensure it's an integer
2674                 MOVNE   R0,#err_numNeeded       ;No -- moan then
2675                 BNE     error_report            ;And stop the program
2676                 ADD     R0,R0,#1                ;BASIC subscripts are odd
2677                 STMFD   R13!,{R0}               ;Stash the subscript
2678                 ADD     R3,R3,#1                ;Increment the counter
2679                 MUL     R4,R0,R4                ;Update the size we nee
2680                 CMP     R9,#','                 ;Is this a comma?
2681                 BLEQ    getToken                ;Yes -- get a token
2682                 BEQ     %b00                    ;And read another subscript
2683                 CMP     R9,#')'                 ;Well, this must be next
2684                 MOVNE   R0,#err_dimKet          ;No -- well, get an error
2685                 BNE     error_report            ;And die horridly
2686                 BL      getToken                ;Get another token
2687
2688                 ; --- We now have the subscripts on the stack ---
2689
2690                 LDR     R14,sail_stracc         ;Find the stracc anchor
2691                 LDR     R14,[R14]               ;Bop WimpExtension for fun
2692                 ADD     R1,R14,R5,LSR #8        ;Find the name base
2693                 MOV     R0,R2                   ;Get the variable type
2694                 MOV     R2,R13                  ;Point to subscripts
2695                 BL      var_create              ;Create the array
2696                 MOV     R0,R5                   ;Get the rvalue again
2697                 BL      stracc_free             ;And release the memory
2698                 ADD     R13,R13,R3,LSL #2       ;Restore the stack pointer
2699                 B       %80ctrl_dim             ;And possibly go round again
2700
2701                 ; --- Allocate a block of memory ---
2702
2703 50ctrl_dim      LDMFD   R13!,{R6-R10}           ;Restore positioning info
2704                 STR     R6,sail_line            ;Restore the line number
2705                 MOV     R0,#1                   ;Read an lvalue
2706                 BL      express_read            ;Read that then
2707                 MOV     R0,#0                   ;Read an rvalue
2708                 BL      express_read            ;And read that too
2709                 BL      express_pop             ;Get the block size
2710                 CMP     R1,#vType_integer       ;Ensure it's an integer
2711                 MOVNE   R0,#err_numNeeded       ;No -- get the error then
2712                 BNE     error_report            ;And moan at the user
2713                 ADD     R3,R0,#8                ;Add a link word, 1 byte and
2714                 BIC     R3,R3,#3                ;...word align too
2715                 MOV     R0,#6                   ;Claim some memory
2716                 SWI     XOS_Module              ;From the RMA (bletch)
2717                 MOVVS   R0,#err_noMem           ;If it failed assume no mem
2718                 BVS     error_report            ;So deal appropriately
2719                 LDR     R14,sail_rmaList                ;Load RMA list head
2720                 STR     R2,sail_rmaList         ;Store this block in there
2721                 STR     R14,[R2],#4             ;Stuff the old link away
2722                 BL      express_pop             ;Pop the lvalue
2723                 MOV     R3,#vType_integer       ;Pointer is an integer
2724                 BL      ctrl_store              ;Store it away
2725
2726                 ; --- Do more DIMs if wee need to ---
2727
2728 80ctrl_dim      CMP     R9,#','                 ;Is there a comma now?
2729                 BLEQ    getToken                ;Yes -- get the next token
2730                 BEQ     ctrl_dim                ;Yes -- do another dim then
2731
2732                 B       interp_next             ;Do another instruction
2733
2734                 LTORG
2735
2736 ;----- Other useful routines ------------------------------------------------
2737
2738 ; --- ctrl_copyString ---
2739 ;
2740 ; On entry:     R0 == buffer to copy string to
2741 ;               R1 == point to the string
2742 ;               R2 == length of string to copy
2743 ;
2744 ; On exit:      --
2745 ;
2746 ; Use:          Copies the string into the buffer.
2747
2748                 EXPORT  ctrl_copyString
2749 ctrl_copyString ROUT
2750
2751                 STMFD   R13!,{R0-R2,R14}        ;Stack registers
2752                 CMP     R2,#0                   ;Is this a short string?
2753 00              LDRGTB  R14,[R1],#1             ;Load a character
2754                 STRGTB  R14,[R0],#1             ;And then store it
2755                 SUBS    R2,R2,#1                ;Reduce the count
2756                 BGT     %b00                    ;And keep on goin'
2757                 MOV     R14,#0                  ;Get a terminator
2758                 STRB    R14,[R0],#1             ;Store the byte and return
2759                 LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
2760
2761                 LTORG
2762
2763 ; --- ctrl__notAnInt ---
2764 ;
2765 ; On entry:     --
2766 ;
2767 ; On exit:      --
2768 ;
2769 ; Use:          Moans because something isn't an integer.
2770
2771 ctrl__notAnInt  ROUT
2772
2773                 MOV     R0,#err_numNeeded
2774                 B       error_report
2775
2776                 LTORG
2777
2778 ; --- ctrl__notAString ---
2779 ;
2780 ; On entry:     --
2781 ;
2782 ; On exit:      --
2783 ;
2784 ; Use:          Moans because something isn't a string.
2785
2786 ctrl__notAString ROUT
2787
2788                 MOV     R0,#err_strNeeded
2789                 B       error_report
2790
2791                 LTORG
2792
2793 ; --- ctrl__findFrame ---
2794 ;
2795 ; On entry:     R0 == frame type
2796 ;
2797 ; On exit:      R0 == frame type we stopped at
2798 ;               R1 == pointer to base of frame
2799 ;               CS if frame type matched, else CC
2800 ;
2801 ; Use:          Finds a frame with the given type.  It pops frames from the
2802 ;               exec stack until it finds either a frame which matches the
2803 ;               type in R0 or a routine frame.  The frame which stopped the
2804 ;               loop is *not* popped.
2805
2806 ctrl__findFrame ROUT
2807
2808                 ORR     R14,R14,#C_flag         ;Assume a match -- be happy
2809                 STMFD   R13!,{R2,R14}           ;Save some registers
2810                 MOV     R2,R0                   ;Look after the frame type
2811 10              BL      ctrl__peekFrame         ;Look at the top frame
2812                 CMP     R0,R2                   ;Is this a match?
2813                 LDMEQFD R13!,{R2,PC}^           ;Yes -- unstack and return
2814                 CMP     R0,#cFrame__routine     ;Is this a routine frame?
2815                 BLCC    ctrl__popFrame          ;No -- remove it then
2816                 BCC     %10ctrl__findFrame      ;And keep on going
2817                 LDMFD   R13!,{R2,R14}           ;Unstack registers
2818                 BICS    PC,R14,#C_flag          ;And return with C clear
2819
2820                 LTORG
2821
2822 ; --- ctrl_store ---
2823 ;
2824 ; On entry:     R0,R1 == lvalue to store in
2825 ;               R2,R3 == rvalue to write
2826 ;
2827 ;               If bit 31 of R1 is set, then for strings only, the old
2828 ;               string is NOT removed from the stracc. This is
2829 ;               so that variables can be restored after a procedure.
2830 ;
2831 ; On exit:      --
2832 ;
2833 ; Use:          Stores an rvalue into an lvalue.
2834
2835                 EXPORT  ctrl_store
2836 ctrl_store      ROUT
2837
2838                 ; --- First, see what we're storing in ---
2839
2840                 STMFD   R13!,{R14}              ;Save a register
2841                 BIC     R14,R1,#(1<<31)         ;Clear the weird bit
2842                 SUB     R14,R14,#vType_lvInt    ;Get the lvalue index thing
2843                 CMP     R14,#vType_lvStrArr-vType_lvInt+1
2844                 ADDCC   PC,PC,R14,LSL #2        ;It's OK, dispatch then
2845                 B       %00ctrl_store           ;Righty ho, on we go
2846
2847                 B       ctrl__strInt            ;Store in an integer var
2848                 B       ctrl__strStr            ;Store in a string var
2849                 B       ctrl__strWord           ;Store in a memory word
2850                 B       ctrl__strByte           ;Store in a memory byte
2851                 B       ctrl__strBytes          ;Store in a memory string
2852                 B       ctrl__strIntArr         ;Store in a whole int array
2853                 B       ctrl__strStrArr         ;Store in a whole str array
2854
2855 00ctrl_store    MOV     R0,#err_erk             ;This should never happen...
2856                 B       error_report            ;Since we always get lvalues
2857
2858                 ; --- Store in an integer variable ---
2859
2860 ctrl__strInt    CMP     R3,#vType_integer       ;Make sure we're storing int
2861                 LDREQ   R14,sail_varTree                ;Find the tree base
2862                 LDREQ   R14,[R14]               ;Why is WimpExt so odd?
2863                 STREQ   R2,[R14,R0]             ;Store the value in node
2864                 LDMEQFD R13!,{PC}^              ;And return to caller
2865                 B       ctrl__notAnInt
2866
2867                 ; --- Store in a memory word somewhere ---
2868
2869 ctrl__strWord   CMP     R3,#vType_integer       ;Make sure we're storing int
2870                 STREQ   R2,[R0,#0]              ;Save the word away
2871                 LDMEQFD R13!,{PC}^              ;And return to caller
2872                 B       ctrl__notAnInt
2873
2874                 ; --- Store in a byte somewhere ---
2875
2876 ctrl__strByte   CMP     R3,#vType_integer       ;Make sure we're storing int
2877                 STREQB  R2,[R0,#0]              ;Save the byte away
2878                 LDMEQFD R13!,{PC}^              ;And return to caller
2879                 B       ctrl__notAnInt
2880
2881                 ; --- Store in a string variable ---
2882
2883 ctrl__strStr    CMP     R3,#vType_string        ;Make sure we've got a string
2884                 BNE     ctrl__notAString        ;No -- complain then
2885
2886                 ; --- Now do some messing about ---
2887
2888                 STMFD   R13!,{R0-R5}            ;Store some registers
2889                 MOV     R5,R1                   ;Look after our flag bit
2890
2891                 LDR     R4,sail_varTree         ;Find the tree base
2892                 LDR     R4,[R4]                 ;Who designed this heap?
2893                 ADD     R4,R4,R0                ;Work out the node address
2894                 LDR     R0,[R4,#0]              ;Load the old string offset
2895                 BL      strBucket_free          ;Don't want it any more
2896
2897                 AND     R0,R2,#&FF              ;Get the string's length
2898                 BL      strBucket_alloc         ;Get a new string entry
2899                 STR     R1,[R4,#0]              ;Tuck that away nicely
2900
2901                 LDR     R4,sail_stracc          ;Find string accumulator
2902                 LDR     R4,[R4]                 ;It must be one of those days
2903                 ADD     R4,R4,R2,LSR #8         ;Work out string address
2904                 ANDS    R3,R2,#&FF              ;Get the length
2905 00              LDRNEB  R14,[R4],#1             ;Load a string byte
2906                 STRNEB  R14,[R0],#1             ;Save it in the bucket
2907                 SUBNES  R3,R3,#1                ;Decrement the length count
2908                 BNE     %b00                    ;And loop back again
2909
2910                 TST     R5,#(1<<31)             ;Do we remove from bucket?
2911                 MOV     R0,R2                   ;Get the offset
2912                 BLEQ    stracc_free             ;Free it nicely
2913
2914                 LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
2915
2916                 LTORG
2917
2918                 ; --- Store a string in memory ---
2919
2920 ctrl__strBytes  CMP     R3,#vType_string        ;Make sure we've got a string
2921                 BNE     ctrl__notAString        ;No -- complain then
2922
2923                 STMFD   R13!,{R0-R4}            ;Store some registers
2924                 LDR     R4,sail_stracc          ;Find string accumulator
2925                 LDR     R4,[R4]                 ;It must be one of those days
2926                 ADD     R4,R4,R2,LSR #8         ;Work out string address
2927                 ANDS    R3,R2,#&FF              ;Get the length
2928 00              LDRNEB  R14,[R4],#1             ;Load a string byte
2929                 STRNEB  R14,[R0],#1             ;Save it in the bucket
2930                 SUBNES  R3,R3,#1                ;Decrement the length count
2931                 BNE     %b00                    ;And loop back again
2932                 MOV     R14,#13                 ;Get the terminator
2933                 STRB    R14,[R0],#1             ;And store that too
2934
2935                 TST     R1,#(1<<31)             ;Do we remove from bucket?
2936                 MOV     R0,R2                   ;Put offset in R1
2937                 BLEQ    stracc_free             ;Free it nicely
2938                 LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
2939
2940                 LTORG
2941
2942 ctrl__strIntArr
2943 ctrl__strStrArr
2944
2945                 MOV     R0,#err_arrayBad        ;Point to the error message
2946                 B       error_report            ;And report the message
2947
2948 ; --- ctrl_load ---
2949 ;
2950 ; On entry:     R0,R1 == lvalue to read
2951 ;
2952 ; On exit:      R2,R3 == rvalue read from lvalue
2953 ;
2954 ; Use:          Loads the current value of the given lvalue.
2955
2956                 EXPORT  ctrl_load
2957 ctrl_load       ROUT
2958
2959                 ; --- First, see what we're storing in ---
2960
2961                 SUB     R2,R1,#vType_lvInt      ;Get the lvalue index thing
2962                 CMP     R2,#vType_lvStrArr-vType_lvInt+1
2963                 ADDCC   PC,PC,R2,LSL #2         ;It's OK, dispatch then
2964                 B       %00ctrl_load            ;Righty ho, on we go
2965
2966                 B       ctrl__ldInt             ;Store in an integer var
2967                 B       ctrl__ldStr             ;Store in a string var
2968                 B       ctrl__ldWord            ;Store in a memory word
2969                 B       ctrl__ldByte            ;Store in a memory byte
2970                 B       ctrl__ldBytes           ;Store in a memory string
2971                 B       ctrl__ldIntArr          ;Store in a whole int array
2972                 B       ctrl__ldStrArr          ;Store in a whole str array
2973
2974 00ctrl_load     MOV     R0,#err_erk             ;This should never happen...
2975                 B       error_report            ;Since we always get lvalues
2976
2977                 ; --- Load an integer variable ---
2978
2979 ctrl__ldInt     MOV     R3,#vType_integer       ;We're loading an integer
2980                 LDR     R2,sail_varTree         ;Find the tree base
2981                 LDR     R2,[R2]                 ;Why is WimpExt so odd?
2982                 LDR     R2,[R2,R0]              ;Load the value out
2983                 MOVS    PC,R14                  ;Return to caller
2984
2985                 ; --- Load from a memory word somewhere ---
2986
2987 ctrl__ldWord    MOV     R3,#vType_integer       ;We're loading an integer
2988                 LDR     R2,[R0,#0]              ;Load the word
2989                 MOVS    PC,R14                  ;And return to caller
2990
2991                 ; --- Load from a byte somewhere ---
2992
2993 ctrl__ldByte    MOV     R3,#vType_integer       ;We're loading an integer
2994                 LDRB    R2,[R0,#0]              ;Load the byte
2995                 MOVS    PC,R14                  ;And return to caller
2996
2997                 ; --- Load a string into stracc ---
2998
2999 ctrl__ldStr     STMFD   R13!,{R0,R1,R4,R14}     ;Save some registers
3000
3001                 LDR     R14,sail_varTree                ;Find the variable tree
3002                 LDR     R14,[R14]               ;Irate?  Me?
3003                 ADD     R3,R14,R0               ;Find the actual node
3004                 BL      stracc_ensure           ;Make sure there's enough
3005
3006                 LDR     R3,[R3,#0]              ;Find the bucket entry
3007                 CMP     R3,#0                   ;Is there a string here
3008                 MOVEQ   R2,R1                   ;Yes -- return 0 length
3009                 BEQ     %f10                    ;...and branch ahead
3010                 LDR     R14,sail_bucket         ;Find the bucket anchor
3011                 LDR     R14,[R14]               ;I hate this!  I hate it!
3012                 ADD     R3,R14,R3               ;Find the actual string
3013
3014                 LDRB    R4,[R3,#-1]             ;Load the string length
3015                 ORR     R2,R4,R1                ;Build the rvalue ready
3016
3017 00              LDRB    R14,[R3],#1             ;Load a byte from string
3018                 STRB    R14,[R0],#1             ;And store byte in stracc
3019                 SUBS    R4,R4,#1                ;Decrement the length
3020                 BNE     %b00
3021
3022 10              MOV     R3,#vType_string        ;This is a string
3023                 MOV     R0,R2                   ;Damn -- we need it in R0,R1
3024                 BL      stracc_added            ;Tell stracc about string
3025                 LDMFD   R13!,{R0,R1,R4,PC}^     ;And return to caller
3026
3027                 ; --- Load a string from memory ---
3028
3029 ctrl__ldBytes   STMFD   R13!,{R0,R1,R4,R14}     ;Save some registers
3030
3031                 MOV     R3,R0                   ;Remember string pointer
3032                 BL      stracc_ensure           ;Make sure there's enough
3033
3034                 MOV     R4,#0                   ;Make the length 0
3035 00              LDRB    R14,[R3],#1             ;Load a byte from string
3036                 CMP     R14,#13                 ;Is it the terminator
3037                 BEQ     %f10                    ;Yes -- jump ahead
3038                 STRB    R14,[R0],#1             ;And store byte in stracc
3039                 ADD     R4,R4,#1                ;Decrement the length
3040                 CMP     R4,#255                 ;Are we at the limit
3041                 BLT     %b00                    ;No -- go round for more
3042
3043 10              MOV     R3,#vType_string        ;This is a string
3044                 ORR     R2,R1,R4                ;Get the rvalue
3045                 MOV     R0,R2                   ;Damn -- we need it in R0,R1
3046                 BL      stracc_added            ;Tell stracc about string
3047                 LDMFD   R13!,{R0,R1,R4,PC}^     ;And return to caller
3048
3049                 LTORG
3050
3051 ctrl__ldIntArr
3052 ctrl__ldStrArr
3053                 MOV     R0,#err_arrayBad        ;Get the error number
3054                 B       error_report            ;And report the error
3055
3056 ; --- ctrl_compare ---
3057 ;
3058 ; On entry:     R0,R1 == thing to compare
3059 ;               R2,R3 == thing to compare the other thing with
3060 ;
3061 ; On exit:      The flags indicate the result of the comparison
3062 ;
3063 ; Use:          Compares two things.  Note that R3 contains the dominant
3064 ;               type. If it is comparing strings, the string in R0,R1
3065 ;               will be removed from stracc.
3066
3067                 EXPORT  ctrl_compare
3068 ctrl_compare    ROUT
3069
3070                 CMP     R3,#vType_integer       ;Is it an integer?
3071                 BNE     %10ctrl_compare         ;No -- jump ahead
3072
3073                 ; --- We are comparing integers ---
3074
3075                 CMP     R1,#vType_integer       ;Make sure we have an int
3076                 BNE     ctrl__notAnInt          ;No -- barf then
3077                 CMP     R0,R2                   ;Do the comparison
3078                 MOV     PC,R14                  ;And return to caller
3079
3080                 ; --- Try to compare strings ---
3081
3082 10ctrl_compare  CMP     R3,#vType_string        ;Is it a string?
3083                 MOVNE   R0,#err_arrayBad        ;No -- get the error number
3084                 BNE     error_report            ;...and report the error
3085                 CMP     R1,#vType_string        ;Make sure other is string
3086                 MOVNE   R0,#err_strNeeded       ;Nope -- complain
3087                 BNE     error_report
3088
3089                 STMFD   R13!,{R0-R5,R14}        ;Stack some registers
3090                 AND     R1,R0,#&FF              ;Get length of first string
3091                 AND     R3,R2,#&FF              ;And of the second one
3092                 CMP     R3,R1                   ;Find the lowest
3093                 EORLT   R1,R1,R3                ;And put lowest in R1
3094                 EORLT   R3,R1,R3
3095                 EORLT   R1,R3,R1
3096                 MOVS    R5,R1                   ;How long is it?
3097                 BEQ     %50ctrl_compare         ;0 length -- jump ahead
3098
3099                 LDR     R4,sail_stracc          ;Find string accumulator
3100                 LDR     R4,[R4]                 ;It must be one of those days
3101                 ADD     R2,R4,R2,LSR #8         ;of both strings
3102                 ADD     R0,R4,R0,LSR #8         ;Work out string address
3103 00              LDRB    R14,[R0],#1             ;Load a string byte
3104                 LDRB    R4,[R2],#1              ;from both strings
3105                 CMP     R14,R4                  ;Are they the same?
3106                 BNE     %19ctrl_compare         ;Nope -- return failure
3107                 SUBS    R5,R5,#1                ;Decrement the length count
3108                 BNE     %b00                    ;And loop back again
3109                 CMP     R1,R3                   ;Compare lengths then
3110
3111 19ctrl_compare  LDR     R0,[R13,#0]             ;Load an rvalue
3112                 BL      stracc_free             ;Free it then
3113                 LDMFD   R13!,{R0-R5,PC}         ;Load back registers
3114
3115 50ctrl_compare  CMP     R1,R3                   ;Make another comaprison
3116                 B       %19ctrl_compare         ;And return
3117
3118                 LTORG
3119
3120 ;----- Stack frames ---------------------------------------------------------
3121
3122 ; --- Frame types ---
3123
3124                 ^       0
3125
3126 cFrame__loop    #       0
3127
3128 cFrame__for     #       1
3129 cFrame__while   #       1
3130 cFrame__repeat  #       1
3131
3132 cFrame__routine #       0
3133
3134 cFrame__gosub   #       1
3135 cFrame__local   #       1
3136 cFrame__return  #       1
3137 cFrame__proc    #       1
3138 cFrame__fn      #       1
3139 cFrame__dead    #       1
3140
3141 ; --- Frame formats ---
3142
3143                 ; --- FOR ---
3144
3145                 ^       0
3146 cFor__lval      #       8
3147 cFor__end       #       4
3148 cFor__step      #       4
3149 cFor__resume    #       8
3150 cFor__size      #       0
3151
3152                 ; --- PROC ---
3153
3154                 ^       0
3155 cProc__resume   #       8
3156 cProc__anchor   #       4
3157 cProc__stracc   #       4
3158 cProc__size     #       0
3159
3160                 ; --- FN ---
3161
3162                 ^       0
3163 cFn__resume     #       8
3164 cFn__flags      #       4
3165 cFn__anchor     #       4
3166 cFn__stracc     #       4
3167 cFn__stack      #       32
3168 cFn__size       #       0
3169
3170                 ; --- REPEAT ---
3171
3172                 ^       0
3173 cRepeat__resume #       8
3174 cRepeat__size   #       0
3175
3176                 ; --- WHILE ---
3177
3178                 ^       0
3179 cWhile__resume  #       8
3180 cWhile__size    #       0
3181
3182                 ; --- GOSUB ---
3183
3184                 ^       0
3185 cGosub__resume  #       8
3186 cGosub__size    #       0
3187
3188                 ; --- LOCAL ---
3189
3190                 ^       0
3191 cLocal__lval    #       8
3192 cLocal__rval    #       8
3193 cLocal__size    #       0
3194
3195                 ; --- RETURN ---
3196
3197                 ^       0
3198 cReturn__lvalA  #       8
3199 cReturn__lvalF  #       8
3200 cReturn__size   #       0
3201
3202                 ; --- DEAD ---
3203
3204                 ^       0
3205 cDead__lval     #       8
3206 cDead__rval     #       8
3207 cDead__size     #       0
3208
3209 ;----- That's all, folks ----------------------------------------------------
3210
3211                 END