;;***Main.asm
;#dialect=RASM

;Current progress:
;(Mostly) fully reverse engineered as far as **TK

;'Unassembled'[1] Amstrad CPC6128 BASIC 1.1 Source Code

;[1] 'Unassembled' meaning that this code can be modified and reassembled.
;(As far as I can tell) all links etc have been converted to labels etc in
;such a way that the code can be assembled at a different target address
;and still function correctly (excepting code which must run at a specific
;address).

;Based on the riginal commented disassembly at:
; http://cpctech.cpc-live.com/docs/basic.asm

;There are two versions of this file: a single monolithic version and
;one which has been broken out into separate 'includes'. The latter may
;prove better for modification, assembly and re-use. The former for 
;exploration and reverse engineering.

;For more details see: https://github.com/Bread80/Amstrad-CPC-BASIC-Source
;and http://Bread80.com


;;***Initialisation.asm
;;=======
;;BASIC 1.1

c000
;ROM header
defb $80		;; foreground rom
defb $01        ;mark
defb $02        ;version
defb $00        ;modification

defw $c040		;; name table

;On entry
;DE = first byte of available memory
;HL=last byte of memory not used by BASIC
;BC=last byte of memory not used by firmware

c006 3100c0    ld      sp,$c000         ;##LIT##
c009 cdcbbc    call    $bccb			; firmware function: kl rom walk

c00c cd3ff5    call    $f53f
c00f da0000    jp      c,$0000			;; reboot if not enough memory

c012 af        xor     a
c013 3200ac    ld      ($ac00),a

c016 2133c0    ld      hl,$c033			; startup message "BASIC 1.1"
c019 cd7dc3    call    $c37d

c01c cdaade    call    $deaa
c01f cd37cb    call    $cb37
c022 cdbbbd    call    $bdbb			; maths function - initialise random number generator?
c025 cddec0    call    $c0de
c028 cd45c1    call    $c145
c02b 11f000    ld      de,$00f0			; DE = 240
c02e cde9f7    call    $f7e9			; symbol after 240
c031 1825      jr      $c058            

;;= version string message

c033 defb " BASIC 1.1",10,10,0

;;=rsx name table
c040 defb "BASI","C"+$80			;; |BASIC
c045 defb 0                         ;end of rsx name table




;;***ProgramEntry.asm
;;<< PROGRAM ENTRY ROUTINES
;;< REPL loop, EDIT, AUTO, NEW, CLEAR (INPUT)
;;========================================================================
;; command EDIT
;EDIT <line number>
;Edit the given line number

c046 cd48cf    call    $cf48
c049 c0        ret     nz

c04a 3100c0    ld      sp,$c000         ;##LIT##
c04d cd5ce8    call    $e85c
c050 cd54e2    call    $e254            ;convert line to string (detokenise)

c053 cd01cb    call    $cb01			; edit
c056 385f      jr      c,$c0b7          ; (+$5f)

;;========================================
;;REPL Read Eval Print Loop
;;REPL = Read, Evaluate, Print, Loop
;;This is the command line!
c058 3100c0    ld      sp,$c000         ;##LIT##
c05b cd66c1    call    $c166
c05e cdb5de    call    $deb5
c061 dcb6bc    call    c,$bcb6			; firmware function: sound hold
c064 cdd0c4    call    $c4d0			; ON BREAK CONT

c067 cdd0c3    call    $c3d0
c06a 3a2cae    ld      a,($ae2c)		; program protection flag
;; do a new
c06d b7        or      a
c06e c445c1    call    nz,$c145

c071 3a90ad    ld      a,($ad90)		;; error number
c074 d602      sub     $02
c076 2009      jr      nz,$c081         ; (+$09)
c078 3290ad    ld      ($ad90),a

c07b cdaacb    call    $cbaa
c07e eb        ex      de,hl
c07f 38c9      jr      c,$c04a          ; (-$37)

;;=display ready message
c081 21d7c0    ld      hl,$c0d7			; "Ready" message
c084 cd8bc3    call    $c38b			;; display 0 terminated string

;;-----------------------------------------------------------------
;;=REPL input loop
c087 cdaade    call    $deaa
c08a 3a01ac    ld      a,($ac01)        ; AUTO active?
c08d b7        or      a
c08e 281f      jr      z,$c0af          ; (+$1f)

;;next AUTO line number
c090 cd0dc1    call    $c10d
c093 30c3      jr      nc,$c058         ; (-$3d)

c095 cd4dde    call    $de4d ; skip space, lf or tab	
c098 cdcfee    call    $eecf
c09b 300a      jr      nc,$c0a7         

c09d cd4dde    call    $de4d ; skip space, lf or tab	
c0a0 b7        or      a
c0a1 37        scf     
c0a2 cc64e8    call    z,$e864
c0a5 30e3      jr      nc,$c08a         ; (-$1d)

;;=REPL no line number
c0a7 d4dec0    call    nc,$c0de
c0aa 218aac    ld      hl,$ac8a
c0ad 1808      jr      $c0b7            ; (+$08)

;;-----------------------------------------------------------------
;;=REPL get input
c0af cdf9ca    call    $caf9			; edit
c0b2 30fb      jr      nc,$c0af         ; (-$05)
c0b4 cd98c3    call    $c398      ;; new text line

;;=REPL execute or insert in program
c0b7 cd4dde    call    $de4d ; skip space, lf or tab
c0ba b7        or      a
c0bb 28ca      jr      z,$c087          ; (-$36) empty buffer - loop
c0bd cdcfee    call    $eecf
c0c0 300b      jr      nc,$c0cd         ; (+$0b) no line number so execute
c0c2 cd4dfb    call    $fb4d
c0c5 cda5e7    call    $e7a5
c0c8 cd8fc1    call    $c18f
c0cb 18ba      jr      $c087            ; (-$46)

;;+-----------------------------------------------------------------
;;REPL tokenise and execute
c0cd cda4df    call    $dfa4
c0d0 cdd3c4    call    $c4d3			; ON BREAK STOP
c0d3 2b        dec     hl
c0d4 c360de    jp      $de60

;;========================================================================
;; ready message
c0d7 defb "Ready",10,0

;;========================================================================
;; cancel AUTO mode
c0de af        xor     a
c0df 1805      jr      $c0e6            ; (+$05)

;;+------------------
;; set AUTO mode
c0e1 2202ac    ld      ($ac02),hl       ;current auto mode
c0e4 3eff      ld      a,$ff            ;auto mode active

;;=set auto mode
;A=ff=active, A=0=inactive
c0e6 3201ac    ld      ($ac01),a        ;current auto mode
c0e9 c9        ret   
  
 
;;==================================================================
;; command AUTO
;AUTO [<line number>],[<increment>]
;Generate line numbers. Values default to 10

c0ea 110a00    ld      de,$000a			; default line number is 10
c0ed 2802      jr      z,$c0f1          ;no parameters

c0ef fe2c      cp      $2c				; ',' no first parameter
c0f1 c448cf    call    nz,$cf48         ;read initial line number, if given
c0f4 d5        push    de
c0f5 110a00    ld      de,$000a			; default increment is 10
c0f8 cd41de    call    $de41
c0fb dc48cf    call    c,$cf48          ; read increment if given
c0fe cd37de    call    $de37
c101 eb        ex      de,hl
c102 2204ac    ld      ($ac04),hl       ;AUTO increment step
c105 e1        pop     hl
c106 cde1c0    call    $c0e1            ;store line number to create or edit
c109 c1        pop     bc
c10a c387c0    jp      $c087

;;=-----------------------------------------------------------------
;;next AUTO line number
c10d 2a02ac    ld      hl,($ac02)
c110 eb        ex      de,hl
c111 d5        push    de
c112 cd38e2    call    $e238
c115 cddec0    call    $c0de
c118 cd01cb    call    $cb01			; edit
c11b d1        pop     de
c11c d0        ret     nc
;;========================================================================

c11d e5        push    hl
c11e 2a04ac    ld      hl,($ac04)       ;AUTO increment step
c121 19        add     hl,de
c122 d4e1c0    call    nc,$c0e1
c125 e1        pop     hl
c126 37        scf     
c127 c9        ret     

;;========================================================================
;; command NEW
;NEW
;Completely clears the current contents of memory

c128 c0        ret     nz
c129 cd45c1    call    $c145
c12c c358c0    jp      $c058

;;=============================================================================
;; command CLEAR, CLEAR INPUT
;CLEAR
;Clear all variables and files

c12f fea3      cp      $a3				; token for "INPUT"
c131 280c      jr      z,$c13f          ; CLEAR INPUT

c133 e5        push    hl
c134 cd78c1    call    $c178
c137 cd5fc1    call    $c15f
c13a cd8fc1    call    $c18f
c13d e1        pop     hl
c13e c9        ret     

;;========================================================================
;; CLEAR INPUT
;CLEAR INPUT ??

c13f cd2cde    call    $de2c			; get next token skipping space
c142 c33dbd    jp      $bd3d			; firmware function: km flush

;;========================================================================
;; reset basic
;; clear all memory and reset
c145 2a62ae    ld      hl,($ae62)    ;input buffer/start of BASIC memory
c148 eb        ex      de,hl

c149 2a5eae    ld      hl,($ae5e) ; HIMEM
c14c cde4ff    call    $ffe4			; BC = HL-DE
c14f 62        ld      h,d
c150 6b        ld      l,e
c151 13        inc     de
c152 af        xor     a
c153 77        ld      (hl),a
c154 edb0      ldir    
c156 322cae    ld      ($ae2c),a
c159 cdead5    call    $d5ea
c15c cd6fc1    call    $c16f
;;=close streams and reset angle mode, string stack and fn params
c15f cd00d3    call    $d300			; close input and output streams
;;=reset angle mode, string stack and fn params
c162 af        xor     a
c163 cd97bd    call    $bd97			; maths: set angle mode

;;=reset string stack and fn params
c166 cdccfb    call    $fbcc			; string catenation
c169 cd20da    call    $da20
c16c c3a1c1    jp      $c1a1

;;-------------------------------------------------------------------
;;=clear program and variables etc
c16f cdc5de    call    $dec5				;; TROFF
c172 cddec0    call    $c0de
c175 cd89c1    call    $c189

;;=reset variable data
c178 c5        push    bc
c179 e5        push    hl
c17a cd8cf6    call    $f68c
c17d cdead5    call    $d5ea
c180 cd38d6    call    $d638
c183 cd4dea    call    $ea4d
c186 e1        pop     hl
c187 c1        pop     bc
c188 c9        ret     

;;-----------------------------------------------------------------
;;=reset zone and clear program
c189 cd99f2    call    $f299
c18c cd61e7    call    $e761        ;; ?

;;-----------------------------------------------------------------
;;=reset exec data
;Appears to be a 'light' reset after running and before editing etc.
c18f cdaccc    call    $ccac
c192 cd7ecc    call    $cc7e
c195 cda3c9    call    $c9a3
c198 cd4ff6    call    $f64f
c19b cd0ed6    call    $d60e
c19e c3d4dc    jp      $dcd4



;;***Streams.asm
;;<< (TEXT) STREAM MANAGEMENT
;;=========================================
;;select txt stream zero
c1a1 af        xor     a
c1a2 cdb3c1    call    $c1b3
c1a5 af        xor     a
;;=select txt stream
c1a6 e5        push    hl
c1a7 f5        push    af
c1a8 fe08      cp      $08
c1aa dcb4bb    call    c,$bbb4			; firmware function: txt str select
c1ad f1        pop     af
c1ae 2106ac    ld      hl,$ac06
c1b1 1804      jr      $c1b7            ; (+$04)

;;==========================================
;;swap input streams
c1b3 e5        push    hl
c1b4 2107ac    ld      hl,$ac07

;;=swap stream number atHL
c1b7 d5        push    de
c1b8 5f        ld      e,a
c1b9 7e        ld      a,(hl)
c1ba 73        ld      (hl),e
c1bb d1        pop     de
c1bc e1        pop     hl
c1bd c9        ret     

;;-----------------------------------------------------------------
;;=get output stream
c1be 3a06ac    ld      a,($ac06)
c1c1 fe08      cp      $08
c1c3 c9        ret     

;;-----------------------------------------------------------------
;;=get input stream
;returns Carry clear if stream is on screen, Carry set if not on screen (i.e. a file)
c1c4 3a07ac    ld      a,($ac07)
c1c7 fe09      cp      $09
c1c9 c9        ret     

;;-----------------------------------------------------------------
;;=eval and select txt stream
c1ca cdfbc1    call    $c1fb
c1cd 18d7      jr      $c1a6            ; (-$29)

;;=exec following on evalled stream and swap back
c1cf cdfbc1    call    $c1fb
c1d2 1818      jr      $c1ec            ; (+$18)

;;=swap both streams, exec TOS and swap back
c1d4 cdfbc1    call    $c1fb
c1d7 cdb3c1    call    $c1b3
c1da c1        pop     bc
c1db f5        push    af
c1dc cdc4c1    call    $c1c4
c1df cdedc1    call    $c1ed
c1e2 f1        pop     af
c1e3 18ce      jr      $c1b3            ; (-$32)


;;===============================================
;;=exec TOS on evalled stream and swap back
c1e5 cdfbc1    call    $c1fb
c1e8 fe08      cp      $08
c1ea 3031      jr      nc,$c21d         ; (+$31)
;;=exec TOS on stream and swap back
c1ec c1        pop     bc
;;=exec BC on stream and swap back
c1ed cda6c1    call    $c1a6
c1f0 f5        push    af
c1f1 7e        ld      a,(hl)
c1f2 fe2c      cp      $2c				; ','
c1f4 cdfcff    call    $fffc			; JP (BC)
c1f7 f1        pop     af
c1f8 c3a6c1    jp      $c1a6

;;======================================
;;=eval and validate stream number if present
c1fb 7e        ld      a,(hl)
c1fc fe23      cp      $23				; #
c1fe 3e00      ld      a,$00
c200 c0        ret     nz

c201 cd0dc2    call    $c20d
c204 f5        push    af
c205 cd41de    call    $de41
c208 d437de    call    nc,$de37
c20b f1        pop     af
c20c c9        ret     

;;====================================
;;=eval and validate stream number
c20d cd25de    call    $de25
c210 defb $23      ;Inline token to test "#"

c211 3e0a      ld      a,$0a
;;=check byte value in range.
;; if not give "Improper Argument" error message
;; In: A = max value
;; Out: A = value if in range
c213 c5        push    bc
c214 d5        push    de
c215 47        ld      b,a
c216 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
c219 b8        cp      b	; compare to value we want
c21a d1        pop     de
c21b c1        pop     bc
c21c d8        ret     c	;; return if less than value

;; greater than value
;;=raise Improper Argument error
c21d c34dcb    jp      $cb4d			; Error: Improper Argument
       





;;***Screen.asm
;;<< SCREEN HANDLING FUNCTIONS

;;========================================================================
;; check number is less than 2
c220 3e02      ld      a,$02
c222 18ef      jr      $c213 	; check value is in range 

;;========================================================================
;; command PEN
;PEN [#<stream expression>,]<masked ink>
;Sets the ink to use for the foreground of the given window.

c224 cde5c1    call    $c1e5
c227 0190bb    ld      bc,$bb90			; firmware function: txt set pen
c22a c43fc2    call    nz,$c23f
c22d cd41de    call    $de41
c230 d0        ret     nc
c231 cd20c2    call    $c220 			; check number is less than 2
c234 019fbb    ld      bc,$bb9f			; firmware function: txt set back
c237 1809      jr      $c242           

;;========================================================================
;; command PAPER
;PAPER [#<stream expression>,]<masked ink>
;Sets the ink to use for the background of the given window.

c239 cde5c1    call    $c1e5
c23c 0196bb    ld      bc,$bb96			; firmware function: txt set paper
c23f cd71c2    call    $c271 ; check parameter is less than 16

c242 e5        push    hl
c243 cdfcff    call    $fffc			; JP (BC)
c246 e1        pop     hl
c247 c9        ret     

;;=========================================================================
;; command BORDER
;BORDER <colour>[,colour]
;Set the border colour. If two values are supplied border will flash between them

c248 cd62c2    call    $c262		 ; one or two numbers each less than 32
;; B,C = numbers which are the inks
c24b e5        push    hl
c24c cd38bc    call    $bc38			; firmware function: scr set border
c24f e1        pop     hl
c250 c9        ret     

;;=========================================================================
;; command INK
;INK <ink number>,<colour>[,<colour>]
;Specifies the colour for an ink. If two colours are given the ink flashes between the two.

c251 cd71c2    call    $c271 ; check parameter is less than 16
c254 f5        push    af
c255 cd15de    call    $de15 ; check for comma
c258 cd62c2    call    $c262 ; one or two numbers each less than 32

;; B,C = numbers which are the inks
c25b f1        pop     af
c25c e5        push    hl
c25d cd32bc    call    $bc32			; firmware function: scr set ink
c260 e1        pop     hl
c261 c9        ret     

;;=========================================================================
;; eval one or two numbers less than 32
;; used to get ink values
;;
;; first number in B, second number in C

c262 cd6ac2    call    $c26a
c265 41        ld      b,c
c266 cd41de    call    $de41
c269 d0        ret     nc

c26a 3e20      ld      a,$20
c26c cd13c2    call    $c213 ; check value is in range
c26f 4f        ld      c,a
c270 c9        ret     

;;========================================================================
;; check value is less than 16
c271 3e10      ld      a,$10
c273 189e      jr      $c213 ; check value is in range            

;;========================================================================
;; command MODE
;MODE <integer expression>
;Changes screen mode

c275 3e03      ld      a,$03
c277 cd13c2    call    $c213 			; check value is in range
;; A = mode
c27a e5        push    hl
c27b cd0ebc    call    $bc0e			; firmware function: scr set mode
c27e e1        pop     hl
c27f c9        ret     

;;=============================================================================
;; command CLS
;CLS [#<stream expression>]
;Clear the screen window for a stream
;Stream expression must be 0..7. If no value is given stream #0 is cleared.

c280 cde5c1    call    $c1e5
c283 e5        push    hl
c284 cd6cbb    call    $bb6c			; firmware function: txt clear window
c287 e1        pop     hl
c288 c9        ret     

;;=eval stream param, and exec TOS, and swap back
c289 cd0dc2    call    $c20d
c28c fe08      cp      $08
c28e 308d      jr      nc,$c21d         ; (-$73)
;;=exec TOS on stream and swap back
c290 f5        push    af
c291 cd1dde    call    $de1d ; check for close bracket
c294 f1        pop     af
c295 c3ecc1    jp      $c1ec

;;========================================================================
;; function COPYCHR$

c298 cd89c2    call    $c289
c29b cd60bb    call    $bb60			; firmware function: txt rd char
c29e c378fa    jp      $fa78

;;========================================================================
;; function VPOS
;VPOS(#<stream expression>)
;Returns the vertical position of the given stream

c2a1 cd89c2    call    $c289
c2a4 e5        push    hl
c2a5 cdc7c2    call    $c2c7			; get y cursor position
c2a8 180a      jr      $c2b4            ; (+$0a)

;;========================================================================
;; function POS
;POS(#<stream expression>)
;Established the position of the specified stream.
;1. Screen streams #0..#7: Returns the current x coordinate. 1 is the left column
;2. Printer stream #8: Returns the current position across the printer, counting 
;all character codes greater than &1F. 1 is the left column
;3. Cassette output stream #9: Returns the number of printing characters since the last 
;carriage return, where printing characters are those > &1F. 1 is the leftmost column.

c2aa cd0dc2    call    $c20d
c2ad cd90c2    call    $c290
c2b0 e5        push    hl
c2b1 cdb9c2    call    $c2b9
c2b4 cd32ff    call    $ff32
c2b7 e1        pop     hl
c2b8 c9        ret     

;;========================================================================
;;=get xpos of output stream
;stream can be stream, file or printer
c2b9 cdbec1    call    $c1be
c2bc 3a08ac    ld      a,($ac08)
c2bf c8        ret     z

c2c0 3a0aac    ld      a,($ac0a)
c2c3 d0        ret     nc

c2c4 c3ecc3    jp      $c3ec

;;========================================================================
;; get Y cursor position
c2c7 cd78bb    call    $bb78			; firmware function: txt get cursor
c2ca cd87bb    call    $bb87			; firmware function: txt validate
c2cd 7d        ld      a,l
c2ce c9        ret     

;;========================================================================
;;=pos is xpos in D in range
c2cf cdbec1    call    $c1be
c2d2 280d      jr      z,$c2e1          ; (+$0d)
c2d4 d0        ret     nc

c2d5 d5        push    de
c2d6 e5        push    hl
c2d7 cd69bb    call    $bb69			; firmware function: txt get window
c2da 7a        ld      a,d
c2db 94        sub     h
c2dc 3c        inc     a
c2dd e1        pop     hl
c2de d1        pop     de
c2df 37        scf     
c2e0 c9        ret     

;;=poss get screen width
c2e1 3a09ac    ld      a,($ac09)
c2e4 feff      cp      $ff
c2e6 c9        ret     

;;=poss validate xpos in D
c2e7 e5        push    hl
c2e8 67        ld      h,a
c2e9 cdcfc2    call    $c2cf
c2ec 3f        ccf     
c2ed 380e      jr      c,$c2fd          ; (+$0e)
c2ef 6f        ld      l,a
c2f0 cdb9c2    call    $c2b9
c2f3 3d        dec     a
c2f4 37        scf     
c2f5 2806      jr      z,$c2fd          ; (+$06)
c2f7 84        add     a,h
c2f8 3f        ccf     
c2f9 3002      jr      nc,$c2fd         ; (+$02)
c2fb 3d        dec     a
c2fc bd        cp      l
c2fd e1        pop     hl
c2fe c9        ret     

;;========================================================================
;; command LOCATE
;LOCATE [#<stream expression>,]<x coordinate>,<y coordinate>
;Positions the text cursor in the specified stream, default 0.
;Valid coordinates are 0..255. (1,1) is the top-left or the window.

c2ff cde5c1    call    $c1e5
c302 cd51c3    call    $c351
c305 e5        push    hl
c306 eb        ex      de,hl
c307 24        inc     h
c308 2c        inc     l
c309 cd75bb    call    $bb75			; firmware function: txt set cursor
c30c e1        pop     hl
c30d c9        ret     

;;========================================================================
;; command WINDOW, WINDOW SWAP
;WINDOW [#<stream expression>,]<left>,<right>,<top>,<bottom>
;Defines a text window. Values can be 1..255
;WINDOW SWAP <stream expression>,<stream expression>
;Swaps two text windows

c30e fee7      cp      $e7
c310 2816      jr      z,$c328          ; (+$16)
c312 cde5c1    call    $c1e5
c315 cd51c3    call    $c351
c318 d5        push    de
c319 cd15de    call    $de15 ; check for comma
c31c cd51c3    call    $c351
c31f e3        ex      (sp),hl
c320 7a        ld      a,d
c321 55        ld      d,l
c322 6f        ld      l,a
c323 cd66bb    call    $bb66			; firmware function: txt win enable
c326 e1        pop     hl
c327 c9        ret     

;;========================================================================
;;=window swap
c328 cd2cde    call    $de2c			; get next token skipping space
c32b cd3ec3    call    $c33e 		; get number less than 8
c32e 4f        ld      c,a
c32f cd41de    call    $de41
c332 3e00      ld      a,$00
c334 dc3ec3    call    c,$c33e 		; get number less than 8
c337 47        ld      b,a
c338 e5        push    hl
c339 cdb7bb    call    $bbb7			; firmware function: txt swap streams
c33c e1        pop     hl
c33d c9        ret     

;;=eval number less than 8
c33e 3e08      ld      a,$08
c340 c313c2    jp      $c213 ; check value is in range

;;========================================================================
;; command TAG
;TAG [#<stream expression>]
;Enables text at graphics on the given stream
;Text is printed with the top left pixel at the graphics cursor position.
;Control characters have to effect and print as symbols

c343 cde5c1    call    $c1e5
c346 3eff      ld      a,$ff
c348 1804      jr      $c34e            ; (+$04)

;;========================================================================
;; command TAGOFF
;TAGOFF [#<stream expression>]
;Cancels TAG for the given stream

c34a cde5c1    call    $c1e5
c34d af        xor     a
c34e c363bb    jp      $bb63			; firmware function: txt set graphic

;;-------------------------------------------------------------------------
;;=eval two params minus 1 to D E
c351 cd58c3    call    $c358
c354 53        ld      d,e
c355 cd15de    call    $de15 ; check for comma

;;--------------------------------------------------------------------------
;;=eval param minus 1 to E
c358 d5        push    de
c359 cdc3ce    call    $cec3
c35c d1        pop     de
c35d 5f        ld      e,a
c35e 1d        dec     e
c35f c9        ret     

;;========================================================================
;; command CURSOR

c360 cde5c1    call    $c1e5
c363 280a      jr      z,$c36f          ; (+$0a)
c365 cd20c2    call    $c220 ; check number is less than 2
c368 b7        or      a
c369 cc84bb    call    z,$bb84			; firmware function: txt cur off
c36c c481bb    call    nz,$bb81			; firmware function: txt cur on
c36f cd41de    call    $de41
c372 d0        ret     nc

c373 cd20c2    call    $c220 ; check number is less than 2
c376 b7        or      a
c377 ca7ebb    jp      z,$bb7e			; firmware function: txt cur disable
c37a c37bbb    jp      $bb7b			; firmware function: txt cur enable





;;***StreamIO.asm
;;<< STREAM I/O
;;< Low level I/O via streams, WIDTH and EOF
;;=====================================================

;; init streams and display ASCIIZ string

c37d e5        push    hl
c37e 210184    ld      hl,$8401
c381 2208ac    ld      ($ac08),hl
c384 cd69c4    call    $c469
c387 cda1c1    call    $c1a1
c38a e1        pop     hl

;;+----------------------------------------------------
;;output ASCIIZ string
c38b f5        push    af
c38c e5        push    hl
c38d 7e        ld      a,(hl)			; get character
c38e 23        inc     hl
c38f b7        or      a
c390 c4a0c3    call    nz,$c3a0           ;; display text char
c393 20f8      jr      nz,$c38d         ; (-$08)

c395 e1        pop     hl
c396 f1        pop     af
c397 c9        ret     

;;=======================================================
;; output new line
c398 f5        push    af
c399 3e0a      ld      a,$0a
c39b cda0c3    call    $c3a0           ;; display text char
c39e f1        pop     af
c39f c9        ret     

;;=======================================================
;; output char
c3a0 f5        push    af
c3a1 c5        push    bc
c3a2 cda8c3    call    $c3a8
c3a5 c1        pop     bc
c3a6 f1        pop     af
c3a7 c9        ret     
;;-=======================================================
;;=output char or new line
c3a8 fe0a      cp      $0a
c3aa 200c      jr      nz,$c3b8         ; (+$0c)

c3ac cdbec1    call    $c1be
c3af caf5c3    jp      z,$c3f5
c3b2 d231c4    jp      nc,$c431 ; write cr, lf to file
c3b5 c3e2c3    jp      $c3e2

;;-------------------------------------------------------------------
;;=output raw char
;A=char
c3b8 f5        push    af
c3b9 c5        push    bc
c3ba 4f        ld      c,a
c3bb cdc1c3    call    $c3c1
c3be c1        pop     bc
c3bf f1        pop     af
c3c0 c9        ret     
;;-------------------------------------------------------------------
;;=output raw char to current stream
;C=char
;stream could be printer, file or display
c3c1 3a06ac    ld      a,($ac06)
c3c4 fe08      cp      $08
c3c6 cafcc3    jp      z,$c3fc

c3c9 d238c4    jp      nc,$c438 ; write char to file
c3cc 79        ld      a,c
c3cd c3e9c3    jp      $c3e9

;;========================================================================
;;=turn display on
;and move cursor to new line if not at start of line
c3d0 af        xor     a				; output letters using text functions
c3d1 cd63bb    call    $bb63			; firmware function: txt set graphic	
c3d4 af        xor     a				; opaque characters
c3d5 e5        push    hl
c3d6 cd9fbb    call    $bb9f			; firmware function: txt set back
c3d9 e1        pop     hl
c3da cd54bb    call    $bb54			; firmware function: txt vdu enable

c3dd cdecc3    call    $c3ec			; get x cursor position
c3e0 3d        dec     a
c3e1 c8        ret     z

;;=display cr lf
c3e2 3e0d      ld      a,$0d			; print CR,LF
c3e4 cde9c3    call    $c3e9
c3e7 3e0a      ld      a,$0a
;;=do txt output
c3e9 c35abb    jp      $bb5a			; firmware function: txt output

;;========================================================================
;; get x cursor position
c3ec c5        push    bc
c3ed e5        push    hl
c3ee cdc7c2    call    $c2c7					
c3f1 7c        ld      a,h
c3f2 e1        pop     hl
c3f3 c1        pop     bc
c3f4 c9        ret     
;;========================================================================
;;=printer new line
c3f5 0e0d      ld      c,$0d
c3f7 cdfcc3    call    $c3fc
c3fa 0e0a      ld      c,$0a
;;=output char to printer
c3fc e5        push    hl
c3fd 2a08ac    ld      hl,($ac08)
c400 cd11c4    call    $c411
c403 3208ac    ld      ($ac08),a
c406 e1        pop     hl

;;=print char
c407 79        ld      a,c
c408 cd2bbd    call    $bd2b			; firmware function: mc print char
c40b d8        ret     c                ;printed? (otherwise port busy)

c40c cd72c4    call    $c472			; key - abort if break
c40f 18f6      jr      $c407            ; repeat until printed?

;;=process new lines for file or printer
c411 79        ld      a,c
c412 ee0d      xor     $0d
c414 2810      jr      z,$c426          ; (+$10)
c416 79        ld      a,c
c417 fe20      cp      $20				; ' '
c419 7d        ld      a,l
c41a d8        ret     c

c41b 24        inc     h
c41c 2808      jr      z,$c426          ; (+$08)
c41e bc        cp      h
c41f 2005      jr      nz,$c426         ; (+$05)
c421 cd98c3    call    $c398      ;; new text line			
c424 3e01      ld      a,$01
c426 3c        inc     a
c427 c0        ret     nz

c428 3d        dec     a
c429 c9        ret     

;;========================================================================
;; command WIDTH
;WIDTH <integer expression>
;Set the printer width so BASIC can insert carriage returns.
;Default 132. 255 means do not insert carriage returns

c42a cdc3ce    call    $cec3
c42d 3209ac    ld      ($ac09),a
c430 c9        ret   
  
;;========================================================================
;; write cr,lf to file
c431 0e0d      ld      c,$0d			;; cr
c433 cd38c4    call    $c438 ; write char to file
c436 0e0a      ld      c,$0a			;; lf

;;=write char to file
c438 e5        push    hl
c439 2a0aac    ld      hl,($ac0a)
c43c 26ff      ld      h,$ff
c43e cd11c4    call    $c411
c441 320aac    ld      ($ac0a),a
c444 e1        pop     hl
c445 79        ld      a,c
c446 cd95bc    call    $bc95			; firmware function: cas out char
c449 d8        ret     c

c44a 2019      jr      nz,$c465         ; (+$19)
;;=raise File not open error
c44c c337cc    jp      $cc37

;;=================================================
;; variable EOF
;EOF
;Test for end of input file
;Returns -1 (true) or 0 (false)
;If no file is open returns true

c44f e5        push    hl
c450 cd89bc    call    $bc89			; firmware function: cas test eof
c453 28f7      jr      z,$c44c          ; (-$09)
c455 3f        ccf     
c456 9f        sbc     a,a
c457 cd2dff    call    $ff2d
c45a e1        pop     hl
c45b c9        ret     

;;==================================================
;; read byte from cassette or disc
c45c cd80bc    call    $bc80			; firmware function: cas in char
c45f d8        ret     c

c460 28ea      jr      z,$c44c          ; (-$16)
c462 ee0e      xor     $0e
c464 c0        ret     nz

;;=raise File not open error
c465 cd45cb    call    $cb45
c468 defb $1f                         ;Inline error code: File not open

;;=set file output stream line pos to 1
c469 3e01      ld      a,$01
c46b 320aac    ld      ($ac0a),a
c46e c9        ret     




;;***Keyboard.asm
;;<< LOW LEVEL KEYBOARD HANDLING
;;< including BREAK key handler
;;=======================================================================================
;;jp km read char
c46f c309bb    jp      $bb09			; firmware function: km read char

;;=======================================================================================
;;test for break key
c472 cd09bb    call    $bb09			; firmware function: km read char
c475 d0        ret     nc
c476 fefc      cp      $fc				;Break?
c478 c0        ret     nz
c479 cda1c4    call    $c4a1			; key
c47c da3ecc    jp      c,$cc3e

;;=arm break handler
c47f e5        push    hl
;;=arm break handler
c480 c5        push    bc
c481 d5        push    de
c482 1192c4    ld      de,$c492         ;##LABEL##
c485 0efd      ld      c,$fd            ;ROM select address for break handling routine
c487 3a0bac    ld      a,($ac0b)        ;&00=ON BREAK CONTINUE, else ON BREAK STOP
c48a b7        or      a
c48b c445bb    call    nz,$bb45			; firmware function: km arm break
c48e d1        pop     de
c48f c1        pop     bc
c490 e1        pop     hl
c491 c9        ret     

;;=======================================================================================
;;break handling routine
;Called from firmware break handler

;Clear any characters in the input buffer prior to the break key being pressed
c492 cd09bb    call    $bb09			; firmware function: km read char
c495 3004      jr      nc,$c49b         ; (+$04) No key available  
c497 feef      cp      $ef              ; 
c499 20f7      jr      nz,$c492         ; (-$09) Loop until $ef. Code for break key.

c49b cda1c4    call    $c4a1			; wait for second break, or resume
c49e c3f2c8    jp      $c8f2

;;=======================================================================================
;;=break pause
;Wait for second break key (break)
;or any other key (continue execution)
c4a1 c5        push    bc
c4a2 d5        push    de
c4a3 e5        push    hl
c4a4 cdb6bc    call    $bcb6			; firmware function: sound hold
c4a7 f5        push    af
c4a8 cd40bd    call    $bd40			; firmware function: txt ask state
c4ab 47        ld      b,a
c4ac cd81bb    call    $bb81			; firmware function: txt cur on
c4af cd06bb    call    $bb06			; firmware function: km wait char
c4b2 feef      cp      $ef              ;token for '='
c4b4 28f9      jr      z,$c4af          ; (-$07)
c4b6 cb48      bit     1,b
c4b8 c484bb    call    nz,$bb84			; firmware function: txt cur off
c4bb fefc      cp      $fc
c4bd 37        scf     
c4be 280b      jr      z,$c4cb          ; (+$0b)
c4c0 fe20      cp      $20				; ' ' 
c4c2 c40cbb    call    nz,$bb0c			; firmware function: km char return
c4c5 f1        pop     af
c4c6 f5        push    af
c4c7 dcb9bc    call    c,$bcb9			; firmware function: sound continue
c4ca b7        or      a
c4cb e1        pop     hl
c4cc e1        pop     hl
c4cd d1        pop     de
c4ce c1        pop     bc
c4cf c9        ret     

;;========================================================================
;; ON BREAK CONT
c4d0 af        xor     a
c4d1 1802      jr      $c4d5            ; (+$02)

;;========================================================================
;; ON BREAK STOP
c4d3 3eff      ld      a,$ff
;;------------------------------------------------------------------------
c4d5 320bac    ld      ($ac0b),a
c4d8 e5        push    hl
c4d9 cd48bb    call    $bb48			; firmware function: km disarm break
c4dc 18a2      jr      $c480            ; (-$5e)




;;***Graphics.asm
;;<< GRAPHICS FUNCTIONS
;;========================================================================
;; command ORIGIN
;ORIGIN <x>,<y>[,<left>,<right>,<top>,<bottom>]
;Sets graphics screen origin and window
;If left, right, top, bottom are omitted then current window remains unchanged.
;(0,0) is the bottom, left of the screen.

c4de cd8cc5    call    $c58c            ;params x,y
c4e1 c5        push    bc
c4e2 d5        push    de
c4e3 cd41de    call    $de41
c4e6 3017      jr      nc,$c4ff         ; (+$17) only two params
c4e8 cd8cc5    call    $c58c            ;params left, right
c4eb c5        push    bc
c4ec d5        push    de
c4ed cd15de    call    $de15 ; check for comma
c4f0 cd8cc5    call    $c58c            ;params top,bottom
c4f3 c5        push    bc
c4f4 e3        ex      (sp),hl
c4f5 cdd2bb    call    $bbd2			; firmware function: gra win height
c4f8 e1        pop     hl
c4f9 d1        pop     de
c4fa e3        ex      (sp),hl
c4fb cdcfbb    call    $bbcf			; firmware function: gra win width
c4fe e1        pop     hl
c4ff d1        pop     de
c500 e3        ex      (sp),hl
c501 cdc9bb    call    $bbc9			; firmware function: gra set origin
c504 e1        pop     hl
c505 c9        ret     

;;=============================================================================
;; command CLG
;CLG [<masked ink>]
;Clear the graphics screen to the given ink. If no ink is given the value
;from the last call to CLG is used, or ink 0 if no CLG command has been executed

c506 cd3dde    call    $de3d
c509 d4b4c5    call    nc,$c5b4
c50c e5        push    hl
c50d cddbbb    call    $bbdb			; firmware function: GRA CLEAR WINDOW
c510 e1        pop     hl
c511 c9        ret     

;;========================================================================
;; command FILL
c512 cd71c2    call    $c271 ; check parameter is less than 16
c515 e5        push    hl
c516 f5        push    af
c517 cd64fc    call    $fc64        ;(free up?) and calc free memory?
c51a cdfcf6    call    $f6fc
c51d 011d00    ld      bc,$001d
c520 cddeff    call    $ffde ; HL=BC?
c523 3e07      ld      a,$07            ;Memory full error
c525 da55cb    jp      c,$cb55
c528 eb        ex      de,hl
c529 f1        pop     af
c52a cd52bd    call    $bd52			; firmware function: GRA FILL
c52d e1        pop     hl
c52e c9        ret     

;;========================================================================
;; command MOVE
;MOVE <x coordinate>,<y coordinate>
;Moves the graphic cursor

c52f 01c0bb    ld      bc,$bbc0			; firmware function: gra move absolute
c532 1817      jr      $c54b            

;;========================================================================
;; command MOVER
;MOVER <x coordinate>,<y coordinate>
;Moves the graphic cursor relative to it's current position

c534 01c3bb    ld      bc,$bbc3			; firmware function: gra move relative
c537 1812      jr      $c54b            

;;========================================================================
;; command DRAW
;DRAW <x coordinate>,<y coordinate>[,<masked ink>]
;Draw a line on the screen from the current position to that given.
;If no masked ink is specified that given in the last call to DRAW, DRAWR, PLOT or PLOTR 
;will be used. If no such commands have been used, ink 1 will be used.

c539 01f6bb    ld      bc,$bbf6			; firmware function: gra line absolute
c53c 180d      jr      $c54b            

;;========================================================================
;; command DRAWR
;DRAWR <x offset>,<y offset>[,<masked ink>]
;Draws a line from the current position to the given offset from that position
;See DRAW

c53e 01f9bb    ld      bc,$bbf9			; firmware function: gra line relative
c541 1808      jr      $c54b

;;========================================================================
;; command PLOT
;PLOT <x coordinate>,<y coordinate>[,<masked ink>]
;Plots a pixel at the given location
;See DRAW

c543 01eabb    ld      bc,$bbea			; firmware function: gra plot absolute
c546 1803      jr      $c54b            

;;========================================================================
;; command PLOTR
;PLOTR <x offset>,<y offset>[,<masked ink>]
;Plots a pixel at the given offset from the current position
;See DRAW

c548 01edbb    ld      bc,$bbed			; firmware function: gra plot relative

;;+------------------------------------------------------------------------
;; plot/draw general function
;;reads parameters and calls the address in BC to do the actual function
c54b c5        push    bc
c54c cd8cc5    call    $c58c
c54f cd41de    call    $de41
c552 3005      jr      nc,$c559         ; (+$05)
c554 fe2c      cp      $2c				; ','
c556 c4bac5    call    nz,$c5ba

c559 cd41de    call    $de41
c55c 300a      jr      nc,$c568         ; (+$0a)
c55e 3e04      ld      a,$04
c560 cd13c2    call    $c213 ; check value is in range
c563 e5        push    hl
c564 cd59bc    call    $bc59			; firmware function: scr access 
c567 e1        pop     hl

c568 e3        ex      (sp),hl
c569 c5        push    bc
c56a e3        ex      (sp),hl
c56b c1        pop     bc
c56c cdfcff    call    $fffc			; JP (BC)
c56f e1        pop     hl
c570 c9        ret     

;;========================================================================
;; function TEST
;TEST(<x coordinate>,<y coordinate>)
;Returns the ink at the given pixel location. Also moves th graphics cursor.
;If the location is outside the current graphics window the value used in the last CLG
;command is returned. If no CLG command hs been used returns 0

c571 01f0bb    ld      bc,$bbf0			; firmware function: GRA TEST ABSOLUTE
c574 1803      jr      $c579            ; 

;;========================================================================
;; function TESTR
;TESTR(<x offset>,<y offset>)
;As TEST but the position is relative to the current graphics cursor position

c576 01f3bb    ld      bc,$bbf3			; firmware function: GRA TEST RELATIVE
;;------------------------------------------------------------------------
c579 c5        push    bc
c57a cd8cc5    call    $c58c
c57d cd1dde    call    $de1d ; check for close bracket
c580 e3        ex      (sp),hl
c581 c5        push    bc
c582 e3        ex      (sp),hl
c583 c1        pop     bc
c584 cdfcff    call    $fffc			; JP (BC)
c587 cd32ff    call    $ff32
c58a e1        pop     hl
c58b c9        ret     
;;------------------------------------------------------------------------
;;=eval two int params
c58c cdd8ce    call    $ced8 ; get number
c58f d5        push    de
c590 cd15de    call    $de15 ; check for comma
c593 cdd8ce    call    $ced8 ; get number
c596 42        ld      b,d
c597 4b        ld      c,e
c598 d1        pop     de
c599 c9        ret     

;;========================================================================
;; command GRAPHICS PAPER / GRAPHICS PEN and set graphics draw mode
c59a feba      cp      $ba				; token for "PAPER"
c59c 2813      jr      z,$c5b1    		; set graphics paper
      
c59e cd25de    call    $de25
c5a1 defb $bb						    ; token for "PEN"
c5a2 fe2c      cp      $2c				; ','
c5a4 c4bac5    call    nz,$c5ba			; set graphics pen

c5a7 cd41de    call    $de41
c5aa d0        ret     nc

;;=validate and set graphics background mode
c5ab cd20c2    call    $c220 ; check number is less than 2
c5ae c346bd    jp      $bd46			; firmware function: GRA SET BACK

;;=eval and set graphics paper
c5b1 cd2cde    call    $de2c			; get next token skipping space
;;=validate and set graphics paper
c5b4 cd71c2    call    $c271 			; check parameter is less than 16
c5b7 c3e4bb    jp      $bbe4			; firmware function: GRA SET PAPER	

;;=validate and set graphics pen
c5ba cd71c2    call    $c271 			; check parameter is less than 16
c5bd c3debb    jp      $bbde			; firmware function: GRA SET PEN

;;========================================================================
;; command MASK

c5c0 fe2c      cp      $2c				; ','
c5c2 2806      jr      z,$c5ca          ; 

c5c4 cdb8ce    call    $ceb8 			; get number and check it's less than 255 
c5c7 cd4cbd    call    $bd4c			; firmware function: GRA SET LINE MASK	

c5ca cd41de    call    $de41
c5cd d0        ret     nc

c5ce cd20c2    call    $c220 			; check number is less than 2
c5d1 c349bd    jp      $bd49			; firmware function: GRA SET FIRST





;;***ControlFlow.asm
;;<< CONTROL FLOW
;;< FOR, IF, GOTO, GOSUB, WHILE
;;========================================================================
;; command FOR
;FOR <simple variable>=<start> TO <end> [STEP <step size>]
;Variable and values can be integer or real.
;The matching NEXT is established when executing the FOR, and is the next matching 
;NEXT (taking account of nesting) sequentially in the program code, ignoring order 
;of execution.
;Terminates when the variable is >= the end value (positive step) or 
;<= the end value (negative step)
;The FOR loop can be terminated by avoiding the NEXT

c5d4 cdecd6    call    $d6ec
c5d7 e5        push    hl
c5d8 c5        push    bc
c5d9 d5        push    de
c5da cd76ca    call    $ca76
c5dd 2212ac    ld      ($ac12),hl
c5e0 d5        push    de
c5e1 e5        push    hl
c5e2 eb        ex      de,hl
c5e3 cdd9c6    call    $c6d9
c5e6 cc5df6    call    z,$f65d
c5e9 e1        pop     hl
c5ea cd3dde    call    $de3d
c5ed 110000    ld      de,$0000         ;##LIT##
c5f0 d4bfd6    call    nc,$d6bf
c5f3 44        ld      b,h
c5f4 4d        ld      c,l
c5f5 e1        pop     hl
c5f6 e3        ex      (sp),hl
c5f7 7a        ld      a,d
c5f8 b3        or      e
c5f9 c4d8ff    call    nz,$ffd8 ; HL=DE?
c5fc c29ec6    jp      nz,$c69e

c5ff eb        ex      de,hl
c600 cdb1de    call    $deb1
c603 e3        ex      (sp),hl
c604 cdadde    call    $dead
c607 e1        pop     hl
c608 f1        pop     af
c609 e3        ex      (sp),hl
c60a d5        push    de
c60b c5        push    bc
c60c e5        push    hl
c60d 010516    ld      bc,$1605
c610 b9        cp      c
c611 2809      jr      z,$c61c          ; (+$09)

c613 010210    ld      bc,$1002         ;B=bytes to allocate on execution stack. C=int variable type
c616 b9        cp      c
c617 3e0d      ld      a,$0d            ;Type mismatch error
c619 c255cb    jp      nz,$cb55

c61c 78        ld      a,b
c61d cd72f6    call    $f672
c620 73        ld      (hl),e
c621 23        inc     hl
c622 72        ld      (hl),d
c623 23        inc     hl
c624 e3        ex      (sp),hl

c625 cd21de    call    $de21            ;test for "=" after var name
c628 cd62cf    call    $cf62            ;Get initial value
c62b 79        ld      a,c
c62c cdfffe    call    $feff
c62f e5        push    hl
c630 210dac    ld      hl,$ac0d
c633 cd83ff    call    $ff83
c636 e1        pop     hl

c637 cd25de    call    $de25
c63a defb $ec      ;Inline token to test "TO"
c6eb cd62cf    call    $cf62    ;Read to value
c63e e3        ex      (sp),hl
c63f 79        ld      a,c
c640 cdfffe    call    $feff
c643 cd83ff    call    $ff83
c646 eb        ex      de,hl
c647 e3        ex      (sp),hl
c648 eb        ex      de,hl

c649 210100    ld      hl,$0001         ;Default step to 1
c64c cd35ff    call    $ff35
c64f eb        ex      de,hl
c650 7e        ld      a,(hl)
c651 fee6      cp      $e6              ;STEP token
c653 2006      jr      nz,$c65b         ; (+$06)

c655 cd2cde    call    $de2c			; get next token skipping space
c658 cd62cf    call    $cf62            ;Step value

c65b 79        ld      a,c
c65c cdfffe    call    $feff
c65f e3        ex      (sp),hl
c660 cd83ff    call    $ff83
c663 cdc4fd    call    $fdc4
c666 eb        ex      de,hl
c667 77        ld      (hl),a
c668 23        inc     hl
c669 eb        ex      de,hl
c66a e1        pop     hl
c66b cd37de    call    $de37            ;Validate step is an INT
c66e eb        ex      de,hl
c66f 73        ld      (hl),e
c670 23        inc     hl
c671 72        ld      (hl),d
c672 23        inc     hl
c673 eb        ex      de,hl

c674 cdb1de    call    $deb1            ;Address of current line (for NEXT to jump to)
c677 eb        ex      de,hl
c678 73        ld      (hl),e
c679 23        inc     hl
c67a 72        ld      (hl),d
c67b 23        inc     hl
c67c d1        pop     de
c67d 73        ld      (hl),e
c67e 23        inc     hl
c67f 72        ld      (hl),d
c680 23        inc     hl
c681 ed5b12ac  ld      de,($ac12)
c685 73        ld      (hl),e
c686 23        inc     hl
c687 72        ld      (hl),d
c688 23        inc     hl
c689 70        ld      (hl),b
c68a d1        pop     de

c68b 210dac    ld      hl,$ac0d
c68e cd87ff    call    $ff87
c691 af        xor     a
c692 320cac    ld      ($ac0c),a    ;&00=NEXT not yet used
c695 e1        pop     hl
c696 cdadde    call    $dead
c699 2a12ac    ld      hl,($ac12)
c69c 1809      jr      $c6a7            ; (+$09)

;;=raise Unexpected NEXT
c69e cd45cb    call    $cb45
c6a1 defb $01                         ;Inline error code: Unexpected NEXT

;;========================================================================
;; command NEXT
;NEXT [<list of: <variable>>]
;Ends a FOR loop. See FOR

c6a2 3eff      ld      a,$ff
c6a4 320cac    ld      ($ac0c),a    ;&ff=NEXT has been used
c6a7 eb        ex      de,hl
c6a8 cdd9c6    call    $c6d9
c6ab 20f1      jr      nz,$c69e         ; (-$0f)

c6ad eb        ex      de,hl
c6ae cd5df6    call    $f65d
c6b1 eb        ex      de,hl
c6b2 e5        push    hl
c6b3 cd02c7    call    $c702
c6b6 280f      jr      z,$c6c7          ; (+$0f)

;;Go to end of for statement
c6b8 f1        pop     af
c6b9 23        inc     hl
c6ba 5e        ld      e,(hl)
c6bb 23        inc     hl
c6bc 56        ld      d,(hl)
c6bd 23        inc     hl
c6be 7e        ld      a,(hl)
c6bf 23        inc     hl
c6c0 66        ld      h,(hl)
c6c1 6f        ld      l,a
c6c2 cdadde    call    $dead
c6c5 eb        ex      de,hl
c6c6 c9        ret     

;;=for loop done
;remove data from execution stack
c6c7 010500    ld      bc,$0005
c6ca 09        add     hl,bc
c6cb 5e        ld      e,(hl)
c6cc 23        inc     hl
c6cd 56        ld      d,(hl)
c6ce e1        pop     hl
c6cf cd5df6    call    $f65d
c6d2 eb        ex      de,hl
c6d3 cd41de    call    $de41            ;Test for another NEXT variable
c6d6 38cf      jr      c,$c6a7          ; (-$31) if so, process it
c6d8 c9        ret     

;;=get execution stack data
c6d9 2a6fb0    ld      hl,($b06f)
c6dc e5        push    hl
c6dd 2b        dec     hl
c6de 46        ld      b,(hl)
c6df 23        inc     hl
c6e0 7d        ld      a,l
c6e1 90        sub     b
c6e2 6f        ld      l,a
c6e3 9f        sbc     a,a
c6e4 84        add     a,h
c6e5 67        ld      h,a
c6e6 e3        ex      (sp),hl
c6e7 78        ld      a,b
c6e8 fe07      cp      $07
c6ea 380f      jr      c,$c6fb          ; (+$0f)
c6ec 2000      jr      nz,$c6ee         ; (+$00)
c6ee e5        push    hl
c6ef 2b        dec     hl
c6f0 2b        dec     hl
c6f1 7e        ld      a,(hl)
c6f2 2b        dec     hl
c6f3 6e        ld      l,(hl)
c6f4 67        ld      h,a
c6f5 cdd8ff    call    $ffd8 ; HL=DE?
c6f8 e1        pop     hl
c6f9 2004      jr      nz,$c6ff         ; (+$04)
c6fb eb        ex      de,hl
c6fc e1        pop     hl
c6fd 78        ld      a,b
c6fe c9        ret     

c6ff e1        pop     hl
c700 18da      jr      $c6dc            ; (-$26)

;;=update and test FOR loop counter
c702 5e        ld      e,(hl)
c703 23        inc     hl
c704 56        ld      d,(hl)
c705 23        inc     hl
c706 e5        push    hl
c707 fe10      cp      $10              ;Alternative loop counter variable type??
c709 282c      jr      z,$c737          ; (+$2c)

;counter is a float
c70b 010500    ld      bc,$0005
c70e 79        ld      a,c
c70f eb        ex      de,hl
c710 cd6cff    call    $ff6c
c713 e1        pop     hl
c714 3a0cac    ld      a,($ac0c)
c717 b7        or      a
c718 2810      jr      z,$c72a          ; (+$10) &00=NEXT not yet used (we're still in the FOR!)

c71a e5        push    hl               ;Otherwise update FOR variable (var = var + step)
c71b 09        add     hl,bc
c71c cd0cfd    call    $fd0c
c71f e1        pop     hl
c720 e5        push    hl
c721 2b        dec     hl
c722 56        ld      d,(hl)
c723 2b        dec     hl
c724 5e        ld      e,(hl)
c725 eb        ex      de,hl
c726 cd83ff    call    $ff83
c729 e1        pop     hl

c72a e5        push    hl               ;Compare counter to 'to' value
c72b 0e05      ld      c,$05            ;Comparison operation? greater or equals?
c72d cd49fd    call    $fd49
c730 e1        pop     hl
c731 010a00    ld      bc,$000a
c734 09        add     hl,bc
c735 96        sub     (hl)
c736 c9        ret     

;;=update and test INT for loop counter
c737 eb        ex      de,hl
c738 5e        ld      e,(hl)
c739 23        inc     hl
c73a 56        ld      d,(hl)
c73b 3a0cac    ld      a,($ac0c)
c73e b7        or      a
c73f 2816      jr      z,$c757          ; (+$16) &00=NEXT not yet used (still in FOR statement!)

c741 e3        ex      (sp),hl
c742 e5        push    hl
c743 23        inc     hl
c744 23        inc     hl
c745 7e        ld      a,(hl)
c746 23        inc     hl
c747 66        ld      h,(hl)
c748 6f        ld      l,a
c749 cd4add    call    $dd4a
c74c 3e06      ld      a,$06            ;Overflow error
c74e d255cb    jp      nc,$cb55

c751 eb        ex      de,hl
c752 e1        pop     hl
c753 e3        ex      (sp),hl
c754 72        ld      (hl),d
c755 2b        dec     hl
c756 73        ld      (hl),e

c757 e1        pop     hl               ;Test loop counter against 'to' condition
c758 7e        ld      a,(hl)
c759 23        inc     hl
c75a e5        push    hl
c75b 66        ld      h,(hl)
c75c 6f        ld      l,a
c75d eb        ex      de,hl
c75e cd02de    call    $de02
c761 e1        pop     hl
c762 23        inc     hl
c763 23        inc     hl
c764 23        inc     hl
c765 96        sub     (hl)
c766 c9        ret     

;;========================================================================
;; command IF
;IF <logical expression> THEN <option part> [ELSE <option part>]
;IF <logical expression> GOTO <line number> [ELSE <option part>]
;where <option part> is <statements> or <line number>
;Conditional execution.
;An IF statement terminates at the end of the line.
;GOTO can also be GO TO
;Line numbers must be constants
;IF statements can be nested as long as they are all on the same line.

c767 cd62cf    call    $cf62
c76a fea0      cp      $a0              ;GOTO token
c76c 2804      jr      z,$c772          ; (+$04) IF [cond] GOTO [n] syntax
c76e cd25de    call    $de25
c771 defb $eb    ;Token to test "THEN"

c772 cdc4fd    call    $fdc4            ;test condition
c775 cc5be9    call    z,$e95b          ;condition false - skip to ELSE
c778 c8        ret     z                ;No else?

c779 cd3dde    call    $de3d       
c77c d8        ret     c             ;end of statement/line

c77d fe1e      cp      $1e				; 16-bit integer BASIC line number
c77f 2805      jr      z,$c786          ;if so it's a GOTO
c781 fe1d      cp      $1d				; 16-bit BASIC program line memory address pointer
c783 c28fde    jp      nz,$de8f         ;if not memory address pointer then execute whatever it is
                                        ;otherwise fall through to...

;;========================================================================
;; command GOTO
;GOTO <line number>
;GO TO <line number>
;Jump to a line. Line number must be a constant

c786 cd27e8    call    $e827
c789 c0        ret     nz

c78a eb        ex      de,hl
c78b c9        ret     

;;========================================================================
;; command GOSUB
;GOSUB <line number>
;GO SUB <line number>
;Call a subroutine. Line number must be a constant.

c78c cd27e8    call    $e827
c78f c0        ret     nz

;;=GOSUB HL
c790 eb        ex      de,hl
c791 0e00      ld      c,$00        ;C=type of GOSUB. &00=regular

;;=special GOSUB HL
;C=gosub type (e.g. ON ERROR, ON BREAK, event etc).
;This code sets the next current line pointer and returns eith execution address in HL
c793 e5        push    hl
c794 3e06      ld      a,$06
c796 cd72f6    call    $f672
c799 71        ld      (hl),c
c79a 23        inc     hl
c79b 73        ld      (hl),e
c79c 23        inc     hl
c79d 72        ld      (hl),d
c79e 23        inc     hl
c79f eb        ex      de,hl
c7a0 cdb1de    call    $deb1
c7a3 eb        ex      de,hl
c7a4 73        ld      (hl),e
c7a5 23        inc     hl
c7a6 72        ld      (hl),d
c7a7 23        inc     hl
c7a8 3606      ld      (hl),$06
c7aa 23        inc     hl
c7ab cd5df6    call    $f65d
c7ae e1        pop     hl
c7af c9        ret     

;;========================================================================
;; command RETURN
;RETURN
;Returns from a subroutine

c7b0 c0        ret     nz
c7b1 cdcfc7    call    $c7cf
c7b4 cd5df6    call    $f65d
c7b7 4e        ld      c,(hl)
c7b8 23        inc     hl
c7b9 5e        ld      e,(hl)
c7ba 23        inc     hl
c7bb 56        ld      d,(hl)
c7bc 23        inc     hl
c7bd 7e        ld      a,(hl)
c7be 23        inc     hl
c7bf 66        ld      h,(hl)
c7c0 6f        ld      l,a
c7c1 cdadde    call    $dead
c7c4 eb        ex      de,hl
c7c5 79        ld      a,c
c7c6 fe01      cp      $01
c7c8 d8        ret     c

c7c9 ca51c9    jp      z,$c951
c7cc c361c9    jp      $c961

;;=find last RETURN item on execution stack
c7cf 2a6fb0    ld      hl,($b06f)
c7d2 2b        dec     hl
c7d3 7e        ld      a,(hl)
c7d4 f5        push    af
c7d5 7d        ld      a,l
c7d6 96        sub     (hl)
c7d7 6f        ld      l,a
c7d8 9f        sbc     a,a
c7d9 84        add     a,h
c7da 67        ld      h,a
c7db 23        inc     hl
c7dc f1        pop     af
c7dd fe06      cp      $06
c7df c8        ret     z

c7e0 b7        or      a
c7e1 20ef      jr      nz,$c7d2         ; (-$11)
c7e3 cd45cb    call    $cb45
c7e6 defb $03                         ;Inline error code: Unexpected RETURN

;;========================================================================
;; command WHILE
;WHILE <logical expression>
;Begins a WHILE ... WEND loop
;The matching WEND is established when WHILE is encountered, and is searched for sequentially
;in the code, ignoring order of execution, but respecting and nested WHILE loops.
;WHILE can be terminated by avoiding the WEND

c7e7 e5        push    hl
c7e8 cdc9ca    call    $cac9
c7eb e5        push    hl
c7ec eb        ex      de,hl

;Find data on execution stack
c7ed 2214ac    ld      ($ac14),hl
c7f0 cd5dc8    call    $c85d
c7f3 cc5df6    call    z,$f65d

;Data not found on execution stack so add it
c7f6 3e07      ld      a,$07
c7f8 cd72f6    call    $f672
c7fb eb        ex      de,hl
c7fc cdb1de    call    $deb1
c7ff eb        ex      de,hl
c800 73        ld      (hl),e
c801 23        inc     hl
c802 72        ld      (hl),d
c803 23        inc     hl
c804 d1        pop     de
c805 73        ld      (hl),e
c806 23        inc     hl
c807 72        ld      (hl),d
c808 23        inc     hl
c809 eb        ex      de,hl
c80a e3        ex      (sp),hl
c80b eb        ex      de,hl
c80c 73        ld      (hl),e
c80d 23        inc     hl
c80e 72        ld      (hl),d
c80f 23        inc     hl
c810 3607      ld      (hl),$07
c812 23        inc     hl
c813 cd5df6    call    $f65d
c816 eb        ex      de,hl
c817 d1        pop     de
c818 182a      jr      $c844            ; (+$2a)

;;========================================================================
;; command WEND
;WEND
;Terminates a WHILE ... WEND loop.
;See WHILE

c81a c0        ret     nz
c81b eb        ex      de,hl
c81c cd5dc8    call    $c85d
c81f 3e1e      ld      a,$1e          ; Unexpected WEND error
c821 c255cb    jp      nz,$cb55

c824 e5        push    hl
c825 110700    ld      de,$0007
c828 19        add     hl,de
c829 cd5df6    call    $f65d
c82c cdb1de    call    $deb1
c82f 2214ac    ld      ($ac14),hl
c832 e1        pop     hl
c833 5e        ld      e,(hl)
c834 23        inc     hl
c835 56        ld      d,(hl)
c836 23        inc     hl
c837 eb        ex      de,hl
c838 cdadde    call    $dead        ;Go to the WHILE statement?
c83b eb        ex      de,hl
c83c 5e        ld      e,(hl)
c83d 23        inc     hl
c83e 56        ld      d,(hl)
c83f 23        inc     hl
c840 7e        ld      a,(hl)
c841 23        inc     hl
c842 66        ld      h,(hl)
c843 6f        ld      l,a

;;=eval WHILE condition
c844 d5        push    de
c845 cd62cf    call    $cf62
c848 cdc4fd    call    $fdc4
c84b d1        pop     de
c84c c0        ret     nz           ;Condition true? - continue after the WHILE

c84d 2a14ac    ld      hl,($ac14)   ;else remove execution stack data and continue after the WEND
c850 cdadde    call    $dead
c853 3e07      ld      a,$07
c855 cd62f6    call    $f662
c858 cd5df6    call    $f65d
c85b eb        ex      de,hl
c85c c9        ret     

;;=find WHILE/WEND data on execution stack
c85d 2a6fb0    ld      hl,($b06f)
c860 2b        dec     hl
c861 e5        push    hl
c862 7d        ld      a,l
c863 96        sub     (hl)
c864 6f        ld      l,a
c865 9f        sbc     a,a
c866 84        add     a,h
c867 67        ld      h,a
c868 23        inc     hl
c869 e3        ex      (sp),hl
c86a 7e        ld      a,(hl)
c86b fe07      cp      $07
c86d 380e      jr      c,$c87d          ; (+$0e)
c86f 200e      jr      nz,$c87f         ; (+$0e)
c871 2b        dec     hl
c872 2b        dec     hl
c873 2b        dec     hl
c874 7e        ld      a,(hl)
c875 2b        dec     hl
c876 6e        ld      l,(hl)
c877 67        ld      h,a
c878 cdd8ff    call    $ffd8 ; HL=DE?
c87b 2002      jr      nz,$c87f         ; (+$02)
c87d e1        pop     hl
c87e c9        ret     

c87f e1        pop     hl
c880 18de      jr      $c860            ; (-$22)




;;***EventsExceptions.asm
;;<< ERROR AND EVENT HANDLERS
;;< ON xx, DI, EI, AFTER, EVERY, REMAIN
;;========================================================================
;; command ON, ON ERROR GOTO
;(except ON ERROR GOTO 0!)

;ON <selector> GOTO <list of: <line number>>
;ON <selector> GOSUB <list of: <line number>>
;Choose on of a number of destinations based off a value.
;Value must be 0..255
;Value 1 selects the first target, 2 the second and so on.
;Value 0 or any value greater than the number of items in the list does nothing.

;ON ERROR GOTO <line number>
;Turns on error processing mode. Can be turned off with ON ERROR GOTO 0 (see elsewhere)
;The specified line will be jumped to when an error occurs. ERR and ERL can be used to 
;handle errors, or ERROR to invoke default error handling. RESUME can be used to return.

c882 fe9c      cp      $9c              ;token for ERROR
c884 cab8cc    jp      z,$ccb8



c887 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
c88a 4f        ld      c,a              ;C = index into list of item to goto/gosub
c88b 7e        ld      a,(hl)
c88c fea0      cp      $a0              ;GOTO token
c88e f5        push    af
c88f 2805      jr      z,$c896          ; (+$05)

c891 cd25de    call    $de25
c894 defb $9f   ;Inline token to test "GOSUB"
c895 2b        dec     hl

;Loop reading line numbers and decrementing C until C gets to zero or we run out of items
c896 cd2cde    call    $de2c			; get next token skipping space
c899 0d        dec     c
c89a 280a      jr      z,$c8a6          ; (+$0a)
c89c cd48cf    call    $cf48
c89f cd41de    call    $de41
c8a2 38f5      jr      c,$c899          ; (-$0b)
c8a4 f1        pop     af
c8a5 c9        ret     

;;=do on goto gosub
c8a6 cd27e8    call    $e827
c8a9 c4a3e9    call    nz,$e9a3			;NZ means item not found - call DATA to 
                                        ;skip over list and contnue execution at the next line
c8ac f1        pop     af
c8ad c290c7    jp      nz,$c790         ;Do a GOSUB
c8b0 eb        ex      de,hl            ;else do a GOTO
c8b1 c9        ret     

;;=prob process pending events
c8b2 af        xor     a
c8b3 3216ac    ld      ($ac16),a

c8b6 cdfbbc    call    $bcfb			; firmware function: kl next sync 
c8b9 301d      jr      nc,$c8d8         ; (+$1d)
c8bb 47        ld      b,a
c8bc 3a16ac    ld      a,($ac16)
c8bf e67f      and     $7f
c8c1 3216ac    ld      ($ac16),a
c8c4 c5        push    bc
c8c5 e5        push    hl
c8c6 cdfebc    call    $bcfe			; firmware function: kl do sync
c8c9 e1        pop     hl
c8ca c1        pop     bc
c8cb 3a16ac    ld      a,($ac16)
c8ce 17        rla     
c8cf f5        push    af
c8d0 78        ld      a,b
c8d1 d401bd    call    nc,$bd01			; firmware function: kl done sync
c8d4 f1        pop     af
c8d5 17        rla     
c8d6 30de      jr      nc,$c8b6         ; (-$22) Loop for more

;;=finished processing events
c8d8 3a16ac    ld      a,($ac16)
c8db e604      and     $04
c8dd c47fc4    call    nz,$c47f
c8e0 2a1bae    ld      hl,($ae1b)
c8e3 3a16ac    ld      a,($ac16)
c8e6 e603      and     $03
c8e8 c8        ret     z

c8e9 1f        rra     
c8ea da3ecc    jp      c,$cc3e
c8ed 23        inc     hl
c8ee f1        pop     af
c8ef c377de    jp      $de77

;;=do ON BREAK
;(Called after the break pause and then unpause)
c8f2 221cac    ld      ($ac1c),hl
c8f5 3e04      ld      a,$04
c8f7 3052      jr      nc,$c94b         ; (+$52) ON BREAK STOP?

c8f9 2a1aac    ld      hl,($ac1a)
c8fc 7c        ld      a,h
c8fd b5        or      l
c8fe c4b5de    call    nz,$deb5
c901 3e41      ld      a,$41
c903 3046      jr      nc,$c94b         ; (+$46) ON BREAK GOSUB

c905 c5        push    bc               ;ON BREAK CONTinue?
c906 cdb9bc    call    $bcb9			; firmware function: sound continue
c909 c1        pop     bc
c90a 1117ac    ld      de,$ac17
c90d 0e02      ld      c,$02
c90f 1822      jr      $c933            ; (+$22)

;;=eval and setup event GOSUB handler
;Used by ON SQ, AFTER and EVERY
;evals the gosub and line number and stores in the relevant event data block
;DE=event data block address?
c911 d5        push    de
c912 cd25de    call    $de25
c915 defb $9f  ;Inline token to test "GOSUB"
c916 cd27e8    call    $e827
c919 42        ld      b,d
c91a 4b        ld      c,e
c91b d1        pop     de
c91c e5        push    hl
c91d 210a00    ld      hl,$000a
c920 19        add     hl,de
c921 71        ld      (hl),c
c922 23        inc     hl
c923 70        ld      (hl),b
c924 e1        pop     hl
c925 c9        ret     

;;==============================================
;;event handler routine
;Called by the firmware for events
c926 23        inc     hl
c927 23        inc     hl
c928 23        inc     hl
c929 eb        ex      de,hl
c92a cdb5de    call    $deb5
c92d 3e40      ld      a,$40
c92f 301a      jr      nc,$c94b         ; (+$1a)
c931 0e01      ld      c,$01            ;GOSUB type

;;=handle event etc GOSUBs
;C specifies gosub type
;DE=address to store data for this event type
c933 d5        push    de
c934 cd93c7    call    $c793            
c937 2a1bae    ld      hl,($ae1b)
c93a eb        ex      de,hl
c93b e1        pop     hl
c93c 70        ld      (hl),b
c93d 23        inc     hl
c93e 73        ld      (hl),e
c93f 23        inc     hl
c940 72        ld      (hl),d
c941 23        inc     hl
c942 5e        ld      e,(hl)
c943 23        inc     hl
c944 56        ld      d,(hl)
c945 eb        ex      de,hl
c946 221bae    ld      ($ae1b),hl
c949 3ec2      ld      a,$c2

;;=poss event done?
c94b 2116ac    ld      hl,$ac16
c94e b6        or      (hl)
c94f 77        ld      (hl),a
c950 c9        ret     

;;=prob RETURN from event handler
;RETURN statement executed in an event handler
c951 7e        ld      a,(hl)
c952 23        inc     hl
c953 5e        ld      e,(hl)
c954 23        inc     hl
c955 56        ld      d,(hl)
c956 d5        push    de
c957 01f7ff    ld      bc,$fff7         ;##LIT##
c95a 09        add     hl,bc
c95b cd01bd    call    $bd01			; firmware function: KL DONE SYNC
c95e e1        pop     hl
c95f 1811      jr      $c972            ; (+$11)

;;=prob RETURN from break handler
c961 7e        ld      a,(hl)
c962 2a1cac    ld      hl,($ac1c)
c965 01fcff    ld      bc,$fffc			; JP (BC) ##LIT##
c968 09        add     hl,bc
c969 cd01bd    call    $bd01			; firmware function: KL DONE SYNC
c96c cd7fc4    call    $c47f
c96f 2a18ac    ld      hl,($ac18)
c972 f1        pop     af
c973 c360de    jp      $de60

;;========================================================================
;; command ON BREAK GOSUB, ON BREAK CONT, ON BREAK STOP
;ON BREAK GOSUB <line number>
;ON BREAK STOP
;Performs the specified action when [ESC][ESC] is pressed

c976 cd7cc9    call    $c97c
c979 c32cde    jp      $de2c			; get next token skipping space

c97c fe8b      cp      $8b				; token for "CONT"
c97e cad0c4    jp      z,$c4d0			; ON BREAK CONT

c981 fece      cp      $ce				; token for "STOP"
c983 110000    ld      de,$0000         ;##LIT##
c986 2808      jr      z,$c990          ; ON BREAK STOP

;; 
c988 cd25de    call    $de25
c98b defb $9f								; token for "GOSUB"
c98c cd27e8    call    $e827
c98f 2b        dec     hl

;;=set ON BREAK handler line address
c990 ed531aac  ld      ($ac1a),de
c994 c3d3c4    jp      $c4d3			; ON BREAK STOP


;;EVENTS
;;========================================================================
;; command DI
;DI
;Disables interrupts (BASIC interrupts, not system/machine code interrupts)
;Does not affect break interrupts (ESC key)
;If interrupts are disabled in an interrupt handler subroutine they are
;implicitly re-enabled by the terminating RETURN statement

c997 e5        push    hl
c998 cd04bd    call    $bd04			; firmware function: KL EVENT DISABLE
c99b e1        pop     hl
c99c c9        ret     

;;========================================================================
;; command EI
;EI
;Enables interrupts which have been disabled by DI
;See DI

c99d e5        push    hl
c99e cd07bd    call    $bd07			; firmware function: KL EVENT ENABLE
c9a1 e1        pop     hl
c9a2 c9        ret     

;;========================================================================
;;initialise event system
c9a3 cda7bc    call    $bca7			; firmware function: SOUND RESET
c9a6 2142ac    ld      hl,$ac42
c9a9 0604      ld      b,$04

;;delete sound events loop
c9ab e5        push    hl
c9ac cdecbc    call    $bcec			; firmware function: KL DEL TICKER
c9af e1        pop     hl
c9b0 111200    ld      de,$0012
c9b3 19        add     hl,de
c9b4 10f5      djnz    $c9ab            

c9b6 cd48bb    call    $bb48			; firmware function: KL DISARM BREAK
c9b9 cdf5bc    call    $bcf5			; firmware function: KL SYNC RESET
c9bc 210000    ld      hl,$0000         ;##LIT##
c9bf 221aac    ld      ($ac1a),hl
c9c2 cd7fc4    call    $c47f
c9c5 211eac    ld      hl,$ac1e
c9c8 110503    ld      de,$0305
c9cb 010008    ld      bc,$0800
c9ce cddac9    call    $c9da
c9d1 2148ac    ld      hl,$ac48        ;address of event block
c9d4 110b04    ld      de,$040b
c9d7 010102    ld      bc,$0201        ;B = event class

;;=Initialise event blocks
;D=count of event blocks to initialise
c9da c5        push    bc
c9db d5        push    de
c9dc 0efd      ld      c,$fd           ;ROM select address
c9de 1126c9    ld      de,$c926         ;address of event routine ##LLABEL##
c9e1 cdefbc    call    $bcef			; firmware function: KL INIT EVENT 
c9e4 d1        pop     de
c9e5 d5        push    de
c9e6 1600      ld      d,$00
c9e8 19        add     hl,de
c9e9 d1        pop     de
c9ea c1        pop     bc
c9eb 79        ld      a,c
c9ec b7        or      a
c9ed 2802      jr      z,$c9f1          ; (+$02)
c9ef cb00      rlc     b
c9f1 15        dec     d
c9f2 20e6      jr      nz,$c9da         ; (-$1a) Loop for next block
c9f4 c9        ret     

;;========================================================================
;; command ON SQ
;ON SQ(<channel>) GOSUB <line number>
;channel number = 1,2,4 for channels A, B, or C
;Enables an interrupt for when there is a free slot in the given sound queue.
;The SOUND command and SQ function disable ON SQ interrupts

c9f5 cd19de    call    $de19 ; check for open bracket
c9f8 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
c9fb f5        push    af
c9fc cd10ca    call    $ca10
c9ff b7        or      a
ca00 201d      jr      nz,$ca1f         ; (+$1d)
ca02 cd1dde    call    $de1d ; check for close bracket
ca05 cd11c9    call    $c911    ;Read GOSUB and address and set up
ca08 f1        pop     af
ca09 e5        push    hl
ca0a eb        ex      de,hl
ca0b cdb0bc    call    $bcb0				; firmware function: sound arm event
ca0e e1        pop     hl
ca0f c9        ret     

;;=get event block for channel
ca10 1f        rra     
ca11 111eac    ld      de,$ac1e
ca14 d8        ret     c

ca15 1f        rra     
ca16 112aac    ld      de,$ac2a
ca19 d8        ret     c

ca1a 1f        rra     
ca1b 1136ac    ld      de,$ac36
ca1e d8        ret     c

;;=raise Improper argument error
ca1f c34dcb    jp      $cb4d			; Error: Improper Argument

;;==================================================================
;; command AFTER
;AFTER <time delay>[,<timer number>] GOSUB <line number>
;Call a subroutine after the specified period in 1/50ths of a second
;Timer number 0-3, default 0. Timer 3 has highest priority, 0 the lowest.

ca22 cdcece    call    $cece            ;Get delay
ca25 010000    ld      bc,$0000         ;##LIT##
ca28 1805      jr      $ca2f            ; (+$05)

;;==================================================================
;; command EVERY
;EVERY <time delay>[,<timer number>] GOSUB <line number>
;Call a subroutine at regular intervals, given in 1/50ths of a second
;Timer number 0-3, default 0

ca2a cdcece    call    $cece            ;Get period
ca2d 42        ld      b,d
ca2e 4b        ld      c,e

;;=init timer event
ca2f d5        push    de
ca30 c5        push    bc
ca31 cd41de    call    $de41
ca34 110000    ld      de,$0000         ;##LIT##
ca37 dcd8ce    call    c,$ced8          ; get timer number
ca3a eb        ex      de,hl
ca3b cd62ca    call    $ca62

ca3e e5        push    hl
ca3f 010600    ld      bc,$0006
ca42 09        add     hl,bc
ca43 eb        ex      de,hl
ca44 cd11c9    call    $c911
ca47 d1        pop     de
ca48 c1        pop     bc
ca49 e3        ex      (sp),hl
ca4a eb        ex      de,hl
ca4b cde9bc    call    $bce9			; firmware function: kl add ticker
ca4e e1        pop     hl
ca4f c9        ret     

;;========================================================
;; function REMAIN
;REMAIN(<timer number>)
;Gets the timer remaining count for a timer.
;Values 0..3
;Returns zero if the timer was not enabled

ca50 cdb6fe    call    $feb6
ca53 cd62ca    call    $ca62
ca56 cdecbc    call    $bcec			; firmware function: kl del ticker
ca59 3803      jr      c,$ca5e          ; (+$03)
ca5b 110000    ld      de,$0000         ;##LIT##
ca5e eb        ex      de,hl
ca5f c335ff    jp      $ff35

;;=calc AFTER/EVERY ticker block address
;HL=ticker block number (0-3)
;out: HL=address
ca62 7c        ld      a,h
ca63 b7        or      a
ca64 20b9      jr      nz,$ca1f         ; (-$47)
ca66 7d        ld      a,l
ca67 fe04      cp      $04
ca69 30b4      jr      nc,$ca1f         ; (-$4c)
ca6b 87        add     a,a              ;Calc offset/address within ticker block
ca6c 87        add     a,a
ca6d 87        add     a,a
ca6e 85        add     a,l
ca6f 87        add     a,a
ca70 6f        ld      l,a
ca71 0142ac    ld      bc,$ac42
ca74 09        add     hl,bc
ca75 c9        ret     




;;***ControlFlowUtils.asm
;;<< FIND ENDS OF CONTROL LOOPS
;;< Don't have a good phrase for this :(
;;============================

;;=find matching NEXT
;Scan forward from a FOR statement to find the matching NEXT,
;ie. the NEXT with the same loop counter variable, considering that a NEXT 
;can list multiple variables, (or with an implicit control variable)
;Records the 'depth' for FOR..NEXT nesting in the B register - this
;must be zero when we find the matching NEXT.

ca76 eb        ex      de,hl
ca77 cdb1de    call    $deb1
ca7a eb        ex      de,hl
ca7b 2b        dec     hl
ca7c 0601      ld      b,$01            ;Nesting depth counter
ca7e 0e1a      ld      c,$1a            ;NEXT missing error
ca80 cddde9    call    $e9dd            ;Skip guff
ca83 e5        push    hl
ca84 cd2cde    call    $de2c			
ca87 feb0      cp      $b0              ;NEXT token
ca89 2808      jr      z,$ca93          ; (+$08)
ca8b e1        pop     hl

ca8c fe9e      cp      $9e              ;FOR token
ca8e 20ee      jr      nz,$ca7e         ; (-$12) Not a FOR - loop
ca90 04        inc     b                ;Found a nested FOR - increase depth and loop
ca91 18eb      jr      $ca7e            ; (-$15)

;;==============================================
;;=match within NEXT
ca93 f1        pop     af
ca94 eb        ex      de,hl
ca95 e5        push    hl
ca96 cdb1de    call    $deb1
ca99 e3        ex      (sp),hl
ca9a cdadde    call    $dead
ca9d eb        ex      de,hl
ca9e 05        dec     b                ;Dec depth
ca9f 2824      jr      z,$cac5          ; (+$24) Done if zero
caa1 cd2cde    call    $de2c			; get next token skipping space
caa4 280e      jr      z,$cab4          ; (+$0e) No variables specified

caa6 c5        push    bc               ;NEXT has one or more variable names listed - check them
caa7 d5        push    de
caa8 cdbfd6    call    $d6bf
caab d1        pop     de
caac c1        pop     bc
caad cd41de    call    $de41
cab0 3002      jr      nc,$cab4         ; (+$02) End of list - done
cab2 10f2      djnz    $caa6            ; (-$0e) Loop until nestin depth=0

cab4 2b        dec     hl
cab5 78        ld      a,b
cab6 b7        or      a
cab7 280c      jr      z,$cac5          ; (+$0c) Nesting level zero - done

cab9 eb        ex      de,hl
caba cdb1de    call    $deb1
cabd e3        ex      (sp),hl
cabe cdadde    call    $dead
cac1 e1        pop     hl
cac2 eb        ex      de,hl
cac3 18b9      jr      $ca7e            ; (-$47) Continue looking for NEXTs

;;=match within NEXT done
cac5 d1        pop     de
cac6 c32cde    jp      $de2c			; get next token skipping space

;;==============================================
;;=find matching WEND
;Scan forward to find the next WEND, ignoring any intermedtiate WHILE/WEND loops
;It does this with a depth counter in the B register
cac9 2b        dec     hl
caca eb        ex      de,hl
cacb cdb1de    call    $deb1
cace eb        ex      de,hl
cacf 0600      ld      b,$00            ;Init depth counter

cad1 04        inc     b                ;Inc depth counter

cad2 0e1d      ld      c,$1d            ;WEND missing error
cad4 cddde9    call    $e9dd            ;Find next statement
cad7 e5        push    hl
cad8 cd2cde    call    $de2c			; get next token skipping space
cadb e1        pop     hl
cadc fed6      cp      $d6              ;WHILE token
cade 28f1      jr      z,$cad1          ; (-$0f) Inc depth counter

cae0 fed5      cp      $d5              ;WEND token
cae2 20ee      jr      nz,$cad2         ; (-$12)
cae4 10ec      djnz    $cad2            ; (-$14) Dec depth counter and loop if non zero

cae6 cd2cde    call    $de2c			; get next token skipping space
cae9 c32cde    jp      $de2c			; get next token skipping space






;;***BasicInput.asm
;;<< BASIC INPUT BUFFER
;;< As used by EDIT and INPUT etc.
;;===================================

;; prob read buffer and or break
;Called by (LINE) INPUT and RANDOMISE to get text input.
caec cdf9ca    call    $caf9			; edit
caef d8        ret     c

caf0 cda1c1    call    $c1a1
caf3 3100c0    ld      sp,$c000         ;##LIT##
caf6 c35dde    jp      $de5d

;;------------------------------------------------------------------------------------------
;;=input text to BASIC input area
caf9 218aac    ld      hl,$ac8a
cafc 3600      ld      (hl),$00
cafe c35ebd    jp      $bd5e			; TEXT INPUT

;;------------------------------------------------------------------------------------------
;;=edit text in BASIC input area and display new line
cb01 218aac    ld      hl,$ac8a
cb04 cd5ebd    call    $bd5e		; TEXT INPUT
cb07 c398c3    jp      $c398      ;; new text line

;;------------------------------------------------------------------------------------------
;;=read line from cassette or disc
;Reads into the BASIC input area
;Returns CF=1 if success
cb0a c5        push    bc
cb0b 218aac    ld      hl,$ac8a
cb0e e5        push    hl
cb0f 0600      ld      b,$00            ;Buffer free bytes remaining

cb11 0ef5      ld      c,$f5            ;C=previous byte

;;=read to buffer loop
cb13 3600      ld      (hl),$00         ;End of buffer marker
cb15 cd5cc4    call    $c45c ; read byte from cassette or disc
cb18 301a      jr      nc,$cb34         ; (+$1a) end of file?
cb1a fe0d      cp      $0d              ;CR
cb1c 2810      jr      z,$cb2e          ; (+$10) end of line = done
cb1e 4f        ld      c,a
cb1f 04        inc     b
cb20 1004      djnz    $cb26            ; (+$04) skip if not end of line
cb22 fe0a      cp      $0a              ;LF 
cb24 28eb      jr      z,$cb11          ; (-$15) happy to skip LF at end of line
                                        ;(if may be followed by CR, which is true end of line
                                        
cb26 77        ld      (hl),a           ;Store byte
cb27 23        inc     hl
cb28 10e9      djnz    $cb13            ; (-$17) Loop for next byte

cb2a cd45cb    call    $cb45            ;Buffer full
cb2d defb $17                         ;Inline error code: Line too long
     
;CR read
cb2e 79        ld      a,c              ;get previous byte
cb2f fe0a      cp      $0a              ;LF
cb31 28de      jr      z,$cb11          ; (-$22) End of line is LF followed by CR. If not keep reading
cb33 37        scf                      ;Success

cb34 e1        pop     hl
cb35 c1        pop     bc
cb36 c9        ret     






;;***Errors.asm
;;<< EXCEPTION HANDLING
;;< Includes ERROR, STOP, END, ON ERROR GOTO 0 (not ON ERROR GOTO n!), RESUME and error messages
;;========================================================================
;; clear errors and set resume addr to current
cb37 af        xor     a
cb38 3291ad    ld      ($ad91),a
;;=clear error and set resume addr to current
cb3b 3290ad    ld      ($ad90),a
cb3e cdb1de    call    $deb1
cb41 228cad    ld      ($ad8c),hl    ;resume address
cb44 c9        ret     

;;========================================================================
;; - byte following call is error code
cb45 e3        ex      (sp),hl
cb46 7e        ld      a,(hl)
cb47 180c      jr      $cb55            

;;========================================================================
;; Error: Syntax Error
cb49 3e02      ld      a,$02        ;Syntax error error
cb4b 1808      jr      $cb55            ; (+$08)

;;========================================================================
;; Error: Improper Argument

cb4d 3e05      ld      a,$05        ;Improper argument error
cb4f 1804      jr      $cb55            ; (+$04)

;;========================================================================
;; command ERROR
;ERROR <integer expression>
;Raise the given error.
;Valid values are 1..255. If the error number is not recognised then 'Unknown error' is produced

cb51 cdc3ce    call    $cec3
cb54 c0        ret     nz

;;+raise error
; A = Error code
cb55 cd3bcb    call    $cb3b
cb58 2a1bae    ld      hl,($ae1b)
cb5b 228ead    ld      ($ad8e),hl
cb5e cd83cc    call    $cc83             ; I presume we're testing for ON ERROR handlers
cb61 cd3cf6    call    $f63c
;;=raise error no tracking
cb64 3100c0    ld      sp,$c000           ;##LIT##
cb67 2a19ae    ld      hl,($ae19)
cb6a cd6ef6    call    $f66e
cb6d cdccfb    call    $fbcc
cb70 cd20da    call    $da20
cb73 cdaacb    call    $cbaa  ;C set if we have resume address
cb76 2a96ad    ld      hl,($ad96)     
cb79 eb        ex      de,hl
cb7a 2198ad    ld      hl,$ad98
cb7d 300c      jr      nc,$cb8b         ; (+$0c) no resume address
cb7f 7a        ld      a,d              ;
cb80 b3        or      e
cb81 2808      jr      z,$cb8b          ; (+$08) resume address is zero
cb83 a6        and     (hl)             ; test if ON ERROR RESUME active ??
cb84 2005      jr      nz,$cb8b         ; (+$05)
cb86 35        dec     (hl)
cb87 eb        ex      de,hl
cb88 c377de    jp      $de77            ; ON ERROR RESUME??

;;=display error then do REPL
cb8b 3600      ld      (hl),$00
cb8d 3a90ad    ld      a,($ad90)
cb90 cd8cce    call    $ce8c
cb93 2a8cad    ld      hl,($ad8c)       ;resume address
cb96 cdadde    call    $dead
cb99 3a90ad    ld      a,($ad90)
cb9c ee20      xor     $20
cb9e 2004      jr      nz,$cba4         ; (+$04)
cba0 3a91ad    ld      a,($ad91)
cba3 17        rla     
cba4 d404cc    call    nc,$cc04
cba7 c358c0    jp      $c058

;;=======================================================================
;;get resume line number
;C set if we have a resume line
cbaa 2a8cad    ld      hl,($ad8c)      ;resume address
cbad cdb8de    call    $deb8
cbb0 d8        ret     c
cbb1 210000    ld      hl,$0000         ;##LIT##
cbb4 c9        ret     

;;=======================================================================
;;division by zero error
cbb5 d5        push    de
cbb6 e5        push    hl
cbb7 21f6cd    ld      hl,$cdf6
cbba 1e0b      ld      e,$0b            ;Division by zero error
cbbc 1807      jr      $cbc5            ; (+$07)

;;=overflow error
cbbe d5        push    de
cbbf e5        push    hl
cbc0 21bfcd    ld      hl,$cdbf
cbc3 1e06      ld      e,$06            ;Overflow error

;;=maths error
;HL=error message address
;E=error code
cbc5 f5        push    af
cbc6 e5        push    hl
cbc7 2a96ad    ld      hl,($ad96)
cbca 7c        ld      a,h
cbcb b5        or      l
cbcc e1        pop     hl
cbcd 7b        ld      a,e              ;Error code
cbce c255cb    jp      nz,$cb55         ;If we have ON ERROR handler raise by usual method

cbd1 af        xor     a                ;Otherwise raise manually
cbd2 cda6c1    call    $c1a6
cbd5 f5        push    af
cbd6 eb        ex      de,hl
cbd7 cd79ce    call    $ce79
cbda eb        ex      de,hl
cbdb cd98c3    call    $c398      ;; new text line
cbde f1        pop     af
cbdf cda6c1    call    $c1a6
cbe2 f1        pop     af
cbe3 e1        pop     hl
cbe4 d1        pop     de
cbe5 c9        ret     

;;==================================================
;;undefined line n in n error
cbe6 cdd0c3    call    $c3d0
cbe9 21f1cb    ld      hl,$cbf1
cbec cd15cc    call    $cc15
cbef 181c      jr      $cc0d            ; (+$1c)

;;=undefined line message
cbf1 defb "Undefined line ",0

;;=========================================
;;break in n error
cc01 111ccc    ld      de,$cc1c			; "Break"

;;=display error "in [current line number]"
cc04 cda1c1    call    $c1a1
cc07 cdd0c3    call    $c3d0
cc0a cd79ce    call    $ce79

;;=displey error "in [current line number]"
cc0d cdb5de    call    $deb5
cc10 d0        ret     nc

cc11 eb        ex      de,hl
cc12 2121cc    ld      hl,$cc21		;; " in " message

;;=display error with line number
cc15 cd8bc3    call    $c38b		;; display 0 terminated string
cc18 eb        ex      de,hl
cc19 c344ef    jp      $ef44

;;=Break message
cc1c defb "Brea","k"+$80		;($eb)

;;= in message
cc21 defb " in ",0

;;========================================================================
;; command STOP
;STOP
;Halts execution leaving BASIC in a state where the program can be restarted.
;Useful when debugging. Program can be restarted with CONT

cc26 c0        ret     nz
cc27 e5        push    hl
cc28 cd01cc    call    $cc01
cc2b e1        pop     hl
cc2c cd66cc    call    $cc66
cc2f 1832      jr      $cc63            ; (+$32)

;;========================================================================
;; command END
;END
;End program execution. Closes all files. Does not stop sound generation.

cc31 c0        ret     nz
cc32 cd66cc    call    $cc66
cc35 1823      jr      $cc5a            ; (+$23)

;;=raise File not open error
cc37 3291ad    ld      ($ad91),a
cc3a cd45cb    call    $cb45
cc3d defb $20                         ;File not open error

;;=unknown execution error
cc3e cd01cc    call $cc01
cc41 2a1bae    ld hl,($ae1b)
cc44 cd83cc    call    $cc83
cc47 181a      jr      $cc63            ; (+$1a)

;;=prob end of program
cc49 cdb5de    call    $deb5
cc4c 3012      jr      nc,$cc60         ; (+$12)
cc4e cd7ecc    call    $cc7e
cc51 3a98ad    ld      a,($ad98)
cc54 b7        or      a
cc55 3e13      ld      a,$13            ;RESUME missing error
cc57 c255cb    jp      nz,$cb55

;;=close files and do REPL
cc5a cdedd2    call    $d2ed			; CLOSEIN
cc5d cdf5d2    call    $d2f5			; CLOSEOUT

;;=zero current line and do REPL
cc60 cdaade    call    $deaa

;;=goto REPL
cc63 c358c0    jp      $c058

;;=set if error data before stopping
cc66 eb        ex      de,hl
cc67 cdb5de    call    $deb5
cc6a eb        ex      de,hl
cc6b d0        ret     nc

cc6c 7e        ld      a,(hl)
cc6d fe01      cp      $01
cc6f 280b      jr      z,$cc7c          ; (+$0b)
cc71 23        inc     hl
cc72 7e        ld      a,(hl)
cc73 23        inc     hl
cc74 b6        or      (hl)
cc75 2807      jr      z,$cc7e          ; (+$07)
cc77 23        inc     hl
cc78 cdadde    call    $dead
cc7b 23        inc     hl
cc7c 1805      jr      $cc83            ; (+$05)

;;= clear last RUN error line address
cc7e 210000    ld      hl,$0000         ;##LIT##
cc81 180c      jr      $cc8f            ; (+$0c)

;;=set last RUN error line data
cc83 eb        ex      de,hl
cc84 cdb5de    call    $deb5
cc87 d0        ret     nc

cc88 cdb1de    call    $deb1
cc8b 2294ad    ld      ($ad94),hl
cc8e eb        ex      de,hl
cc8f 2292ad    ld      ($ad92),hl
cc92 c9        ret     

;;=============================================================================
;; command CONT
;CONT
;Continues execution after a [ESC][ESC] break sequence, or STOP or END command

cc93 c0        ret     nz
cc94 2a92ad    ld      hl,($ad92)
cc97 7c        ld      a,h
cc98 b5        or      l
cc99 3e11      ld      a,$11            ;Cannot CONTinue error
cc9b ca55cb    jp      z,$cb55
cc9e e5        push    hl
cc9f 2a94ad    ld      hl,($ad94)
cca2 cdadde    call    $dead
cca5 cdb9bc    call    $bcb9			; firmware function: sound continue
cca8 e1        pop     hl
cca9 c360de    jp      $de60

;;=clear error handlers
ccac af        xor     a
ccad 3298ad    ld      ($ad98),a
;;=clear ON ERROR GOTO target
ccb0 110000    ld      de,$0000         ;##LIT##
;;=set ON ERROR GOTO line address
ccb3 ed5396ad  ld      ($ad96),de
ccb7 c9        ret     

;;=ON ERROR GOTO
ccb8 cd2cde    call    $de2c			; get next token skipping space
ccbb cd25de    call    $de25
ccbe defb $a0      ;Inline token to test "GOTO"
ccbf cd48cf    call    $cf48
ccc2 e5        push    hl
ccc3 cd5ce8    call    $e85c
ccc6 eb        ex      de,hl
ccc7 e1        pop     hl
ccc8 18e9      jr      $ccb3            ; (-$17)

;;========================================================================
;; command ON ERROR GOTO 0
;(but not ON ERROR GOTO <line number>!)
;Turns off error processing mode. See On ERROR GOTO <line number>

ccca cdb0cc    call    $ccb0
cccd 3a98ad    ld      a,($ad98)
ccd0 b7        or      a
ccd1 c8        ret     z

ccd2 c364cb    jp      $cb64

;;========================================================================
;; command RESUME
;RESUME
;RESUME <line number>
;RESUME NEXT
;Resumes execution after an error.
;Only valid in error processing mode enabled with ON ERROR GOTO <line number>
;With no parameter resumes at the beginning of the statement containing the error
;With line number resumes with the specified line
;With NEXT resumes with the statement after that containing the error

ccd5 2811      jr      z,$cce8          ; (+$11)
ccd7 feb0      cp      $b0
ccd9 2814      jr      z,$ccef          ; (+$14)
ccdb cd27e8    call    $e827
ccde c0        ret     nz

ccdf cdfacc    call    $ccfa
cce2 eb        ex      de,hl
cce3 23        inc     hl
cce4 f1        pop     af
cce5 c377de    jp      $de77

;;=resume and execute
cce8 cdfacc    call    $ccfa
cceb f1        pop     af
ccec c360de    jp      $de60

;;=resume, skip statement and execute
ccef cd2cde    call    $de2c			; get next token skipping space
ccf2 c0        ret     nz

ccf3 cdfacc    call    $ccfa
ccf6 23        inc     hl
ccf7 c3a3e9    jp      $e9a3			;; DATA

;;=restore RESUME data or error
ccfa 3a98ad    ld      a,($ad98)
ccfd b7        or      a
ccfe 3e14      ld      a,$14            ;Unexpected RESUME error
cd00 ca55cb    jp      z,$cb55
cd03 af        xor     a
cd04 3290ad    ld      ($ad90),a
cd07 3298ad    ld      ($ad98),a
cd0a 2a8cad    ld      hl,($ad8c)     ;resume address
cd0d cdadde    call    $dead
cd10 2a8ead    ld      hl,($ad8e)
cd13 c9        ret     


;;ERROR MESSAGES
;;===================================
;;+-----------------------------
;;error message partials list

;Compressed table of error message.
;Each message or sub-message ends with bit 7 set.
;Constants within messages are indexes of other sub-messages to include.
cd14 defb "p","e"+$80		        ;;$00 "pe"
cd16 defb "i","n"+$80		        ;;$01 "in"
cd18 defb "e","r"+$80		        ;;$02 "er"
cd1a defb "e","x"+$80		        ;;$03 "ex"
cd1c defb "io","n"+$80		        ;;$04 "ion"
cd1f defb " f","u"+$80		        ;;$05 " fu"
cd22 defb "co","m"+$80		        ;;$06 "com"
cd25 defb "ra","n"+$80		        ;;$07 "ran"
cd28 defb "t ","o"+$80		        ;;$08 "t o"
cd2b defb "me","n"+$80		        ;;$09 "men"
cd2e defb "te","d"+$80		        ;;$0a "ted"
cd31 defb "WEN","D"+$80		        ;;$0b "WEND"
cd35 defb "o",$00,"n"+$80		    ;;$0c "open"
cd38 defb "File"," "+$80		    ;;$0d "File "
cd3d defb "not"," "+$80		        ;;$0e "not "
cd41 defb "too"," "+$80		        ;;$0f "too "
cd45 defb " mi","s"+$80		        ;;$10 " mis"
cd49 defb "L",$01,"e"," "+$80		;;$11 "Line "
cd4d defb "NEX","T"+$80	        	;;$12 "NEXT"
cd51 defb "s",$04," "+$80	    	;;$13 "sion "
cd54 defb $05,"l","l"+$80   		;;$14 " full"
cd57 defb " ",$02,"ro","r"+$80		;;$15 " error"
cd5c defb "RESUM","E"+$80		    ;;$16 "RESUME"
cd62 defb "Str",$01,"g"," "+$80		;;$17 "String "
cd68 defb " ",$06,"man","d"+$80		;;$18 " command"
cd6e defb $10,"s",$01,"g"+$80		;;$19 " missing"
cd72 defb "Unknow","n"+$80		    ;;$1a "Unknown"
cd79 defb $0f,"lon","g"+$80		    ;;$1b "too long"
cd7e defb "already"," "+$80		    ;;$1c "already "
cd86 defb "Un",$03,"pec",$0a," "+$80    ;;$1d "Unexpected "
cd8e defb "irect",$18+$80		    ;;$1e "irect command"

;;=error message full list
;;Value equals error message number
cd94 defb $1a,$15+$80		        ;;$00 "Unknown error"
cd96 defb $1d,$12+$80		        ;;$01 "Unexpected NEXT"
cd98 defb "Syntax",$15+$80		    ;;$02 "Syntax error"
cd9f defb $1d,"RETUR","N"+$80       ;;$03 "Unexpected RETURN"
cda6 defb "DATA ",$03,"haus",$0a+$80    ;;$04 "DATA exhausted"
cdb1 defb "Impro",$00,"r argu",$09,"t"+$80  ;;$05 "Improper argument"
;;=overflow message
cdbf defb "Ov",$02,"flo","w"+$80	;;$06 "Overflow"
cdc6 defb "Memory",$14+$80		    ;;$07 "Memory full"
cdcd defb $11,"does ",$0e,$03,"is","t"+$80  ;;$08 "Line does not exist"
cdd8 defb "Subscrip",$08,"u",$08,"f ",$07,"g","e"+$80   ;;$09 "Subscript out of range"
cde8 defb "Array ",$1c,"di",$09,"s",$04,"e","d"+$80 ;;$0a "Array already dimensioned"
;;=division by zero message
cdf6 defb "Divi",$13,"by z",$02,"o"+$80	;;$0b "Division by zero"
ce01 defb "Invalid d",$1e+$80		;;$0c "Invalid direct command"
ce0b defb "Ty",$00,$10,"matc","h"+$80   ;;$0d "Type mismatch"
ce14 defb $17,"space",$14+$80		;;$0e "String space full"
ce1b defb $17,$1b+$80		        ;;$0f "String too long"
ce1d defb $17,$03,"pres",$13,$0f,$06,"pl",$03+$80   ;;$10 "String expression too complex"
ce29 defb "Can",$0e,"CONT",$01,"u","e"+$80	;;$11 "Cannot CONTinue"
ce34 defb $1a," us",$02,$05,"nct",$04+$80   ;;$12 "Unknown user function"
ce3e defb $16,$19+$80		        ;;$13 "RESUME missing"
ce40 defb $1d,$16+$80		        ;;$14 "Unexpected RESUME"
ce42 defb "D",$1e," foun","d"+$80	;;$15 "Direct command found"
ce4a defb "O",$00,$07,"d",$19+$80	;;$16 "Operand missing"
ce4f defb $11,$1b+$80		        ;;$17 "Line too long"
ce51 defb "EOF me","t"+$80		    ;;$18 "EOF met"
ce58 defb $0d,"ty",$00,$15+$80		;;$19 "File type error"
ce5d defb $12,$19+$80		        ;;$1a "NEXT missing"
ce5f defb $0d,$1c,$0c+$80		    ;;$1b "File already open"
ce62 defb $1a,$18+$80		        ;;$1c "Unknown command"
ce64 defb $0b,$19+$80		        ;;$1d "WEND missing"
ce66 defb $1d,$0b+$80		        ;;$1e "Unexpected WEND"
ce68 defb $0d,$0e,$0c+$80		    ;;(WAS WRONG!!)$1f "File not open"
ce6b defb "Broken ",$01+$80		    ;;(WAS WRONG!!)$20 "Broken in" (user terminated a cassette/disc operation?)

;;+------------------------------------------------------
;;display error partial
;A=partial number
ce73 1114cd    ld      de,$cd14
ce76 cd92ce    call    $ce92

;;+display error message atDE
ce79 d5        push    de
ce7a 1a        ld      a,(de)			; get code
ce7b e67f      and     $7f
ce7d fe20      cp      $20

;; if $20<code<$7f -> code is a ASCII character. Display character.
;; if $00<code<$1f -> code is a message number. Display this message.
ce7f d4a0c3    call    nc,$c3a0           ;; display text char
ce82 dc73ce    call    c,$ce73			  ;; display message partial
ce85 d1        pop     de
;; get char
ce86 1a        ld      a,(de)
ce87 13        inc     de
;; end of string marker
ce88 17        rla     
ce89 30ee      jr      nc,$ce79         ; (-$12)

ce8b c9        ret     

;;+------------------------------------------------------
;;find full error message
;; A=error number

ce8c 1194cd    ld      de,$cd94
ce8f fe21      cp      $21
ce91 d0        ret     nc

;;+find error message in table
;; DE=table ptr
;; A=error index
ce92 b7        or      a
ce93 c8        ret     z

ce94 c5        push    bc
ce95 47        ld      b,a
ce96 1a        ld      a,(de)
ce97 13        inc     de
ce98 17        rla     
ce99 30fb      jr      nc,$ce96         ; (-$05)
ce9b 10f9      djnz    $ce96            ; (-$07)
ce9d c1        pop     bc
ce9e c9        ret     

;;+---------------------------
;;unknown data block after error messages??
ce9f d3c7      out     ($c7),a
cea1 c7        rst     $00
cea2 c7        rst     $00
cea3 c7        rst     $00
cea4 c7        rst     $00
cea5 c7        rst     $00
cea6 c7        rst     $00
cea7 c7        rst     $00
cea8 c7        rst     $00
cea9 c7        rst     $00
ceaa c7        rst     $00
ceab c7        rst     $00
ceac c7        rst     $00
cead c7        rst     $00
ceae c7        rst     $00
ceaf c7        rst     $00
ceb0 c7        rst     $00
ceb1 c7        rst     $00
ceb2 c7        rst     $00
ceb3 c7        rst     $00
ceb4 c7        rst     $00
ceb5 c7        rst     $00
ceb6 c7        rst     $00
ceb7 c7        rst     $00





;;***ExprEvaluator.asm
;;<< EXPRESSION EVALUATION
;;< Includes prefix operators and various lookup tables (operators, system vars etc.)
;;=====================================
;;EVAL EXPRESSIONS
;;====================================================
;;eval expr as byte or error
;; returns value in A
ceb8 cdd8ce    call    $ced8 			; get number
cebb f5        push    af

;;=error if D non zero
cebc 7a        ld      a,d
cebd b7        or      a
cebe 200b      jr      nz,$cecb   		; Error: Improper argument      

;; it's lower than 256 return number
cec0 f1        pop     af
cec1 7b        ld      a,e
cec2 c9        ret     

;;=============================================
;;eval expr as int less than 256
cec3 cdd8ce    call    $ced8 ; get number
cec6 f5        push    af
cec7 7a        ld      a,d
cec8 b3        or      e
cec9 20f1      jr      nz,$cebc         ; (-$0f)

;;+raise improper argument error
cecb c34dcb    jp      $cb4d			; Error: Improper Argument

;;=======================================
;;eval expr as positive int or error
;(0-32676)
cece cdd8ce    call    $ced8 ; get number
ced1 f5        push    af
ced2 7a        ld      a,d
ced3 17        rla     
ced4 38f5      jr      c,$cecb          ; (-$0b)
ced6 f1        pop     af
ced7 c9        ret     

;;========================================
;;eval expr as int
ced8 cd62cf    call    $cf62
cedb f5        push    af
cedc eb        ex      de,hl
cedd cdb6fe    call    $feb6
cee0 eb        ex      de,hl
cee1 f1        pop     af
cee2 c9        ret     

;;========================================
;;eval expr as string
cee3 cd62cf    call    $cf62
cee6 cd66ff    call    $ff66
cee9 200d      jr      nz,$cef8         ; (+$0d)
ceeb e5        push    hl
ceec 2aa0b0    ld      hl,($b0a0)
ceef cd58fb    call    $fb58
cef2 eb        ex      de,hl
cef3 e1        pop     hl
cef4 c9        ret     

;;========================================
;;eval expr as uint
cef5 cd62cf    call    $cf62
cef8 f5        push    af
cef9 c5        push    bc
cefa e5        push    hl
cefb cdebfe    call    $feeb
cefe eb        ex      de,hl
ceff e1        pop     hl
cf00 c1        pop     bc
cf01 f1        pop     af
cf02 c9        ret     

;;===========================================
;;eval expr as string and get length
cf03 cd62cf    call    $cf62
cf06 c3f5fb    jp      $fbf5

;;===========================================
;;eval expr and error if not string
cf09 cd62cf    call    $cf62
cf0c c35eff    jp      $ff5e

;;===========================================
;;eval line number range params
;Params for LIST and DELETE: [first][,|-][last]
cf0f 010100    ld      bc,$0001         ;Default values
cf12 11ffff    ld      de,$ffff          ;##LIT##
cf15 cd41de    call    $de41
cf18 d43dde    call    nc,$de3d
cf1b d8        ret     c

cf1c fe23      cp      $23				; "#"
cf1e c8        ret     z

cf1f fef5      cp      $f5              ;"-"
cf21 280a      jr      z,$cf2d          ; (+$0a)

cf23 cd48cf    call    $cf48
cf26 42        ld      b,d
cf27 4b        ld      c,e
cf28 c8        ret     z

cf29 cd41de    call    $de41
cf2c d8        ret     c

;;=get range end
cf2d cd25de    call    $de25
cf30 defb $f5    ;Inline token to test "-"
cf31 11ffff    ld      de,$ffff         ;##LIT##
cf34 c8        ret     z

cf35 cd41de    call    $de41
cf38 d8        ret     c

cf39 cd48cf    call    $cf48
cf3c c441de    call    nz,$de41
cf3f eb        ex      de,hl
cf40 cddeff    call    $ffde ; HL=BC?
cf43 da4dcb    jp      c,$cb4d			; Error: Improper Argument
cf46 eb        ex      de,hl
cf47 c9        ret     

;;===============================================
;;eval line number or error
;If data is a line pointer returns the line number of the line it points to.
cf48 7e        ld      a,(hl)
cf49 23        inc     hl
cf4a 5e        ld      e,(hl)
cf4b 23        inc     hl
cf4c 56        ld      d,(hl)
cf4d fe1e      cp      $1e          ; 16-bit line number
cf4f 280e      jr      z,$cf5f          ; (+$0e)

cf51 fe1d      cp      $1d          ; 16-bit line address pointer
cf53 c249cb    jp      nz,$cb49			; Error: Syntax Error
cf56 e5        push    hl
cf57 eb        ex      de,hl        ;fetch line number from line address pointer
cf58 23        inc     hl
cf59 23        inc     hl
cf5a 23        inc     hl
cf5b 5e        ld      e,(hl)
cf5c 23        inc     hl
cf5d 56        ld      d,(hl)
cf5e e1        pop     hl

cf5f c32cde    jp      $de2c			; get next token skipping space

;; EXPRESSION EVALUATOR
;;==================================
;; eval expression
;; This gets called to evaluate an expression after a statement or function
;; but will also be called recursively for sub-expressions, 
;; eg. after an open bracket or by a function call within the expression
;; HL = ptr to first token

cf62 c5        push    bc
cf63 0600      ld      b,$00            ;B=operator precedence
cf65 cd6dcf    call    $cf6d
cf68 c1        pop     bc
cf69 2b        dec     hl
cf6a c32cde    jp      $de2c			; return with the next token after the expression
                                        ; or sub expression

;;=do eval expression
cf6d 2b        dec     hl
cf6e c5        push    bc
cf6f cd33d0    call    $d033			; process tokenised line
cf72 e5        push    hl

;;=infix operator or done
;If next token is an infix operator then expression continues, 
;otherwise end of expression so return
cf73 e1        pop     hl               ; look for possible infix operator
cf74 c1        pop     bc
cf75 7e        ld      a,(hl)
cf76 feee      cp      $ee
cf78 d8        ret     c

cf79 fefe      cp      $fe
cf7b d0        ret     nc   ;continue if token >= $ee and < $fe (infix operators)

; infix operators

;comparison
; ee: >
; ef: =
; f0: >= =>
; f1: <
; f2: <>
; f3: <= =<

;maths and logic
; f4: +
; f5: -
; f6: *
; f7: /
; f8: ^
; f9: \ integer division
; fa: AND
; fb: MOD
; fc: OR
; fd: XOR

;;infix operators
cf7c fef4      cp      $f4              ;"+" token
cf7e 3845      jr      c,$cfc5          ; (+$45) tokens $ee to $f3
cf80 cc66ff    call    z,$ff66          ;If "+" then is operand a string?
cf83 2012      jr      nz,$cf97         ; (+$12) 

;accumulator is a string and operator is addition.
cf85 c5        push    bc
cf86 e5        push    hl
cf87 2aa0b0    ld      hl,($b0a0)
cf8a e3        ex      (sp),hl
cf8b cd33d0    call    $d033			; process tokenised line
cf8e cd5eff    call    $ff5e
cf91 e3        ex      (sp),hl
cf92 cd1df9    call    $f91d
cf95 18dc      jr      $cf73            ; (-$24)

;;=maths and logic infix operators
;; handle tokens f4 to fd
cf97 7e        ld      a,(hl)
cf98 d6f4      sub     $f4              ;Table address = table start + ((token - $f4) * 3)
cf9a 5f        ld      e,a              ; E = A * 3
cf9b 87        add     a,a
cf9c 83        add     a,e              ; use A as index into table at $cfed
cf9d c6ed      add     a,$cfed and $ff;   $ed
cf9f 5f        ld      e,a
cfa0 cecf      adc     a,$cfed >> 8; $cf
cfa2 93        sub     e
cfa3 57        ld      d,a
cfa4 eb        ex      de,hl            ;HL=table item addr
cfa5 78        ld      a,b              ;Precedence of previous operator
cfa6 be        cp      (hl)             ;Compare with value in table
cfa7 eb        ex      de,hl
cfa8 d0        ret     nc               ;Return if new operator is lower precedence

cfa9 c5        push    bc
;;=dispatch infix operator
;;DE = ptr to address of table entry
cfaa cd74ff    call    $ff74
cfad d5        push    de
cfae c5        push    bc
cfaf 1a        ld      a,(de)           ;Read or restore previous operator precedence value?
cfb0 47        ld      b,a
cfb1 cd6ecf    call    $cf6e     ;eval expression after operator
cfb4 c1        pop     bc
cfb5 e3        ex      (sp),hl
cfb6 23        inc     hl
cfb7 7e        ld      a,(hl)           ;Read code address from table...
cfb8 23        inc     hl
cfb9 66        ld      h,(hl)
cfba 6f        ld      l,a
cfbb eb        ex      de,hl            ;...into DE
cfbc 79        ld      a,c
cfbd cd62f6    call    $f662
cfc0 cdfeff    call    $fffe			; JP (DE) call infix eval routine
cfc3 18ae      jr      $cf73            ; (-$52)

;;=comparison infix operator
; tokens ee to f3
cfc5 78        ld      a,b              ;Precedence
cfc6 fe0a      cp      $0a
cfc8 d0        ret     nc               ;Return if previous operator is higher

cfc9 c5        push    bc
cfca 7e        ld      a,(hl)           ;Operator
cfcb d6ed      sub     $ed              ;Calc precedence?
cfcd 47        ld      b,a              ;Predence
cfce cd66ff    call    $ff66            ; check operand type
cfd1 110bd0    ld      de,$d00b         ; 
cfd4 20d4      jr      nz,$cfaa         ; (-$2c) do comparison for non strings

cfd6 e5        push    hl               ; otherwise it's a string comparison
cfd7 2aa0b0    ld      hl,($b0a0)
cfda e3        ex      (sp),hl
cfdb c5        push    bc
cfdc 060a      ld      b,$0a            ;Precedence
cfde cd6ecf    call    $cf6e             ;eval expression after operator
cfe1 c1        pop     bc
cfe2 e3        ex      (sp),hl
cfe3 c5        push    bc
cfe4 cd3ff9    call    $f93f            ;string compare???
cfe7 c1        pop     bc
cfe8 cd13d0    call    $d013
cfeb 1886      jr      $cf73            ; (-$7a)

;;=======================================
;Maths infix operator table format:
;byte=operator precedence? (higher values take higher priority)
;word=code address or evaluation routine


;;infix maths table
cfed defb $0c
cfee defw $fd0c ; + ##LABEL##
cff0 defb $0c      
cff1 defw $fd21 ; - ##LABEL##
cff3 defb $12   
cff4 defw $fd35 ; * ##LABEL##
cff6 defb $12      
cff7 defw $fd52 ; / ##LABEL##
cff9 defb $16
cffa defw $d536 ; ^ ##LABEL##
cffc defb $10
cffd defw $fd67 ; \ integer division ##LABEL##
cfff defb $06
d000 defw $fd87 ; AND ##LABEL##
d002 defb $0e
d003 defw $fd79 ; MOD ##LABEL##
d005 defb $04   
d006 defw $fd92 ;OR ##LABEL##
d008 defb $02      
d009 defw $fd9c ;XOR ##LABEL##

;;=infix comparison table
d00b defb $0a 
d00c defw $d00e ; ##LABEL##

;;=eval comparison infix
; ee: >
; ef: =
; f0: >= =>
; f1: <
; f2: <>
; f3: <= =<
d00e c5 push bc
d00f cd49fd call $fd49
d012 c1 pop bc     

;;= process comparison result
;called after we've done a comparison operator. Presumably converts the result
;into a boolean value?
d013 c601      add     a,$01
d015 8f        adc     a,a
d016 a0        and     b
d017 c6ff      add     a,$ff
d019 9f        sbc     a,a
d01a c32dff    jp      $ff2d




;;=======================================
;; PREFIX OPERATORS
;;=======================================================================
;; prefix minus -
d01d 0614      ld      b,$14        ;Operator precedence
d01f cd6dcf    call    $cf6d
d022 e5        push    hl
d023 cdb4fd    call    $fdb4
d026 e1        pop     hl
d027 c9        ret     

;;=======================================================================
;; prefix NOT

d028 0608      ld      b,$08        ;Operator precedence
d02a cd6dcf    call    $cf6d
d02d e5        push    hl
d02e cda6fd    call    $fda6
d031 e1        pop     hl
d032 c9        ret     

;;=========================================
;; EVAL A TOKENISED EXPRESSION
;;==========================================================================
;; eval sub expression
;; evaluate a sub-expression. Doesn't evaluate infix operators

d033 cd2cde    call    $de2c			; get next token skipping space
;;+-----------
;;prefix plus
;if we have + as a prefix operator we don't need to do anything!

d036 281d      jr      z,$d055          ; (+$1d)
d038 fe0e      cp      $0e
d03a 3838      jr      c,$d074          ; 
d03c fe20      cp      $20				; (space)
d03e 3852      jr      c,$d092          ; 
d040 fe22      cp      $22				; (double quote)
d042 ca79f8    jp      z,$f879

d045 feff      cp      $ff				; keyword with $ff prefix?
d047 cadad0    jp      z,$d0da

d04a e5        push    hl
d04b 2159d0    ld      hl,$d059
d04e cdb4ff    call    $ffb4
d051 e3        ex      (sp),hl
d052 c32cde    jp      $de2c			; get next token skipping space
                                        ; (Function will be returned to with a token in A)

;;+---------------------------------------------------------------------------
;;raise missing operand
d055 cd45cb    call    $cb45
d058 defb $16									; Error: Operand Missing

;;===========================================================================
;; prefix token table
d059

;(call this entry if token not found)
defb $08
defw $d0d7				;; Error: Syntax Error ##LABEL##

defb $f5				;; -
defw $d01d              ;##LABEL##
defb $f4				;; +
defw $d036              ;##LABEL##
defb $28				;; (
defw $d0d1              ;##LABEL##
defb $fe				;; NOT
defw $d028              ;##LABEL##
defb $e3				;; ERL
defw $d142              ;##LABEL##
defb $e4				;; FN
defw $d18a              ;##LABEL##
defb $ac				;; MID$
defw $f9e2              ;##LABEL##
defb $40				;; @
defw $d14e              ;##LABEL##

;;===========================================================================
;; eval variable references
;eval tokens $00 to $0d
;These tokens are for variables. Tokens $00 (end of line) and $01 (end of statement)
;have already been preocessed.
;Tokens:
;&02: integer variable definition with % suffix
;&03: string variable definition with $ suffix
;&04: real variable definition with % suffix
;&05: ??
;&06: ??
;&07: ??
;&08: ??
;&09: ??
;&0a: ??
;&0b: integer variable definition (no suffix)
;&0c: string variable definition (no suffix)
;&0d: real variable definition (no suffix)
;Unknown stuff probably includes DEF FNs and DIMs

d074 cdc9d6    call    $d6c9
d077 300b      jr      nc,$d084         ; (+$0b) Variable not declared/no value set yet
d079 fe03      cp      $03              ;String
d07b 280f      jr      z,$d08c          ; (+$0f)
d07d e5        push    hl
d07e eb        ex      de,hl
d07f cd6cff    call    $ff6c
d082 e1        pop     hl
d083 c9        ret     

;;=undeclared variable
;undeclared/no value set so return zero or empty string
d084 fe03      cp      $03
d086 c21bff    jp      nz,$ff1b
d089 1191d0    ld      de,$d091         ;Pointer to an empty string

;;=eval string variable reference
d08c ed53a0b0  ld      ($b0a0),de
d090 c9        ret     

;;=empty string
d091 defb $00

;;===========================================================================
;;eval constants
;; eval tokens $0e to $1f
;; Raw token|After sub $0e|Meaning
;; $0e..$17? $00-$0a       Constants 0-10
;; $18       $0b:          Byte constant following token
;; $19       $0c:          Word constant following token = decimal constant
;; $1a       $0d:          Word constant following token = binary constant (&X prefix)
;; $1b       $0e:          Word constant following token = hex constant (&H or & prefix)
;; $1c       $0f:          UINT at (token + 3)?? = BASIC program line pointer
;; $1d       $10:          UINT constant following token = BASIC line number
;; $1e       $11:          REAL cinstant following token

d092 d60e      sub     $0e
d094 5f        ld      e,a
d095 1600      ld      d,$00
d097 fe0a      cp      $0a      ;Constant 0-10
d099 381b      jr      c,$d0b6          

d09b 23        inc     hl
d09c 5e        ld      e,(hl)
d09d fe0b      cp      $0b	    ;Token $18: Byte following token
d09f 2815      jr      z,$d0b6          

d0a1 23        inc     hl
d0a2 56        ld      d,(hl)
d0a3 fe0f      cp      $0f      ;Tokens $19, $1a, $1b. Word following token. Values 0c, 0d, 0e
d0a5 380f      jr      c,$d0b6          ; (+$0f)
d0a7 fe11      cp      $11      ;Tokens $1c, $1d. Extended. Values 0f, 10h
d0a9 3812      jr      c,$d0bd          ; (+$12)
d0ab 202a      jr      nz,$d0d7         ;; Error: Syntax Error. Values <> 11h (shouldn't be here!)
d0ad 2b        dec     hl               ;Token $1e, Value 11h
d0ae 3e05      ld      a,$05            ;REAL
d0b0 cd6cff    call    $ff6c
d0b3 2b        dec     hl
d0b4 1818      jr      $d0ce            ; (+$18)

;;===========================================================================
;; eval DE as number constant
;; DE=value

d0b6 eb        ex      de,hl
d0b7 cd35ff    call    $ff35
d0ba eb        ex      de,hl
d0bb 1811      jr      $d0ce            ; (+$11)

;;+---------------------------------------------------------------------------
;;eval number constant extended
;DE=value stored after token
d0bd e5        push    hl
d0be fe0f      cp      $0f
d0c0 2007      jr      nz,$d0c9         ; (+$07)

d0c2 13        inc     de               ;Token $1c value $0f
d0c3 eb        ex      de,hl
d0c4 23        inc     hl
d0c5 23        inc     hl
d0c6 5e        ld      e,(hl)           ;Read word at (token + 3)??
d0c7 23        inc     hl
d0c8 56        ld      d,(hl)

;;=eval DE as UINT
d0c9 eb        ex      de,hl
d0ca cd89fe    call    $fe89
d0cd e1        pop     hl

;;=eval number done
d0ce c32cde    jp      $de2c			; get next token skipping space

;;=======================================================================
;; prefix open bracket (
d0d1 cd62cf    call    $cf62
d0d4 c31dde    jp      $de1d ; check for close bracket

;;======================================================================
;; raise syntax error
d0d7 c349cb    jp      $cb49			; Error: Syntax Error

;;======================================================================
;; eval functions with $ff prefix

d0da 23        inc     hl
d0db 4e        ld      c,(hl)			;; get function token
d0dc cd2cde    call    $de2c			; get next token skipping space

;; A = keyword id
d0df 79        ld      a,c
d0e0 fe40      cp      $40
d0e2 3805      jr      c,$d0e9          ; (+$05)
d0e4 fe4a      cp      $4a              ;****Change this value if extending the table.
d0e6 da10d1    jp      c,$d110

;;-------------------------------------------------------------------------
;;=eval function which arent system variables
;;Followed by: token < $40 or => $4a
d0e9 cd19de    call    $de19 ; function so we need opening bracket

;Convert token to index into table.
;Function tokens are:
;$71 - $7f (complex parameter functions) and 
;$00 - $1d (single simple parameter functions)
;This code converts them to a zero based index into the function look up table.
d0ec 79        ld      a,c   
d0ed 87        add     a,a      ;Doubling A gives us values <initial> - $fe and $00 - <final>
d0ee c61e       add     a,$d203 - $d1e5 ;<function_table>
;d0ee c61e      add     a,$1e    ;(Original) This value is twice the number of entries in the 
                                ;complex parameter function part of the table (tokens $71 - $7f)
                                ;Adding it to A gives us our zero based index.
d0f0 4f        ld      c,a

;; $00-$1d -> $1e->$58
;; $71-$7f -> $00->$1c
;; $40-$49 -> $9e->$b0

d0f1 fe59      cp    $d23f - $d1e5 - 1
;d0f1 fe59      cp      $59             ;(Original) Number of bytes in total function table plus 1
d0f3 30e2      jr      nc,$d0d7         ; Error: Syntax Error
d0f5 fe1d       cp      $d203 - $d1e5 - 1
;d0f5 fe1d      cp      $1d              ;(Original) Number of bytes in complex parameter function table + 1
;For these functions we'll make them process their own parameters.
;Presumably for functions which don't take a single, simple, parameter.
;(Contrast with next code section). Tokens $71 - $7f
d0f7 3809      jr      c,$d102          ; (+$09)

;; $ff prefix followed by $00-$1d
;For these functions we'll eval the parameter beforehand and save it some work.
;These are, presumably, functions which take a single, simple, parameter.
;(Contrast with JR immediately above). Tokens $00 - $1d
d0f9 cdd1d0    call    $d0d1
d0fc e5        push    hl
d0fd cd02d1    call    $d102
d100 e1        pop     hl
d101 c9        ret     

;;==========================================================================
;;jp to routine in function table
;; $ff prefix followed by $71 to $7f

d102 11e5d1    ld      de,$d1e5			; functions
;;= jp to routine in table
;; DE=table
;; C=offset
d105 e5        push    hl
d106 eb        ex      de,hl
d107 0600      ld      b,$00
d109 09        add     hl,bc
d10a 7e        ld      a,(hl)
d10b 23        inc     hl
d10c 66        ld      h,(hl)
d10d 6f        ld      l,a
d10e e3        ex      (sp),hl    ; Routine address on stack
d10f c9        ret     

;;==========================================================================
;;eval system variables
;; keywords: $ff followed by $40 to $49
;; 
;; A = keyword index ($40-$49)

d110 87        add     a,a				;; $40->$80, $41->$82...
d111 4f        ld      c,a

;; A = keyword index
;; C = offset in table
d112 1197d0    ld      de,$d117 - $80			; d117-$80
d115 18ee      jr      $d105

;;+------------------------------------------------------------
;; system variables table
d117
defw $c44f		;; EOF  ##LABEL##
defw $d130		;; ERR  ##LABEL##
defw $d148		;; HIMEM  ##LABEL##
defw $fa7e		;; INKEY$  ##LABEL##
defw $d51d		;; PI  ##LABEL##
defw $d5c1		;; RND  ##LABEL##
defw $d139		;; TIME  ##LABEL##
defw $d161		;; XPOS  ##LABEL##
defw $d168		;; YPOS  ##LABEL##
defw $d12b		;; DERR  ##LABEL##




;;***SystemVars.asm
;;<< SYSTEM VARIABLES
;;< (most of them). And the @ prefix operator.
;;==========================================================================
;; variable DERR
d12b 3a91ad    ld      a,($ad91)
d12e 1803      jr      $d133
            
;;==========================================================================
;; variable ERR
;ERR
;Returns the last error number

d130 3a90ad    ld      a,($ad90)
d133 e5        push    hl
d134 cd32ff    call    $ff32
d137 e1        pop     hl
d138 c9        ret     

;;==========================================================================
;; variable TIME
;TIME
;Returns elapsed time since the machine was switched on in 1/300ths of a second

d139 e5        push    hl
d13a cd0dbd    call    $bd0d		;; firmware function: KL TIME PLEASE
d13d cda5fe    call    $fea5
d140 e1        pop     hl
d141 c9        ret     

;;=======================================================================
;; prefix ERL
;ERL
;Returns the line number of the last error
;If used in a relational expression ERL must be on the left hand side of the comparison for
;BASIC to recognise the right hand side as a line number and RENUM to work correctly.

d142 e5        push    hl
d143 cdaacb    call    $cbaa
d146 1814      jr      $d15c            ; (+$14)

;;==========================================================================
;; variable HIMEM
;HIMEM
;Returns the address of the highest memory address available for BASIC.

d148 e5        push    hl
d149 2a5eae    ld      hl,($ae5e) ; HIMEM
d14c 180e      jr      $d15c            ; (+$0e)

;;==========================================================================
;; prefix at operator @
;returns the address of (pointer to) a variable

d14e cdc9d6    call    $d6c9
d151 d24dcb    jp      nc,$cb4d			; Error: Improper Argument

d154 e5        push    hl
d155 eb        ex      de,hl
d156 78        ld      a,b
d157 fe03      cp      $03              ;String type
d159 cc58fb    call    z,$fb58
;;=store UINT to accumulator
d15c cd89fe    call    $fe89
d15f e1        pop     hl
d160 c9        ret     

;;==========================================================================
;; variable XPOS
;XPOS
;Returns the x position of the graphics cursor

d161 e5        push    hl
d162 cdc6bb    call    $bbc6			;; firmware function: gra ask cursor 
d165 eb        ex      de,hl
d166 1804      jr      $d16c

;;==========================================================================
;; variable YPOS
;YPOS
;Returns the y position of the graphics cursor

d168 e5        push    hl
d169 cdc6bb    call    $bbc6			;; firmware function: gra ask cursor
d16c cd35ff    call    $ff35
d16f e1        pop     hl
d170 c9        ret     





;;***DEFFN.asm
;;<< DEF and DEF FN
;;========================================================================
;; command DEF
;DEF FN<function name>[(<formal parameters>)]=<expression>
;Defines a function with the given name

d171 cd25de    call    $de25
d174 defb $e4      ; inline token to test "FN"
d175 eb        ex      de,hl
d176 cdb5de    call    $deb5
d179 eb        ex      de,hl
d17a 3e0c      ld      a,$0c            ;Invalid direct command error
d17c d255cb    jp      nc,$cb55
d17f cddbd6    call    $d6db
d182 eb        ex      de,hl
d183 73        ld      (hl),e
d184 23        inc     hl
d185 72        ld      (hl),d
d186 eb        ex      de,hl
d187 c3a3e9    jp      $e9a3			;; DATA

;;=======================================================================
;; prefix FN

d18a cddbd6    call    $d6db            ;find the DEF FN for this item
d18d c5        push    bc
d18e e5        push    hl
d18f eb        ex      de,hl
d190 5e        ld      e,(hl)           ;read DEF FN address
d191 23        inc     hl
d192 56        ld      d,(hl)
d193 eb        ex      de,hl            ;HL=DEF FN address. We are now 'executing' the DEF FN code
d194 7c        ld      a,h              ;is address zero?
d195 b5        or      l
d196 3e12      ld      a,$12            ;Unknown user function error
d198 ca55cb    jp      z,$cb55

;alloc space on execution stack for the FN and any parameters
d19b cd2ada    call    $da2a
d19e 7e        ld      a,(hl)           ;Does the DEF FN have any parameters?
d19f fe28      cp      $28              ; '('
d1a1 2028      jr      nz,$d1cb         ; (+$28) no params, skip next bit
d1a3 cd2cde    call    $de2c			; get next token skipping space
d1a6 e3        ex      (sp),hl
d1a7 cd19de    call    $de19 ; check for open bracket
d1aa e3        ex      (sp),hl

;;=prefix FN read params loop
d1ab cd6ada    call    $da6a            ;Read both DEF FN definition parameter list...
d1ae e3        ex      (sp),hl          ;...and parameters passed in FN invocation
d1af d5        push    de
d1b0 cd62cf    call    $cf62            ;eval parameter
d1b3 e3        ex      (sp),hl
d1b4 78        ld      a,b
d1b5 cd9fd6    call    $d69f
d1b8 e1        pop     hl
d1b9 cd41de    call    $de41            ;more parameters?
d1bc 3006      jr      nc,$d1c4         ; (+$06) nope, done
d1be e3        ex      (sp),hl
d1bf cd15de    call    $de15 ; check for comma
d1c2 18e7      jr      $d1ab            ; (-$19)

;;=prefix FN finished reading params
d1c4 cd1dde    call    $de1d            ; check for close bracket at end of FN
d1c7 e3        ex      (sp),hl
d1c8 cd1dde    call    $de1d            ; check for close bracket at end of DEF FN
;;=prefix FN execute
d1cb cd49da    call    $da49            ;tidy up system variables?

d1ce cd21de    call    $de21            ;HL=address of the equals sign in the DEF FN
d1d1 cd62cf    call    $cf62            ;eval the FN (ie run it as code)
d1d4 c249cb    jp      nz,$cb49			; Error: Syntax Error
d1d7 cd66ff    call    $ff66
d1da cc8afb    call    z,$fb8a

d1dd cd52da    call    $da52
d1e0 e1        pop     hl
d1e1 f1        pop     af
d1e2 c3fffe    jp      $feff




;;***FunctionTable.asm
;;<< FUNCTION LOOK UP TABLE
;;======================================================
;; function table

;These functions take multiple parameters, or less straight-forward parameter(s).
;The function will have to read it's own parameters.
;Numbers after function names are the tokens
d1e5
defw $f964					;; BIN$ $71 ##LABEL##
defw $f98f					;; DEC$ $72 ##LABEL##
defw $f969					;; HEX$ $73 ##LABEL##
defw $fae5					;; INSTR$ $74 ##LABEL##
defw $f9d3					;; LEFT$ $75 ##LABEL##
defw $d243					;; MAX $76 ##LABEL##
defw $d23f					;; MIN $77 ##LABEL##
defw $c2aa					;; POS $78	  ##LABEL##
defw $f9d8					;; RIGHT$ $79 ##LABEL##
defw $d26a					;; ROUND $7a	  ##LABEL##
defw $fa8d					;; STRING$ $7b	  ##LABEL##
defw $c571					;; TEST	$7c	  ##LABEL##
defw $c576					;; TESTR $7d ##LABEL##
defw $c298					;; COPYCHR$	$7e	  ##LABEL##
defw $c2a1					;; VPOS $7f ##LABEL##

;;=simple function table
;These functions take a single, simple, parameter. The parameter will be read before the
;function is dispatched and passed to it.
d203
defw $fdb0                                                                     ;; ABS $00     ##LABEL##
defw $fa6e                                                                     ;; ASC $01 ##LABEL##
defw $d57e                                                                    ;; ATN $02 ##LABEL##
defw $fa74                                                                     ;; CHR$  ##LABEL##
defw $feb6                                                                     ;; CINT  ##LABEL##
defw $d574                                                                    ;; COS  ##LABEL##
defw $ff14                                                                     ;; CREAL  ##LABEL##
defw $d560                                                                    ;; EXP  ##LABEL##
defw $fe0e                                                                     ;; FIX  ##LABEL##
defw $fc53                                                                     ;; FRE  ##LABEL##
defw $d456                                                                    ;; INKEY  ##LABEL##
defw $f219                                                                     ;; INP  ##LABEL##
defw $fe13                                                                     ;; INT  ##LABEL##
defw $d470                                                                    ;; JOY  ##LABEL##
defw $fa69                                                                     ;; LEN  ##LABEL##
defw $d56a                                                                    ;; LOG  ##LABEL##
defw $d565                                                                    ;; LOG10  ##LABEL##
defw $f8ec                                                                     ;; LOWER$  ##LABEL##
defw $f208                                                                     ;; PEEK  ##LABEL##
defw $ca50                                                                    ;; REMAIN  ##LABEL##
defw $ff2a                                                                     ;; SGN  ##LABEL##
defw $d56f                                                                     ;; SIN  ##LABEL##
defw $faad                                                                     ;; SPACE$  ##LABEL##
defw $d37b                                                                    ;; SQ  ##LABEL##
defw $d531                                                                    ;; SQR  ##LABEL##
defw $f9bc                                                                     ;; STR$  ##LABEL##
defw $d579                                                                    ;; TAN  ##LABEL##
defw $feeb                                                                     ;; UNT  ##LABEL##
defw $f8fa                                                                     ;; UPPER$  ##LABEL##
defw $fabe                                                                     ;; VAL $1d ##LABEL##




;;***MathsAgain.asm
;;<< MATHS FUNCTIONS MIN, MAX and ROUND
;;========================================================================
;; function MIN
;MIN(<list of: <numeric expression>>)
;Returns the smallest of the numeric expressions

d23f 06ff	   ld      b,$ff
d241 1802      jr      $d245            ; (+$02)

;;========================================================================
;; function MAX
;MAX(<list of: <numeric expression>>)
;Returns the largest of the numeric expressions

d243 0601      ld      b,$01
;;------------------------------------------------------------------------
d245 cd62cf    call    $cf62
d248 cd41de    call    $de41
d24b d21dde    jp      nc,$de1d ; check for close bracket
d24e cd74ff    call    $ff74
d251 cd62cf    call    $cf62
d254 e5        push    hl
d255 79        ld      a,c
d256 cd62f6    call    $f662
d259 c5        push    bc
d25a e5        push    hl
d25b cd49fd    call    $fd49
d25e e1        pop     hl
d25f c1        pop     bc
d260 b7        or      a
d261 2804      jr      z,$d267          ; (+$04)
d263 b8        cp      b
d264 c46fff    call    nz,$ff6f
d267 e1        pop     hl
d268 18de      jr      $d248            ; (-$22)

;;========================================================================
;; function ROUND
;ROUND(<numeric expression>[,decimals])
;Rounds a number to the given number of decimal places.

d26a cd62cf    call    $cf62
d26d cd74ff    call    $ff74
d270 cd41de    call    $de41
d273 110000    ld      de,$0000             ;##LIT##
d276 dcd8ce    call    c,$ced8 ; get number
d279 cd1dde    call    $de1d ; check for close bracket
d27c e5        push    hl
d27d d5        push    de
d27e 212700    ld      hl,$0027
d281 19        add     hl,de
d282 114f00    ld      de,$004f
d285 cdd8ff    call    $ffd8 ; HL=DE?
d288 d24dcb    jp      nc,$cb4d			; Error: Improper Argument
d28b d1        pop     de
d28c 79        ld      a,c
d28d cd62f6    call    $f662
d290 43        ld      b,e
d291 cdd5fd    call    $fdd5
d294 e1        pop     hl
d295 c9        ret     


;;***FileIO.asm
;;<< FILE I/O COMMANDS
;;< CAT, OPENIN, OPENOUT, CLOSEIN, CLOSEOUT
;;=============================================================================
;; command CAT
;CAT
;Show a list of files on cassette/disc

d296 c0        ret     nz
d297 e5        push    hl
d298 cd00d3    call    $d300
d29b cd2af7    call    $f72a            ;alloc 2k buffer??
d29e cd9bbc    call    $bc9b			; firmware function: cas catalog
d2a1 ca37cc    jp      z,$cc37
d2a4 e1        pop     hl
d2a5 c361f7    jp      $f761            ;release 2k buffer??

;;=============================================================================
;; command OPENOUT
;Opens the given file for output.
;If the filename begins with ! it will suppress messages

d2a8 cdc7d2    call    $d2c7
d2ab cd25f7    call    $f725
d2ae cd69c4    call    $c469
d2b1 c38cbc    jp      $bc8c			; firmware function: cas out open

;;=============================================================================
;; command OPENIN
;OPENIN <filename>
;Opens the given file for input.
;If the filename begins with ! it will suppress messages

d2b4 cdbed2    call    $d2be
d2b7 fe16      cp      $16
d2b9 c8        ret     z

d2ba cd45cb    call    $cb45
d2bd defb $19                         ;Inline error code: File type error

;;=read filename and open in
d2be cdc7d2    call    $d2c7
d2c1 cd20f7    call    $f720
d2c4 c377bc    jp      $bc77			; firmware function: cas in open

;;=read filename
d2c7 cd2af7    call    $f72a
d2ca cd03cf    call    $cf03
d2cd e3        ex      (sp),hl
d2ce eb        ex      de,hl
d2cf cddbd2    call    $d2db
d2d2 ca37cc    jp      z,$cc37
d2d5 e1        pop     hl
d2d6 d8        ret     c

d2d7 cd45cb    call    $cb45
d2da defb $1b                         ;Inline error code: File already open

;;=set CAS NOISY
d2db d5        push    de
d2dc 78        ld      a,b
d2dd b7        or      a
d2de 280a      jr      z,$d2ea          ; (+$0a)
d2e0 7e        ld      a,(hl)
d2e1 fe21      cp      $21				; "!" character?
d2e3 3e00      ld      a,$00
d2e5 2003      jr      nz,$d2ea         ; (+$03)
d2e7 23        inc     hl
d2e8 05        dec     b
d2e9 2f        cpl     
d2ea c36bbc    jp      $bc6b			; firmware function: cas set noisy

;;==========================================================================
;; command CLOSEIN
;CLOSEIN
;Close the input file

d2ed e5        push    hl
d2ee cd7abc    call    $bc7a			; firmware function: cas in close
d2f1 e1        pop     hl
d2f2 c359f7    jp      $f759

;;==========================================================================
;; command CLOSEOUT
;CLOSEOUT
;Close the output file

d2f5 e5        push    hl
d2f6 cd8fbc    call    $bc8f			; firmware function: cas out close
d2f9 ca37cc    jp      z,$cc37
d2fc e1        pop     hl
d2fd c35df7    jp      $f75d

;;==========================================================================
;;close input and output streams
d300 c5        push    bc
d301 d5        push    de
d302 e5        push    hl
d303 cd7dbc    call    $bc7d			; firmware function: cas in abandon
d306 cd59f7    call    $f759
d309 cd92bc    call    $bc92			; firmware function: cas out abandon
d30c cd5df7    call    $f75d
d30f e1        pop     hl
d310 d1        pop     de
d311 c1        pop     bc
d312 c9        ret     




;;***Sound.asm
;;<< SOUND FUNCTIONS
;;========================================================================
;; command SOUND
;SOUND <channel status>,<tone period>[,<duration>[,<volume>[,volume envelope>[,<tone envelope>[,<noise period>]]]]]
;Puts a sound in the sound queue
;Channel status:
;   Bits 0,1,2: Channel A, B, C respectively
;   Bits 3,4,5: Rendezvous with channel A, B, C respectively
;               Pauses this channel until a sound on rendezvous channel set to rendezvous with this channel
;   Bit 6: Hold - when sound reaches head of queue, channel waits until a RELEASE command
;   Bit 7: Flush - flushes specified channels and plays this sound
;Tone period:   Produces a frequency of 125000/P where P is the tone period. Values 0..4095. 0 is no sound
;Duration:      Default 20 (1/5th second)
;   > 0:        Duration in 1/100ths second
;   = 0:        Until the end of the colume envelope
;   < 0:        Repeat the volume envelope abs(duration) times
;Volume:    Initial volume for the sound. Values 0..15. Default 12
;Volume envelope:   Specifies a volume envelope. Values 0..15. Default 0 (constants volume for 2 seconds)
;Tone envelope:     Tone envelope. Values 0..15. Default 0 (constant)
;Noise period:      0..31 where 0 means no noise



d313 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
d316 3299ad    ld      ($ad99),a
d319 cd15de    call    $de15 ; check for comma
d31c cd4cd4    call    $d44c
d31f ed539cad  ld      ($ad9c),de
d323 cd41de    call    $de41
d326 111400    ld      de,$0014
d329 dcd8ce    call    c,$ced8 ; get number
d32c ed53a0ad  ld      ($ada0),de
d330 010c10    ld      bc,$100c
d333 cd5fd3    call    $d35f
d336 329fad    ld      ($ad9f),a
d339 0e00      ld      c,$00
d33b cd5fd3    call    $d35f
d33e 329aad    ld      ($ad9a),a
d341 cd5fd3    call    $d35f
d344 329bad    ld      ($ad9b),a
d347 0620      ld      b,$20
d349 cd5fd3    call    $d35f
d34c 329ead    ld      ($ad9e),a
d34f cd37de    call    $de37
d352 e5        push    hl
d353 2199ad    ld      hl,$ad99
d356 cdaabc    call    $bcaa					; firmware function: sound queue
d359 e1        pop     hl
d35a d8        ret     c

d35b f1        pop     af
d35c c35dde    jp      $de5d

;;=eval and validate sound parameter
d35f cd41de    call    $de41
d362 79        ld      a,c
d363 d0        ret     nc

d364 7e        ld      a,(hl)
d365 fe2c      cp      $2c
d367 79        ld      a,c
d368 c8        ret     z

;;=eval expr and check less than B
d369 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
d36c b8        cp      b
d36d d8        ret     c

d36e 182b      jr      $d39b            ; (+$2b)

;;========================================================================
;; command RELEASE
;RELEASE <sound channels>
;Release sound channel(s) from a hold state
;Channel is a bitwise value. 0, 1, 2 equal channels A,B,C

d370 0608      ld      b,$08
d372 cd69d3    call    $d369
d375 e5        push    hl
d376 cdb3bc    call    $bcb3			; firmware function: sound release
d379 e1        pop     hl
d37a c9        ret     

;;========================================================
;; function SQ
;SQ(<channel>)
;Test the state of a sound queue
;Channel can be 1,2 or 4 for channel A,B or C
;Returns a bitwise value:
;Bits
;0..2:  Number of free entries in the queue
;3..5:  Rendezvous state of the head of the queue
;6:     Set if the head of the queue is Held
;7:     Set if the channel is currently active
;The last three items are mutually exclusive.
;Disables any ON SQ interrupts

d37b cdb6fe    call    $feb6
d37e 7d        ld      a,l
d37f b7        or      a
d380 1f        rra     
d381 3806      jr      c,$d389          ; (+$06)
d383 1f        rra     
d384 3803      jr      c,$d389          ; (+$03)
d386 1f        rra     
d387 3012      jr      nc,$d39b         ; (+$12)
d389 b4        or      h
d38a 200f      jr      nz,$d39b         ; (+$0f)
d38c 7d        ld      a,l
d38d cdadbc    call    $bcad			; firmware function: sound check
d390 c332ff    jp      $ff32

;;=eval expr and validate less than 128
d393 cdd8ce    call    $ced8 ; get number
d396 7b        ld      a,e
d397 87        add     a,a
d398 9f        sbc     a,a
d399 ba        cp      d
d39a c8        ret     z

;;=raise improper argument error
d39b c34dcb    jp      $cb4d			; Error: Improper Argument

;;========================================================================
;; command ENV
;ENV <envelope number>[,<list of: <envelope section>>]
;Where <envelope section> is <step count>,<step count>,<pause time>
;                           or <hardware envelope>,<envelope period>
;There can be up to five envelope sections
;Envelope number is     1..15
;Step count is          0..127. If zero then set an absolute volume
;Step size is           -128..+127. If <step count> is zero this is the absolute volume setting
;Pause time is          0..255 in 1/100ths of a second where 0=256
;Hardware envelope is   value for register 13
;Envelope period is     value for registers 11 and 12

;Creates a volume envelope

;; get envelope number (must be between 0 and 15)
d39e cdc3ce    call    $cec3
d3a1 fe10      cp      $10				; 16
d3a3 30f6      jr      nc,$d39b         

d3a5 f5        push    af
d3a6 11b7d3    ld      de,$d3b7			; read parameters    ##LABEL##
d3a9 cd25d4    call    $d425
d3ac f1        pop     af
d3ad e5        push    hl
d3ae 21a2ad    ld      hl,$ada2
d3b1 71        ld      (hl),c			; number of sections

d3b2 cdbcbc    call    $bcbc			; firmware function: sound ampl envelope
d3b5 e1        pop     hl
d3b6 c9        ret     

;;----------------------------------
;;=callback for ENV
d3b7 7e        ld      a,(hl)
d3b8 feef      cp      $ef				; equals???
d3ba 2011      jr      nz,$d3cd         

d3bc cd2cde    call    $de2c			; get next token skipping space
d3bf 0610      ld      b,$10
d3c1 cd69d3    call    $d369			; get number and check less than 255
d3c4 f680      or      $80
d3c6 4f        ld      c,a
d3c7 cd15de    call    $de15 ; check for comma
d3ca c3f5ce    jp      $cef5

;; ------------------------------?
d3cd 0680      ld      b,$80
d3cf cd69d3    call    $d369			; get number and check less than 255
d3d2 1840      jr      $d414            ; (+$40)

;;========================================================================
;; command ENT
;ENT <envelope number>[,<list of: <envelope section>>]
;Where <envelope section> is <step count>,<step size>,<pause time>
;                         or =<tone period>,<pause time>
;There can be up to 5 envelope sections
;Envelope number is 1..15
;Step count is      0..239
;Step size is       -128..+127
;Pause time is      0..255 in 1/100ths of a second where 0=256
;Tone period is     0..4095

;Creates a tone envelope

d3d4 cd93d3    call    $d393			; get number
d3d7 7a        ld      a,d
d3d8 b7        or      a
d3d9 7b        ld      a,e
d3da 2802      jr      z,$d3de          ; (+$02)

;; negate?
d3dc 2f        cpl     
d3dd 3c        inc     a

d3de 5f        ld      e,a
d3df b7        or      a
d3e0 28b9      jr      z,$d39b          ; (-$47)

d3e2 fe10      cp      $10				; 16
d3e4 30b5      jr      nc,$d39b         

d3e6 d5        push    de
d3e7 11fdd3    ld      de,$d3fd          ; read parameters   ##LABEL##
d3ea cd25d4    call    $d425
d3ed d1        pop     de
d3ee e5        push    hl
d3ef 21a2ad    ld      hl,$ada2
d3f2 7a        ld      a,d
d3f3 e680      and     $80
d3f5 b1        or      c
d3f6 77        ld      (hl),a
d3f7 7b        ld      a,e
d3f8 cdbfbc    call    $bcbf						; firmware function: sound tone envelope
d3fb e1        pop     hl
d3fc c9        ret     

;;--------------------------------------
;;=callback for ENT
d3fd 7e        ld      a,(hl)
d3fe feef      cp      $ef
d400 200d      jr      nz,$d40f         ; (+$0d)

d402 cd2cde    call    $de2c			; get next token skipping space
d405 cd4cd4    call    $d44c
d408 7a        ld      a,d
d409 c6f0      add     a,$f0
d40b 4f        ld      c,a
d40c 43        ld      b,e
d40d 180d      jr      $d41c            ; (+$0d)

d40f 06f0      ld      b,$f0
d411 cd69d3    call    $d369
d414 4f        ld      c,a
d415 cd15de    call    $de15 ; check for comma
d418 cd93d3    call    $d393
d41b 43        ld      b,e
d41c cd15de    call    $de15 ; check for comma
d41f cdb8ce    call    $ceb8 ; get number and check it's less than 255 
d422 57        ld      d,a
d423 58        ld      e,b
d424 c9        ret     

;;==================================
;;read parameters for ENV and ENT
; DE = address of subroutine to eval parameters for a single step
d425 010005    ld      bc,$0500
d428 cd41de    call    $de41
d42b 301c      jr      nc,$d449         ; (+$1c)
d42d d5        push    de               ;push callback as return address
d42e c5        push    bc
d42f cdfeff    call    $fffe			; JP (DE)
d432 79        ld      a,c
d433 c1        pop     bc
d434 c5        push    bc
d435 e5        push    hl
d436 21a3ad    ld      hl,$ada3
d439 0600      ld      b,$00
d43b 09        add     hl,bc
d43c 09        add     hl,bc
d43d 09        add     hl,bc
d43e 77        ld      (hl),a
d43f 23        inc     hl
d440 73        ld      (hl),e
d441 23        inc     hl
d442 72        ld      (hl),d
d443 e1        pop     hl
d444 c1        pop     bc
d445 0c        inc     c
d446 d1        pop     de
d447 10df      djnz    $d428            ; (-$21)
d449 c337de    jp      $de37

;;=eval and validate tone period
d44c cdd8ce    call    $ced8 ; get number
d44f 7a        ld      a,d
d450 e6f0      and     $f0
d452 c29bd3    jp      nz,$d39b
d455 c9        ret     





;;***Input.asm
;;<< INPUT FUNCTIONS
;;< INKEY, JOY, KEY (DEF). Also SPEED (WRITE/KEY/INK)
;;========================================================
;; function INKEY
;INKEY(<key number>)
;Tests the state of a key and whether [SHIFT] and/or [CTRL] are also down.
;Valid key numbers are 0..79
;Returns:
;Value  Key     [SHIFT] [CTRL]
; -1    Up      Unknown Unknown
;  0    Down    Up      Up
; 32    Down    Down    Up
;128    Down    Up      Down
;160    Down    Down    Down

d456 cdb6fe    call    $feb6
d459 115000    ld      de,$0050
d45c cdd8ff    call    $ffd8 ; HL=DE?
d45f 3022      jr      nc,$d483         ; (+$22)
d461 7d        ld      a,l
d462 cd1ebb    call    $bb1e			; firmware function: km read key
d465 21ffff    ld      hl,$ffff         ;##LIT##
d468 2803      jr      z,$d46d          ; (+$03)
d46a 69        ld      l,c
d46b 2600      ld      h,$00
d46d c335ff    jp      $ff35

;;========================================================
;; function JOY
;JOY(<joystick number>)
;Reads joystick status.
;Joystick numbers are 0..1
;Result is bitwise as follows:
;Bit 0: Up
;    1: Down
;    2: Left
;    3: Right
;    4: Fire 2
;    5: Fire 1

d470 cd24bb    call    $bb24			; firmware function: km get joystick
d473 eb        ex      de,hl
d474 cdb6fe    call    $feb6
d477 7c        ld      a,h
d478 b5        or      l
d479 2802      jr      z,$d47d          ; (+$02)
d47b 53        ld      d,e
d47c 2b        dec     hl
d47d 7c        ld      a,h
d47e b5        or      l
d47f 7a        ld      a,d
d480 ca32ff    jp      z,$ff32

;;=raise improper argument
d483 c34dcb    jp      $cb4d			; Error: Improper Argument

;;========================================================================
;; command KEY
;KEY <expansion token number>,<string expression>
;Sets up a keyboard expansion
;expansion token numbers are 0..31

d486 fe8d      cp      $8d				; DEF token
d488 2816      jr      z,$d4a0          ; 

d48a cdb8ce    call    $ceb8 ; get number and check it's less than 255 
d48d f5        push    af
d48e cd15de    call    $de15 ; check for comma
d491 cd03cf    call    $cf03
d494 48        ld      c,b
d495 f1        pop     af
d496 47        ld      b,a
d497 e5        push    hl
d498 eb        ex      de,hl
d499 cd0fbb    call    $bb0f			; firmware function: KM SET EXPAND
d49c e1        pop     hl
d49d 30e4      jr      nc,$d483         ; (-$1c)
d49f c9        ret     

;;========================================================================
;; KEY DEF
;KEY DEF <key number>,<repeat>[,<normal>[,<shifted>[,<control>]]]
;Defines a key value
;key number is 0..79
;repeat is 1 to enable repeat and 0 to disable repeat
;Other parameters are 0..255 to define the value generated by the key as follows:
;0..31      Control codes
;32..127    Ordinary keys, usually ASCII
;128..159   Expansion tokens which can be defined by the KEY command
;160..223   Ordinary characters
;224..254   Special values used for [ESC], edit and copy cursor keys
;255        Ignored

d4a0 cd2cde    call    $de2c			; get next token skipping space
d4a3 0650      ld      b,$50
d4a5 cd69d3    call    $d369
d4a8 4f        ld      c,a
d4a9 cd15de    call    $de15 ; check for comma
d4ac 0602      ld      b,$02
d4ae cd69d3    call    $d369
d4b1 1f        rra     
d4b2 9f        sbc     a,a
d4b3 47        ld      b,a
d4b4 c5        push    bc
d4b5 e5        push    hl
d4b6 79        ld      a,c
d4b7 cd39bb    call    $bb39			; firmware function: KM SET REPEAT
d4ba e1        pop     hl
d4bb c1        pop     bc
d4bc 1127bb    ld      de,$bb27			; KM SET TRANSLATE
d4bf cdcbd4    call    $d4cb
d4c2 112dbb    ld      de,$bb2d			; KM SET SHIFT
d4c5 cdcbd4    call    $d4cb
d4c8 1133bb    ld      de,$bb33			; KM SET CONTROL
d4cb cd41de    call    $de41
d4ce d0        ret     nc

d4cf d5        push    de
d4d0 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
d4d3 47        ld      b,a
d4d4 e3        ex      (sp),hl
d4d5 79        ld      a,c
d4d6 cdfbff    call    $fffb			; JP (HL)
d4d9 e1        pop     hl
d4da c9        ret     

;;========================================================================
;; command SPEED WRITE, SPEED KEY, SPEED INK
;SPEED INK <period>,<period>
;Changes the rate at which flashing inks update.
;In 1/50ths second in Europe, 1/60ths in the USA (i.e. matches the frame rate)

;SPEED KEY <start delay>,<repeat period>
;Sets the start delay before a key repeats and the speed at which it repeats.
;All times in 1/50ths of a second

;SPEED WRITE <integer expression>
;Sets the cassette write speed.
;0 = 1000 bits per second
;1 = 2000 bits per second
;Read speed is auto adjusted

d4db fed9      cp      $d9				; token for "WRITE"
d4dd 2826      jr      z,$d505          

d4df fea4      cp      $a4				; token for "KEY"
d4e1 013fbb    ld      bc,$bb3f			; firmware function: KM SET DELAY
d4e4 2808      jr      z,$d4ee          ; 
d4e6 fea2      cp      $a2				; token for "INK"
d4e8 013ebc    ld      bc,$bc3e			; firmware function: SCR SET FLASHING
d4eb c249cb    jp      nz,$cb49			; Error: Syntax Error

;;=do SPEED KEY, SPEED INK
d4ee c5        push    bc               ;BC = routine to call to set delay
d4ef cd2cde    call    $de2c			; get next token skipping space
d4f2 cdc3ce    call    $cec3
d4f5 4f        ld      c,a
d4f6 cd15de    call    $de15 ; check for comma
d4f9 cdc3ce    call    $cec3
d4fc 5f        ld      e,a
d4fd 51        ld      d,c
d4fe c1        pop     bc
d4ff eb        ex      de,hl
d500 cdfcff    call    $fffc			; JP (BC)
d503 eb        ex      de,hl
d504 c9        ret     

;;=do SPEED WRITE
d505 cd2cde    call    $de2c			; get next token skipping space
d508 0602      ld      b,$02
d50a cd69d3    call    $d369
d50d e5        push    hl
d50e 21a700    ld      hl,$00a7
d511 3d        dec     a
d512 3e32      ld      a,$32
d514 2802      jr      z,$d518          ; (+$02)
d516 29        add     hl,hl
d517 0f        rrca    
d518 cd68bc    call    $bc68			; firmware function: cas set speed
d51b e1        pop     hl
d51c c9        ret     


;;***MathsFunctions.asm
;;<< (REAL) MATHS FUNCTIONS
;;< Including ^ and random numbers
;;========================================================================
;; variable PI
;PI
;Returns the closest available representation of PI - 3.1415926534683

d51d e5        push    hl
d51e cd41ff    call    $ff41
d521 cd45ff    call    $ff45
d524 cd9abd    call    $bd9a
d527 e1        pop     hl
d528 c9        ret     

;;========================================================================
;; command DEG
;DEG
;Set degrees mode

d529 3eff      ld      a,$ff
d52b 1801      jr      $d52e            ; (+$01)

;;========================================================================
;; command RAD
;RAD
;Set radians mode

d52d af        xor     a
d52e c397bd    jp      $bd97			; maths: set angle mode

;;========================================================
;; function SQR
;SQR(<numeric expression>)
;Returns the square root of the value

d531 019dbd    ld      bc,$bd9d
d534 1816      jr      $d54c            ; (+$16)

;;========================================================
;; infix power ^
d536 e5        push    hl
d537 c5        push    bc
d538 cd14ff    call    $ff14
d53b eb        ex      de,hl
d53c 21b2ad    ld      hl,$adb2
d53f cd61bd    call    $bd61
d542 c1        pop     bc
d543 e3        ex      (sp),hl
d544 79        ld      a,c
d545 cd6cff    call    $ff6c
d548 d1        pop     de
d549 01a0bd    ld      bc,$bda0

;;+-----------------
;; read real param and validate

d54c cd59d5    call    $d559
d54f d8        ret     c

d550 cab5cb    jp      z,$cbb5
d553 fabecb    jp      m,$cbbe
d556 c34dcb    jp      $cb4d			; Error: Improper Argument

;;= read real param
d559 c5        push    bc
d55a d5        push    de
d55b cd14ff    call    $ff14
d55e d1        pop     de
d55f c9        ret     

;;========================================================
;; function EXP
;EXP(<numeric expression>)
;Exponential. Calculates e to the given power.
;Values over 88 will overflow and raise an error.
;Values much less than -88.7 will underflow and return 0

d560 01a9bd    ld      bc,$bda9
d563 18e7      jr      $d54c            ; (-$19)

;;========================================================
;; function LOG10
;LOG10(<numeric expression>)
;Returns the base 10 logarithm of the value, which must be greater than zero

d565 01a6bd    ld      bc,$bda6
d568 18e2      jr      $d54c            ; (-$1e)

;;========================================================
;; function LOG
;LOG(<numeric expression>)
;Returns the natural logarithm of the expression, which must be greater than 0.

d56a 01a3bd    ld      bc,$bda3
d56d 18dd      jr      $d54c            ; (-$23)

;;========================================================
;; function SIN
;SIN(<numeric expression>)
;Returns sine of expression

d56f 01acbd    ld      bc,$bdac
d572 18d8      jr      $d54c            ; (-$28)

;;========================================================
;; function COS
;COS(<numeric expression>)
;Calculates the cosine of the given value

d574 01afbd    ld      bc,$bdaf
d577 18d3      jr      $d54c            ; (-$2d)

;;========================================================
;; function TAN
;TAN(<numeric expression>)
;Returns the tangent of the expression.

d579 01b2bd    ld      bc,$bdb2
d57c 18ce      jr      $d54c            ; (-$32)

;;========================================================
;; function ATN
;ATN(<numeric expression>)
;Returns the arctangent of the supplied value

d57e 01b5bd    ld      bc,$bdb5
d581 18c9      jr      $d54c            ; (-$37)

;;========================================================================
;; random number seed message
d583 defb "Random number seed ? ",0
;;========================================================================
;; command RANDOMIZE
;RANDOMIZE [<numeric expression>]
;Sets the initial value for the random number generator
;If no value is given prompts the user for one.

d599 2806      jr      z,$d5a1          ; (+$06) Do we have inline parameter, if not prompt for input
d59b cd62cf    call    $cf62            ; if so read it
d59e e5        push    hl               ; Save code ptr
d59f 1818      jr      $d5b9            ; (+$18)

;;=random seed prompt
d5a1 e5        push    hl               ; Save code ptr
;;=random seed loop
d5a2 2183d5    ld      hl,$d583			;; "Random number seed?" message
d5a5 cd8bc3    call    $c38b			;; display 0 terminated string
d5a8 cdecca    call    $caec            ; Key input text
d5ab cd98c3    call    $c398			;; new text line
d5ae cd6fed    call    $ed6f            ; Validate/convert to a number
d5b1 30ef      jr      nc,$d5a2         ; (-$11) Loop if invalid
d5b3 cd4dde    call    $de4d			; skip space, lf or tab
d5b6 b7        or      a
d5b7 20e9      jr      nz,$d5a2         ; (-$17) Loop if invalid

;;=do_randomize
d5b9 cd14ff    call    $ff14            ; Convert to a real
d5bc cdbebd    call    $bdbe            ; Firmware: RANDOMIZE seed
d5bf e1        pop     hl               ; Retrieve code ptr
d5c0 c9        ret     

;;========================================================================
;; variable RND
;RND[(<numeric expression>)]
;Returns a random number <= value < 1
;With no argument or a value >= 0 returns a new random number
;With a value = 0 returns a copy of the last random number
;With a value < 0 starts a new sequence based on that value and
;returns the first value in that sequence

d5c1 7e        ld      a,(hl)           ;Do we have a parameter?
d5c2 fe28      cp      $28				; '('
d5c4 201b      jr      nz,$d5e1         ;If not return simple value

d5c6 cd2cde    call    $de2c			; get next token skipping space
d5c9 cd62cf    call    $cf62
d5cc cd1dde    call    $de1d ; check for close bracket
d5cf e5        push    hl
d5d0 cd14ff    call    $ff14
d5d3 cd94bd    call    $bd94            ;Is parameter +ve, zero or -ve?
d5d6 2005      jr      nz,$d5dd         ; (+$05) Non-zero
d5d8 cd8bbd    call    $bd8b            ;If zero, return copy of previous value
d5db e1        pop     hl
d5dc c9        ret     

;;=rnd param non-zero
d5dd fcbebd    call    m,$bdbe          ;If parameter is negative, new random seed
d5e0 e1        pop     hl
;;=rnd generate
d5e1 e5        push    hl
d5e2 cd3eff    call    $ff3e
d5e5 cd7fbd    call    $bd7f
d5e8 e1        pop     hl
d5e9 c9        ret     





;;***VariableArrayFN.asm
;;<< VARIABLE ALLOCATION AND ASSIGNMENT
;;< DEFINT/REAL/STR, LET, DIM, ERASE
;;< (Lots more work to do here)
;;===================================

;;=clear all variables
d5ea cdfad5    call    $d5fa
d5ed 2a66ae    ld      hl,($ae66)
d5f0 2268ae    ld      ($ae68),hl
d5f3 226aae    ld      ($ae6a),hl
d5f6 226cae    ld      ($ae6c),hl
d5f9 c9        ret     

;;=prob reset variable linked list pointers
;zero 36h bytes at adb7
d5fa 21b7ad    ld      hl,$adb7
d5fd 3e36      ld      a,$36
d5ff cd07d6    call    $d607

;;=reset array linked list headers
;zero 6 bytes at aded
d602 21edad    ld      hl,$aded
d605 3e06      ld      a,$06

;;=zero A bytes at HL
d607 3600      ld      (hl),$00
d609 23        inc     hl
d60a 3d        dec     a
d60b 20fa      jr      nz,$d607         ; (-$06)
d60d c9        ret     

;;===================================
;;=clear DEFFN list and reset variable types and pointers
d60e 210000    ld      hl,$0000         ;##LIT##
d611 22ebad    ld      ($adeb),hl
d614 c34dea    jp      $ea4d

;;===================================
;;=get VarFN area and FN list head ptr
d617 3e5b      ld      a,$5b            ;91 Returns with HL=&ade6

;;=get VarFN area and list head ptr
;Calculates an address for a linked list header relative to &ad35
;Entry: A=a value between &41 .. &5b, i.e. one of 'A'..'Z','[' (that final entry is for DEF FNs)
;Exit: BC=addr of variables/DEF FN area -1
;HL=address (based on A) in the BASIC data area of a pointer to a linked list
;HL=&ad35 + (A*2) = (&adb7 - ('A' * 2)) + (A * 2)
;where &adb7 is the block of data for the variable linked list headers
d619 ed4b68ae  ld      bc,($ae68)
d61d 0b        dec     bc               ;A=&41   |&5b 
d61e 87        add     a,a              ;A=&82   |&b6  A=A*2
d61e c635 add a,$adb7 - ('A' * 2) and $ff ;formula version
;OLDd61f c635      add     a,$35            ;A=&b7   |&eb. A=A*2+53
d621 6f        ld      l,a              ;L=&b7   |&eb
d622 cead adc a,$adb7 >> 8 ;formula version
;OLDd622 cead      adc     a,$ad            ;A=&(1)64|$(1)98 (ie. carry)  173 
d624 95        sub     l                ;A=&ad   |$ad
d625 67        ld      h,a              ;HL=&adb7|&adeb
d626 c9        ret     

;;===================================
;;=get array area and array list head ptr for type
;Usually (always?) called with A=a variable data type 
;Entry: A=variable data type (which equals a variable data size) = 2,3 or 5
;Exit: BC=addr of arrays area -1
;HL=address (based on A) in the BASIC data area (adef, adf1, or aded) of
;a pointer for a linked list of arrays of the given type
;Calculates: HL=&aded + (((A and 3) - 1) * 2)
d627 ed4b6aae  ld      bc,($ae6a)
d62b 0b        dec     bc               ;A=   2  |  3  |  5    (int|string|real)
d62c e603      and     $03              ;A=   2  |  3  |  1
d62e 3d        dec     a                ;A=   1  |  2  |  0
d62f 87        add     a,a              ;A=   2  |  4  |  0
d630 c6ed      add     a,$aded and 255 ;formula version
;OLDd630 c6ed      add     a,$ed            ;A= $ef  |$f1  |$ed  I.e add a,$aded and $ff
d632 6f        ld      l,a              ;L= $ef  |$f1  |$ed
d633 cead      adc     a,$aded >> 8 ;formula version
;OLDd633 cead      adc     a,$ad            ;A= $19c |$19e |$19a (i.e. carry)  I.e. adc a,&aded shr 8
d635 95        sub     l                ;A= $ad  |$ad  |$ad
d636 67        ld      h,a              ;HL=$adef|$adf1|$aded -> addresses in BASIC data area!
d637 c9        ret     

;;===================================
;;=defreal a to z
d638 015a41    ld      bc,$415a         ;'A''Z' - letter range
d63b 1e05      ld      e,$05            ;REAL data type

;;=def letters BC to type E
;DEFs the type of a range of variables
;B=start of letter range ('A' to 'Z')
;C=end of letter range ('A' to 'Z')
;E=variable type (2,3,5)
d63d 79        ld      a,c
d63e 90        sub     b                ;calc number of items to set
d63f 383d      jr      c,$d67e          ; (+$3d)
d641 e5        push    hl
d642 3c        inc     a
d643 21b2ad    ld      hl,$adf3 - 'A'   ;Relative to start of DEFxxxx table
d646 0600      ld      b,$00
d648 09        add     hl,bc            ;HL=last item in range

d649 73        ld      (hl),e
d64a 2b        dec     hl
d64b 3d        dec     a
d64c 20fb      jr      nz,$d649         ; (-$05) Loop

d64e e1        pop     hl
d64f c9        ret     


;;======================================================
;; command DEFSTR
;DEFSTR <list of: <letter range>>
;where <letter range> is <letter> or <letter>-<letter>
;Defines the default type for variables starting with the given letter(s)
;Letter ranges are inclusive

d650 1e03      ld      e,$03            ;String type
d652 1806      jr      $d65a            ; (+$06)

;;=============================================================================
;; command DEFINT
;DEFINT <list of: <letter range>>
;As DEFSTR

d654 1e02      ld      e,$02            ;Int type
d656 1802      jr      $d65a            ; (+$02)

;;=============================================================================
;; command DEFREAL
;DEFREAL <list of: <letter range>>
;As DEFSTR

d658 1e05      ld      e,$05            ;Real type

;;-----------------------------------------------------------------------------
;;=do DEFtype
d65a 7e        ld      a,(hl)
d65b cd92ff    call    $ff92			; is a alphabetical letter?
d65e 301e      jr      nc,$d67e         ; (+$1e)
d660 4f        ld      c,a
d661 47        ld      b,a
d662 cd2cde    call    $de2c			; get next token skipping space
d665 fe2d      cp      $2d				; '-' - range of values
d667 200c      jr      nz,$d675         ; (+$0c)
d669 cd2cde    call    $de2c			; get next token skipping space
d66c cd92ff    call    $ff92			; is a alphabetical letter?
d66f 300d      jr      nc,$d67e         ; (+$0d)
d671 4f        ld      c,a
d672 cd2cde    call    $de2c			; get next token skipping space

d675 cd3dd6    call    $d63d
d678 cd41de    call    $de41
d67b 38dd      jr      c,$d65a          ; (-$23) comma = more items in list
d67d c9        ret     

;;=raise Syntax Error
d67e c349cb    jp      $cb49			; Error: Syntax Error

;;=raise Subscript out of range
d681 cd45cb    call    $cb45
d684 defb $09                         ;Inline error code: Subscript out of range

;;=raise Array already dimensioned
d685 cd45cb    call    $cb45
d688 defb $0a                         ;Inline error code: Array already dimensioned

;;========================================================================
;; BAR command or implicit LET
d689 fef8      cp      $f8				; '|'
d68b ca45f2    jp      z,$f245

;;========================================================================
;; command LET
;LET <variable>=<expression>
;Assign a value to a variable

d68e cdbfd6    call    $d6bf            ;Find (or alloc) the variables
d691 d5        push    de               ;Preserve address(?)
d692 cd21de    call    $de21            ;Test for '=' sign
d695 cd62cf    call    $cf62            ;Evaluate the new value
d698 78        ld      a,b
d699 e3        ex      (sp),hl          ;Retrieve the address
d69a cd9fd6    call    $d69f            ;Store the new value (also stores a string if appropriate)
d69d e1        pop     hl               ;Retrieve code pointer
d69e c9        ret     

;;=copy accumulator to atHL as type B
d69f 47        ld      b,a
d6a0 cd4bff    call    $ff4b
d6a3 b8        cp      b
d6a4 78        ld      a,b
d6a5 c4fffe    call    nz,$feff
;;=copy accumulator to atHL
d6a8 cd66ff    call    $ff66
d6ab c283ff    jp      nz,$ff83         ;It's a number
d6ae e5        push    hl               ;Otherwise it's a string
d6af cd94fb    call    $fb94            ;Store string to strings area
d6b2 d1        pop     de
d6b3 c387ff    jp      $ff87

;;========================================================================
;; command DIM
;DIM <list of: <subscripted variable>>
;Where <subscripted variable> is <variable name>(<dimension list>)
;and <dimension list> is <list of: <integer expression>>
;Declare array dimensions

d6b6 cde0d7    call    $d7e0
d6b9 cd41de    call    $de41
d6bc 38f8      jr      c,$d6b6          ; (-$08) Comma = more items in list
d6be c9        ret     

;;===================================================
;The variable/array/deffn token is followed by a pointer into the variables/arrays/deffn area.
;At reset this value is cleared to zero. Here we read the value. If it's set then add it to the base address,
;if not the search the relevant linked list to: find it; store the found value (and possibly clarify the variables type);
;(depeding on the routine) allocate space if the item isn't already created.


;;=parse and find or create a var
;Returns DE = address of variables value
d6bf cd31d9    call    $d931
d6c2 cd06d8    call    $d806
d6c5 3842      jr      c,$d709          ; (+$42) variable offset set -> return
d6c7 1828      jr      $d6f1            ; (+$28) variable offset not set -> find (and maybe alloc)

;;=parse and find var
d6c9 cd31d9    call    $d931
d6cc cd06d8    call    $d806
d6cf 3838      jr      c,$d709          ; (+$38) variable offset set -> return
d6d1 e5        push    hl
d6d2 79        ld      a,c
d6d3 cd19d6    call    $d619            ;search list of vars (list depends on type)
d6d6 cd17d7    call    $d717
d6d9 182d      jr      $d708            ; (+$2d) return

;;=parse and find or create an FN
d6db cd31d9    call    $d931
d6de 3821      jr      c,$d701          ; (+$21) variable offset set -> add offset and return
d6e0 e5        push    hl
d6e1 cd17d6    call    $d617            ;search list of DEF FNs
d6e4 cd32d7    call    $d732
d6e7 d46fd7    call    nc,$d76f         ;not found - alloc
d6ea 181c      jr      $d708            ; (+$1c)

;;=parse and find or alloc FOR var
d6ec cd31d9    call    $d931
d6ef 3810      jr      c,$d701          ; (+$10) variable offset set -> return

;;=find var and alloc if not found
d6f1 e5        push    hl
d6f2 79        ld      a,c
d6f3 cd19d6    call    $d619            ;search list of variables (list depends on type)
d6f6 cd17d7    call    $d717
d6f9 3a9fb0    ld      a,($b09f)
d6fc d47bd7    call    nc,$d77b         ;not found - alloc
d6ff 1807      jr      $d708            ; (+$07)

;;=add offset to addr in var FN area
d701 e5        push    hl
d702 2a68ae    ld      hl,($ae68)
d705 2b        dec     hl
d706 19        add     hl,de
d707 eb        ex      de,hl

;;=pop hl and get accum data type in A B and C 
d708 e1        pop     hl

;;=get accum data type in A B and C
d709 3a9fb0    ld      a,($b09f)
d70c 47        ld      b,a
d70d 4f        ld      c,a
d70e c9        ret     

;;============================
;;prob just skip over variable
d70f cd31d9    call    $d931
d712 cd7ae9    call    $e97a
d715 18f2      jr      $d709            ; (-$0e)

;;==================================
;;=find var in FN or var linked lists
;Appears to check multiple lists? Maybe depends on variable type
d717 d5        push    de
d718 e5        push    hl
d719 2a12ae    ld      hl,($ae12)       ;Are we in an FN?
d71c 7c        ld      a,h
d71d b5        or      l
d71e 2810      jr      z,$d730          ; (+$10) Nope - just check regular variables
d720 23        inc     hl               ;otherwise check variable linked list for the FN...
d721 23        inc     hl
d722 c5        push    bc
d723 010000    ld      bc,$0000         ;which uses an absolute address (well, an offset from zero) ##LIT##
d726 cd40d7    call    $d740
d729 c1        pop     bc               ;and then check the regular variable linked list
d72a 3004      jr      nc,$d730         ; (+$04)
d72c f1        pop     af
d72d f1        pop     af
d72e 37        scf     
d72f c9        ret     

;;=prob find item in linked list
;finds an item within a single list
d730 e1        pop     hl
d731 d1        pop     de

d732 d5        push    de               ;this entry point searches DEF FNs list
d733 e5        push    hl
d734 cd40d7    call    $d740
d737 e1        pop     hl
d738 3802      jr      c,$d73c          ; (+$02)
d73a d1        pop     de
d73b c9        ret     

d73c e1        pop     hl
d73d c39ed7    jp      $d79e

;;==================================
;;find named item in linked list
;BC=start of linked list
;HL=ptr to offset into list - item is at BC + (HL)
;($AE0E) addr of ASCIIZ name to compare to
;Type must match that of the accumulator
;EXIT: Carry set if item found
;(If found):
;HL = address of start of item
;DE = address of items data area (address after type specifier)

;Table format:
;Word: Offset (from BC) of next item in table (or zero if end of list)
;ASCIIZ string: item name
;Byte: Item type (2/3/5)
;Data area

d740 7e        ld      a,(hl)
d741 23        inc     hl
d742 66        ld      h,(hl)
d743 6f        ld      l,a
d744 b4        or      h
d745 c8        ret     z                ;Offset? is zero - end of list (or empty list)  

d746 09        add     hl,bc            ;Add offset to start of table
d747 e5        push    hl
d748 23        inc     hl               ;Step over (pointer) to string (var name)
d749 23        inc     hl               ;Ptr = offset of next item?
d74a ed5b0eae  ld      de,($ae0e)       ;Address of another string

d74e 1a        ld      a,(de)           ;Compare ASCII7 string at HL to that at DE
d74f be        cp      (hl)
d750 200d      jr      nz,$d75f         ; (+$0d) Char doesn't match - fail
d752 23        inc     hl               ;Next char
d753 13        inc     de
d754 17        rla                      ;Is bit 7 set?
d755 30f7      jr      nc,$d74e         ; (-$09) Loop for next char if not

d757 3a9fb0    ld      a,($b09f)        ;Does the type also match?
d75a 3d        dec     a
d75b ae        xor     (hl)
d75c e607      and     $07
d75e eb        ex      de,hl
d75f e1        pop     hl               ;Retrieve start address of item = ptr to next item
d760 20de      jr      nz,$d740         ; (-$22) Not a match, loop. 
d762 13        inc     de               ;DE = ptr to the items data
d763 37        scf     
d764 c9        ret     

;;=poss step over string
d765 54        ld      d,h
d766 5d        ld      e,l
d767 23        inc     hl
d768 23        inc     hl
d769 cb7e      bit     7,(hl)
d76b 23        inc     hl
d76c 28fb      jr      z,$d769          ; (-$05)
d76e c9        ret     

;;=prob alloc space for a DEF FN
d76f 3e02      ld      a,$02
d771 cd7bd7    call    $d77b
d774 1b        dec     de
d775 1a        ld      a,(de)
d776 f640      or      $40
d778 12        ld      (de),a
d779 13        inc     de
d77a c9        ret     

;;=prob alloc space for new var
d77b d5        push    de
d77c e5        push    hl
d77d c5        push    bc
d77e f5        push    af
d77f cda8d7    call    $d7a8
d782 f5        push    af
d783 2a6aae    ld      hl,($ae6a)
d786 eb        ex      de,hl
d787 cdb8f6    call    $f6b8
d78a cd1af6    call    $f61a
d78d f1        pop     af
d78e cdb8d7    call    $d7b8
d791 c1        pop     bc

d792 af        xor     a                ;Zero B bytes
d793 2b        dec     hl
d794 77        ld      (hl),a
d795 10fc      djnz    $d793            ; (-$04)

d797 c1        pop     bc
d798 e3        ex      (sp),hl
d799 cdd0d7    call    $d7d0
d79c d1        pop     de
d79d e1        pop     hl

;;=prob store offset into code
;stores the newly found/created variable/fn/array offset into the code where it is referenced
d79e 23        inc     hl
d79f 7b        ld      a,e
d7a0 91        sub     c
d7a1 77        ld      (hl),a
d7a2 23        inc     hl
d7a3 7a        ld      a,d
d7a4 98        sbc     a,b
d7a5 77        ld      (hl),a
d7a6 37        scf     
d7a7 c9        ret     

;;=count length of cached string
d7a8 c603      add     a,$03
d7aa 4f        ld      c,a
d7ab 2a0eae    ld      hl,($ae0e)       ;Address of cached string
d7ae af        xor     a                ;Count length of string
d7af 47        ld      b,a
d7b0 03        inc     bc
d7b1 3c        inc     a
d7b2 cb7e      bit     7,(hl)
d7b4 23        inc     hl
d7b5 28f9      jr      z,$d7b0          ; (-$07)
d7b7 c9        ret     

;;=copy cached string and store data type
d7b8 62        ld      h,d
d7b9 6b        ld      l,e
d7ba 09        add     hl,bc
d7bb e5        push    hl
d7bc d5        push    de
d7bd 13        inc     de
d7be 13        inc     de
d7bf 2a0eae    ld      hl,($ae0e)
d7c2 cdecff    call    $ffec			;; copy bytes (A=count, HL=source, DE=dest)
d7c5 3a9fb0    ld      a,($b09f)
d7c8 3d        dec     a
d7c9 12        ld      (de),a
d7ca 13        inc     de
d7cb 42        ld      b,d
d7cc 4b        ld      c,e
d7cd d1        pop     de
d7ce e1        pop     hl
d7cf c9        ret     

;;=poss update list headers
d7d0 7e        ld      a,(hl)
d7d1 12        ld      (de),a
d7d2 7b        ld      a,e
d7d3 91        sub     c
d7d4 77        ld      (hl),a
d7d5 23        inc     hl
d7d6 7e        ld      a,(hl)
d7d7 f5        push    af
d7d8 7a        ld      a,d
d7d9 98        sbc     a,b
d7da 77        ld      (hl),a
d7db f1        pop     af
d7dc 13        inc     de
d7dd 12        ld      (de),a
d7de 13        inc     de
d7df c9        ret     

;;==================================
;;do DIM item
d7e0 cd31d9    call    $d931            ;skip over the array name...
d7e3 7e        ld      a,(hl)           ;...and we should have an open brace (either type)
d7e4 fe28      cp      $28              ;'('
d7e6 2805      jr      z,$d7ed          ; (+$05)
d7e8 ee5b      xor     $5b              ;'['
d7ea c249cb    jp      nz,$cb49			; Error: Syntax Error

d7ed cd83d8    call    $d883
d7f0 e5        push    hl
d7f1 c5        push    bc
d7f2 3a9fb0    ld      a,($b09f)
d7f5 cd27d6    call    $d627            ;Is the array already dimmed? Go look for it
d7f8 cd40d7    call    $d740
d7fb da85d6    jp      c,$d685          ;if so, error

d7fe c1        pop     bc
d7ff 3eff      ld      a,$ff
d801 cdb3d8    call    $d8b3            ;and create it
d804 e1        pop     hl
d805 c9        ret     

;;=convert var or array offset into address
;allocates space for array if needed
;Entry: DE=offset into variables or arrays tables, unless:
;Carry set if the address has stored in the code, and DE = offset of element
;Exit: DE=absolute address of var/FN/array element data
d806 f5        push    af
d807 7e        ld      a,(hl)           ;token after variable name/type
d808 fe28      cp      $28              ;'('
d80a 2810      jr      z,$d81c          ; (+$10)
d80c ee5b      xor     $5b              ;'['
d80e 280c      jr      z,$d81c          ; (+$0c)
d810 f1        pop     af
d811 d0        ret     nc

d812 e5        push    hl               ;variable of FN
d813 2a68ae    ld      hl,($ae68)
d816 2b        dec     hl
d817 19        add     hl,de
d818 eb        ex      de,hl
d819 e1        pop     hl
d81a 37        scf     
d81b c9        ret     

;;=get array element address
;allocates space for array if needed
d81c cd83d8    call    $d883            ;push array dimensions onto execution stack;count in B
d81f f1        pop     af
d820 e5        push    hl
d821 3007      jr      nc,$d82a         ; (+$07) 
d823 2a6aae    ld      hl,($ae6a)       ;address stored in code (which means it's a constant value??)
d826 2b        dec     hl
d827 19        add     hl,de            ;get absolute address
d828 1815      jr      $d83f            ; (+$15)

d82a c5        push    bc
d82b d5        push    de
d82c 3a9fb0    ld      a,($b09f)
d82f cd27d6    call    $d627            ;try and find the array
d832 cd40d7    call    $d740
d835 300f      jr      nc,$d846         ; (+$0f) not found - create it
d837 13        inc     de
d838 13        inc     de
d839 e1        pop     hl
d83a cd9ed7    call    $d79e
d83d c1        pop     bc
d83e eb        ex      de,hl
d83f 78        ld      a,b              ;number of dimensions
d840 96        sub     (hl)             ;compare with stored value
d841 c281d6    jp      nz,$d681
d844 180a      jr      $d850            ; (+$0a)

d846 e1        pop     hl               ;create array
d847 c1        pop     bc
d848 af        xor     a
d849 cdb3d8    call    $d8b3
d84c cd9ed7    call    $d79e
d84f eb        ex      de,hl

d850 110000    ld      de,$0000         ;we now have the address of the array ##LIT##
d853 46        ld      b,(hl)           ;get number of dimensions

d854 23        inc     hl               ;point to size of first dimension
d855 e5        push    hl               ;read size of dimension
d856 d5        push    de
d857 5e        ld      e,(hl)
d858 23        inc     hl
d859 56        ld      d,(hl)
d85a cd27d9    call    $d927            ;pop index into dimension
d85d cdd8ff    call    $ffd8            ; HL=DE? validate
d860 d281d6    jp      nc,$d681         ;index * size of dimension?
d863 e3        ex      (sp),hl
d864 cd72dd    call    $dd72
d867 d1        pop     de
d868 19        add     hl,de            ;add to offset -> new offset
d869 eb        ex      de,hl
d86a e1        pop     hl
d86b 23        inc     hl
d86c 23        inc     hl
d86d 10e6      djnz    $d855            ; (-$1a) loop for more dimensions

d86f eb        ex      de,hl
d870 44        ld      b,h              ;Multiply index by element size
d871 4d        ld      c,l
d872 3a9fb0    ld      a,($b09f)
d875 d603      sub     $03
d877 3804      jr      c,$d87d          ; (+$04)
d879 29        add     hl,hl
d87a 2801      jr      z,$d87d          ; (+$01)
d87c 29        add     hl,hl
d87d 09        add     hl,bc
d87e 19        add     hl,de
d87f eb        ex      de,hl
d880 e1        pop     hl
d881 37        scf     
d882 c9        ret     

;;=read array dimensions
;reads array dimensions and pushes them onto the execution stack
;B returns the number of dimensions
d883 d5        push    de
d884 cd2cde    call    $de2c			; get next token skipping space
d887 3a9fb0    ld      a,($b09f)

d88a f5        push    af
d88b 0600      ld      b,$00            ;B=number of dimensions
d88d cdcece    call    $cece            ;Read value
d890 e5        push    hl
d891 3e02      ld      a,$02            ;push value onto the execution stack
d893 cd72f6    call    $f672
d896 73        ld      (hl),e
d897 23        inc     hl
d898 72        ld      (hl),d
d899 e1        pop     hl

d89a 04        inc     b                ;inc dimension counter
d89b cd41de    call    $de41            ;any more?
d89e 38ed      jr      c,$d88d          ; (-$13) if so, loop
d8a0 7e        ld      a,(hl)           ;finish list with brackets of either type
d8a1 fe29      cp      $29              ;')'
d8a3 2805      jr      z,$d8aa          ; (+$05)
d8a5 fe5d      cp      $5d              ;']'
d8a7 c249cb    jp      nz,$cb49			; otherwise, Error: Syntax Error

d8aa cd2cde    call    $de2c			; get next token skipping space
d8ad f1        pop     af
d8ae 329fb0    ld      ($b09f),a
d8b1 d1        pop     de
d8b2 c9        ret     

;;=create and alloc space for array
;A=dimensions flag: $00=we're creating the array from a DIM statement and the dimensions are on the execution stack
;                   $ff=we're creating a 'default' 10 item array due to the array being used,
;B=number of dimensions
;If A=$00 then the array bounds (dimensions) are pushed on the execution stack
d8b3 e5        push    hl
d8b4 320dae    ld      ($ae0d),a
d8b7 c5        push    bc
d8b8 78        ld      a,b
d8b9 87        add     a,a
d8ba c603      add     a,$03
d8bc cda8d7    call    $d7a8
d8bf f5        push    af
d8c0 2a6cae    ld      hl,($ae6c)
d8c3 eb        ex      de,hl
d8c4 cdb8f6    call    $f6b8            ;Move data up out of the way
d8c7 f1        pop     af
d8c8 cdb8d7    call    $d7b8            ;Copy/store array name and type
d8cb 60        ld      h,b
d8cc 69        ld      l,c
d8cd c1        pop     bc
d8ce d5        push    de
d8cf 23        inc     hl
d8d0 23        inc     hl
d8d1 3a9fb0    ld      a,($b09f)
d8d4 5f        ld      e,a
d8d5 1600      ld      d,$00

d8d7 70        ld      (hl),b           ;number of dimensions (and loop counter)
d8d8 e5        push    hl
d8d9 23        inc     hl

d8da d5        push    de               ;Loop for each dimension
d8db 3a0dae    ld      a,($ae0d)
d8de b7        or      a
d8df 110a00    ld      de,$000a
d8e2 eb        ex      de,hl
d8e3 c427d9    call    nz,$d927         ;pop size of this dimension
d8e6 eb        ex      de,hl
d8e7 13        inc     de
d8e8 73        ld      (hl),e           ;store dimension size
d8e9 23        inc     hl
d8ea 72        ld      (hl),d
d8eb 23        inc     hl
d8ec e3        ex      (sp),hl
d8ed cd72dd    call    $dd72            ;size of this dimension?
d8f0 da81d6    jp      c,$d681

d8f3 eb        ex      de,hl
d8f4 e1        pop     hl
d8f5 10e3      djnz    $d8da            ; (-$1d) loop for more dimensions

d8f7 42        ld      b,d              ;Restore the following memory
d8f8 4b        ld      c,e
d8f9 54        ld      d,h
d8fa 5d        ld      e,l
d8fb cdbbf6    call    $f6bb
d8fe 226cae    ld      ($ae6c),hl

d901 c5        push    bc               ;Clear BC bytes of memory - cleanup? zero allocated space?
d902 2b        dec     hl
d903 3600      ld      (hl),$00
d905 0b        dec     bc
d906 78        ld      a,b
d907 b1        or      c
d908 20f8      jr      nz,$d902         ; (-$08)

d90a c1        pop     bc
d90b e1        pop     hl
d90c 5e        ld      e,(hl)
d90d 57        ld      d,a
d90e eb        ex      de,hl
d90f 29        add     hl,hl
d910 23        inc     hl
d911 09        add     hl,bc
d912 eb        ex      de,hl
d913 2b        dec     hl
d914 2b        dec     hl
d915 73        ld      (hl),e           ;store pointer to next item in list?
d916 23        inc     hl
d917 72        ld      (hl),d
d918 23        inc     hl
d919 e3        ex      (sp),hl
d91a eb        ex      de,hl

d91b 3a9fb0    ld      a,($b09f)
d91e cd27d6    call    $d627           
d921 cdd0d7    call    $d7d0            ;and update list header?
d924 d1        pop     de
d925 e1        pop     hl
d926 c9        ret     

;;=pop word off execution stack
d927 3e02      ld      a,$02
d929 cd62f6    call    $f662
d92c 7e        ld      a,(hl)
d92d 23        inc     hl
d92e 66        ld      h,(hl)
d92f 6f        ld      l,a
d930 c9        ret     

;;=================================
;;parse var type and name
;if the offset is set within the variables token data, returns it in DE and skips over the name,
;otherwise copies the variables name onto the execution stack and sets (&ae0e) to point to the first char,
;and returns the first letter in uppercase in C
;Carry set if we're returning the offset.
;Entry: HL=pointer to variable definition, token data
;Exit:DE=value (offset)
;C=first letter of name converted to upper case
;Carry set if offset found
d931 cdafd9    call    $d9af            ;Set accumulator to match variable token type
d934 23        inc     hl
d935 5e        ld      e,(hl)           ;read var offset into DE
d936 23        inc     hl
d937 56        ld      d,(hl)
d938 7a        ld      a,d
d939 b3        or      e
d93a 280a      jr      z,$d946          ; (+$0a) if offset is zero we need to find offset

d93c 23        inc     hl               ;skip over var name (ends with bit 7 set)
d93d 7e        ld      a,(hl)
d93e 17        rla     
d93f 30fb      jr      nc,$d93c         ; (-$05)

d941 cd2cde    call    $de2c			; get next token skipping space
d944 37        scf     
d945 c9        ret     

;;=copy var name onto exec stack
;;Parse variable name onto execution stack, set (AE0E) as a poiner to it
;Exit: C=first letter of name converted to uppercase
d946 2b        dec     hl
d947 2b        dec     hl               ;HL now ponts to variable type token
d948 eb        ex      de,hl
d949 c1        pop     bc
d94a 2a0eae    ld      hl,($ae0e)       ;Old top of execution stack?
d94d e5        push    hl
d94e 215ed9    ld      hl,$d95e         ;##LABEL##
d951 e5        push    hl               ;!!!Push code address onto stack - not sure where this comes out!!!
d952 c5        push    bc
d953 eb        ex      de,hl
d954 e5        push    hl
d955 cd6cd9    call    $d96c
d958 ed530eae  ld      ($ae0e),de
d95c d1        pop     de
d95d c9        ret     

d95e e5        push    hl
d95f 2a0eae    ld      hl,($ae0e)
d962 cd6ef6    call    $f66e
d965 e1        pop     hl
d966 e3        ex      (sp),hl
d967 220eae    ld      ($ae0e),hl
d96a e1        pop     hl
d96b c9        ret     

;;=======================================
;;=copy var name onto execution stack
;Entry: DE=address of a variable type token
;Exit: C=first letter of name converted to uppercase
d96c e5        push    hl               
d96d 7e        ld      a,(hl)           ;Get var type
d96e 23        inc     hl
d96f 23        inc     hl
d970 23        inc     hl               ;HL=pointer to var name
d971 4e        ld      c,(hl)           ;First char of name
d972 cba9      res     5,c              ;To upper case
d974 e3        ex      (sp),hl
d975 fe0b      cp      $0b              
d977 3817      jr      c,$d990          ; (+$17) variable type is known

;establish the variables type ... and poke that into the variables token data
d979 79        ld      a,c              ;Get index into DEFtype table...
d97a e61f      and     $1f
d97c c6f2      add     a,$f2            ;...which starts at ADF3
d97e 5f        ld      e,a
d97f cead      adc     a,$ad
d981 93        sub     e
d982 57        ld      d,a
d983 1a        ld      a,(de)           ;Type from DEFtype table
d984 329fb0    ld      ($b09f),a
d987 360d      ld      (hl),$0d         ;Set the vars type as real/unspecified
d989 fe05      cp      $05              ;Real?
d98b 2803      jr      z,$d990          ; (+$03)

d98d c609      add     a,$09            ;Set the variables type (as no suffix defined)
d98f 77        ld      (hl),a

;;=do the name copying
d990 d1        pop     de
d991 3e28      ld      a,$28            ;Max name length??
d993 cd72f6    call    $f672
d996 e5        push    hl
d997 0629      ld      b,$29

d999 05        dec     b
d99a ca49cb    jp      z,$cb49			; Error: Syntax Error (name too long)

d99d 1a        ld      a,(de)           ;Copy char
d99e 13        inc     de
d99f e6df      and     $df              ;Convert to upper case
d9a1 77        ld      (hl),a
d9a2 23        inc     hl
d9a3 17        rla                      ;Bit 7 set? (Last char)
d9a4 30f3      jr      nc,$d999         ; (-$0d) Loop for next char

d9a6 cd6ef6    call    $f66e            ;Push onto execution stack
d9a9 eb        ex      de,hl
d9aa 2b        dec     hl
d9ab d1        pop     de
d9ac c32cde    jp      $de2c			; get next token skipping space

;;==============================================
;;=set accum type from variable type atHL
;variable data type tokens = 2/3/4 if have suffix, $b/$c/$d if no suffix
d9af 7e        ld      a,(hl)
d9b0 fe0b      cp      $0b              ;No suffix
d9b2 3802      jr      c,$d9b6          ; (+$02)
d9b4 c6f7      add     a,$f7            ;Subtract 9
d9b6 fe04      cp      $04              ;REAL type token
d9b8 2809      jr      z,$d9c3          ; (+$09)
d9ba 3004      jr      nc,$d9c0         ; (+$04)
d9bc fe02      cp      $02              ;INT type token
d9be 3005      jr      nc,$d9c5         ; (+$05)

;;=raise Syntax Error
d9c0 c349cb    jp      $cb49			; Error: Syntax Error

;;=set accum type as REAL
d9c3 3e05      ld      a,$05
;;=set accumulator type
d9c5 329fb0    ld      ($b09f),a
d9c8 c9        ret     

;;=========================================
;;=update array list heads
;iterate over all arrays and update the list heads (there's one for each data type 2,3,5)
;works by:
;reset heads to nil
;works from start to arrays area
;for each array, update list head for that type
;until end of arrays area
;so, each list head will now point to the last array for it's type
d9c9 cd02d6    call    $d602
d9cc 2a6cae    ld      hl,($ae6c)       ;get bounds of arrays area
d9cf eb        ex      de,hl
d9d0 2a6aae    ld      hl,($ae6a)
d9d3 cdd8ff    call    $ffd8 ; HL=DE?
d9d6 c8        ret     z                ;end once we go beyond end of arrays area

d9d7 d5        push    de               ;DE = start of arrays area
d9d8 cd65d7    call    $d765            ;skip over array name...
d9db 7e        ld      a,(hl)           ;...to get to type
d9dc 23        inc     hl
d9dd e607      and     $07
d9df 3c        inc     a
d9e0 e5        push    hl               ;HL=start of current item
d9e1 cd27d6    call    $d627            ;get list head ptr for item type
d9e4 cdd0d7    call    $d7d0            ;update head ptr to current item
d9e7 e1        pop     hl               ;back to start of item
d9e8 5e        ld      e,(hl)           ;read offset ptr to next item
d9e9 23        inc     hl
d9ea 56        ld      d,(hl)
d9eb 23        inc     hl
d9ec 19        add     hl,de            ;add offset to start of arrays area
d9ed d1        pop     de               ;retrieve start of arrays area
d9ee 18e3      jr      $d9d3            ; (-$1d) next

;;========================================================================
;; command ERASE
;ERASE <list of: <variable name>>
;Erases array(s)

d9f0 cd4dea    call    $ea4d
d9f3 cdfcd9    call    $d9fc
d9f6 cd41de    call    $de41
d9f9 38f8      jr      c,$d9f3          ; (-$08) loop if more parameters
d9fb c9        ret     

;;=do ERASE parameter
d9fc cd31d9    call    $d931            ;find the array
d9ff e5        push    hl
da00 3a9fb0    ld      a,($b09f)
da03 cd27d6    call    $d627
da06 cd40d7    call    $d740
da09 d24dcb    jp      nc,$cb4d			; Error: Improper Argument (array not dimmed)

da0c eb        ex      de,hl
da0d 4e        ld      c,(hl)           ;offset to next item
da0e 23        inc     hl
da0f 46        ld      b,(hl)
da10 23        inc     hl
da11 09        add     hl,bc            ;calc size of item
da12 cde4ff    call    $ffe4			; BC = HL-DE
da15 cde5f6    call    $f6e5            ;move other items to fill gap
da18 cd21f6    call    $f621
da1b cdc9d9    call    $d9c9            ;rebuild list pointers??
da1e e1        pop     hl
da1f c9        ret     

;;============================
;;=clear FN params data
da20 210000    ld      hl,$0000         ;##LIT##
da23 2212ae    ld      ($ae12),hl
da26 2210ae    ld      ($ae10),hl
da29 c9        ret     

;;=push FN header on execution stack
;DE=address of the DEF FN for this FN
da2a e5        push    hl
da2b 2a10ae    ld      hl,($ae10)
da2e eb        ex      de,hl
da2f 3e06      ld      a,$06
da31 cd72f6    call    $f672
da34 2210ae    ld      ($ae10),hl
da37 73        ld      (hl),e       ;store address of DEF FN
da38 23        inc     hl
da39 72        ld      (hl),d
da3a 23        inc     hl
da3b af        xor     a
da3c 77        ld      (hl),a       ;store zero
da3d 23        inc     hl
da3e 77        ld      (hl),a       ;store zero
da3f 23        inc     hl
da40 ed5b12ae  ld      de,($ae12)
da44 73        ld      (hl),e       ;store end of FN params
da45 23        inc     hl
da46 72        ld      (hl),d
da47 e1        pop     hl
da48 c9        ret     

;;=copy FN param start to FN param end
da49 e5        push    hl           ;Called after pushing all params on exec stack
da4a 2a10ae    ld      hl,($ae10)
da4d 2212ae    ld      ($ae12),hl
da50 e1        pop     hl
da51 c9        ret     

;;=remove FN data from stack
da52 2a10ae    ld      hl,($ae10)       ;free our data off the exec stack
da55 cd6ef6    call    $f66e
da58 5e        ld      e,(hl)           ;read and restore previous param_start
da59 23        inc     hl
da5a 56        ld      d,(hl)
da5b 23        inc     hl
da5c ed5310ae  ld      ($ae10),de
da60 23        inc     hl               ;step over list header
da61 23        inc     hl
da62 5e        ld      e,(hl)           ;read and restore prev param_end
da63 23        inc     hl
da64 56        ld      d,(hl)
da65 eb        ex      de,hl
da66 2212ae    ld      ($ae12),hl
da69 c9        ret     

;;=push FN parameter on execution stack
;An FN parameter uses the same data structures a regular variable. I.e a linked list
;this allocates space, copies the name and type, and updates the relevant list pointers
da6a e5        push    hl
da6b 3e02      ld      a,$02            ;alloc space for link to next item
da6d cd72f6    call    $f672
da70 e3        ex      (sp),hl
da71 cdafd9    call    $d9af
da74 cd6cd9    call    $d96c
da77 e3        ex      (sp),hl
da78 eb        ex      de,hl
da79 2a10ae    ld      hl,($ae10)
da7c 23        inc     hl
da7d 23        inc     hl
da7e 010000    ld      bc,$0000         ;##LIT##
da81 cdd0d7    call    $d7d0
da84 3a9fb0    ld      a,($b09f)        ;variable type (and byte-size)
da87 47        ld      b,a
da88 3c        inc     a                ;add a byte for data type descriptor
da89 cd72f6    call    $f672            ;alloc space for variable type and data
da8c 78        ld      a,b
da8d 3d        dec     a
da8e 77        ld      (hl),a           ;store the data type
da8f 23        inc     hl
da90 eb        ex      de,hl
da91 e1        pop     hl
da92 c9        ret     

;;=iterate all string variables
;iterates through all string variables and calls the code in DE for each one.

;Iterator is called with:
;DE=addr of /last/ byte of string descriptor
;BC=string address
;A=string length

da93 2a10ae    ld      hl,($ae10)       ;start with any FNs, if present

;;=FN stack loop
da96 7c        ld      a,h
da97 b5        or      l
da98 280e      jr      z,$daa8          ; (+$0e) no/end of/ FNs, do main variables
da9a 4e        ld      c,(hl)           ;pointer to next FN data block on stack
da9b 23        inc     hl
da9c 46        ld      b,(hl)
da9d 23        inc     hl
da9e c5        push    bc
da9f 010000    ld      bc,$0000         ;FN pointers are relative to start of memory ##LIT##
daa2 cde9da    call    $dae9
daa5 e1        pop     hl
daa6 18ee      jr      $da96            ; (-$12)

;;=iterate all main variables
daa8 01411a    ld      bc,$1a41         ;B=number of linked lists. C=index of first one ('A')
;;=var linked list headers loop
daab c5        push    bc
daac 79        ld      a,c              ;list index
daad cd19d6    call    $d619            ;get list header (and base for offsets)
dab0 cde9da    call    $dae9
dab3 c1        pop     bc
dab4 0c        inc     c                ;next index
dab5 10f4      djnz    $daab            ; (-$0c) loop

                                        ;now do array linked lists
dab7 3e03      ld      a,$03            ;string type
dab9 cd27d6    call    $d627            ;get list header for string arrays (and base for offsets)
dabc e5        push    hl

;;=array linked list loop
dabd e1        pop     hl               ;walk each item in the linked list
dabe 4e        ld      c,(hl)           ;get offset for first/next item
dabf 23        inc     hl
dac0 46        ld      b,(hl)
dac1 78        ld      a,b
dac2 b1        or      c
dac3 c8        ret     z                ;end of list

dac4 2a6aae    ld      hl,($ae6a)
dac7 2b        dec     hl
dac8 09        add     hl,bc            ;absolute address of item
dac9 e5        push    hl
daca d5        push    de
dacb cd65d7    call    $d765            ;step over array name and type
dace d1        pop     de
dacf 23        inc     hl
dad0 4e        ld      c,(hl)           
dad1 23        inc     hl
dad2 46        ld      b,(hl)           ;BC=size of array data?
dad3 23        inc     hl
dad4 e5        push    hl               ;current
dad5 09        add     hl,bc            ;array end
dad6 e3        ex      (sp),hl          ;stack=array end/HL=current
dad7 4e        ld      c,(hl)           ;C=number of dimensions
dad8 23        inc     hl
dad9 0600      ld      b,$00            ;BC=number of dimensions
dadb 09        add     hl,bc            ;step over dimensions data
dadc 09        add     hl,bc            ;HL=first element of array
dadd c1        pop     bc               ;BC=end of elements data

;;=array elements loop
dade cddeff    call    $ffde ; HL=BC?
dae1 28da      jr      z,$dabd          ; (-$26) next item in list
dae3 cd02db    call    $db02
dae6 23        inc     hl
dae7 18f5      jr      $dade            ; (-$0b)

;;=iterate all strings in a linked list
dae9 7e        ld      a,(hl)           ;offset of next item
daea 23        inc     hl
daeb 66        ld      h,(hl)
daec 6f        ld      l,a
daed b4        or      h
daee c8        ret     z                ;end of list

daef 09        add     hl,bc            ;add base to offset
daf0 e5        push    hl
daf1 d5        push    de
daf2 cd65d7    call    $d765            ;step over variable name
daf5 d1        pop     de
daf6 7e        ld      a,(hl)           ;type??
daf7 23        inc     hl
daf8 e607      and     $07
dafa fe02      cp      $02              ;type must be 2??? that's int, not strings!!
dafc cc02db    call    z,$db02          ;do callback
daff e1        pop     hl
db00 18e7      jr      $dae9            ; (-$19) loop

;;=read string data and call callback
db02 c5        push    bc
db03 d5        push    de
db04 7e        ld      a,(hl)           ;length
db05 23        inc     hl
db06 4e        ld      c,(hl)           ;address
db07 23        inc     hl
db08 46        ld      b,(hl)
db09 e5        push    hl
db0a eb        ex      de,hl
db0b b7        or      a
db0c c4fbff    call    nz,$fffb			; JP (HL) - dispatch callback
db0f e1        pop     hl
db10 d1        pop     de
db11 c1        pop     bc
db12 c9        ret     




;;***DataInput.asm
;;<< (TEXT) DATA INPUT
;;< (LINE) INPUT, RESTORE, READ (not DATA)
;;========================================================================
;; command LINE INPUT
;LINE INPUT [#<stream expression>,][;][<quoted string>;]<string variable>
;LINE INPUT [#<stream expression>,][;][<quoted string>,]<string variable>
;As the INPUT command but reads the entire line into a string variable.
;If the line is longer than 255 characters reads 255 characters.

db13 cd25de    call    $de25
db16 defb $a3    ;inline token to test "INPUT"
db17 cdd4c1    call    $c1d4
db1a cd8bdb    call    $db8b
db1d cdbfd6    call    $d6bf
db20 cd5eff    call    $ff5e        ;can only read strings
db23 e5        push    hl
db24 d5        push    de
db25 cd31db    call    $db31
db28 cd8af8    call    $f88a
db2b e1        pop     hl
db2c cda8d6    call    $d6a8
db2f e1        pop     hl
db30 c9        ret     

;;=input to buffer
db31 cdc4c1    call    $c1c4
db34 d257dc    jp      nc,$dc57     ;file stream? read from file
;;=input screen to buffer
db37 cdecca    call    $caec        ;read line to BASIC input buffer
db3a 3a14ae    ld      a,($ae14)
db3d fe3b      cp      $3b          ;';'
db3f c498c3    call    nz,$c398      ;new line unless followed by semicolon?
db42 c9        ret     

;;========================================================================
;; command INPUT
;INPUT [#<stream expression>,][;][<quoted string>;]<list of: <variable>>
;INPUT [#<stream expression>,][;][<quoted string>,]<list of: <variable>>
;If stream expression is omitted, defaults to #0

;For keyboard streams, #0..#8:
;Quoted string is a prompt to display. If the first form (with a semicolon) is used a 
;question mark is output after it. If the second form (with a comma), no question mark.
;If no quote string is given a question mark prompt is used.
;After issuing the prompt a line is read. This is parsed as: <list of: <item>> where
;<item> may be: <numeric value> or <quoted string> or <unquoted string>
;These items are parsed and assigned to variables given in the command. Whitespace between 
;<items> is removed.
;If the optional semicolon is omitted BASIC starts a new line, if present then the cursor 
;is left after the last character entered.

;For file stream, #9:
;No prompt is generated. If given it will be ignored.
;BASIC attempts to read items from the file and match them to variables:
;<numeric value> terminated by whitespace, comma, carriage return or end of file.
;<quoted string> in double quotes, can also be terminated by end of file. A following whitespace, 
;comma or carriage return is ignored.
;<unquoted string> terminated by comma, carriage return or whitespace.
;In all cases leading whitespace is ignored.
;Strings terminate after max 255 characters.

db43 cdd4c1    call    $c1d4
db46 cd5bdb    call    $db5b
db49 d5        push    de
db4a cdbfd6    call    $d6bf
db4d e3        ex      (sp),hl
db4e af        xor     a
db4f cdbddb    call    $dbbd
db52 23        inc     hl
db53 e3        ex      (sp),hl
db54 cd41de    call    $de41
db57 38f1      jr      c,$db4a          ; (-$0f)
db59 d1        pop     de
db5a c9        ret     

;;=input get input
db5b cdc4c1    call    $c1c4
db5e 302b      jr      nc,$db8b         ; (+$2b) if file

db60 e5        push    hl
db61 cd8bdb    call    $db8b            ;show prompt
db64 e5        push    hl
db65 cd37db    call    $db37            ;input to buffer
db68 eb        ex      de,hl
db69 e1        pop     hl
db6a cdcddb    call    $dbcd            ;parse input buffer
db6d c1        pop     bc
db6e d8        ret     c                ;return if valid input

db6f c5        push    bc
db70 2179db    ld      hl,$db79			;; "?Redo from start" message
db73 cd8bc3    call    $c38b			;; display 0 terminated string
db76 e1        pop     hl
db77 18e7      jr      $db60            ; (-$19) retry

;;=redo from start message
db79 defb "?Redo from start",10,0

;;=input display prompt, if given
db8b 7e        ld      a,(hl)
db8c fe3b      cp      $3b              ;';'
db8e 3214ae    ld      ($ae14),a
db91 cc2cde    call    z,$de2c			; get next token skipping space
db94 fe22      cp      $22              ;'"' - prompt string
db96 200b      jr      nz,$dba3         ; (+$0b)
db98 cdb1db    call    $dbb1
db9b cd41de    call    $de41
db9e d8        ret     c                ;if comma then no '? ' after

db9f cd25de    call    $de25
dba2 defb $3b     ;inline token to test ";"
dba3 cdc4c1    call    $c1c4
dba6 d0        ret     nc               ;exit if not reading from screen

dba7 3e3f      ld      a,$3f            ;'?'
dba9 cda0c3    call    $c3a0           ;; display text char
dbac 3e20      ld      a,$20            ;space char
dbae c3a0c3    jp      $c3a0           ;; display text char

;;=input display prompt
dbb1 cd79f8    call    $f879
dbb4 cdc4c1    call    $c1c4
dbb7 d2f5fb    jp      nc,$fbf5
dbba c3d0f8    jp      $f8d0

;;=input parse item or error
dbbd d5        push    de
dbbe cdf7db    call    $dbf7
dbc1 3006      jr      nc,$dbc9         ; (+$06)
dbc3 e3        ex      (sp),hl
dbc4 cd9fd6    call    $d69f
dbc7 e1        pop     hl
dbc8 c9        ret     

;;=raise Type Mismatch error
dbc9 cd45cb    call    $cb45
dbcc defb $0d                         ;Inline error code: Type mismatch

;;=input parse buffer
;returns Carry true if the input was valid/matched variable list etc.
dbcd d5        push    de
dbce e5        push    hl
dbcf d5        push    de
dbd0 cd0fd7    call    $d70f
dbd3 e3        ex      (sp),hl
dbd4 af        xor     a
dbd5 cdf7db    call    $dbf7
dbd8 3019      jr      nc,$dbf3         ; (+$19) end of buffer? failed
dbda fe03      cp      $03              ;string
dbdc ccf5fb    call    z,$fbf5
dbdf e3        ex      (sp),hl
dbe0 cd41de    call    $de41
dbe3 e3        ex      (sp),hl
dbe4 7e        ld      a,(hl)           ;next token
dbe5 3008      jr      nc,$dbef         ; (+$08) end of variable list?
dbe7 ee2c      xor     $2c              ;','
dbe9 2008      jr      nz,$dbf3         ; (+$08) no more entries in variable list?
dbeb 23        inc     hl
dbec e3        ex      (sp),hl
dbed 18e1      jr      $dbd0            ; (-$1f)

dbef b7        or      a                ;A=next token. If zero we have end of line = success
dbf0 2001      jr      nz,$dbf3         ; (+$01)
dbf2 37        scf                      ;success!!
dbf3 e1        pop     hl
dbf4 e1        pop     hl
dbf5 d1        pop     de
dbf6 c9        ret     

;;=input parse item
dbf7 5f        ld      e,a              ;what variable type to we have?
dbf8 cd66ff    call    $ff66
dbfb f5        push    af
dbfc 2006      jr      nz,$dc04         ; (+$06)
dbfe cd15dc    call    $dc15
dc01 37        scf     
dc02 1809      jr      $dc0d            ; (+$09)

;;=input parse number
dc04 cdc4c1    call    $c1c4
dc07 d42cdc    call    nc,$dc2c
dc0a cd6fed    call    $ed6f
dc0d f5        push    af

;;=input parse item done
dc0e dc4dde    call    c,$de4d ; skip space, lf or tab
dc11 f1        pop     af
dc12 d1        pop     de
dc13 7a        ld      a,d
dc14 c9        ret     

;;=input parse string
;inputs quoted string (keyboard) or ASCIIZ string (not keyboard)
dc15 cdc4c1    call    $c1c4
dc18 3806      jr      c,$dc20          ; (+$06)
dc1a cd38dc    call    $dc38
dc1d c38af8    jp      $f88a

;;=input parse quoted string
dc20 cd4dde    call    $de4d ; skip space, lf or tab
dc23 fe22      cp      $22              ;'"'
dc25 ca79f8    jp      z,$f879
dc28 7b        ld      a,e
dc29 c394f8    jp      $f894

;;=====================================
;INPUT from a file
;;=input from file ignore leading whitespace
dc2c cd8edc    call    $dc8e
dc2f 11b5dc    ld      de,$dcb5         ;##LABEL##
dc32 382b      jr      c,$dc5f          ; (+$2b)

;;=raise EOF met error
dc34 cd45cb    call    $cb45
dc37 defb $18                         ;Inline error code: EOF met

;;=input item from file
;reads item terminated by comma or LF, or quoted string
dc38 cd8edc  call $dc8e
dc3b 30f7    jr nc,$dc34   ;Manually calculated!!! Object code should be 31f7
dc3d fe22      cp      $22              ;'"'
dc3f 2805      jr      z,$dc46          ; (+$05)
dc41 11b9dc    ld      de,$dcb9         ;##LABEL##
dc44 1819      jr      $dc5f            ; (+$19)

;;=input quoted string from file
dc46 cd99dc    call    $dc99
dc49 1154dc    ld      de,$dc54         ;##LABEL##
dc4c 3811      jr      c,$dc5f          ; (+$11)
dc4e 218aac    ld      hl,$ac8a
dc51 3600      ld      (hl),$00
dc53 c9        ret     

;;=is A double quotes
dc54 fe22      cp      $22              ;"'
dc56 c9        ret     

;;=input line from file
dc57 cd99dc    call    $dc99
dc5a 30d8      jr      nc,$dc34         ; (-$28)
dc5c 11bcdc    ld      de,$dcbc         ;end of input test routine ##LABEL##

;;=input from file
;;this code takes an address to call in DE
;this routine is called with a character in A and returns Z flag set if it's a terminating character
dc5f 218aac    ld      hl,$ac8a
dc62 e5        push    hl
dc63 06ff      ld      b,$ff            ;max line length
dc65 cdfeff    call    $fffe			; JP (DE) - test for termination char
dc68 280c      jr      z,$dc76          ; (+$0c)
dc6a 77        ld      (hl),a
dc6b 23        inc     hl
dc6c 05        dec     b
dc6d 2805      jr      z,$dc74          ; (+$05)
dc6f cd99dc    call    $dc99            ;read next char
dc72 38f1      jr      c,$dc65          ; (-$0f)    loop for more chars

dc74 f6ff      or      $ff
dc76 3600      ld      (hl),$00
dc78 e1        pop     hl
dc79 c0        ret     nz

dc7a fe0d      cp      $0d              ;CR
dc7c c8        ret     z

dc7d fe22      cp      $22             ;'"'
dc7f c4bfdc    call    nz,$dcbf
dc82 c0        ret     nz

dc83 cd8edc    call    $dc8e
dc86 d0        ret     nc

dc87 cdb9dc    call    $dcb9
dc8a c486bc    call    nz,$bc86			; firmware function: CAS RETURN
dc8d c9        ret     

;;=input char from file, ignore whitespace
dc8e cd99dc    call    $dc99
dc91 d0        ret     nc

dc92 cdbfdc    call    $dcbf
dc95 28f7      jr      z,$dc8e          ; (-$09)
dc97 37        scf     
dc98 c9        ret     

;;=input char from file
;turns CR+LF and LF+CR into single char (returns the first of the pair)
dc99 cd5cc4    call    $c45c ; read byte from cassette or disc
dc9c d0        ret     nc

dc9d f5        push    af
dc9e c5        push    bc
dc9f 010d0a    ld      bc,$0a0d         ;LF CR
dca2 b9        cp      c                ;CR? test for CR LF
dca3 2804      jr      z,$dca9          ; (+$04)
dca5 b8        cp      b                ;not LF? - return as is
dca6 200a      jr      nz,$dcb2         ; (+$0a)
dca8 41        ld      b,c              
dca9 cd5cc4    call    $c45c ; read byte from cassette or disc
dcac 3004      jr      nc,$dcb2         ; (+$04)
dcae b8        cp      b                ;CR followed by LF or LF followed by CR? if not, put the second char back
dcaf c486bc    call    nz,$bc86			;; firmware function: cas return
dcb2 c1        pop     bc
dcb3 f1        pop     af               ;get back the original char we read
dcb4 c9        ret     

;;========================================================================
;; is A space tab cr comma lf
dcb5 cdbfdc    call    $dcbf
dcb8 c8        ret     z

;;=is A comma lf
dcb9 fe2c      cp      $2c		;; ,
dcbb c8        ret     z

;;=is A lf
dcbc fe0d      cp      $0d		;; lf
dcbe c9        ret     

;;========================================================================
;;is A space tab cr
dcbf fe20      cp      $20		;; space
dcc1 c8        ret     z

dcc2 fe09      cp      $09		;; tab
dcc4 c8        ret     z

dcc5 fe0a      cp      $0a		;; cr
dcc7 c9        ret     

;;========================================================================
;; command RESTORE
;RESTORE [<line number>]
;Restores the DATA pointer

dcc8 280a      jr      z,$dcd4          ; (+$0a)
dcca cd48cf    call    $cf48
dccd e5        push    hl
dcce cd5ce8    call    $e85c
dcd1 2b        dec     hl
dcd2 1831      jr      $dd05            ; (+$31)

;;=reset READ pointer
dcd4 e5        push    hl
dcd5 2a64ae    ld      hl,($ae64)       ;first line
dcd8 182b      jr      $dd05            ; (+$2b)

;;========================================================================
;; command READ
;READ <list of: <variable>>
;Reads from DATA statements

dcda e5        push    hl
dcdb 2a17ae    ld      hl,($ae17)
;;=READ item loop
dcde cd0add    call    $dd0a
dce1 e3        ex      (sp),hl
dce2 cdbfd6    call    $d6bf
dce5 e3        ex      (sp),hl
dce6 23        inc     hl
dce7 3e01      ld      a,$01
dce9 cdbddb    call    $dbbd            ;read data
dcec 7e        ld      a,(hl)           ;next token
dced fe02      cp      $02
dcef 380d      jr      c,$dcfe          ; (+$0d) end of line/statement
dcf1 fe2c      cp      $2c              ;','
dcf3 2809      jr      z,$dcfe          ; (+$09) comma
dcf5 2a15ae    ld      hl,($ae15)       ;anything else is error
dcf8 cdadde    call    $dead
dcfb c349cb    jp      $cb49			; Error: Syntax Error

dcfe e3        ex      (sp),hl
dcff cd41de    call    $de41            ;another value to read?
dd02 e3        ex      (sp),hl
dd03 38d9      jr      c,$dcde          ; (-$27) if so, loop
;;=set READ pointer
dd05 2217ae    ld      ($ae17),hl
dd08 e1        pop     hl
dd09 c9        ret     

;;=update READ pointer
;move to comma before next data item, if not currently at one
dd0a 7e        ld      a,(hl)
dd0b fe2c      cp      $2c              ;','
dd0d c8        ret     z

dd0e cda3e9    call    $e9a3			;; DATA
dd11 b7        or      a
dd12 200e      jr      nz,$dd22         ; (+$0e) not end of line
dd14 23        inc     hl
dd15 7e        ld      a,(hl)           ;test for last line
dd16 23        inc     hl
dd17 b6        or      (hl)
dd18 23        inc     hl
dd19 3e04      ld      a,$04            ;DATA exhausted error
dd1b ca55cb    jp      z,$cb55
dd1e 2215ae    ld      ($ae15),hl       ;update line address
dd21 23        inc     hl
dd22 cd2cde    call    $de2c			; get next token skipping space
dd25 fe8c      cp      $8c              ;DATA token
dd27 20e5      jr      nz,$dd0e         ; (-$1b) loop if not DATA token
dd29 c9        ret     




;;***IntegerMaths.asm
;;<< INTEGER MATHS
;;< (used both internally and by functions)
;;=====================================
;;prep regs for int to string
dd2a 44        ld      b,h
dd2b cdeadd    call    $ddea
dd2e 1802      jr      $dd32            ; (+$02)

;;=set B zero E zero C to 2 int type
dd30 0600      ld      b,$00
;;=set E zero C to 2 int type
dd32 1e00      ld      e,$00
dd34 0e02      ld      c,$02
dd36 c9        ret     

;;=unknown maths fixup
;Bit 7 of B = invert value in HL
dd37 7c        ld      a,h
dd38 b7        or      a
dd39 fa42dd    jp      m,$dd42
dd3c b0        or      b
dd3d faeddd    jp      m,$dded
dd40 37        scf     
dd41 c9        ret     

;;--------------------------------------------------------------
;;=unknown maths fixup
dd42 ee80      xor     $80            ;Toggle bit 7
dd44 b5        or      l
dd45 c0        ret     nz

dd46 78        ld      a,b
dd47 37        scf     
dd48 8f        adc     a,a              ;A = 2 * B + 1
dd49 c9        ret     

;;================================================================
;;INT addition with overflow test
dd4a b7        or      a
dd4b ed5a      adc     hl,de
dd4d 37        scf     
dd4e e0        ret     po

dd4f f6ff      or      $ff
dd51 c9        ret     

;;==============================================
;;INT subtraction with overflow test
dd52 eb        ex      de,hl
dd53 b7        or      a
dd54 ed52      sbc     hl,de
dd56 37        scf     
dd57 e0        ret     po

dd58 f6ff      or      $ff
dd5a c9        ret     

;;=============================================
;;INT multiply with overflow test
dd5b cd67dd    call    $dd67
dd5e cd72dd    call    $dd72
dd61 d237dd    jp      nc,$dd37         ;negate result if operands where different signs (B bit 7 set) and ??
dd64 f6ff      or      $ff
dd66 c9        ret     

;;=make both operands positive
dd67 7c        ld      a,h
dd68 aa        xor     d
dd69 47        ld      b,a              ;Bit 7 of B = are both operands the same sign?
dd6a eb        ex      de,hl
dd6b cdeadd    call    $ddea
dd6e eb        ex      de,hl
dd6f c3eadd    jp      $ddea

;;=do 16x16 multiply with overflow
dd72 7c        ld      a,h
dd73 b7        or      a
dd74 2805      jr      z,$dd7b          ; (+$05)
dd76 7a        ld      a,d
dd77 b7        or      a
dd78 37        scf     
dd79 c0        ret     nz

dd7a eb        ex      de,hl
dd7b b5        or      l
dd7c c8        ret     z

dd7d 7a        ld      a,d
dd7e b3        or      e
dd7f 7d        ld      a,l
dd80 6b        ld      l,e
dd81 62        ld      h,d
dd82 c8        ret     z

dd83 fe03      cp      $03
dd85 3810      jr      c,$dd97          ; (+$10)
dd87 37        scf     
dd88 8f        adc     a,a
dd89 30fd      jr      nc,$dd88         ; (-$03)
dd8b 29        add     hl,hl
dd8c d8        ret     c

dd8d 87        add     a,a
dd8e 3002      jr      nc,$dd92         ; (+$02)
dd90 19        add     hl,de
dd91 d8        ret     c

dd92 fe80      cp      $80
dd94 20f5      jr      nz,$dd8b         ; (-$0b)
dd96 c9        ret     

dd97 fe01      cp      $01
dd99 c8        ret     z

dd9a 29        add     hl,hl
dd9b c9        ret     

;;===================
;;INT division with overflow test
dd9c cdabdd    call    $ddab
dd9f da37dd    jp      c,$dd37
dda2 c9        ret     

;;=INT modulo
dda3 4c        ld      c,h
dda4 cdabdd    call    $ddab
dda7 eb        ex      de,hl
dda8 41        ld      b,c
dda9 18f4      jr      $dd9f            ; (-$0c)

ddab cd67dd    call    $dd67
ddae 7a        ld      a,d
ddaf b3        or      e
ddb0 c8        ret     z

ddb1 c5        push    bc
ddb2 eb        ex      de,hl
ddb3 0601      ld      b,$01
ddb5 7c        ld      a,h
ddb6 b7        or      a
ddb7 2009      jr      nz,$ddc2         ; (+$09)
ddb9 7a        ld      a,d
ddba bd        cp      l
ddbb 3805      jr      c,$ddc2          ; (+$05)
ddbd 65        ld      h,l
ddbe 2e00      ld      l,$00
ddc0 0609      ld      b,$09
ddc2 7b        ld      a,e
ddc3 95        sub     l
ddc4 7a        ld      a,d
ddc5 9c        sbc     a,h
ddc6 3805      jr      c,$ddcd          ; (+$05)
ddc8 04        inc     b
ddc9 29        add     hl,hl
ddca 30f6      jr      nc,$ddc2         ; (-$0a)
ddcc 3f        ccf     
ddcd 3f        ccf     
ddce 78        ld      a,b
ddcf 44        ld      b,h
ddd0 4d        ld      c,l
ddd1 210000    ld      hl,$0000
ddd4 180e      jr      $dde4            ; (+$0e)

ddd6 cb18      rr      b
ddd8 cb19      rr      c
ddda eb        ex      de,hl
dddb ed42      sbc     hl,bc
dddd 3001      jr      nc,$dde0         ; (+$01)
dddf 09        add     hl,bc
dde0 eb        ex      de,hl
dde1 3f        ccf     
dde2 ed6a      adc     hl,hl
dde4 3d        dec     a
dde5 20ef      jr      nz,$ddd6         ; (-$11)
dde7 37        scf     
dde8 c1        pop     bc
dde9 c9        ret     

;;--------------------------------------------------------------
;;=negate HL if negative and test if INT
ddea 7c        ld      a,h
ddeb b7        or      a
ddec f0        ret     p            ;if HL is >= 0

;;=negate HL and test if INT
;HL = -HL, then test if it's a valid INT value
;Returns NC if the result is not a valid INT
dded af        xor     a
ddee 95        sub     l
ddef 6f        ld      l,a          ;L = -L
ddf0 9c        sbc     a,h          ;H = -L - H
ddf1 95        sub     l            ;H = -L - H - L
ddf2 bc        cp      h
ddf3 67        ld      h,a
ddf4 37        scf     
ddf5 c0        ret     nz

ddf6 fe01      cp      $01
ddf8 c9        ret     

;;--------------------------------------------------------------
;;=unknown test HL
;; HL = value

;; HL = 0?
ddf9 7c        ld      a,h
ddfa b5        or      l
ddfb c8        ret     z           ;return if HL = 0

ddfc 7c        ld      a,h
ddfd 87        add     a,a         ;A = H + H
ddfe 9f        sbc     a,a         ;A = H + H - H
ddff d8        ret     c

de00 3c        inc     a
de01 c9        ret     

;;==================================================
;;prob compare DE to HL?
;if HL >= 0 and DE=HL then A := 0
de02 7c        ld      a,h
de03 aa        xor     d
de04 7c        ld      a,h
de05 f20dde    jp      p,$de0d            ;if H >= 0 then if DE=HL then return with A=A+1
de08 87        add     a,a                ;If A > &7f then set A to &ff, otherwise 0

de09 9f        sbc     a,a                ;if carry, A will be &ff, otherwise 0
de0a d8        ret     c                  ;A=&ff

de0b 3c        inc     a                  ;A=1
de0c c9        ret     

de0d ba        cp      d
de0e 20f9      jr      nz,$de09         ; (-$07) if A <> D
de10 7d        ld      a,l
de11 93        sub     e
de12 20f5      jr      nz,$de09         ; (-$0b) if A,L <> DE
de14 c9        ret                      ;A=0




;;***Execution.asm
;;<< PROGRAM EXECUTION
;;< Execute tokenised code (except expressions)
;;< Includes token handling utilities, TRON, TROFF, 
;;< and the command/statement look up table.
;;============================================
;This block of routines raise a Syntax Error if the next character/token is not
;the one specified.
;Also, skips over any trailing spaces (ASCII $20) and:
;If the following character (after the one to test) is:
;end-of-line ($00):      returns Carry clear, Zero set
;end-of-statament ($01): returns Carry clear, Zero clear
;(otherwise):            returns Carry set, Zero clear

;; next token if comma
de15 3e2c      ld      a,$2c			; ','
de17 1810      jr      $de29            ; 

;;+----------------------------------------------------------
;; next token if open bracket
de19 3e28      ld      a,$28			; '('
de1b 180c      jr      $de29            ; 

;;+----------------------------------------------------------
;; next token if close bracket
de1d 3e29      ld      a,$29			; ')'
de1f 1808      jr      $de29            

;;+----------------------------------------------------------
;; next token if equals sign
de21 3eef      ld      a,$ef            ;token for '='
de23 1804      jr      $de29            

;;+----------------------------------------------------------
;; next token if equals inline data byte
de25 e3        ex      (sp),hl			; get return address from top of stack/save HL
de26 7e        ld      a,(hl)			; get byte
de27 23        inc     hl				; increment pointer
de28 e3        ex      (sp),hl			; put return address back to stack/restore HL

;;+----------------------------------------------------------
;; next token if value in A
;; A = char to check against
de29 be        cp      (hl)
de2a 200f      jr      nz,$de3b         ; (+$0f)

;;=get next token skipping space
;;Skips spaces (ASCII $20) and returns the next non-space character/token
;If that character is:
;end-on-line ($00):      returns Carry clear, Zero set
;end-of-statement ($01): returns Carry clear, Zero clear
;(other):                returns Carry set, Zero clear
de2c 23        inc     hl
de2d 7e        ld      a,(hl)
de2e fe20      cp      $20				; ' '
de30 28fa      jr      z,$de2c          
 

de32 fe01      cp      $01
de34 d0        ret     nc
de35 b7        or      a
de36 c9        ret     

;;+===========================================================
;;error if not end of statement or eoln
de37 7e        ld      a,(hl)
de38 fe02      cp      $02          ;$00=end of line, $01=end of statement
de3a d8        ret     c

;;=raise syntax error
de3b 186a      jr      $dea7            ; (+$6a)

;;+===========================================================
;;=is next $02
;Carry set if EOLN or end of statement
de3d 7e        ld      a,(hl)
de3e fe02      cp      $02
de40 c9        ret     

;;+===========================================================
;;=next token if prev is comma

;Skips spaces and reads the first token following
;If the that token is a comma, skips any following whitespace and returns the next token and Carry set
;  Otherwise, returns Carry clear
de41 2b        dec     hl
de42 cd2cde    call    $de2c			; get next token skipping space
de45 ee2c      xor     $2c				; ','
de47 c0        ret     nz

de48 cd2cde    call    $de2c			; get next token skipping space
de4b 37        scf     
de4c c9        ret     

;;=======================================================================
;; skip space, tab or line feed
de4d 7e        ld      a,(hl)
de4e 23        inc     hl
de4f fe20      cp      $20				; ' '
de51 28fa      jr      z,$de4d ; skip space, lf or tab          
de53 fe09      cp      $09				; TAB
de55 28f6      jr      z,$de4d ; skip space, lf or tab          
de57 fe0a      cp      $0a				; LF
de59 28f2      jr      z,$de4d ; skip space, lf or tab          
de5b 2b        dec     hl
de5c c9        ret     



;;=======================================================================
;; execute current statement
de5d 2a1bae    ld      hl,($ae1b)

;;=execute statement atHL
;HL points to byte before first token
de60 221bae    ld      ($ae1b),hl     ;HL=current execution address
de63 cd21b9    call    $b921            ;handle pending events
de66 dcb2c8    call    c,$c8b2
de69 cd2cde    call    $de2c			; get next token skipping space
de6c c48fde    call    nz,$de8f         ;end of buffer?
de6f 7e        ld      a,(hl)
de70 fe01      cp      $01              ;next statement on same line
de72 28ec      jr      z,$de60          ; (-$14) Loop until end of line

de74 3031      jr      nc,$dea7         ; (+$31)
de76 23        inc     hl

;;=execute line atHL
de77 7e        ld      a,(hl)           ;Line length zero = end of program
de78 23        inc     hl
de79 b6        or      (hl)
de7a 23        inc     hl
de7b 280f      jr      z,$de8c          ; (+$0f) line length zero = end of code marker

de7d 221dae    ld      ($ae1d),hl       ; Start of current line
de80 23        inc     hl
de81 3a1fae    ld      a,($ae1f)        ;trace on??
de84 b7        or      a
de85 28d9      jr      z,$de60          ; (-$27) if not loop - execute next line
de87 cdcade    call    $deca            ; trace
de8a 18d4      jr      $de60            ; (-$2c) loop - execute next line

;;====================================
;;end execution
de8c c349cc    jp      $cc49

;;============================================
;;execute command token
;A=token
;Tokens >= &80 are tokenised words
;the only token < &80 we should have here are for bar commands or variable names (implicit LET)
de8f 87        add     a,a              
de90 d289d6    jp      nc,$d689         ;token < &80: either a bar command or a variable (implicit LET)
de93 fec3      cp $dfa4 - $dee0 - 1   ;version with formula
;OLD de93 fec3      cp      $c3              ;the last valid token is &e1 which doubles to &c2, so >= &c3 is error
de95 3010      jr      nc,$dea7         ; (+$10)
de97 eb        ex      de,hl
de98 c6e0      add     a,$dee0 and $ff  ;$e0 lookup token in table
de9a 6f        ld      l,a
de9b cede      adc     a,$dee0 >> 8     ;$de
de9d 95        sub     l
de9e 67        ld      h,a
de9f 4e        ld      c,(hl)           ;code address into BC
dea0 23        inc     hl
dea1 46        ld      b,(hl)
dea2 c5        push    bc               ;push so we'll return to code with next token
dea3 eb        ex      de,hl
dea4 c32cde    jp      $de2c			; get next token skipping space

;;=raise syntax error
dea7 c349cb    jp      $cb49			; Error: Syntax Error

;;========================================================================
;; zero current line address
deaa 210000    ld      hl,$0000         ;##LIT##

;;=set current line address
dead 221dae    ld      ($ae1d),hl
deb0 c9        ret     

;;========================================================================
;;get current line address
deb1 2a1dae    ld      hl,($ae1d)
deb4 c9        ret     

;;========================================================================
;; get current line number
;; returns Z if current line number address is zero
;; returns C if we HL returns a current line number
deb5 2a1dae    ld      hl,($ae1d)  ;address of current line

;;+get line number atHL
deb8 7c        ld      a,h
deb9 b5        or      l
deba c8        ret     z			;; no current line 

debb 7e        ld      a,(hl)       ;get line number
debc 23        inc     hl
debd 66        ld      h,(hl)
debe 6f        ld      l,a
debf 37        scf     
dec0 c9        ret     

;;========================================================================
;; command TRON
;TRON
;Turns on execution tracing (the listing of line numbers to the console)

dec1 3eff      ld      a,$ff
dec3 1801      jr      $dec6            ; (+$01)

;;========================================================================
;; command TROFF
;TROFF
;Turns off execution tracing. See TRON

dec5 af        xor     a
dec6 321fae    ld      ($ae1f),a
dec9 c9        ret     

;;=============
;;do trace
deca 3e5b      ld      a,&5b            ;'['
decc cda0c3    call    $c3a0           ;; display text char
decf e5        push    hl
ded0 2a1dae    ld      hl,($ae1d)      ;Current line address
ded3 7e        ld      a,(hl)          ;get line number
ded4 23        inc     hl
ded5 66        ld      h,(hl)
ded6 6f        ld      l,a
ded7 cd44ef    call    $ef44          ;Display current line number
deda e1        pop     hl
dedb 3e5d      ld      a,&5d            ;']'
dedd c3a0c3    jp      $c3a0           ;; display text char

;;====================================================
;; command to code address LUT

;you can add extra items to the end of this list, HOWEVER, there is only one unused item before
;current last item in the table is &e1. You can add an item &e2. Items &e3 onwards are used for other keywords
dee0
defw $ca22		;; AFTER  ##LABEL##
defw $c0ea		;; AUTO  ##LABEL##
defw $c248		;; BORDER  ##LABEL##
defw $f25c		;; CALL  ##LABEL##
defw $d296		;; CAT  ##LABEL##
defw $eafd		;; CHAIN  ##LABEL##
defw $c12f		;; CLEAR  ##LABEL##
defw $c506		;; CLG  ##LABEL##
defw $d2ed		;; CLOSEIN  ##LABEL##
defw $d2f5		;; CLOSEOUT  ##LABEL##
defw $c280		;; CLS   ##LABEL##
defw $cc93		;; CONT  ##LABEL##
defw $e9a3		;; DATA  ##LABEL##
defw $d171		;; DEF   ##LABEL##
defw $d654		;; DEFINT  ##LABEL##
defw $d658		;; DEFREAL  ##LABEL##
defw $d650		;; DEFSTR  ##LABEL##
defw $d529		;; DEG  ##LABEL##
defw $e7ee		;; DELETE  ##LABEL##
defw $d6b6		;; DIM  ##LABEL##
defw $c539		;; DRAW  ##LABEL##
defw $c53e		;; DRAWR  ##LABEL##
defw $c046		;; EDIT  ##LABEL##
defw $e9ad		;; ELSE  ##LABEL##
defw $cc31		;; END  ##LABEL##
defw $d3d4		;; ENT  ##LABEL##
defw $d39e		;; ENV  ##LABEL##
defw $d9f0		;; ERASE  ##LABEL##
defw $cb51		;; ERROR  ##LABEL##
defw $ca2a		;; EVERY  ##LABEL##
defw $c5d4		;; FOR  ##LABEL##
defw $c78c		;; GOSUB  ##LABEL##
defw $c786		;; GOTO  ##LABEL##
defw $c767		;; IF  ##LABEL##
defw $c251		;; INK  ##LABEL##
defw $db43		;; INPUT  ##LABEL##
defw $d486		;; KEY  ##LABEL##
defw $d68e		;; LET   ##LABEL##
defw $db13		;; LINE  ##LABEL##
defw $e1cd		;; LIST  ##LABEL##
defw $eab5		;; LOAD  ##LABEL##
defw $c2ff		;; LOCATE  ##LABEL##
defw $f56b		;; MEMORY  ##LABEL##
defw $eb54		;; MERGE  ##LABEL##
defw $fa07		;; MID$  ##LABEL##
defw $c275		;; MODE  ##LABEL##
defw $c52f		;; MOVE  ##LABEL##
defw $c534		;; MOVER  ##LABEL##
defw $c6a2		;; NEXT  ##LABEL##
defw $c128		;; NEW  ##LABEL##
defw $c882		;; ON   ##LABEL## (and ON ERROR GOTO [line])
defw $c976		;; ON BREAK  ##LABEL##
defw $ccca		;; ON ERROR GOTO 0 ##LABEL##
defw $c9f5		;; ON SQ  ##LABEL##
defw $d2b4		;; OPENIN  ##LABEL##
defw $d2a8		;; OPENOUT  ##LABEL##
defw $c4de		;; ORIGIN  ##LABEL##
defw $f223		;; OUT  ##LABEL##
defw $c239		;; PAPER  ##LABEL##
defw $c224		;; PEN  ##LABEL##
defw $c543		;; PLOT  ##LABEL##
defw $c548		;; PLOTR  ##LABEL##
defw $f20f		;; POKE  ##LABEL##
defw $f2a4		;; PRINT  ##LABEL##
defw $e9a7		;; '  ##LABEL##
defw $d52d		;; RAD  ##LABEL##
defw $d599		;; RANDOMIZE  ##LABEL##
defw $dcda		;; READ  ##LABEL##
defw $d370		;; RELEASE  ##LABEL##
defw $e9a7		;; REM  ##LABEL##
defw $e89e		;; RENUM  ##LABEL##
defw $dcc8		;; RESTORE  ##LABEL##
defw $ccd5		;; RESUME  ##LABEL##
defw $c7b0		;; RETURN  ##LABEL##
defw $ea78		;; RUN  ##LABEL##
defw $ecdc		;; SAVE  ##LABEL##
defw $d313		;; SOUND  ##LABEL##
defw $d4db		;; SPEED  ##LABEL##
defw $cc26		;; STOP  ##LABEL##
defw $f784		;; SYMBOL  ##LABEL##
defw $c343		;; TAG  ##LABEL##
defw $c34a		;; TAGOFF  ##LABEL##
defw $dec5		;; TROFF  ##LABEL##
defw $dec1		;; TRON  ##LABEL##
defw $f229		;; WAIT  ##LABEL##
defw $c81a		;; WEND  ##LABEL##
defw $c7e7		;; WHILE  ##LABEL##
defw $c42a		;; WIDTH   ##LABEL##
defw $c30e		;; WINDOW  ##LABEL##
defw $f508		;; WRITE  ##LABEL##
defw $f29d		;; ZONE  ##LABEL##
defw $c997		;; DI  ##LABEL##
defw $c99d		;; EI  ##LABEL##
defw $c512		;; FILL  ##LABEL##
defw $c59a		;; GRAPHICS  ##LABEL##
defw $c5c0		;; MASK  ##LABEL##
defw $bd19		;; FRAME  ##LABEL##
defw $c360		;; CURSOR  ##LABEL##





;;***Tokenising.asm
;;<< TOKENISING SOURCE CODE
;;==================================================
;; tokenise a BASIC line
dfa4 d5        push    de
dfa5 ed5b62ae  ld de,($ae62)      ;input buffer address
dfa9 d5        push    de
dfaa cd35e0    call    $e035
dfad 012c01    ld      bc,$012c     ;max tokenised line length/buffer length

dfb0 cdc8df    call    $dfc8
dfb3 7e        ld      a,(hl)
dfb4 b7        or      a
dfb5 20f9      jr      nz,$dfb0         ; (-$07) Loop until end of buffer

dfb7 3e2d      ld      a,"-"			; '-'
dfb9 91        sub     c
dfba 4f        ld      c,a
dfbb 3e01      ld      a,$01
dfbd 98        sbc     a,b
dfbe 47        ld      b,a
dfbf af        xor     a
dfc0 12        ld      (de),a
dfc1 13        inc     de
dfc2 12        ld      (de),a
dfc3 13        inc     de
dfc4 12        ld      (de),a
dfc5 e1        pop     hl
dfc6 d1        pop     de
dfc7 c9        ret     

;;=tokenise item
dfc8 7e        ld      a,(hl)           ;get char
dfc9 b7        or      a
dfca c8        ret     z                ;end of buffer

dfcb cd92ff    call    $ff92			; is a alphabetical letter?
dfce 381c      jr      c,$dfec          ; (+$1c)
dfd0 cda0ff    call    $ffa0
dfd3 dae2e0    jp      c,$e0e2
dfd6 fe26      cp      "&"            ;'&' = hex or binary prefix
dfd8 ca36e1    jp      z,$e136
dfdb 23        inc     hl
dfdc b7        or      a
dfdd f8        ret     m

dfde fe21      cp      "!"              ;'!'
dfe0 d25ce1    jp      nc,$e15c         ;anything else which is not whitespace

dfe3 3a00ac    ld      a,($ac00)        ;do we store whitespace?
dfe6 b7        or      a
dfe7 c0        ret     nz

dfe8 3e20      ld      a," "            ;' '
dfea 181c      jr      $e008            ; (+$1c)

;;+----------------
;;tokenise letters
;keywords and variables??
dfec cd3ae0    call    $e03a
dfef d8        ret     c                ;carry set if it's already been written
                                        ;othwise it's a token >= &80
dff0 fec5      cp      $c5              ;REM
dff2 cac3e1    jp      z,$e1c3
dff5 e5        push    hl
dff6 2112e0    ld      hl,$e012         ;DATA and DEFxxxx
dff9 cdcaff    call    $ffca			;; check if byte exists in table 
dffc e1        pop     hl
dffd 3818      jr      c,$e017          ; (+$18) copy sanitised ASCII until end of statement
dfff f5        push    af
e000 fe97      cp      $97              ;ELSE
e002 3e01      ld      a,$01
e004 cc08e0    call    z,$e008          ;insert a New Statement token before an ELSE
e007 f1        pop     af

;;+-----------------------------
;; write tokenised byte to memory
e008 12        ld      (de),a           ;write token
e009 13        inc     de
e00a 0b        dec     bc
e00b 79        ld      a,c
e00c b0        or      b
e00d c0        ret     nz               ;buffer full?

e00e cd45cb    call    $cb45
e011 defb $17                         ;Inline error code: Line too long

;;====================================
;; tokenisation table A

e012 
defb $8c ;DATA
defb $8e ;DEFINT
defb $90 ;DEFSTR
defb $8f ;DEFREAL
defb $00

;;+------------------------------------------
;; token is in tokenisation table A
;; copy literal data until end of statement or end of line
;ignores chars >= &80
;chars < &20 are converted to spaces
;quoted strings are copied unmodified
;; Code is jumped to - loop until return

e017 cd08e0    call    $e008

e01a 7e        ld      a,(hl)
e01b b7        or      a
e01c c8        ret     z                 ; End of buffer

e01d fe3a      cp      ":"              ;':' - end of statement
e01f 2814      jr      z,$e035          ; (+$14)
e021 23        inc     hl
e022 b7        or      a
e023 fa1ae0    jp      m,$e01a          ;ignore chars >= &80

e026 fe20      cp      " "				; ' '
e028 3002      jr      nc,$e02c         ; (+$02)
e02a 3e20      ld      a,$20            ; convert control codes to spaces
e02c fe22      cp      $22				; '"'
e02e 20e7      jr      nz,$e017         ; (-$19) write byte and next
e030 cd95e1    call    $e195
e033 18e5      jr      $e01a            ; (-$1b) next

;;+----------------------
;;clear tokenisation state flag
e035 af        xor     a
e036 3220ae    ld      ($ae20),a
e039 c9        ret     

;;===================================================
;; tokenise identifiers
;tokens >= &80 are returned with carry set, for caller to process
;other items are written by as, and carry returns clear

e03a c5        push    bc
e03b d5        push    de
e03c e5        push    hl

e03d 7e        ld      a,(hl)			;; get initial character of BASIC keyword
e03e 23        inc     hl
e03f cdabff    call    $ffab			;; convert character to upper case
e042 cda8e3    call    $e3a8			;; get list of keywords beginning with this letter
e045 cdebe3    call    $e3eb
e048 3026      jr      nc,$e070         ;;not found? - it's a variable!

e04a 79        ld      a,c
e04b e67f      and     $7f              
e04d cd9cff    call    $ff9c
e050 3009      jr      nc,$e05b         ; (+$09)
e052 1a        ld      a,(de)           ;get prev token
e053 fee4      cp      $e4              ;FN token
e055 7e        ld      a,(hl)
e056 c49cff    call    nz,$ff9c
e059 3815      jr      c,$e070          ; (+$15) tokenise variable name after FN

e05b f1        pop     af
e05c 1a        ld      a,(de)           ;get prev token
e05d b7        or      a                ;tokens >= &80 = statements and miscellaneous
e05e faafe0    jp      m,$e0af          ;do tests and return the token for caller to process
e061 d1        pop     de               ;tokens <&80 = functions
e062 c1        pop     bc
e063 f5        push    af
e064 3eff      ld      a,$ff            ;functions have a &ff prefix
e066 cd08e0    call    $e008
e069 f1        pop     af
e06a cd08e0    call    $e008            ;write function token
e06d af        xor     a
e06e 183a      jr      $e0aa            ; (+$3a)

;;=tokenise variable
e070 e1        pop     hl
e071 d1        pop     de
e072 c1        pop     bc
e073 e5        push    hl
e074 2b        dec     hl

e075 23        inc     hl               ;skip over the variable name to get to the type char
e076 7e        ld      a,(hl)
e077 cd9cff    call    $ff9c            ;I was today years old when I learnt variable names can contain periods :)
e07a 38f9      jr      c,$e075          ; (-$07)

e07c cdd1e0    call    $e0d1            ;interpret the type suffix
e07f 3804      jr      c,$e085          ; (+$04)
e081 3e0d      ld      a,$0d            ;no type suffix - default to a real
e083 1806      jr      $e08b            ; (+$06)

e085 23        inc     hl               
e086 fe05      cp      $05              ;massage var type from 2/3/5 (internal data type) to 2/3/4 (token data type)
e088 2001      jr      nz,$e08b         ; (+$01)
e08a 3d        dec     a
;;=got var type
e08b cd08e0    call    $e008            ;write type type token
e08e af        xor     a                ;write null link pointer (to variable data storage)
e08f cd08e0    call    $e008
e092 af        xor     a
e093 cd08e0    call    $e008
e096 e3        ex      (sp),hl

;;=tokenise variable name loop
e097 7e        ld      a,(hl)           ;copy the variable name
e098 cd9cff    call    $ff9c
e09b 3007      jr      nc,$e0a4         ; (+$07) done
e09d 7e        ld      a,(hl)
e09e cd08e0    call    $e008
e0a1 23        inc     hl
e0a2 18f3      jr      $e097            ; (-$0d)

e0a4 cdb5e1    call    $e1b5            ;set bit 7 of last char of name
e0a7 e1        pop     hl
e0a8 3eff      ld      a,$ff
;;=set tokenise line number flag
e0aa 3220ae    ld      ($ae20),a
e0ad 37        scf     
e0ae c9        ret     

;;==================================
;; test for keywords taking line numbers
;sets tokenise line number flag (ae20) to &ff if token is one of these.
;If set numbers following will be tokenised as line numbers
e0af e5        push    hl
e0b0 4f        ld      c,a
e0b1 21c3e0    ld      hl,$e0c3
e0b4 cdcaff    call    $ffca			;;check if byte exists in table
e0b7 9f        sbc     a,a
e0b8 e601      and     $01
e0ba 3220ae    ld      ($ae20),a
e0bd 79        ld      a,c
e0be e1        pop     hl
e0bf d1        pop     de
e0c0 c1        pop     bc
e0c1 b7        or      a
e0c2 c9        ret     

;;================================================
;; keywords taking line numbers
;; keywords which can be followed by a line number
e0c3 
defb $c7 ;RESTORE
defb $81 ;AUTO
defb $c6 ;RENUM
defb $92 ;DELETE
defb $96 ;EDIT
defb $c8 ;RESUME
defb $e3 ;ERL
defb $97 ;ELSE
defb $ca ;RUN
defb $a7 ;LIST
defb $a0 ;GOTO
defb $eb ;THEN
defb $9f ;GOSUB
defb $00

;;===========================================
;; convert variable type suffix

e0d1 fe21      cp      "!"              ;'!' real
e0d3 2807      jr      z,$e0dc          ; (+$07)
e0d5 fe26      cp      "&"              ;'&' we want < '&'
e0d7 d0        ret     nc

e0d8 fe24      cp      "$"              ;'$' string 
e0da 3f        ccf                      
e0db d0        ret     nc               ;we want >= '$'

e0dc de1f      sbc     a,$1f            ;Use maths to massage them into 2,3,5 (int, string, real)
e0de ee07      xor     $07
e0e0 37        scf     
e0e1 c9        ret     

;;==============================================
;;tokenise period or digit

e0e2 3a20ae    ld      a,($ae20)        ;
e0e5 b7        or      a                ;Flag=$00=Tokenise as a number
e0e6 2810      jr      z,$e0f8          ; (+$10) No

e0e8 7e        ld      a,(hl)           ;
e0e9 23        inc     hl               ;Flag=$ff=Just written a variable, copy as literal(??)
e0ea fa08e0    jp      m,$e008          ;Write token and return

e0ed 2b        dec     hl               ;Flag=$01=Tokenise a line number
e0ee d5        push    de
e0ef cdcfee    call    $eecf
e0f2 3032      jr      nc,$e126         ; (+$32) Not a valid line number, copy as raw data
e0f4 3e1e      ld      a,$1e          ; 16-bit line number
e0f6 184d      jr      $e145            ; (+$4d)

e0f8 d5        push    de
e0f9 c5        push    bc
e0fa cd8aed    call    $ed8a
e0fd c1        pop     bc
e0fe 3026      jr      nc,$e126         ; (+$26)
e100 cd66ff    call    $ff66
e103 3e1f      ld      a,$1f            ;Floating point number
e105 303e      jr      nc,$e145         ; (+$3e)

e107 ed5ba0b0  ld      de,($b0a0)
e10b 7a        ld      a,d              ;Single byte value?
e10c b7        or      a
e10d 3e1a      ld      a,$1a            ;16-bit value displayed in decimal
e10f 2034      jr      nz,$e145         ; (+$34)

e111 e3        ex      (sp),hl          ;Get write buffer addr into HL...
e112 eb        ex      de,hl            ;...then DE; Value into HL
e113 7d        ld      a,l
e114 fe0a      cp      $0a              ;Number <= 10?
e116 3004      jr      nc,$e11c         ; (+$04)
e118 c60e      add     a,$0e            ;Tokens $0e to $18 = numeric constants 0 to 10
e11a 1806      jr      $e122            ; (+$06)

e11c 3e19      ld      a,$19            ;8-bit value displayed in decimal
e11e cd08e0    call    $e008
e121 7d        ld      a,l
e122 e1        pop     hl
e123 c308e0    jp      $e008

;;=tokenise copy invalid data
;Used to copy invalid (untokenisable) code
;HL=source address
;TOS=destination address
;DE=address of last byte to copy
e126 7e        ld      a,(hl)           ;HL=read buffer ptr
e127 23        inc     hl
e128 e3        ex      (sp),hl          ;Get write buffer address...
e129 eb        ex      de,hl            ;...into DE...
e12a cd08e0    call    $e008            ;...and write token to buffer
e12d eb        ex      de,hl            ;New buffer ptr back to HL...
e12e e3        ex      (sp),hl          ;...And back to TOS.
e12f cdd8ff    call    $ffd8 ; HL=DE?
e132 20f2      jr      nz,$e126         ; (-$0e)
e134 d1        pop     de
e135 c9        ret     

;;===========================================
;; tokenise hex or binary number
e136 d5        push    de
e137 c5        push    bc
e138 cd8aed    call    $ed8a
e13b c1        pop     bc
e13c 30e8      jr      nc,$e126         ; (-$18)
e13e fe02      cp      $02
e140 3e1b      ld      a,$1b            ;16-bit constant in displayed in binary format
e142 2801      jr      z,$e145          ; (+$01)
e144 3c        inc     a                ;$1c=16-bit constant displayed in hex format

;;=tokenise write from accumulator
;A=token (prefix)
;Value is in accumulator
e145 d1        pop     de
e146 cd08e0    call    $e008
e149 e5        push    hl
e14a 21a0b0    ld      hl,$b0a0
e14d cd4bff    call    $ff4b
e150 f5        push    af
e151 7e        ld      a,(hl)
e152 23        inc     hl
e153 cd08e0    call    $e008
e156 f1        pop     af
e157 3d        dec     a
e158 20f6      jr      nz,$e150         ; (-$0a)
e15a e1        pop     hl
e15b c9        ret     

;;=====================================
;; tokenise any other ascii char
;; Any ASCII char between $33 and $127 which is not a letter, number, period or '&'
;I.e. strings, bar commands, ? print statement, maths and comparison etc operators, and ' comments

e15c fe22      cp      $22				; '"'
e15e 2835      jr      z,$e195          ; (+$35)
e160 fe7c      cp      "|"				; '|' 
e162 283f      jr      z,$e1a3          ; (+$3f)
e164 c5        push    bc
e165 d5        push    de
e166 ee3f      xor     $3f              ; "?" char
e168 06bf      ld      b,$bf            ; PRINT token
e16a 2810      jr      z,$e17c          ; (+$10)

e16c 2b        dec     hl
e16d 1136e7    ld      de,$e736         ; Symbols (i.e maths operators, comparisons)
e170 cdebe3    call    $e3eb
e173 1a        ld      a,(de)
e174 3802      jr      c,$e178          ; (+$02) 
e176 7e        ld      a,(hl)           ;Not found in symbol table?
e177 23        inc     hl
e178 47        ld      b,a
e179 cd89e1    call    $e189
e17c 3220ae    ld      ($ae20),a
e17f 78        ld      a,b
e180 d1        pop     de
e181 c1        pop     bc
e182 fec0      cp      $c0              ;"'" comment
e184 2836      jr      z,$e1bc          ; (+$36)
e186 c308e0    jp      $e008

;Get new state flag value
;Converts A as follows:
;If A=1 (":" symbol) or $23, returns A=0
;otherwise if flag=$ff returns A=0,
;otherwise returns flag.
e189 3d        dec     a
e18a c8        ret     z

e18b ee22      xor     $22				;$23 = "#". Testing for stream number?
e18d c8        ret     z

e18e 3a20ae    ld      a,($ae20)
e191 3c        inc     a
e192 c8        ret     z

e193 3d        dec     a
e194 c9        ret     

;;=============================================
;; tokenise string
;; Called after a double quote
e195 cd08e0    call    $e008
e198 7e        ld      a,(hl)
e199 b7        or      a
e19a c8        ret     z

e19b 23        inc     hl
e19c fe22      cp      $22				; '"'
e19e 20f5      jr      nz,$e195         ; (-$0b)
e1a0 c308e0    jp      $e008

;;=============================
;;tokenise bar command

e1a3 cd08e0    call    $e008
e1a6 af        xor     a
e1a7 3220ae    ld      ($ae20),a

e1aa cd08e0    call    $e008            ;Copy bar command name
e1ad 7e        ld      a,(hl)
e1ae 23        inc     hl
e1af cd9cff    call    $ff9c
e1b2 38f6      jr      c,$e1aa          ; (-$0a)
e1b4 2b        dec     hl

e1b5 1b        dec     de               ;Set bit 7 of last char of name
e1b6 1a        ld      a,(de)
e1b7 f680      or      $80
e1b9 12        ld      (de),a
e1ba 13        inc     de
e1bb c9        ret     

;;====================================
;; tokenise single quote comment
e1bc 3e01      ld      a,$01            ;End of statement (:). Always written before tick comment
e1be cd08e0    call    $e008
e1c1 3ec0      ld      a,$c0            ;"'"

;;=copy comment to buffer
e1c3 cd08e0    call    $e008
e1c6 7e        ld      a,(hl)
e1c7 23        inc     hl
e1c8 b7        or      a
e1c9 20f8      jr      nz,$e1c3         ; (-$08)

e1cb 2b        dec     hl
e1cc c9        ret     




;;***Detokenising.asm
;;<< LIST AND DETOKENISING BACK TO ASCII
;;========================================================================
;; command LIST
;LIST [<line number range>][,#<stream expression>]
;Lists the program to the given stream, default #0

e1cd cd0fcf    call    $cf0f
e1d0 c5        push    bc
e1d1 d5        push    de
e1d2 cdcac1    call    $c1ca
e1d5 cd37de    call    $de37
e1d8 cdaade    call    $deaa
e1db d1        pop     de
e1dc c1        pop     bc
e1dd cde3e1    call    $e1e3
e1e0 c358c0    jp      $c058

;;========================================================================
;; do LIST
;;BC = starting line number
;;DE = ending line number

e1e3 d5        push    de
e1e4 50        ld      d,b
e1e5 59        ld      e,c
e1e6 cd64e8    call    $e864            ;Find address of start line (HL)
e1e9 d1        pop     de               ;end line number

;;=list line loop
e1ea 4e        ld      c,(hl)           ;BC=line length
e1eb 23        inc     hl
e1ec 46        ld      b,(hl)
e1ed 2b        dec     hl
e1ee 78        ld      a,b
e1ef b1        or      c
e1f0 c8        ret     z                ;End of program

e1f1 cd72c4    call    $c472			; key
e1f4 e5        push    hl               ;Start of line
e1f5 09        add     hl,bc            ;Start of next line
e1f6 e3        ex      (sp),hl          ;Retrieve start of line/start of next line
e1f7 d5        push    de               ;End line number
e1f8 e5        push    hl               ;Start of line
e1f9 23        inc     hl
e1fa 23        inc     hl
e1fb 5e        ld      e,(hl)           ;Get line number in DE
e1fc 23        inc     hl
e1fd 56        ld      d,(hl)
e1fe e1        pop     hl               ;Start of line
e1ff e3        ex      (sp),hl          ;Get end line number
e200 cdd8ff    call    $ffd8 ; HL=DE? Test for > final line number?
e203 e3        ex      (sp),hl          ;Get start of line
e204 3812      jr      c,$e218          ; (+$12) Stop listing

e206 cd54e2    call    $e254
e209 218aac    ld      hl,$ac8a

e20c cd1de2    call    $e21d        ;Copy buffer to stream
e20f 23        inc     hl
e210 7e        ld      a,(hl)
e211 b7        or      a
e212 20f8      jr      nz,$e20c         ; (-$08)

e214 cd98c3    call    $c398      ; new text line
e217 b7        or      a            ;Clear carry

e218 d1        pop     de           ;Get end line number
e219 e1        pop     hl           ;Get start of next line
e21a 30ce      jr      nc,$e1ea         ; (-$32) Loop for next line
e21c c9        ret     

;;=output char to stream
e21d cdbec1    call    $c1be
e220 7e        ld      a,(hl)
e221 380a      jr      c,$e22d          ; (+$0a)
e223 cdb8c3    call    $c3b8
e226 fe0a      cp      $0a              ;Convert LF to LF+CR
e228 c0        ret     nz

e229 3e0d      ld      a,$0d
e22b 1808      jr      $e235            ; (+$08)

e22d fe20      cp      $20          ;Prefix unprintable characters with control code 1 (output literal)
e22f 3e01      ld      a,$01
e231 dcb8c3    call    c,$c3b8
e234 7e        ld      a,(hl)
e235 c3b8c3    jp      $c3b8

;;=detokenise line from line number
;Line number in HL
;If line number not found creates an empty buffer with the line number
e238 cd64e8    call    $e864
e23b 3817      jr      c,$e254          ; (+$17) Line found?
                                        ;Else create empty buffer with line number
;;=detokenise prepare buffer
e23d eb        ex      de,hl
e23e cd4aef    call    $ef4a
e241 110001    ld      de,$0100         ;D=buffer length, E='append space' flag.
e244 018aac    ld      bc,$ac8a         ;Buffer address

e247 7e        ld      a,(hl)           ;Copy line number from (HL) to (BC) (until $00 value). D=buffer free space
e248 23        inc     hl
e249 02        ld      (bc),a
e24a 03        inc     bc
e24b 15        dec     d
e24c b7        or      a
e24d 20f8      jr      nz,$e247         ; (-$08)
e24f 02        ld      (bc),a
e250 0b        dec     bc
e251 c3e8e2    jp      $e2e8

;;========================================
;;detokenise line atHL to buffer
;HL=address of line
e254 e5        push    hl
e255 cd3de2    call    $e23d
e258 e1        pop     hl
e259 23        inc     hl
e25a 23        inc     hl
e25b 23        inc     hl
e25c 23        inc     hl
;;=detokenise item loop
e25d 7e        ld      a,(hl)
e25e 02        ld      (bc),a
e25f b7        or      a
e260 c8        ret     z

e261 cd66e2    call    $e266
e264 18f7      jr      $e25d            ; (-$09)

;;=detokenise single item
e266 faf8e2    jp      m,$e2f8
e269 fe02      cp      $02
e26b 381c      jr      c,$e289          ; (+$1c)
e26d fe05      cp      $05
e26f 3842      jr      c,$e2b3          ; (+$42)
e271 fe0e      cp      $0e
e273 383e      jr      c,$e2b3          ; (+$3e)
e275 fe20      cp      $20				; ' '
e277 3831      jr      c,$e2aa          ; (+$31)
e279 fe7c      cp      $7c				; '|'
e27b 2854      jr      z,$e2d1          ; (+$54)
e27d cdd1e0    call    $e0d1
e280 d49cff    call    nc,$ff9c
e283 dce6e2    call    c,$e2e6
e286 7e        ld      a,(hl)
e287 180d      jr      $e296            ; (+$0d)

;;=detokenise next statement tokens
;Items which follow a &01 (next statement) token
e289 23        inc     hl
e28a 7e        ld      a,(hl)
e28b fec0      cp      $c0              ;"'" comment
e28d 285d      jr      z,$e2ec          ; (+$5d)
e28f fe97      cp      $97              ;ELSE
e291 2869      jr      z,$e2fc          ; (+$69)
e293 2b        dec     hl

e294 3e3a      ld      a,$3a            ;":" If none of the above apply then we actually have a next statement
;;=detokenise colon string or unknown
e296 1e00      ld      e,$00
e298 fe22      cp      $22				; '"'
e29a 200b      jr      nz,$e2a7         ; (+$0b)
;;=detokenise string literal
;terninates with double quote or &00
e29c cdcae2    call    $e2ca
e29f 23        inc     hl
e2a0 7e        ld      a,(hl)
e2a1 b7        or      a
e2a2 c8        ret     z

e2a3 fe22      cp      $22				; '"'
e2a5 20f5      jr      nz,$e29c         ; (-$0b)
;;=detokenise literal char
;(or unknown value)
e2a7 23        inc     hl
e2a8 1820      jr      $e2ca            ; (+$20)

;;=detokenise number
e2aa cde6e2    call    $e2e6
e2ad cd2fe3    call    $e32f
e2b0 1e01      ld      e,$01
e2b2 c9        ret     

;;=detokenise variable reference
e2b3 cde6e2    call    $e2e6
e2b6 7e        ld      a,(hl)           ;Variable type
e2b7 f5        push    af
e2b8 23        inc     hl               ;step over variable type and data pointer
e2b9 23        inc     hl
e2ba 23        inc     hl
e2bb cddbe2    call    $e2db            ;Variable name
e2be f1        pop     af               ;Get variable type
e2bf 1e01      ld      e,$01
e2c1 fe0b      cp      $0b              ;Types >= $0b have no explicit type identifier (%, !, $) in source
e2c3 d0        ret     nc

e2c4 1e00      ld      e,$00            
e2c6 ee27      xor     $27              ;Convert type code to type identifier
e2c8 e6fd      and     $fd

;;=detokenise append char literal
;Copy char in A to buffer at (BC), inc BC and dec D.
;D=remaining free chars in buffer space.
;But if buffer full (D=1) leave BC and D unchanged
;(future calls will overwrite last char in buffer)
e2ca 02        ld      (bc),a
e2cb 03        inc     bc
e2cc 15        dec     d
e2cd c0        ret     nz

e2ce 0b        dec     bc
e2cf 14        inc     d
e2d0 c9        ret     

;;=detokenise bar command
e2d1 1e01      ld      e,$01
e2d3 cdcae2    call    $e2ca
e2d6 23        inc     hl
e2d7 7e        ld      a,(hl)
e2d8 23        inc     hl
e2d9 b7        or      a
e2da c0        ret     nz

;;=detokenise copy bit7 terminated string
;(string where last char has bit 7 set)
e2db 7e        ld      a,(hl)
e2dc e67f      and     $7f
e2de cdcae2    call    $e2ca
e2e1 be        cp      (hl)
e2e2 23        inc     hl
e2e3 30f6      jr      nc,$e2db         ; (-$0a)
e2e5 c9        ret     

;;=detokenise append space if needed
;Appends a space is E = 1
;I think this is optionally inserting spaces. Ie if one is needed after a keyword etc.
;Thus E = 'we've just read a keyword etc' flag
e2e6 1d        dec     e
e2e7 c0        ret     nz

;;=detokenise append space
e2e8 3e20      ld      a,$20
e2ea 18de      jr      $e2ca            ; (-$22)

;;---------------------------------------------------------------------------
;;=detokenise comment
e2ec cdfce2    call    $e2fc
e2ef 7e        ld      a,(hl)			; get token
e2f0 b7        or      a				; end of line?
e2f1 c8        ret     z
e2f2 cdcae2    call    $e2ca
e2f5 23        inc     hl				; increment pointer for next token
e2f6 18f7      jr      $e2ef

;;---------------------------------------------------------------------------
;;=detokenise keyword
e2f8 fec5      cp      $c5              ;REM
e2fa 28f0      jr      z,$e2ec          ; (-$10)
;; =detokenise else and comment
e2fc 23        inc     hl
e2fd feff      cp      $ff              ;Extended keyword table
e2ff 2002      jr      nz,$e303         ; (+$02)
e301 7e        ld      a,(hl)           ;Get token for extended keywords
e302 23        inc     hl
e303 f5        push    af
e304 e5        push    hl
e305 cdb8e3    call    $e3b8
e308 b7        or      a
e309 2808      jr      z,$e313          ; (+$08)
e30b f5        push    af
e30c cde6e2    call    $e2e6
e30f f1        pop     af

;Copy keyword text to buffer
e310 cdcae2    call    $e2ca
e313 7e        ld      a,(hl)
e314 e67f      and     $7f
e316 fe09      cp      $09              ;Filter out TAB chars. These are used in GO TO and GO SUB...
e318 c4cae2    call    nz,$e2ca         ;...so you can type them in either way.
e31b be        cp      (hl)
e31c 23        inc     hl
e31d 28f4      jr      z,$e313          ; (-$0c)

;Set E depending on whether keyword ends in a letter/number or not
;(E='need a space after this' flag)
e31f cd9cff    call    $ff9c
e322 1e00      ld      e,$00
e324 3002      jr      nc,$e328         ; (+$02)
e326 1e01      ld      e,$01
e328 e1        pop     hl
e329 f1        pop     af
e32a d6e4      sub     $e4
e32c c0        ret     nz

e32d 5f        ld      e,a
e32e c9        ret     

;;----------------------------------------------------
;;=detokenise numeric literal
e32f d5        push    de

e330 7e        ld      a,(hl)           ;; get token
e331 23        inc     hl
e332 fe1f      cp      $1f				; floating point value
e334 285d      jr      z,$e393          

e336 5e        ld      e,(hl)           ;; read 16-bit value
e337 23        inc     hl
e338 56        ld      d,(hl)
e339 23        inc     hl

;; DE = 16-bit value
;; A = token value (indicates type of 16-bit data)

e33a fe1b      cp      $1b				; 16-bit integer binary value
e33c 2832      jr      z,$e370          
e33e fe1c      cp      $1c				; 16-bit integer hexadecimal value
e340 2839      jr      z,$e37b          
e342 fe1e      cp      $1e				; 16-bit integer BASIC line number
e344 2823      jr      z,$e369          
e346 fe1d      cp      $1d				; 16-bit BASIC program line memory address pointer
e348 2816      jr      z,$e360          
e34a fe1a      cp      $1a				; 16-bit integer decimal value
e34c 280b      jr      z,$e359          


;8-bit value
e34e 2b        dec     hl
e34f 1600      ld      d,$00            ;Zero high byte
e351 fe19      cp      $19				; 8-bit integer decimal value
e353 2804      jr      z,$e359          ; (+$04)
e355 2b        dec     hl
e356 d60e      sub     $0e              ;Tokens $0e to $18 encode literals 0 to 10
e358 5f        ld      e,a

;;=detokenise 16bit decimal
e359 e3        ex      (sp),hl
e35a eb        ex      de,hl
e35b cd35ff    call    $ff35
e35e 183a      jr      $e39a            ; (+$3a)

;;=detokenise line number ptr
e360 e5        push    hl
e361 eb        ex      de,hl
e362 23        inc     hl
e363 23        inc     hl
e364 23        inc     hl
e365 5e        ld      e,(hl)
e366 23        inc     hl
e367 56        ld      d,(hl)
e368 e1        pop     hl
;;=detokenise line number
e369 e3        ex      (sp),hl
e36a eb        ex      de,hl
e36b cd4aef    call    $ef4a
e36e 182d      jr      $e39d            ; (+$2d)

;;=detokenise binary number
e370 e3        ex      (sp),hl
e371 3e58      ld      a,$58            ; "X" - binary number prefix
e373 37        scf                      ;Set carry to display the above char
e374 f5        push    af
e375 c5        push    bc
e376 010101    ld      bc,$0101         ;One but per digit and digit mask
e379 1807      jr      $e382            ; (+$07)

;;=detokenise hex number
e37b e3        ex      (sp),hl
e37c b7        or      a                ;Clear carry - only display '&' prefix
e37d f5        push    af
e37e c5        push    bc
e37f 010f04    ld      bc,$040f         ;Four digits per pixel and digit mask

;;=detokenise based number
;BC=format. See convert_based_number_to_string
e382 eb        ex      de,hl
e383 af        xor     a                ;No padding
e384 cddff1    call    $f1df
e387 c1        pop     bc
e388 3e26      ld      a,$26            ;"&"
e38a cdcae2    call    $e2ca
e38d f1        pop     af               ;Retrieve carry flag and, if set, second prefix char
e38e dccae2    call    c,$e2ca          ;Append binary number prefix
e391 180a      jr      $e39d            ; (+$0a)

;;------------------------------------------------
;;=detokenise floating point

e393 3e05      ld      a,$05
e395 cd6cff    call    $ff6c
e398 e3        ex      (sp),hl
e399 eb        ex      de,hl

;;------------------------------------------------
;;=detokenise accumulator
e39a cd5aef    call    $ef5a

;;=detokenise copy asciiz
e39d 7e        ld      a,(hl)
e39e 23        inc     hl
e39f cdcae2    call    $e2ca
e3a2 7e        ld      a,(hl)
e3a3 b7        or      a
e3a4 20f7      jr      nz,$e39d         ; (-$09)
e3a6 e1        pop     hl
e3a7 c9        ret     





;;***KeywordLUTs.asm
;;<< KEYWORD LOOK UP TABLES
;;< And associated functions
;;=======================================================================
;; get keyword table for letter
;; A = initial letter of BASIC keyword
e3a8 e5        push    hl
e3a9 d641      sub     $41				; initial letter - 'A'
										; number in range 0->27
e3ab 87        add     a,a				; x2 (two bytes per table entry)
										; A = offset into table

e3ac c618      add     a,($e418) and $ff ;$18  table starts at $e418 Low byte of keyword table address
e3ae 6f        ld      l,a
e3af cee4      adc     a,($e418 >> 8)   ;$e4  high byte of keyword table address
e3b1 95        sub     l
e3b2 67        ld      h,a

e3b3 5e        ld      e,(hl)			; get address of keyword list from table
e3b4 23        inc     hl
e3b5 56        ld      d,(hl)
e3b6 e1        pop     hl
e3b7 c9        ret     

;;========================================================================
;;convert token to keyword text ptr
e3b8 c5        push    bc
e3b9 4f        ld      c,a
e3ba 061a      ld      b,$1a      ; Table count
e3bc 214ce4    ld      hl,$e44c

e3bf cdd7e3    call    $e3d7      ; Loop through each table
e3c2 380e      jr      c,$e3d2          ; (+$0e)
e3c4 23        inc     hl
e3c5 10f8      djnz    $e3bf            ; (-$08)

e3c7 2136e7    ld      hl,$e736    ; Also search symbols table
e3ca cdd7e3    call    $e3d7
e3cd d249cb    jp      nc,$cb49			; Not found: Syntax Error
e3d0 06c0      ld      b,$c0            ;"'" comment

e3d2 78        ld      a,b
e3d3 c640      add     a,$40
e3d5 c1        pop     bc
e3d6 c9        ret     

;;=search within a single table
e3d7 7e        ld      a,(hl)
e3d8 b7        or      a
e3d9 c8        ret     z          ; Until trailing zero byte found

e3da e5        push    hl
e3db 7e        ld      a,(hl)
e3dc 23        inc     hl
e3dd 17        rla                 ; Find byte with bit 7 set
e3de 30fb      jr      nc,$e3db         ; (-$05)

e3e0 7e        ld      a,(hl)
e3e1 23        inc     hl
e3e2 b9        cp      c           ; Next byte is the token
e3e3 2803      jr      z,$e3e8          ; (+$03)
e3e5 f1        pop     af
e3e6 18ef      jr      $e3d7            ; (-$11)

e3e8 e1        pop     hl         ; Entry found
e3e9 37        scf     
e3ea c9        ret     

;;==========================================
;;keyword to token within single table
;;DE=ptr in buffer
;;HL=ptr to table
e3eb 1a        ld      a,(de)    ;End of buffer?
e3ec b7        or      a
e3ed c8        ret     z

e3ee e5        push    hl
e3ef 1a        ld      a,(de)    ; Get buffer char, skipping white space
e3f0 13        inc     de
e3f1 fe09      cp      $09
e3f3 2804      jr      z,$e3f9          ; (+$04)
e3f5 fe20      cp      $20
e3f7 2005      jr      nz,$e3fe         ; (+$05)
e3f9 cd4dde    call    $de4d ; skip space, lf or tab
e3fc 18f1      jr      $e3ef            ; (-$0f)

;;-----------------------------------------------------
;;=test letter for match
e3fe 4f        ld      c,a
e3ff 7e        ld      a,(hl)
e400 23        inc     hl
e401 cdabff    call    $ffab			;; convert character to upper case
e404 a9        xor     c				;; character the same?
e405 28e8      jr      z,$e3ef          ;match but not end of keyword - next character

;; character not the same?
e407 e67f      and     $7f              ;mask out bit 7 - end of word
e409 280a      jr      z,$e415          ; (+$0a) if it wasn't zero but now is the we've found word
e40b 1b        dec     de               ; else skip to next entry
e40c 1a        ld      a,(de)
e40d 13        inc     de
e40e 17        rla     
e40f 30fb      jr      nc,$e40c         ; (-$05)
e411 13        inc     de
e412 e1        pop     hl
e413 18d6      jr      $e3eb            ; (-$2a)

;;=entry found
e415 f1        pop     af
e416 37        scf     
e417 c9        ret     

;;===================
;; keyword table per letter
;; list of keywords sorted into alphabetical order
e418
defw $e720		;; AUTO, ATN, ASC, AND, AFTER, ABS
defw $e715		;; BORDER, BIN$
defw $e6cc		;; CURSOR, CREAL, COS, COPYCHR$, CONT, CLS, CLOSEOUT, CLOSEIN, CLG, CLEAR, CINT, CHR$, CHAIN, CAT, CALL
defw $e692		;; DRAWR, DRAW, DIM, DI, DERR, DELETE, DEG, DEFSTR, DEFREAL, DEFINT, DEF, DEC$, DATA
defw $e663		;; EXP, EVERY, ERROR, ERR, ERL, ERASE, EOF, ENV, ENT, END, ELSE, EI, EDIT
defw $e64e		;; FRE, FRAME, FOR, FN, FIX, FILL
defw $e63a		;; GRAPHICS, GOTO, GOSUB
defw $e630		;; HIMEM, HEX$
defw $e60f		;; INT,INSTR, INPUT, INP, INKEY$, INKEY, INK, IF
defw $e60b		;; JOY
defw $e607		;; KEY
defw $e5db		;; LOWER$, LOG10, LOG, LOCATE, LOAD, LIST, LINE, LET, LEN, LEFT$
defw $e5b1		;; MOVER, MOVE, MODE, MOD, MIN, MID$, MERGE, MEMORY, MAX, MASK
defw $e5a6		;; NOT, NEW, NEXT
defw $e56e		;; OUT, ORIGIN, OR, OPENOUT, OPENIN, ON SQ, ON ERROR GOTO, ON BREAK, ON
defw $e54a		;; PRINT, POS, POKE PLOTR, PLOT, PI, PEN, PEEK, PAPER
defw $e549		;; (no keywords defined)
defw $e4ff		;; RUN, ROUND, RND, RIGHT$, RETURN, RESUME, RESTORE, RENUM, REMAIN, REM, RELEASE, READ, RANDOMIZE, RAD
defw $e4bf		;; SYMBOL, SWAP, STRING$, STR$, STOP, STEP, SQR, SQ, SPEED, SPC, SPACE$, SOUND, SIN, SGN, SAVE
defw $e493		;; TRON, TROFF, TO, TIME, THEN, TESTR, TEST, TAN, TAGOFF, TAG, TAB
defw $e484		;; USING, UPPER$, UNT
defw $e47c		;; VPOS, VAL
defw $e45e		;; WRITE, WINDOW, WIDTH, WHILE, WEND, WAIT
defw $e456		;; XPOS, XOR
defw $e451		;; YPOS
defw $e44c		;; ZONE


;;======================================================================
;; Keyword table
;; list of keyword as text followed by keyword byte (token?)
;; end of list signalled with a 0 byte 
;;
;; - BASIC keyword stored excluding initial letter
;; e.g. "ZONE" is stored as "ONE"
;; - BASIC keyword stored with bit 7 of last letter of keyword set.
;; e.g. "ON","E"+$80 for ZONE
;; - keyword followed by keyword byte (token?)

;;=keyword table Z
e44c 
defb "ON","E"+$80,$da		;; ZONE
defb 0

;;=keyword table Y
e451
defb "PO","S"+$80,$48		;; YPOS
defb 0

;;=keyword table X
e456
defb "PO","S"+$80,$47		;; XPOS
defb "O","R"+$80,$fd		;; XOR
defb 0

;;=keyword table W
e45e
defb "RIT","E"+$80,$d9		;; WRITE
defb "INDO","W"+$80,$d8		;; WINDOW
defb "IDT","H"+$80,$d7		;; WIDTH
defb "HIL","E"+$80,$d6		;; WHILE
defb "EN","D"+$80,$d5		;; WEND 
defb "AI","T"+$80,$d4		;; WAIT
defb 0

;;=keyword table V
e47c
defb "PO","S"+$80,$7f		;; VPOS
defb "A","L"+$80,$1d		;; VAL
defb 0

;;=keyword table U
e484
defb "SIN","G"+$80,$ed		;; USING
defb "PPER","$"+$80,$1c		;; UPPER$
defb "N","T"+$80,$1b		;; UNT
defb 0

;;=keyword table T
e493
defb "RO","N"+$80,$d3		;; TRON
defb "ROF","F"+$80,$d2		;; TROFF
defb "O"+$80,$ec			;; TO
defb "IM","E"+$80,$46		;; TIME
defb "HE","N"+$80,$eb		;; THEN
defb "EST","R"+$80,$7d		;; TESTR
defb "ES","T"+$80,$7c		;; TEST 
defb "A","N"+$80,$1a		;; TAN
defb "AGOF","F"+$80,$d1		;; TAFOFF
defb "A","G"+$80,$d0		;; TAG
defb "A","B"+$80,$ea		;; TAB
defb 0

;;=keyword table S
e4bf
defb "YMBO","L"+$80,$cf		;; SYMBOL
defb "WA","P"+$80,$e7		;; SWAP
defb "TRING","$"+$80,$7b	;; STRING$
defb "TR","$"+$80,$19		;; STR$
defb "TO","P"+$80,$ce		;; STOP
defb "TE","P"+$80,$e6		;; STEP
defb "Q","R"+$80,$18		;; SQR
defb "Q"+$80,$17			;; SQ
defb "PEE","D"+$80,$cd		;; SPEED
defb "P","C"+$80,$e5		;; SPC
defb "PACE","$"+$80,$16		;; SPACE$
defb "OUN","D"+$80,$cc		;; SOUND
defb "I","N"+$80,$15		;; SIN
defb "G","N"+$80,$14		;; SGN
defb "AV","E"+$80,$cb		;; SAVE
defb 0

;;=keyword table R
e4ff
defb "U","N"+$80,$ca		;; RUN
defb "OUN","D"+$80,$7a		;; ROUND
defb "N","D"+$80,$45		;; RND
defb "IGHT","$"+$80,$79		;; RIGHT$
defb "ETUR","N"+$80,$c9		;; RETURN
defb "ESUM","E"+$80,$c8		;; RESUME
defb "ESTOR","E"+$80,$c7	;; RESTORE
defb "ENU","M"+$80,$c6		;; RENUM
defb "EMAI","N"+$80,$13		;; REMAIN
defb "E","M"+$80,$c5		;; REM
defb "ELEAS","E"+$80,$c4	;; RELEASE
defb "EA","D"+$80,$c3		;; READ
defb "ANDOMIZ","E"+$80,$c2	;; RANDOMIZE
defb "A","D"+$80,$c1		;; RAD
defb 0

;;=keyword table Q
e549
defb 0						

;;=keyword table P
e54a
defb "RIN","T"+$80,$bf		;; PRINT
defb "O","S"+$80,$78		;; POS
defb "OK","E"+$80,$be		;; POKE
defb "LOT","R"+$80,$bd		;; PLOTR
defb "LO","T"+$80,$bc		;; PLOT
defb "I"+$80,$44			;; PI
defb "E","N"+$80,$bb		;; PEN 
defb "EE","K"+$80,$12		;; PEEK
defb "APE","R"+$80,$ba		;; PAPER
defb 0

;;=keyword table O
e56e
defb "U","T"+$80,$b9		;; OUT
defb "RIGI","N"+$80,$b8		;; ORIGIN
defb "R"+$80,$fc			;; OR
defb "PENOU","T"+$80,$b7	;; OPENOUT
defb "PENI","N"+$80,$b6		;; OPENIN
defb "N S","Q"+$80,$b5		;; ON SQ
defb "N ERROR GO",$09,"TO ","0"+$80,$b4		;; ON ERROR GOTO 0, ON ERROR GO TO 0 (but not ON ERROR GOTO/GO TO [n])
defb "N BREA","K"+$80,$b3		;; ON BREAK
defb "N"+$80,$b2			;; ON (and ON ERROR GOTO, ON ERROR GO TO)
defb 0

;;=keyword table N
e5a6
defb "O","T"+$80,$fe		;; NOT
defb "E","W"+$80,$b1		;; NEW
defb "EX","T"+$80,$b0		;; NEXT
defb 0

;;=keyword table M
e5b1
defb "OVE","R"+$80,$af		;; MOVER
defb "OV","E"+$80,$ae		;; MOVE
defb "OD","E"+$80,$ad		;; MODE
defb "O","D"+$80,$fb		;; MOD
defb "I","N"+$80,$77		;; MIN
defb "ID","$"+$80,$ac		;; MID$
defb "ERG","E"+$80,$ab		;; MERGE
defb "EMOR","Y"+$80,$aa		;; MEMORY
defb "A","X"+$80,$76		;; MAX
defb "AS","K"+$80,$df		;; MASK
defb 0

;;=keyword table L
e5db
defb "OWER","$"+$80,$11		;; LOWER$
defb "OG1","0"+$80,$10		;; LOG10
defb "O","G"+$80,$0f		;; LOG
defb "OCAT","E"+$80,$a9		;; LOCATE
defb "OA","D"+$80,$a8		;; LOAD
defb "IS","T"+$80,$a7		;; LIST
defb "IN","E"+$80,$a6		;; LINE
defb "E","T"+$80,$a5		;; LET
defb "E","N"+$80,$0e		;; LEN 
defb "EFT","$"+$80,$75		;; LEFT$
defb 0

;;=keyword table K
e607
defb "E","Y"+$80,$a4		;; KEY
defb 0

;;=keyword table J
e60b
defb "O","Y"+$80,$0d		;; JOY
defb 0

;;=keyword table I
e60f
defb "N","T"+$80,$0c		;; INT
defb "NST","R"+$80,$74		;; INSTR
defb "NPU","T"+$80,$a3		;; INPUT
defb "N","P"+$80,$0b		;; INP
defb "NKEY","$"+$80,$43		;; INKEY$
defb "NKE","Y"+$80,$0a		;; INKEY
defb "N","K"+$80,$a2		;; INK
defb "F"+$80,$a1			;; IF
defb 0

;;=keyword table H
e630
defb "IME","M"+$80,$42		;; HIMEM
defb "EX","$"+$80,$73		;; HEX$
defb 0

;;=keyword table G
e63a
defb "RAPHIC","S"+$80,$de	;; GRAPHICS
defb "O",$09,"T","O"+$80,$a0	;;GO TO, GOTO
defb "O",$09,"SU","B"+$80,$9f	;;GO SUB, GOSUB
defb 0

;;=keyword table F
e64e
defb "R","E"+$80,$09		;; FRE
defb "RAM","E"+$80,$e0		;; FRAME
defb "O","R"+$80,$9e		;; FOR
defb "N"+$80,$e4			;; FN
defb "I","X"+$80,$08		;; FIX
defb "IL","L"+$80,$dd		;; FILL
defb 0

;;=keyword table E
e663
defb "X","P"+$80,$07		;; EXP
defb "VER","Y"+$80,$9d		;; EVERY
defb "RRO","R"+$80,$9c		;; ERROR
defb "R","R"+$80,$41		;; ERR
defb "R","L"+$80,$e3		;; ERL
defb "RAS","E"+$80,$9b		;; ERASE
defb "O","F"+$80,$40		;; EOF
defb "N","V"+$80,$9a		;; ENV
defb "N","T"+$80,$99		;; ENT
defb "N","D"+$80,$98		;; END
defb "LS","E"+$80,$97		;; ELSE
defb "I"+$80,$dc			;; EI
defb "DI","T"+$80,$96		;; EDIT
defb 0

;;=keyword table D
e692
defb "RAW","R"+$80,$95		;; DRAWR
defb "RA","W"+$80,$94		;; DRAW
defb "I","M"+$80,$93		;; DIM
defb "I"+$80,$db			;; DI
defb "ER","R"+$80,$49		;; DERR
defb "ELET","E"+$80,$92		;; DELETE
defb "E","G"+$80,$91		;; DEG
defb "EFST","R"+$80,$90		;; DEFSTR
defb "EFREA","L"+$80,$8f	;; DEFREAL
defb "EFIN","T"+$80,$8e		;; DEFINT
defb "E","F"+$80,$8d		;; DEF
defb "EC","$"+$80,$72		;; DEC$
defb "AT","A"+$80,$8c		;; DATA
defb 0

;;=keyword table C
e6cc
defb "URSO","R"+$80,$e1		;; CURSOR
defb "REA","L"+$80,$06		;; CREAL
defb "O","S"+$80,$05		;; COS
defb "OPYCHR","$"+$80,$7e	;; COPYCHR$
defb "ON","T"+$80,$8b		;; CONT
defb "L","S"+$80,$8a		;; CLS
defb "LOSEOU","T"+$80,$89	;; CLOSEOUT
defb "LOSEI","N"+$80,$88	;; CLOSEIN
defb "L","G"+$80,$87		;; CLG
defb "LEA","R"+$80,$86		;; CLEAR
defb "IN","T"+$80,$04		;; CINT
defb "HR","$"+$80,$03		;; CHR$
defb "HAI","N"+$80,$85		;; CHAIN
defb "A","T"+$80,$84		;; CAT
defb "AL","L"+$80,$83		;; CALL
defb 0

;;=keyword table B
e715
defb "ORDE","R"+$80,$82		;; BORDER
defb "IN","$"+$80,$71		;; BIN$
defb 0

;;=keyword table A
e720
defb "UT","O"+$80,$81		;; AUTO
defb "T","N"+$80,$02		;; ATN
defb "S","C"+$80,$01		;; ASC
defb "N","D"+$80,$fa		;; AND
defb "FTE","R"+$80,$80		;; AFTER
defb "B","S"+$80,$00		;; ABS
defb 0

;;=symbols table
e736
defb "^"+$80,$f8		;;
defb $5c+$80,$f9		;; "\"
defb ">",$09,"="+$80,$f0		;;
defb "= ",">"+$80,$f0		;;
defb ">"+$80,$ee		;;
defb "<",$09,">"+$80,$f2		;;
defb "<",$09,"="+$80,$f3		;;
defb "= ","<"+$80,$f3		;;
defb "="+$80,$ef		;;
defb "<"+$80,$f1		;;
defb "/"+$80,$f7		;;
defb ":"+$80,$01		;;
defb "*"+$80,$f6		;;
defb "-"+$80,$f5		;;
defb "+"+$80,$f4		;;
defb "'"+$80,$c0		;;
defb 0





;;***ProgramManipulation.asm
;;<< PROGRAM EDITING AND MANIPULATION
;;< DELETE, RENUM, DATA, REM, ', ELSE and
;;< a bunch of related utility stuff
;;=====================================================
;;clear program
e761 af        xor     a
e762 2a64ae    ld      hl,($ae64)
e765 77        ld      (hl),a           ;Write zeros to line length and number. aka no program
e766 23        inc     hl
e767 77        ld      (hl),a
e768 23        inc     hl
e769 77        ld      (hl),a
e76a 23        inc     hl
e76b 2266ae    ld      ($ae66),hl
e76e 1811      jr      $e781            ; (+$11)

;;=============================================================================
;;=convert all line addresses to line numbers
;Line numbers are stored as line numbers during editing,
;then converted to addresses as they are encountered during execution.
;This routine converts them back to numbers (ready for edit mode)
e770 3a21ae    ld      a,($ae21)
e773 b7        or      a
e774 c8        ret     z            ;Abort if we already have line addresses

e775 c5        push    bc
e776 d5        push    de
e777 e5        push    hl
e778 0186e7    ld      bc,$e786       ; convert line addresses to line number ##LABEL##
e77b cdb9e9    call    $e9b9        ;Iterator - calls code at BC for every statement
e77e e1        pop     hl
e77f d1        pop     de
e780 c1        pop     bc

;;=clear line address vs line number flag
e781 af        xor     a
e782 3221ae    ld      ($ae21),a    ;Set flag
e785 c9        ret     

;;=================================================
;; convert line addresses to line numbers
;Converts any line addresses (pointers) within a statement to line numbers
e786 cdfde9    call    $e9fd
e789 fe02      cp      $02
e78b d8        ret     c            ;Return at end of line or end of statement

e78c fe1d      cp      $1d          ; 16-bit line address pointer token
e78e 20f6      jr      nz,$e786        

e790 56        ld      d,(hl)       ; get line address (target of GOTO, GOSUB etc)
e791 2b        dec     hl
e792 5e        ld      e,(hl)
e793 2b        dec     hl
e794 e5        push    hl
e795 eb        ex      de,hl
e796 23        inc     hl
e797 23        inc     hl
e798 23        inc     hl
e799 5e        ld      e,(hl)       ; get line number
e79a 23        inc     hl
e79b 56        ld      d,(hl)
e79c e1        pop     hl
e79d 361e      ld      (hl),$1e     ; 16-bit line number token
e79f 23        inc     hl
e7a0 73        ld      (hl),e       ;Write line number back into code
e7a1 23        inc     hl
e7a2 72        ld      (hl),d
e7a3 18e1      jr      $e786

;;-----------------------------------------------------------------
;;=prob tokenise and insert line
;Tokenises the line in the edit buffer and inserts into the program
;at the appropriate position. The rest of the program is shifted up 
;(or down if the new line is shorter) as needed.
;Also handles deleting a line if only a line number is in the buffer.
e7a5 7e        ld      a,(hl)           ;Step over if leading space
e7a6 fe20      cp      $20
e7a8 2001      jr      nz,$e7ab         ; (+$01)
e7aa 23        inc     hl

e7ab cd70e7    call    $e770        ; line address to line number
e7ae cda4df    call    $dfa4
e7b1 e5        push    hl
e7b2 cd4dde    call    $de4d ; skip space, lf or tab
e7b5 b7        or      a                ;Empty line? if so, delete
e7b6 2828      jr      z,$e7e0          ; (+$28)
e7b8 c5        push    bc
e7b9 d5        push    de
e7ba 210400    ld      hl,$0004         ;Add four bytes for line length and line number...
e7bd 09        add     hl,bc            ;...to raw tokenised line length
e7be e5        push    hl
e7bf e5        push    hl
e7c0 cd64e8    call    $e864
e7c3 e5        push    hl
e7c4 dce4e7    call    c,$e7e4
e7c7 d1        pop     de
e7c8 c1        pop     bc
e7c9 cdb8f6    call    $f6b8
e7cc cd07f6    call    $f607
e7cf eb        ex      de,hl
e7d0 d1        pop     de
e7d1 73        ld      (hl),e           ;Write line length?
e7d2 23        inc     hl
e7d3 72        ld      (hl),d
e7d4 23        inc     hl
e7d5 d1        pop     de
e7d6 73        ld      (hl),e           ;Write line number?
e7d7 23        inc     hl
e7d8 72        ld      (hl),d
e7d9 23        inc     hl
e7da c1        pop     bc
e7db eb        ex      de,hl
e7dc e1        pop     hl
e7dd edb0      ldir                     ;Copy line from buffer
e7df c9        ret     

;;=do delete line
;(internal routine)
e7e0 e1        pop     hl
e7e1 cd5ce8    call    $e85c

;---------------------------------------------
;;=prob move program data down
;E.g. after deleting a line, or when an edited line is shorter
e7e4 78        ld      a,b          ;BC=bytes to delete
e7e5 b1        or      c
e7e6 c8        ret     z            ;Abort if zero

e7e7 eb        ex      de,hl
e7e8 cde5f6    call    $f6e5
e7eb c307f6    jp      $f607

;;========================================================================
;; command DELETE
;DELETE <line number range>
;Deletes the lines in the given range

e7ee cd00e8    call    $e800
e7f1 cd37de    call    $de37
e7f4 cd4dfb    call    $fb4d
e7f7 cd1ae8    call    $e81a
e7fa cd8fc1    call    $c18f
e7fd c358c0    jp      $c058

;;+do DELETE find byte range
e800 cd0fcf    call    $cf0f
e803 e5        push    hl
e804 c5        push    bc
e805 cd82e8    call    $e882            ;Find addr of first line to delete?
e808 d1        pop     de
e809 e5        push    hl
e80a cd64e8    call    $e864            ;Find addr of end of last line to delete?
e80d 2222ae    ld      ($ae22),hl       ;Save start address
e810 eb        ex      de,hl
e811 e1        pop     hl
e812 b7        or      a
e813 ed52      sbc     hl,de            ;Start - end = byte count
e815 2224ae    ld      ($ae24),hl       ;Save byte count
e818 e1        pop     hl
e819 c9        ret     

;;+do DELETE delete lines
e81a cd70e7    call    $e770
e81d ed4b24ae  ld      bc,($ae24)       ;Retrieve byte count
e821 2a22ae    ld      hl,($ae22)       ;Retrieve start address
e824 c3e4e7    jp      $e7e4

;;=============================================================================
;;=eval and convert line number to line address
;HL points to either a line number ($1e) or line address ($1d) token
;If it's a line address, just return it.
;If it's a line number then convert it to a line address, store
;it back in the code and return it.
e827 23        inc     hl
e828 5e        ld      e,(hl)           ;Read line number or address
e829 23        inc     hl
e82a 56        ld      d,(hl)
e82b fe1d      cp      $1d            ; 16-bit line address pointer token
e82d 282a      jr      z,$e859          ; (+$2a) if already an address so skip to end
e82f fe1e      cp      $1e            ; 16-bit line number token
e831 c249cb    jp      nz,$cb49			; Error: Syntax Error

e834 e5        push    hl
e835 cdb5de    call    $deb5            ;Compare target line number to current?
e838 dcd8ff    call    c,$ffd8 ; HL=DE? Carry = we have current line
e83b 300a      jr      nc,$e847         ; (+$0a), if target <= current line skip next bit

e83d e1        pop     hl               ;If target line after current then scan to next line and scan from there
e83e e5        push    hl
e83f 23        inc     hl
e840 cdade9    call    $e9ad			;; Start scanning at next line
e843 23        inc     hl
e844 cd68e8    call    $e868

e847 d45ce8    call    nc,$e85c         ;If NC then line number <= current so scan from the start
e84a 2b        dec     hl
e84b eb        ex      de,hl
e84c e1        pop     hl               ;Retrieve execution address (last byte of line number/address)
e84d 2b        dec     hl               ;Point to token
e84e 2b        dec     hl

                                    ;write line address and suitable token
e84f 3e1d      ld      a,$1d        ; 16-bit line address pointer
e851 3221ae    ld      ($ae21),a
e854 77        ld      (hl),a       ;Write token
e855 23        inc     hl
e856 73        ld      (hl),e       ;Write address
e857 23        inc     hl
e858 72        ld      (hl),d

e859 c32cde    jp      $de2c			; get next token skipping space

;;==================================
;;find line or error
e85c cd64e8    call    $e864
e85f d8        ret     c

e860 cd45cb    call    $cb45
e863 defb $08                         ;Inline error code: "Line does not exist"

;;====================================
;;find line
;;DE=line number
e864 2a64ae    ld      hl,($ae64)
e867 23        inc     hl
;;=find line from current
;Scan forward starting at current
;If line found, returns C, Z
;If next line >= requested, returns NC, NZ
;If end of program found before line (last line number < requested line), returns NC, Z
e868 4e        ld      c,(hl)         ;BC=line length
e869 23        inc     hl
e86a 46        ld      b,(hl)
e86b 2b        dec     hl
e86c 78        ld      a,b              ;End of program?
e86d b1        or      c
e86e c8        ret     z

e86f e5        push    hl
e870 23        inc     hl           ;Step over length
e871 23        inc     hl
e872 7e        ld      a,(hl)       ;HL=line number
e873 23        inc     hl
e874 66        ld      h,(hl)
e875 6f        ld      l,a
e876 eb        ex      de,hl
e877 cdd8ff    call    $ffd8 ; Compare line number to requested
e87a eb        ex      de,hl
e87b e1        pop     hl       ;Retrieve start of line
e87c 3f        ccf     
e87d d0        ret     nc       ;Line number > requested?

e87e c8        ret     z        ;Line number = requested?

e87f 09        add     hl,bc    ;Add line length to line address (ie. get next line)
e880 18e6      jr      $e868            ; (-$1a)

;;======================================
;;find line at or after line number
;;BC=line number
e882 2a64ae    ld      hl,($ae64)
e885 23        inc     hl
;Loop
e886 e5        push    hl
e887 4e        ld      c,(hl)       ;BC=Line length
e888 23        inc     hl
e889 46        ld      b,(hl)
e88a 23        inc     hl
e88b 78        ld      a,b          ;End of program?
e88c b1        or      c
e88d 37        scf     
e88e 2809      jr      z,$e899          ; (+$09)

e890 7e        ld      a,(hl)       ;HL=line number
e891 23        inc     hl
e892 66        ld      h,(hl)
e893 6f        ld      l,a
e894 eb        ex      de,hl
e895 cdd8ff    call    $ffd8 ; Compare line number to requested
e898 eb        ex      de,hl

e899 e1        pop     hl
e89a d8        ret     c

e89b 09        add     hl,bc        ;Add line length to line address
e89c 18e8      jr      $e886            ; (-$18) Loop

;;========================================================================
;; command RENUM
;RENUM [<new line number>][,[<old line number>][,<increment>]]
;Renumbers part or all of a program and any references to line numbers

e89e 110a00    ld      de,$000a     ;Default first new line number
e8a1 c41ae9    call    nz,$e91a     ;Eval first new line number, if given
e8a4 d5        push    de
e8a5 110000    ld      de,$0000     ;Default first old line number ###LIT### 
e8a8 cd41de    call    $de41
e8ab dc1ae9    call    c,$e91a      ;Eval first old line number, if given
e8ae d5        push    de
e8af 110a00    ld      de,$000a     ;Default step
e8b2 cd41de    call    $de41
e8b5 dc48cf    call    c,$cf48      ;Eval step, if given
e8b8 cd37de    call    $de37

e8bb e1        pop     hl           ;HL=old line
e8bc eb        ex      de,hl        ;HL=step, DE=old line
e8bd e3        ex      (sp),hl      ;HL=new line, TOS=step
e8be eb        ex      de,hl        ;HL=old line, DE=new line
e8bf d5        push    de           ;Push new line number
e8c0 e5        push    hl           ;Push old line number
e8c1 cd64e8    call    $e864        ; find address of first new line
e8c4 d1        pop     de           ;Retrieve old line number
e8c5 e5        push    hl           ;Save new line address
e8c6 cd64e8    call    $e864        ; find address of first old line
e8c9 eb        ex      de,hl        ;DE=address of first old line
e8ca e1        pop     hl           ;HL=address of first new line
e8cb cdd8ff    call    $ffd8        
e8ce 381d      jr      c,$e8ed          ; (+$1d) Error if renumbering would re-order lines

e8d0 eb        ex      de,hl        ;HL=addr of first old
e8d1 d1        pop     de           ;DE=first new line number
e8d2 c1        pop     bc           ;BC=step
e8d3 d5        push    de           ;first new line number
e8d4 e5        push    hl           ;addr of first line

;;=renum scan loop
;Steps over the lines to be renumbered, this verifies the line numbers won't overflow
;before writing any changes
;DE=new line number
;HL=line address
e8d5 c5        push    bc           ;step
e8d6 4e        ld      c,(hl)       ;BC=line length
e8d7 23        inc     hl
e8d8 46        ld      b,(hl)
e8d9 78        ld      a,b          ;End of program?
e8da b1        or      c
e8db 2813      jr      z,$e8f0          ; (+$13)
e8dd 2b        dec     hl           ;HL=line addr

e8de 09        add     hl,bc        ;HL=line addr + line length
e8df 7e        ld      a,(hl)       ;End of program?
e8e0 23        inc     hl
e8e1 b6        or      (hl)
e8e2 280c      jr      z,$e8f0          ; (+$0c)
e8e4 2b        dec     hl

e8e5 c1        pop     bc           ;Step
e8e6 e5        push    hl           ;Current
e8e7 eb        ex      de,hl        ;HL=new line number
e8e8 09        add     hl,bc        ;Next line number
e8e9 eb        ex      de,hl        ;DE=next line number
e8ea e1        pop     hl           ;Current
e8eb 30e8      jr      nc,$e8d5         ; (-$18) Loop if no overflow on next line number

;;=raise Improper Argument error
e8ed c34dcb    jp      $cb4d			; Error: Improper Argument

;;=do renum
;Do the renumbering, having verified there won't be any errors
e8f0 0120e9    ld      bc,$e920     ; convert all line number tokens to line address tokens ##LABEL##
                                    ;this ensures any GOTOs, GOSUBs etc will still point to the correct place
e8f3 cdb9e9    call    $e9b9

e8f6 c1        pop     bc           ;Step
e8f7 e1        pop     hl           ;Addr of first line
e8f8 d1        pop     de           ;First new line number

;;=do renum loop
e8f9 c5        push    bc           ;Step
e8fa e5        push    hl           ;Addr of line
e8fb 4e        ld      c,(hl)       ;BC=line length
e8fc 23        inc     hl
e8fd 46        ld      b,(hl)
e8fe 23        inc     hl
e8ff 78        ld      a,b          ;End of program?
e900 b1        or      c
e901 280c      jr      z,$e90f          ; (+$0c)

e903 73        ld      (hl),e       ;Write new line number
e904 23        inc     hl
e905 72        ld      (hl),d
e906 23        inc     hl

e907 e1        pop     hl           ;Addr of line
e908 09        add     hl,bc        ;Add line length
e909 c1        pop     bc           ;Step
e90a eb        ex      de,hl        ;DE=line addr, HL=new line number
e90b 09        add     hl,bc        ;Next line number
e90c eb        ex      de,hl        ;HL=line addr, DE=new line number
e90d 18ea      jr      $e8f9            ; (-$16) Loop

;;=renum done
e90f e1        pop     hl           ;Cleanup stack
e910 e1        pop     hl
e911 0144e9    ld      bc,$e944     ;RENUM can't cope with any references to lines which don't exist ##LABEL##
e914 cdb9e9    call    $e9b9        ;This call will find any report them as errors to the user
e917 c358c0    jp      $c058

;;=eval renum parameter
e91a fe2c      cp      $2c          ;","
e91c c448cf    call    nz,$cf48
e91f c9        ret     

;;----------------------------------------------------------
;;=convert line numbers to line addresses callback
;Called via iterator__call_BC_for_each_statement
;Converts any line numbers (i.e GOTO, GOSUB etc) within a statement to line addresses
e920 cdfde9    call    $e9fd
e923 fe02      cp      $02
e925 d8        ret     c            ;End of line/end of statement - done

;; convert line number to line address

e926 fe1e      cp      $1e            ; 16-bit line number token
e928 20f6      jr      nz,$e920       ;Loop across any tokens we're not interested in

;; 16-bit line number
e92a e5        push    hl
e92b 56        ld      d,(hl)       ;DE=Line number
e92c 2b        dec     hl
e92d 5e        ld      e,(hl)
e92e cd64e8    call    $e864          ; find address of line
e931 300e      jr      nc,$e941     ;Not found - should never happen
e933 2b        dec     hl
e934 eb        ex      de,hl
e935 e1        pop     hl
e936 e5        push    hl

;; store 16-bit line address in reverse order
e937 72        ld      (hl),d
e938 2b        dec     hl
e939 73        ld      (hl),e
e93a 2b        dec     hl
;; Convert token to 16-bit line address
e93b 3e1d      ld      a,$1d          ; 16 bit line address pointer
e93d 77        ld      (hl),a

e93e 3221ae    ld      ($ae21),a

e941 e1        pop     hl
e942 18dc      jr      $e920           ;Loop 

;;-------------------------------------------------------
;;=report hanging line numbers
;Called via iterator__call_BC_for_each_statement
;Looks for any line number (i.e GOTO, GOSUB etc) and raises an error if it finds any
;RENUMbering will fail if there are any references to line numbers which don't exist,
;this routine finds any and reports them.
e944 cdfde9    call    $e9fd
e947 fe02      cp      $02
e949 d8        ret     c            ;End of line/end of statement - done

;; 16-bit line number?
e94a fe1e      cp      $1e          ; 16-bit line number token
e94c 20f6      jr      nz,$e944         ; (-$0a) Loop across any tokens we're not interested in

e94e e5        push    hl
e94f 56        ld      d,(hl)       ;DE=line number
e950 2b        dec     hl
e951 5e        ld      e,(hl)
e952 cdb5de    call    $deb5        ;Get current line number for error reporting?
e955 cde6cb    call    $cbe6        ;Report the error
e958 e1        pop     hl
e959 18e9      jr      $e944            ; (-$17) Loop

;;=============================================================================
;;=skip to ELSE statement
;Skip tokens within a line until the matching ELSE statement.
;We also need to skip nested IF statements. This is done by
;storing the nesting depth in the B register.
e95b 0600      ld      b,$00
e95d 2b        dec     hl
e95e 04        inc     b                ;Inc nesting depth
e95f cdfde9    call    $e9fd
e962 fea1      cp      $a1              ;IF token
e964 28f8      jr      z,$e95e          ; (-$08) - inc nesting depth
e966 fe02      cp      $02              ;end of statement
e968 30f5      jr      nc,$e95f         ; (-$0b)
e96a b7        or      a
e96b c8        ret     z                ;end of line - done

e96c cdfde9    call    $e9fd
e96f fe97      cp      $97              ;ELSE token
e971 20ef      jr      nz,$e962         ; (-$11)
e973 10ea      djnz    $e95f            ; (-$16) dec nesting depth and loop if non zero
e975 cd2cde    call    $de2c			; get next token skipping space
e978 04        inc     b
e979 c9        ret     

;;=============================================================================
;;=skip over matched braces
;Starting at a '[' or '(', skips to the matching ')' or ']'.
;Note that array dimensions can use either character and start and end characters need 
;not be of the same type!
;Maintains a nesting depth in the B register
e97a 7e        ld      a,(hl)
e97b fe5b      cp      $5b              ; '['
e97d 2803      jr      z,$e982          ; (+$03)
e97f fe28      cp      $28              ; '('
e981 c0        ret     nz

e982 0600      ld      b,$00            ;Initialise nesting depth
e984 04        inc     b
e985 cdfde9    call    $e9fd
e988 fe5b      cp      $5b              ;'['
e98a 28f8      jr      z,$e984          ; (-$08) Inc depth
e98c fe28      cp      $28              ;'('
e98e 28f4      jr      z,$e984          ; (-$0c) Inc depth
e990 fe5d      cp      $5d              ;']'
e992 280b      jr      z,$e99f          ; (+$0b) Dec depth
e994 fe29      cp      $29              ;')'
e996 2807      jr      z,$e99f          ; (+$07) Dec depth

e998 fe02      cp      $02              ;End of line/statement?
e99a 30e9      jr      nc,$e985         ; (-$17) No - loop

e99c c349cb    jp      $cb49			; Error: Syntax Error (unmatched braces)

e99f 10e4      djnz    $e985            ; (-$1c) Dec depth and loop
e9a1 23        inc     hl
e9a2 c9        ret     

;;=============================================================================
;;skip to end of statement
;; command DATA
;DATA <list of: <constant>>
;Declares constant data
e9a3 0601      ld      b,$01            ;End of statement token
e9a5 1808      jr      $e9af            ; (+$08)

;;========================================================================
;; command ' or REM
;REM <rest of line>
;' <rest of line>
;Remark
;Ignores eveything until the end of the line, including colons
;The single quote version is invalid in a DATA statement

e9a7 7e        ld      a,(hl)           ;Loop over everything until we hit an end of line ($00) value
e9a8 b7        or      a
e9a9 c8        ret     z
e9aa 23        inc     hl
e9ab 18fa      jr      $e9a7            ; (-$06)

;;========================================================================
;; skip to end of line
;;command ELSE
;We arrive at an ELSE because we've just executed the preceding THEN code.

e9ad 0600      ld      b,$00           ;End of line token

;;=skip to EOLN or token in B
e9af 2b        dec     hl

e9b0 cdfde9    call    $e9fd
e9b3 b7        or      a
e9b4 c8        ret     z                ;return at end of line

e9b5 b8        cp      b                ;check for token
e9b6 20f8      jr      nz,$e9b0         ; (-$08) Loop if no match
e9b8 c9        ret                    

;;===================================================================
;;=statement iterator
;Iterates over every statement and calls the code in BC for each.
;BC=address of subroutine to call.
;The subroutine returns with HL pointing to the end-of-statement or end-of-line marker
e9b9 cdb1de    call    $deb1            ;Fetch and preserve current line
e9bc e5        push    hl

e9bd 2a64ae    ld      hl,($ae64)       ;Address of first line

;Loop for each line
e9c0 23        inc     hl
e9c1 7e        ld      a,(hl)           ;Line length = 0?
e9c2 23        inc     hl
e9c3 b6        or      (hl)
e9c4 2813      jr      z,$e9d9          ; (+$13) If so, we're done
e9c6 23        inc     hl
e9c7 cdadde    call    $dead
e9ca 23        inc     hl

;Loop for each statement
e9cb c5        push    bc
e9cc cdfcff    call    $fffc			; JP (BC) - execute the code
e9cf c1        pop     bc
e9d0 2b        dec     hl
e9d1 cdefe9    call    $e9ef            ;Skip to next statment
e9d4 b7        or      a
e9d5 20f4      jr      nz,$e9cb         ; (-$0c) Not end of line, next statement

e9d7 18e7      jr      $e9c0            ; (-$19) Otherwise, next line

e9d9 e1        pop     hl
e9da c3adde    jp      $dead

;;=================================================
;;=skip until ELSE, THEN or next statement or error
;Raises an error if we hit the end of program before any of the above
;C=error code
e9dd cdefe9    call    $e9ef
e9e0 b7        or      a
e9e1 c0        ret     nz               ;Non-zero = not end of statement

e9e2 23        inc     hl
e9e3 7e        ld      a,(hl)
e9e4 23        inc     hl
e9e5 b6        or      (hl)             ;Test for end of program marker (line length zero)
e9e6 79        ld      a,c              ;Error code
e9e7 ca55cb    jp      z,$cb55
e9ea 23        inc     hl
e9eb 54        ld      d,h
e9ec 5d        ld      e,l
e9ed 23        inc     hl
e9ee c9        ret     

;;---------------------------------------------
;;=skip until ELSE, THEN or next statement
e9ef cdfde9    call    $e9fd
e9f2 fe02      cp      $02              ;End of line/end of statement
e9f4 d8        ret     c

e9f5 fe97      cp      $97             ;ELSE
e9f7 c8        ret     z

e9f8 feeb      cp      $eb              ;THEN
e9fa 20f3      jr      nz,$e9ef         ; (-$0d) Loop
e9fc c9        ret     

;;==============================================
;;=skip next tokenised item
;Advances over the next tokenised item, 
;including stepping over strings, comments, bar commands etc.
e9fd cd2cde    call    $de2c			; get next token skipping space
ea00 c8        ret     z

ea01 fe0e      cp      $0e              ;Tokens $02 to $0d are variables
ea03 3825      jr      c,$ea2a          ; (+$25)
ea05 fe20      cp      $20				; space
ea07 382b      jr      c,$ea34          ; Tokens $0e to $19 are number constants
ea09 fe22      cp      $22				; double quote
ea0b 2811      jr      z,$ea1e          
ea0d fe7c      cp      $7c              ;'|'
ea0f 281b      jr      z,$ea2c          ; (+$1b)
ea11 fec0      cp      $c0              ;"'" comment
ea13 2830      jr      z,$ea45          ; (+$30)
ea15 fec5      cp      $c5              ;REM
ea17 282c      jr      z,$ea45          ; (+$2c)
ea19 feff      cp      $ff              ; Extended/function tokens
ea1b c0        ret     nz

ea1c 23        inc     hl
ea1d c9        ret     

;;----------------------------------------------
;;=skip over string
;Skip until $22 - double quote - or end of line
ea1e 23        inc     hl
ea1f 7e        ld      a,(hl)
ea20 fe22      cp      $22              ;'"'
ea22 c8        ret     z                ;Done
ea23 b7        or      a                ;End of line?
ea24 20f8      jr      nz,$ea1e         ; (-$08) If not, loop

ea26 2b        dec     hl               ;Step back to last character of string
ea27 3e22      ld      a,$22            ;'"' - Return the correct token
ea29 c9        ret     

;;----------------------------------------------
;;=skip over variable
ea2a 23        inc     hl               ;Step over variable (data) pointer
ea2b 23        inc     hl

;;=skip over bar command
ea2c f5        push    af

ea2d 23        inc     hl               ;Skip over ASCII7 string - loop until bit 7 set
ea2e 7e        ld      a,(hl)
ea2f 17        rla     
ea30 30fb      jr      nc,$ea2d         ; (-$05)

ea32 f1        pop     af
ea33 c9        ret     

;;--------------------------------------------------
;;=skip over numbers
ea34 fe18      cp      $18              ;Tokens $0e to $18 encode numbers 0..10
                                        ;But shouldn't that be CP $19?
ea36 d8        ret     c

ea37 fe19      cp      $19				; token for 8-bit integer decimal value
ea39 2808      jr      z,$ea43          
ea3b fe1f      cp      $1f				; Tokens $1a to $1e are two-byte values. $1f is floating point value
ea3d 3803      jr      c,$ea42          

; skip 5 bytes (length of floating point value representation)
ea3f 23        inc     hl
ea40 23        inc     hl
ea41 23        inc     hl

;;=skip 2 bytes 
;(length of 16-bit values)
;; - 16 bit integer decimal value
;; - 16 bit integer binary value
;; - 16 bit integer hexidecimal value
ea42 23        inc     hl

;;=skip 1 byte 
;(length of 8-bit values)
ea43 23        inc     hl
ea44 c9        ret  
   
;;--------------------------------
;;=skip over comment
ea45 f5        push    af
ea46 23        inc     hl
ea47 cda7e9    call    $e9a7			; ' or REM
ea4a f1        pop     af
ea4b 2b        dec     hl
ea4c c9        ret     

;;==============================================================
;;=reset variable types and pointers
;Could also be removing links to allocated strings, arrays etc.
;Iterates over program and:
; - resets all variable type tokens to &0d (real)
; - clears the pointer to the variables data &0000
ea4d c5        push    bc
ea4e d5        push    de
ea4f e5        push    hl
ea50 015aea    ld      bc,$ea5a      ;##LABEL##
ea53 cdb9e9    call    $e9b9
ea56 e1        pop     hl
ea57 d1        pop     de
ea58 c1        pop     bc
ea59 c9        ret     

;;=callback for reset variable types and pointers
ea5a e5        push    hl
ea5b cdfde9    call    $e9fd
ea5e d1        pop     de
ea5f fe02      cp      $02
ea61 d8        ret     c                ;Exit at end of line or end (&00) of statement (&01)

ea62 fe0e      cp      $0e              ;Tokens $02 ..$0d are for variables
ea64 30f4      jr      nc,$ea5a         ; (-$0c) Loop for other tokens

ea66 eb        ex      de,hl            ;So, token is a variable
ea67 cd2cde    call    $de2c			; get next token skipping space
ea6a fe0d      cp      $0d
ea6c 3802      jr      c,$ea70          ; (+$02) Skip if token is already $0d (real)
ea6e 360d      ld      (hl),$0d         ;Otherwise change token to $0d (real)

ea70 23        inc     hl
ea71 af        xor     a                
ea72 77        ld      (hl),a           ;Next two bytes are the pointer to the data - reset them
ea73 23        inc     hl
ea74 77        ld      (hl),a
ea75 eb        ex      de,hl
ea76 18e2      jr      $ea5a            ; (-$1e) loop for more





;;***LoadSaveRun.asm
;;<< FILE HANDLING
;;< RUN, LOAD, CHAIN, MERGE, SAVE
;;==========================================================================
;; command RUN
;RUN <filename>
;Loads and runs a file

;RUN [<line number>]
;Runs the current program from the specified line number

ea78 cd3dde    call    $de3d
ea7b ed5b64ae  ld      de,($ae64)
ea7f 381d      jr      c,$ea9e          ; (+$1d) No parameters
ea81 fe1e      cp      $1e            ; 16-bit line number
ea83 2815      jr      z,$ea9a          ; (+$15)
ea85 fe1d      cp      $1d             ;Line pointer
ea87 2811      jr      z,$ea9a          ; (+$11)

ea89 cdd1ea    call    $ead1            ;Otherwise we're running a file
ea8c 21f1ea    ld      hl,$eaf1         ;If machine code program, call if via a firmware reset ###LABEL##
ea8f d213bd    jp      nc,$bd13			; firmware function: mc boot program

ea92 cd6dec    call    $ec6d            ;Load BASIC program...
ea95 2a64ae    ld      hl,($ae64)       ;...get execution address...
ea98 1812      jr      $eaac            ; (+$12) ...and RUN it


;;=RUN from line ptr
ea9a cd27e8    call    $e827
ea9d c0        ret     nz
;;=RUN from line number
ea9e d5        push    de
ea9f cd00d3    call    $d300			; close input and output streams
eaa2 cd78c1    call    $c178
eaa5 cd8fc1    call    $c18f
eaa8 cd62c1    call    $c162
eaab e1        pop     hl
;;=RUN from HL
eaac e3        ex      (sp),hl
eaad cd43bd    call    $bd43
eab0 e1        pop     hl
eab1 23        inc     hl
eab2 c377de    jp      $de77

;;========================================================================
;; command LOAD
;LOAD <filename>[,<address expression>]
;Loads the given file. If the file is binary, it will be loaded to memory at the 
;address is was written from unless address expression is given.
;If the file name is empty, loads the first file found on cassette
;If the first character of filename is ! it is removed and any messages suppressed.
;Binary files can only be loaded outside the BASIC program area - i.e above HIMEM

eab5 cdd1ea    call    $ead1
eab8 3006      jr      nc,$eac0         ; (+$06)
eaba cd6dec    call    $ec6d
eabd c358c0    jp      $c058

;;=do LOAD binary
eac0 e5        push    hl
eac1 cdabf5    call    $f5ab
eac4 2a26ae    ld      hl,($ae26)
eac7 cd83bc    call    $bc83			; firmware function: cas in direct
eaca ca37cc    jp      z,$cc37
eacd e1        pop     hl
eace c3edd2    jp      $d2ed			; CLOSEIN

;;--------------------------------------------
;;=eval filename and open for input
ead1 cd54ec    call    $ec54
ead4 e60e      and     $0e
ead6 ee02      xor     $02
ead8 2808      jr      z,$eae2          ; (+$08)
eada cd37de    call    $de37
eadd cd6fc1    call    $c16f
eae0 37        scf     
eae1 c9        ret     

;;=eval binary file load addr
eae2 cd41de    call    $de41            ;If we have another parameter...
eae5 dcf5ce    call    c,$cef5          ;...then it's the binary file load address. (If not retain the value from the file header)
eae8 ed5326ae  ld      ($ae26),de
eaec cd37de    call    $de37
eaef b7        or      a
eaf0 c9        ret     

;;==========================================================================
;;=callback to load a binary
;Called from MC_BOOT_PROGRAM when running a binary

eaf1 2a26ae    ld      hl,($ae26)		; load address
eaf4 cd83bc    call    $bc83			; firmware function: cas in direct
eaf7 e5        push    hl				; execution address
eaf8 dc7abc    call    c,$bc7a			; firmware function: cas in close
eafb e1        pop     hl				; execution address passed into firmare function "mc boot program"
eafc c9        ret     

;;==========================================================================
;; command CHAIN
;CHAIN <filename>[,<line number expression>]
;CHAIN MERGE <filename>[,[<line number expression>][,DELETE <line number range>]]
;Load and runs the given file, starting at the given line number, and retaining all current variables.
;If no line number is given execution starts at the first line.
;CHAIN deletes the current program and runs the new one
;CHAIN MERGE merges the new program with the existing one, optionally deleting 
;any lines in the current program within the specified range.

eafd eeab      xor     $ab              ;Token for MERGE, e.e CHAIN MERGE. Not sure how we get here though.
eaff 3228ae    ld      ($ae28),a        ;$00=(CHAIN) MERGE, other = CHAIN?
eb02 cc2cde    call    z,$de2c			; step over MERGE token?

eb05 cd54ec    call    $ec54

eb08 110000    ld      de,$0000         ;DE=default line number ###LIT###
eb0b cd41de    call    $de41
eb0e 3006      jr      nc,$eb16         ; (+$06) No parameter
eb10 7e        ld      a,(hl)           ;If parameter is blank use default
eb11 fe2c      cp      $2c              ;","
eb13 c4f5ce    call    nz,$cef5         ;Otherwise read line number

eb16 d5        push    de
eb17 cd41de    call    $de41
eb1a 3008      jr      nc,$eb24         ; (+$08) No more parameters

eb1c cd25de    call    $de25            ;Next parameter must start with DELETE
eb1f defb $92    ;Inline token to test for "DELETE"
eb20 cd00e8    call    $e800            ;DELETE specified line number range
eb23 37        scf     

;Parameters read, now do the CHAIN (MERGE)
eb24 f5        push    af
;Do some memory clean-up
eb25 cd37de    call    $de37
eb28 cd4dfb    call    $fb4d
eb2b cd64fc    call    $fc64
eb2e cd0ed6    call    $d60e
eb31 f1        pop     af

eb32 dc1ae8    call    c,$e81a      ;DELETE line range

eb35 cd47eb    call    $eb47        ;Load and (if needed) MERGE the file

eb38 d1        pop     de
eb39 2a64ae    ld      hl,($ae64)   ;Execution address...
eb3c 7a        ld      a,d
eb3d b3        or      e
eb3e c8        ret     z            ;if running from start of program

eb3f cdaade    call    $deaa        ;otherwise continue from where we left off...
eb42 cd5ce8    call    $e85c        ;...after verifying the line still exists
eb45 2b        dec     hl
eb46 c9        ret     

;;=do CHAIN and CHAIN MERGE load
eb47 3a28ae    ld      a,($ae28)
eb4a b7        or      a
eb4b ca62ec    jp      z,$ec62
eb4e cd89c1    call    $c189
eb51 c36dec    jp      $ec6d

;;========================================================================
;; command MERGE
;MERGE <filename>
;Merges a second program with the current one

eb54 cd54ec    call    $ec54
eb57 cd37de    call    $de37
eb5a cd78c1    call    $c178
eb5d cd62ec    call    $ec62
eb60 c358c0    jp      $c058

;;========================================================================
;;do MERGE
;The entire program is moved to the end of memory,
;During merge lines will be moved down or read into the bottom of
;memory after any lines already merged.
;As the file is read line numbers are compared,
;file line number < memory line number: insert file line
;file line number > memory line number: move memory line down
;file line number = memory line number: insert file line, skip over memory line
eb63 cd8fc1    call    $c18f
eb66 cd70e7    call    $e770        ; line address to line number
eb69 cd29f6    call    $f629
eb6c 2a66ae    ld      hl,($ae66)
eb6f eb        ex      de,hl
eb70 2a64ae    ld      hl,($ae64)
eb73 23        inc     hl
eb74 2266ae    ld      ($ae66),hl
eb77 eb        ex      de,hl
eb78 cde4ff    call    $ffe4			; BC = HL-DE
eb7b eb        ex      de,hl
eb7c cd07f7    call    $f707
eb7f eb        ex      de,hl
eb80 2b        dec     hl
eb81 edb8      lddr    
eb83 13        inc     de
eb84 eb        ex      de,hl

;;=merge file line loop
;Loop for each line in file
eb85 cd4bec    call    $ec4b            ;Read file line length
eb88 304a      jr      nc,$ebd4         ; (+$4a)
eb8a b3        or      e
eb8b 284c      jr      z,$ebd9          ; (+$4c) Line length = 0? EOF?
eb8d d5        push    de

eb8e cd4bec    call    $ec4b            ;Read file line number
eb91 3041      jr      nc,$ebd4         ; (+$41)

;;=merge move memory lines loop
;Loop over lines in memory moving each down in turn until we find a 
;line to insert or replace
eb93 7e        ld      a,(hl)           ;Memory line length zero = end of program
eb94 23        inc     hl
eb95 b6        or      (hl)
eb96 2b        dec     hl
eb97 281b      jr      z,$ebb4          ; (+$1b)
eb99 e5        push    hl
eb9a 23        inc     hl
eb9b 23        inc     hl
eb9c 7e        ld      a,(hl)           ;HL=memory line number
eb9d 23        inc     hl
eb9e 66        ld      h,(hl)
eb9f 6f        ld      l,a
eba0 cdd8ff    call    $ffd8 ; HL=DE? Compare file line number to memory line number
eba3 e1        pop     hl
eba4 2807      jr      z,$ebad          ; (+$07)
eba6 300c      jr      nc,$ebb4         ; (+$0c)
eba8 cd19ec    call    $ec19
ebab 18e6      jr      $eb93            ; (-$1a)

;;=merge replace line
;Found a line with the same number so overwrite it
ebad d5        push    de
ebae 5e        ld      e,(hl)       ;DE=memory line length
ebaf 23        inc     hl
ebb0 56        ld      d,(hl)
ebb1 2b        dec     hl
ebb2 19        add     hl,de        ;Add length to current pointer - i.e. addr of next line
ebb3 d1        pop     de
;;=merge insert line
ebb4 e5        push    hl
ebb5 2a66ae    ld      hl,($ae66)   ;HL=addr to write to
ebb8 23        inc     hl
ebb9 23        inc     hl
ebba 73        ld      (hl),e       ;Write file line number
ebbb 23        inc     hl
ebbc 72        ld      (hl),d
ebbd 111d00    ld      de,$001d
ebc0 19        add     hl,de        ;HL=curr + 1d
ebc1 eb        ex      de,hl        ;DE=curr + 1d
ebc2 e1        pop     hl           ;HL=memory curr
ebc3 e3        ex      (sp),hl      ;TOS=memory curr, HL=mem line length
ebc4 eb        ex      de,hl        ;DE=mem line length, HL=curr + 1d
ebc5 19        add     hl,de        ;HL=curr + mem line length + 1d
ebc6 eb        ex      de,hl        ;DE=curr + mem line length + 1d, HL=mem line length
ebc7 e3        ex      (sp),hl      ;TOS=mem line length, HL=memory curr
ebc8 cdd8ff    call    $ffd8 ; HL=DE? Is new end-of-line > start of memory line at top of memory
ebcb 3825      jr      c,$ebf2          ; (+$25) If so we're out of memory
ebcd e3        ex      (sp),hl      ;TOS=memory curr, HL=mem line length
ebce cd2cec    call    $ec2c
ebd1 e1        pop     hl
ebd2 38b1      jr      c,$eb85          ; (-$4f) Loop if no errors

;;=merge file error
ebd4 cdd9eb    call    $ebd9
ebd7 1836      jr      $ec0f            ; (+$36)

;;=merge error cleanup
;Move remaining lines down in memory
ebd9 7e        ld      a,(hl)       ;Test for end of program
ebda 23        inc     hl
ebdb b6        or      (hl)
ebdc 2b        dec     hl
ebdd 2805      jr      z,$ebe4          ; (+$05)
ebdf cd19ec    call    $ec19
ebe2 18f5      jr      $ebd9            ; (-$0b)

ebe4 2a66ae    ld      hl,($ae66)
ebe7 af        xor     a
ebe8 77        ld      (hl),a       ;Write end of program marker
ebe9 23        inc     hl
ebea 77        ld      (hl),a
ebeb 23        inc     hl
ebec 2266ae    ld      ($ae66),hl
ebef c3b0ec    jp      $ecb0

;;=merge out of memory
ebf2 cdd9eb    call    $ebd9
ebf5 cdaade    call    $deaa
ebf8 3e07      ld      a,$07            ;Memory full error
ebfa 1815      jr      $ec11            ; (+$15)

;;=merge read char
;Returns carry true if no error
ebfc cd80bc    call    $bc80			; firmware function: cas in char
ebff d8        ret     c

ec00 fe1a      cp      $1a              ;Disc error: CP/M end of file
ec02 37        scf     
ec03 c8        ret     z

ec04 3291ad    ld      ($ad91),a
ec07 3f        ccf     
ec08 c9        ret     

;;=raise disc error
ec09 3291ad    ld      ($ad91),a
ec0c cd6fc1    call    $c16f
;;=raise EOF error
ec0f 3e18      ld      a,$18            ;EOF met error
;;=raise error
;Error code in A
ec11 f5        push    af
ec12 cd00d3    call    $d300					; close input and output streams
ec15 f1        pop     af
ec16 c355cb    jp      $cb55

;;=merge move line
;Move memory line to end of merged program
ec19 c5        push    bc
ec1a d5        push    de
ec1b 4e        ld      c,(hl)           ;BC=line length
ec1c 23        inc     hl
ec1d 46        ld      b,(hl)
ec1e 2b        dec     hl
ec1f ed5b66ae  ld      de,($ae66)
ec23 edb0      ldir                     ;Move line
ec25 ed5366ae  ld      ($ae66),de
ec29 d1        pop     de
ec2a c1        pop     bc
ec2b c9        ret     

;;=merge do read line
;Line number has already been written by merg_insert_line
ec2c eb        ex      de,hl            ;DE=mem line length
ec2d 2a66ae    ld      hl,($ae66)
ec30 73        ld      (hl),e           ;Write line length
ec31 23        inc     hl
ec32 72        ld      (hl),d
ec33 23        inc     hl
ec34 23        inc     hl
ec35 23        inc     hl               ;HL=write addr addr
ec36 1b        dec     de
ec37 1b        dec     de
ec38 1b        dec     de

;;=merge read line loop
ec39 1b        dec     de               ;DE=remaining bytes counter
ec3a 7a        ld      a,d
ec3b b3        or      e                ;Test if DE=0
ec3c 2808      jr      z,$ec46          ; (+$08)

ec3e cdfceb    call    $ebfc            ;Copy byte from char to memory
ec41 77        ld      (hl),a
ec42 23        inc     hl
ec43 38f4      jr      c,$ec39          ; (-$0c) Loop unless file error

ec45 c9        ret     

ec46 2266ae    ld      ($ae66),hl   ;Line copied
ec49 37        scf     
ec4a c9        ret     

;;=merge read word to DE
ec4b cdfceb    call    $ebfc
ec4e 5f        ld      e,a
ec4f dcfceb    call    c,$ebfc
ec52 57        ld      d,a
ec53 c9        ret     

;;=read filename and open for input
ec54 cd00d3    call    $d300			; close input and output streams
ec57 cdbed2    call    $d2be
ec5a 3229ae    ld      ($ae29),a
ec5d ed432aae  ld      ($ae2a),bc
ec61 c9        ret     

;;=========
;;=validate and MERGE
ec62 3a29ae    ld      a,($ae29)
ec65 b7        or      a
ec66 ca63eb    jp      z,$eb63          ;Type 0 = tokenised, unprotected
ec69 fe16      cp      $16              ;ASCII file?
ec6b 200b      jr      nz,$ec78         ; (+$0b)

;;=validate and LOAD BASIC
ec6d 3a29ae    ld      a,($ae29)
ec70 fe16      cp      $16              ;ASCII file?
ec72 2842      jr      z,$ecb6          ; (+$42)
ec74 e6fe      and     $fe              ;Bit 0 set = protected
ec76 2804      jr      z,$ec7c          ; (+$04)

;;=raise File type error
ec78 cd45cb    call    $cb45
ec7b defb $19                         ;Inline error code: File type error

;;=============================================
;;=load tokenised file
ec7c cd8fc1    call    $c18f
ec7f cd29f6    call    $f629

;Validate we have enough free space
ec82 ed4b64ae  ld      bc,($ae64)       ;BC=size of lower memory
ec86 03        inc     bc
ec87 cd07f7    call    $f707            ;HL=upper memory?
ec8a 1180ff    ld      de,$ff80        ;DE=buffer space? ###LIT###
ec8d 19        add     hl,de
ec8e b7        or      a
ec8f ed42      sbc     hl,bc        ;HL=free space
ec91 ed5b2aae  ld      de,($ae2a)   ;DE=file length
ec95 d4d8ff    call    nc,$ffd8 ; HL=DE?
ec98 daf5eb    jp      c,$ebf5      ;Error if not enough memory

ec9b eb        ex      de,hl        ;DE=file length
ec9c 09        add     hl,bc        ;HL=last available addr?
ec9d 2266ae    ld      ($ae66),hl

eca0 3a29ae    ld      a,($ae29)
eca3 1f        rra     
eca4 9f        sbc     a,a
eca5 322cae    ld      ($ae2c),a

eca8 60        ld      h,b          ;HL=start of program space
eca9 69        ld      l,c
ecaa cd83bc    call    $bc83			; firmware function: CAS IN DIRECT - load file
ecad ca09ec    jp      z,$ec09

;;=move vars and arrays down and close input file
ecb0 cd3cf6    call    $f63c
ecb3 c3edd2    jp      $d2ed			; CLOSEIN

;;=load ASCII file
ecb6 cd8fc1    call    $c18f
ecb9 cdaade    call    $deaa
ecbc cd29f6    call    $f629

;;=load ASCII line loop
ecbf cd0acb    call    $cb0a            ;Read line into buffer
ecc2 30ec      jr      nc,$ecb0         ; (-$14) Error or end of file
ecc4 cd4dde    call    $de4d            ; skip loading whitespace
ecc7 b7        or      a                ;Empty buffer?
ecc8 c4cdec    call    nz,$eccd         ;Tokise line (and append to program)
eccb 18f2      jr      $ecbf            ; (-$0e) Loop for more

;;=load ASCII tokenise line
eccd cdcfee    call    $eecf            ;Convert line number?
ecd0 daa5e7    jp      c,$e7a5

ecd3 3e15      ld      a,$15            ;Direct command found error
ecd5 2802      jr      z,$ecd9          ; (+$02) Line with no line number?
ecd7 3e06      ld      a,$06            ;Overflow error
ecd9 c355cb    jp      $cb55

;;========================================================================
;; command SAVE
;SAVE <file name>[,<file type>[,<binary parameters>]]
;Saves a file
;File type:
;   None:   Tokenised BASIC
;   A:      ASCII BASIC
;   P:      Protected BASIC
;   B:      Binary file
;Binary parameters (only for binary files):
;<start address>,<length>[,<entry point>]
;Entry point is used if the file is loaded with RUN

ecdc cd00d3    call    $d300			;; close input and output streams
ecdf cda8d2    call    $d2a8			;; OPENOUT - reads filename parameter and opens the file
ece2 0600      ld      b,$00            ;File type for unprotected tokenised BASIC
ece4 cd41de    call    $de41            ;Is there a file type parameter?
ece7 3025      jr      nc,$ed0e         ; (+$25)

ece9 cd25de    call    $de25			;read file type letter
ecec defb $0d  ;inline token to test CR
eced 23        inc     hl
ecee 23        inc     hl
ecef 7e        ld      a,(hl)			; parameter (,A ,B ,P)
ecf0 e6df      and     $df
ecf2 f249cb    jp      p,$cb49			; Error: Syntax Error - invalid file type parameter

ecf5 e5        push    hl
ecf6 2100ed    ld      hl,$ed00
ecf9 cdb4ff    call    $ffb4            ;Lookup parameter in table
ecfc e3        ex      (sp),hl          ;Put result (code address) onto TOS so next line RETurns into it
ecfd c32cde    jp      $de2c			; get next token skipping space

;;=save parameters list
ed00 defb $03            ;Number of parameter options
ed01 defw $cb49	     	; Error if not found: Syntax Error   ##LABEL##

defb $c1					;; ,A
defw $ed53                  ;  ##LABEL##
defb $c2					;; ,B
defw $ed2b                  ;  ##LABEL##
defb $d0					;; ,P
defw $ed0c                  ;  ##LABEL##

;;---------------------------------------------------
;; SAVE ,P
;;=save BASIC protected
ed0c 0601      ld      b,$01        ;File type for protected tokenised BASIC

;;=save BASIC tokenised
ed0e cd37de	   call    $de37
ed11 e5        push hl
ed12 c5        push    bc
;Prepare code for saving
ed13 cd70e7    call    $e770        ; line address to line number
ed16 cd4dea    call    $ea4d
;Calc file (program) size
ed19 2a64ae    ld      hl,($ae64)
ed1c 23        inc     hl           ;HL=first byte of program
ed1d eb        ex      de,hl
ed1e 2a66ae    ld      hl,($ae66)   ;HL=end of program
ed21 b7        or      a            ;Clear carry
ed22 ed52      sbc     hl,de        ;HL=length of program
ed24 eb        ex      de,hl
ed25 f1        pop     af           ;A=file type
ed26 010000    ld      bc,$0000         ;Execution address (not valid for BASIC) ##LIT##
ed29 1820      jr      $ed4b            ; (+$20)

;; SAVE ,B
;;=save binary
ed2b cd15de    call    $de15 ; check for comma			; start
ed2e cdf5ce    call    $cef5        ;Read start addr parameter
ed31 d5        push    de
ed32 cd15de    call    $de15 ; check for comma			; length
ed35 cdf5ce    call    $cef5        ;Read length parameter
ed38 d5        push    de
ed39 cd41de    call    $de41			; execution
ed3c 110000    ld      de,$0000         ;Default execution address ##LIT##
ed3f dcf5ce    call    c,$cef5          ;Read execution address parameter, if present
ed42 d5        push    de
ed43 cd37de    call    $de37            ;Error if more parameters

ed46 3e02      ld      a,$02			;; File type binary
ed48 c1        pop     bc               ;Execution address
ed49 d1        pop     de               ;File length
ed4a e3        ex      (sp),hl          ;HL=start addr

;;=do binary file save
ed4b cd98bc    call    $bc98			;; firmware function: cas out direct - write the file
ed4e d237cc    jp      nc,$cc37         ;abort if error
ed51 1817      jr      $ed6a            ; (+$17)

;; SAVE ,A
;;=save ASCII
ed53 cd37de    call    $de37
ed56 e5        push    hl
ed57 3e09      ld      a,$09            ;Select file as output stream
ed59 cda6c1    call    $c1a6
ed5c f5        push    af               ;Save previous stream

ed5d 010100    ld      bc,$0001         ;starting line number
ed60 11ffff    ld      de,$ffff         ;ending line number ##LIT##

ed63 cde3e1    call    $e1e3		    ;LIST (to file stream)

ed66 f1        pop     af               ;Restore previous stream
ed67 cda6c1    call    $c1a6

;;=save close file
ed6a cdf5d2    call    $d2f5			; CLOSEOUT
ed6d e1        pop     hl
ed6e c9        ret     




;;***StringsToNumbers.asm
;;<< STRINGS TO NUMBERS
;;==============================
;;convert string to number
;Converts a string which can have a preceding + or - sign

ed6f cd0fee    call    $ee0f
ed72 2005      jr      nz,$ed79         ; (+$05) No plus or minus sign
ed74 cd4dde    call    $de4d ; skip space, lf or tab
ed77 182f      jr      $eda8            ; (+$2f)

ed79 fe26      cp      $26              ;'&' - Hex prefix
ed7b 281c      jr      z,$ed99          ; (+$1c)
ed7d cda0ff    call    $ffa0
ed80 3826      jr      c,$eda8          ; (+$26) Carry set if decimal digit or period

ed82 cd38ff    call    $ff38
ed85 cd1bff    call    $ff1b
ed88 37        scf     
ed89 c9        ret     

;;=convert string to positive number
;Converts a string which doesn't have a preceding sign. The result will always be positive
ed8a e5        push    hl
ed8b cd92ed    call    $ed92
ed8e d1        pop     de
ed8f d8        ret     c

ed90 eb        ex      de,hl
ed91 c9        ret     

ed92 1600      ld      d,$00            ;Positive number
ed94 7e        ld      a,(hl)
ed95 fe26      cp      $26              ;'&' - Hex prefix
ed97 200f      jr      nz,$eda8         ; (+$0f)

;;=convert hex or binary to accumulator
ed99 cde7ee    call    $eee7
ed9c eb        ex      de,hl
ed9d f5        push    af
ed9e cd35ff    call    $ff35
eda1 f1        pop     af
eda2 eb        ex      de,hl
eda3 d8        ret     c

eda4 c8        ret     z

eda5 c3becb    jp      $cbbe

;;=convert decimal
;D=&00 if positive, &ff if negative
eda8 e5        push    hl
eda9 7e        ld      a,(hl)
edaa 23        inc     hl
edab fe2e      cp      $2e          ;'.' - prefix for a float
edad cc4dde    call    z,$de4d ; skip space, lf or tab
edb0 cda4ff    call    $ffa4			;; test if ASCII character represents a decimal number digit
edb3 e1        pop     hl
edb4 3806      jr      c,$edbc          ; (+$06) Carry set = digit
edb6 7e        ld      a,(hl)
edb7 ee2e      xor     $2e              ;Set zero flag if char is a period...
edb9 c0        ret     nz

edba 23        inc     hl               ;...and if so step over it
edbb c9        ret     

;Copy ASCII number to pre-conversion buffer. Digits are converted from ASCII to binary equivalents
edbc cd38ff    call    $ff38            ;Convert as an integer until we know otherwise
edbf d5        push    de
edc0 010000    ld      bc,$0000         ;Initialise counters ##LIT##
edc3 112dae    ld      de,$ae2d
edc6 cd1eee    call    $ee1e
edc9 fe2e      cp      $2e              ;'.'
edcb 200b      jr      nz,$edd8         ; (+$0b) - no period - all digits read

;period found - number is a real
edcd cd94ee    call    $ee94
edd0 cd41ff    call    $ff41
edd3 0c        inc     c
edd4 cd1eee    call    $ee1e            ;Read remaining decimal digits
edd7 0d        dec     c

edd8 eb        ex      de,hl
edd9 36ff      ld      (hl),$ff
eddb eb        ex      de,hl
eddc cd42ee    call    $ee42            ;Test for (and copy if found) exponent
eddf d1        pop     de
ede0 5f        ld      e,a              ;E=exponent
ede1 e5        push    hl
ede2 d5        push    de

ede3 212dae    ld      hl,$ae2d
ede6 cd99ee    call    $ee99            ;Do the conversion?
ede9 d1        pop     de

edea cd66ff    call    $ff66            ;Test result type?
eded 3008      jr      nc,$edf7         ; (+$08) Real?

edef e5        push    hl
edf0 42        ld      b,d              ;B=sign?
edf1 cd2cfe    call    $fe2c            ;Attempt to store as an int
edf4 e1        pop     hl
edf5 3811      jr      c,$ee08          ; (+$11) If succeeds then were done...
                                        ;...else store as a real
edf7 7a        ld      a,d              ;A=sign?
edf8 4e        ld      c,(hl)
edf9 23        inc     hl
edfa cdb8bd    call    $bdb8            ;Convert binary to real?
edfd 7b        ld      a,e              ;A=exponent
edfe cd79bd    call    $bd79            ;Exponent?
ee01 eb        ex      de,hl
ee02 cd3eff    call    $ff3e
ee05 dc61bd    call    c,$bd61          ;Copy to accumulator?

ee08 3e0a      ld      a,$0a            ;We found a decimal number?
ee0a e1        pop     hl
ee0b d8        ret     c                ;Return if no errors

ee0c c3becb    jp      $cbbe

;;=test for plus or minus sign
;If next char is:
;'-': returns Zero set, D=$ff
;'+': returns Zero set, D=$00
;Otherwise returns Zero clear
ee0f cd4dde    call    $de4d ; skip space, lf or tab
ee12 23        inc     hl
ee13 16ff      ld      d,$ff
ee15 fe2d      cp      $2d               ;'-'
ee17 c8        ret     z

ee18 14        inc     d
ee19 fe2b      cp      $2b              ;'+'
ee1b c8        ret     z

ee1c 2b        dec     hl
ee1d c9        ret     

;;=copy while decimal digits
;Copies decimal digits to buffer in DE, ignoring leading zeros (B=0) and 
;ending at the first non-digit.
;Following char is returned in A
;Digits are converted from ASCII to binary equivalents
;B=count of digits copied to buffer
;C will be non-zero if more than one digit has been copied
ee1e e5        push    hl
ee1f cd4dde    call    $de4d ; skip space, lf or tab
ee22 23        inc     hl
ee23 cda4ff    call    $ffa4			;; test if ASCII character represents a decimal number digit
ee26 3804      jr      c,$ee2c          ; (+$04) Carry set if decimal digit
ee28 e1        pop     hl
ee29 c3abff    jp      $ffab			;; convert character to upper case

ee2c e3        ex      (sp),hl
ee2d e1        pop     hl
ee2e d630      sub     $30              ;Converts ASCII number to decimal value
ee30 12        ld      (de),a           ;Write digit to buffer
ee31 b0        or      b                ;If digit=0 and digits copied = 0, result will be zero - i.e. leading zero
ee32 2807      jr      z,$ee3b          ; (+$07) Step over leading zeroes
ee34 78        ld      a,b
ee35 04        inc     b
ee36 fe0c      cp      $0c              ;Max buffer length?
ee38 3001      jr      nc,$ee3b         ; (+$01) Buffer overflow - ignore digits
ee3a 13        inc     de
ee3b 79        ld      a,c
ee3c b7        or      a
ee3d 28df      jr      z,$ee1e          ; (-$21)
ee3f 0c        inc     c
ee40 18dc      jr      $ee1e            

;;=test for and eval exponent
ee42 fe45      cp      $45				;; 'E' - exponent
ee44 2010      jr      nz,$ee56         ;Not exponent
         
ee46 e5        push    hl
ee47 cd94ee    call    $ee94
ee4a cd0fee    call    $ee0f
ee4d cc4dde    call    z,$de4d ; skip space, lf or tab
ee50 cda4ff    call    $ffa4			;; test if ASCII character represents a decimal number digit
ee53 3804      jr      c,$ee59          ; (+$04)
ee55 e1        pop     hl

ee56 af        xor     a                ;Exponent is zero
ee57 181e      jr      $ee77            ; (+$1e)

;;=eval exponent
ee59 e3        ex      (sp),hl
ee5a e1        pop     hl
ee5b cd41ff    call    $ff41
ee5e d5        push    de
ee5f c5        push    bc
ee60 cd00ef    call    $ef00
ee63 3009      jr      nc,$ee6e         ; (+$09)
ee65 7b        ld      a,e
ee66 d664      sub     $64              ;Maximum exponent?
ee68 7a        ld      a,d
ee69 de00      sbc     a,$00
ee6b 7b        ld      a,e
ee6c 3802      jr      c,$ee70          ; (+$02)
ee6e 3e7f      ld      a,$7f
ee70 c1        pop     bc
ee71 d1        pop     de
ee72 14        inc     d                ;D=sign
ee73 2002      jr      nz,$ee77         ; (+$02)
ee75 2f        cpl     
ee76 3c        inc     a

;A=exponent - encode?
ee77 c680      add     a,$80
ee79 5f        ld      e,a
ee7a 78        ld      a,b
ee7b d60c      sub     $0c
ee7d 3001      jr      nc,$ee80         ; (+$01)
ee7f af        xor     a
ee80 91        sub     c
ee81 3009      jr      nc,$ee8c         ; (+$09)
ee83 83        add     a,e
ee84 3801      jr      c,$ee87          ; (+$01)
ee86 af        xor     a
ee87 fe01      cp      $01
ee89 ce80      adc     a,$80
ee8b c9        ret     

ee8c 83        add     a,e
ee8d 3002      jr      nc,$ee91         ; (+$02)
ee8f 3eff      ld      a,$ff           
ee91 d680      sub     $80
ee93 c9        ret     

;;=skip whitespace
ee94 cd4dde    call    $de4d ; skip space, lf or tab
ee97 23        inc     hl
ee98 c9        ret     

;;=do decimal conversion
ee99 eb        ex      de,hl
ee9a 213fae    ld      hl,$ae3e + 1     ;Zero buffer for result
ee9d 010105    ld      bc,$0501         ;B=counter for next loop;C=count of how many bytes we need to multiply
eea0 2b        dec     hl
eea1 3600      ld      (hl),$00
eea3 10fb      djnz    $eea0            ; (-$05)
eea5 1a        ld      a,(de)
eea6 feff      cp      $ff              ;End of ASCII digits marker
eea8 c8        ret     z

eea9 77        ld      (hl),a           ;Write first digit

;;=decimal convert loop for digits in input buffer
eeaa 213aae    ld      hl,$ae3a
eead 13        inc     de
eeae 1a        ld      a,(de)           ;Read next digit
eeaf feff      cp      $ff              ;End of buffer marker
eeb1 c8        ret     z

eeb2 d5        push    de
eeb3 41        ld      b,c              ;Source digit counter
eeb4 1600      ld      d,$00

;;=decimal convert multiply loop
eeb6 e5        push    hl
eeb7 5e        ld      e,(hl)
eeb8 62        ld      h,d
eeb9 6b        ld      l,e
eeba 29        add     hl,hl
eebb 29        add     hl,hl
eebc 19        add     hl,de
eebd 29        add     hl,hl
eebe 5f        ld      e,a
eebf 19        add     hl,de
eec0 5d        ld      e,l
eec1 7c        ld      a,h
eec2 e1        pop     hl
eec3 73        ld      (hl),e
eec4 23        inc     hl
eec5 10ef      djnz    $eeb6            ; (-$11)

eec7 d1        pop     de
eec8 b7        or      a
eec9 28df      jr      z,$eeaa          ; (-$21)
eecb 77        ld      (hl),a
eecc 0c        inc     c
eecd 18db      jr      $eeaa            ; (-$25)

;;=======================================================================
;;parse line number
eecf c5        push    bc
eed0 e5        push    hl
eed1 cd00ef    call    $ef00
eed4 eb        ex      de,hl
eed5 cd35ff    call    $ff35
eed8 eb        ex      de,hl
eed9 c1        pop     bc
eeda 3006      jr      nc,$eee2         ; (+$06)
eedc 7a        ld      a,d
eedd b3        or      e
eede c6ff      add     a,$ff
eee0 3803      jr      c,$eee5          ; (+$03)
eee2 50        ld      d,b
eee3 59        ld      e,c
eee4 eb        ex      de,hl
eee5 c1        pop     bc
eee6 c9        ret     


;;=======================================================================
;;convert hex or binary to HL
eee7 23        inc     hl
eee8 cd4dde    call    $de4d 			; skip space, lf or tab
eeeb cdabff    call    $ffab			;; convert character to upper case

eeee 0602      ld      b,$02			;; base 2
eef0 fe58      cp      $58				;; X
eef2 2806      jr      z,$eefa          

eef4 0610      ld      b,$10			;; base 16
eef6 fe48      cp      $48				;; H
eef8 2004      jr      nz,$eefe          

eefa 23        inc     hl
eefb cd4dde    call    $de4d 			; skip space, lf or tab
eefe 1802      jr      $ef02            ; (+$02)

;;=======================================================================
;; convert decimal integer
ef00 060a      ld      b,$0a			;; base 10

;;=convert number using base in B
; B = base: 2 for binary, 16 for hexadecimal, 10 for decimal
ef02 eb        ex      de,hl
ef03 cd2cef    call    $ef2c

ef06 2600      ld      h,$00            ;Result
ef08 6f        ld      l,a
ef09 301e      jr      nc,$ef29         ; (+$1e) Digit conversion failed

ef0b 0e00      ld      c,$00            ;Overflow flag?

;;=based conversion loop
ef0d cd2cef    call    $ef2c            ;Next digit
ef10 3014      jr      nc,$ef26         ; (+$14) End of digits
ef12 d5        push    de

ef13 1600      ld      d,$00            ;DE=new digit
ef15 5f        ld      e,a              
ef16 d5        push    de

ef17 58        ld      e,b              ;DE=base
ef18 cd72dd    call    $dd72
ef1b d1        pop     de
ef1c 3803      jr      c,$ef21          ; (+$03) Overflow
ef1e 19        add     hl,de
ef1f 3002      jr      nc,$ef23         ; (+$02) No overflow
ef21 0eff      ld      c,$ff            ;Overflow flag?
ef23 d1        pop     de
ef24 18e7      jr      $ef0d            ; (-$19) Loop for next digit

ef26 79        ld      a,c
ef27 fe01      cp      $01
ef29 eb        ex      de,hl
ef2a 78        ld      a,b
ef2b c9        ret     

;;=convert digit using base in B
;Convert single ASCII digit to binary in selected base
ef2c 1a        ld      a,(de)
ef2d 13        inc     de
ef2e cda4ff    call    $ffa4			;; test if ASCII character represents a decimal number digit
ef31 380a      jr      c,$ef3d          ; (+$0a) Carry set if decimal digit
ef33 cdabff    call    $ffab			;; convert character to upper case
ef36 fe41      cp      $41              ;'A'
ef38 3f        ccf     
ef39 3005      jr      nc,$ef40         ; (+$05)
ef3b d607      sub     $07              ;Move ASCII letters to 'follow' ASCII numbers
ef3d d630      sub     $30              ;'0' - convert ASCII to binary
ef3f b8        cp      b                ;Validate we're within given base
ef40 d8        ret     c

ef41 1b        dec     de
ef42 af        xor     a
ef43 c9        ret     




;;***NumbersToStrings.asm
;;<< NUMBERS TO STRINGS
;;============================================
;;display decimal number
;Display the value in HL to the current stream
ef44 cd4aef    call    $ef4a
ef47 c38bc3    jp      $c38b		;; display 0 terminated string

;;=convert int in HL to string
;Convert the value in HL to a string. Could be integer or real depending on the size of the number
ef4a d5        push    de
ef4b c5        push    bc
ef4c cd35ff    call    $ff35
ef4f cd03fd    call    $fd03        ;HL=accumulator + 1; B=0; E=0; C=2 (size of int)
ef52 af        xor     a            ;Conversion format?
ef53 cd72ef    call    $ef72
ef56 23        inc     hl
ef57 c1        pop     bc
ef58 d1        pop     de
ef59 c9        ret     

;;=convert accumulator to string
;Converts accumulator to 'natural' format - ie. unspecified, could be real, integer or exponent 
;depending on the number
ef5a d5        push    de
ef5b c5        push    bc
ef5c af        xor     a            ;Conversion format?
ef5d cd6aef    call    $ef6a
ef60 c1        pop     bc
ef61 d1        pop     de
ef62 7e        ld      a,(hl)
ef63 fe20      cp      $20				;; ' '
ef65 c0        ret     nz

ef66 23        inc     hl
ef67 c9        ret     

;;==================================
;;conv number to decimal string
;Converts accumulator to decimal integer string
ef68 3e40      ld      a,$40            ;Integer

;;=convert number to string by format
;A=Display format
;If bit 7 of A is clear then the format is as follows:
;$00=Flexible (could be real or integer depending on the number)
;$40=Integer
;(Other values are possible but unlikely)

;If bit 7 of A is set then the value is formatted with a format string (i.e. PRINT USING or DEC$)
;using bitwise values as follows
;Bit    Hex
;7      $80 Always set - indicates we have a format 
;            (as opposed to calling the conversion routines without a format)
;6      &40 Exponent ('^^^^' at the end)
;5      $20 Asterisk prefix
;4      $10 If clear then show sign prefix, otherwise sign suffix
;3      $08 If bit 4 set, bit 3 set specifies always show sign prefix, even for positive numbers
;                         bit 3 clear specifies sign prefix only if negative
;           If bit 4 clear, bit 3 clear specifies sign suffix of '-' or space
;                           bit 3 set specifies sign suffix of '-' or '+'
;2      &04 Currency symbol prefix (actual symbol is stored at &ae54)
;1      &02 Contains comma(s)
;(Bit zero is used as a flag when doing conversions)
;
;DE=Address of format template (prob not used)
;B=length of format template (prob not used)
;H=number of chars before the decimal point
;L=number of chars after, and including, the decimal point
ef6a 2252ae    ld      ($ae52),hl       ;Store char counts
ef6d f5        push    af
ef6e cdf3fc    call    $fcf3            ;HL=accumulator plus 1, 
ef71 f1        pop     af

;;=do number to string
;For an integer value:
;For a real value (i.e. a value which has a fractional part or which is too large for an integer):
;REAL_prepare_for_decimal (in he firmware) is called prior to this.
;I /think/ this unpacks the value into BCD and sets up registers
;
;Either way, by the time we arrive here:
;A=format string
;B bit 7=set for -ve, clear for +ve
;C=Number of bytes in the input buffer. $02=16-bit integer, $01=8-bit integer, Real=??
;E=$00 for integers, possible number of digits for real
;HL=last used byte of source buffer
ef72 c5        push    bc
ef73 57        ld      d,a          ;D=format
ef74 d5        push    de
ef75 cd8af1    call    $f18a        ;Converts to a raw ASCII formatted number
                                    ;Returns: C=number of chars digits in number
                                    ;HL=addr of first digit
ef78 d1        pop     de           ;D=format, E=number of digits processed(??)
ef79 cd96ef    call    $ef96
ef7c cd1af1    call    $f11a
ef7f f1        pop     af
ef80 5f        ld      e,a
ef81 78        ld      a,b
ef82 b7        or      a
ef83 cc2cf1    call    z,$f12c
ef86 cd45f1    call    $f145
ef89 cd4ff1    call    $f14f
ef8c cd6ff1    call    $f16f
ef8f 7a        ld      a,d
ef90 1f        rra     
ef91 d0        ret     nc

ef92 2b        dec     hl
ef93 3625      ld      (hl),$25         ;'%' Conversion failed(?) eg too many chars
ef95 c9        ret     

;;=prob scale and add exponent if needed
ef96 7a        ld      a,d
ef97 87        add     a,a
ef98 302d      jr      nc,$efc7         ; (+$2d) No format string
ef9a faedef    jp      m,$efed          ;Already showing exponent

;Check length of the number, display in exponent format if too long
ef9d 7b        ld      a,e              ;C+E=number of digits
ef9e 81        add     a,c
ef9f d615      sub     $15
efa1 fa56f0    jp      m,$f056          ;Not too long
efa4 7a        ld      a,d
efa5 f641      or      $41				; Add show exponent flag to format
efa7 57        ld      d,a
efa8 1843      jr      $efed            ; (+$43)

;;=unformatted scale loop
efaa 41        ld      b,c
efab 79        ld      a,c
efac b7        or      a
efad 2815      jr      z,$efc4          ; (+$15)
efaf 83        add     a,e
efb0 3d        dec     a
efb1 5f        ld      e,a
efb2 cddef0    call    $f0de
efb5 0601      ld      b,$01
efb7 79        ld      a,c
efb8 fe07      cp      $07
efba 3804      jr      c,$efc0          ; (+$04)
efbc cb72      bit     6,d              ;Show exponent?
efbe 2026      jr      nz,$efe6         ; (+$26)
efc0 b8        cp      b
efc1 c474f0    call    nz,$f074
efc4 c332f0    jp      $f032

;;=unformatted scale and exp if needed
efc7 7b        ld      a,e
efc8 b7        or      a
efc9 fad0ef    jp      m,$efd0
efcc 20dc      jr      nz,$efaa         ; (-$24)
efce 41        ld      b,c
efcf c9        ret     

efd0 43        ld      b,e
efd1 cddef0    call    $f0de
efd4 78        ld      a,b
efd5 b7        or      a
efd6 28f6      jr      z,$efce          ; (-$0a)
efd8 93        sub     e
efd9 58        ld      e,b
efda 47        ld      b,a
efdb 81        add     a,c
efdc 83        add     a,e
efdd faaaef    jp      m,$efaa
efe0 cd87f0    call    $f087
efe3 c374f0    jp      $f074

efe6 3e06      ld      a,$06
efe8 3252ae    ld      ($ae52),a
efeb 182e      jr      $f01b            ; (+$2e)

;;=do scale and add exponent
efed cdfbf0    call    $f0fb
eff0 3003      jr      nc,$eff5         ; (+$03)
eff2 cbc2      set     0,d
eff4 af        xor     a
eff5 47        ld      b,a
eff6 cc13f1    call    z,$f113
eff9 200e      jr      nz,$f009         ; (+$0e)
effb cbc2      set     0,d
effd 04        inc     b
effe 3a52ae    ld      a,($ae52)
f001 b7        or      a
f002 2805      jr      z,$f009          ; (+$05)
f004 05        dec     b
f005 3c        inc     a
f006 3252ae    ld      ($ae52),a
f009 cb4a      bit     1,d
f00b 2807      jr      z,$f014          ; (+$07)
f00d 78        ld      a,b
f00e 04        inc     b
f00f 05        dec     b
f010 d604      sub     $04
f012 30fb      jr      nc,$f00f         ; (-$05)
f014 79        ld      a,c
f015 b7        or      a
f016 2804      jr      z,$f01c          ; (+$04)
f018 83        add     a,e
f019 90        sub     b
f01a 5f        ld      e,a
f01b 78        ld      a,b
f01c f5        push    af
f01d 47        ld      b,a
f01e cd59f0    call    $f059
f021 f1        pop     af
f022 b8        cp      b
f023 280d      jr      z,$f032          ; (+$0d)
f025 1c        inc     e
f026 23        inc     hl
f027 05        dec     b
f028 e5        push    hl
f029 7e        ld      a,(hl)
f02a fe2e      cp      $2e              ;'.'
f02c 2001      jr      nz,$f02f         ; (+$01)
f02e 23        inc     hl
f02f 3631      ld      (hl),$31         ;'1'
f031 e1        pop     hl
f032 3e04      ld      a,$04
f034 cdc2f0    call    $f0c2
f037 e5        push    hl

;write exponent letter and sign
f038 21452b    ld      hl,$2b45         ;'+','E'
f03b 7b        ld      a,e              ;A=exponent
f03c b7        or      a
f03d f244f0    jp      p,$f044
f040 af        xor     a                ;Convert exponent
f041 93        sub     e
f042 262d      ld      h,$2d			; '-'
f044 224cae    ld      ($ae4c),hl       ;Write 'E+' or 'E-' before exponent

;Convert exponent into chars in HL
f047 2e2f      ld      l,$2f            ;'/' - one before '0'
f049 2c        inc     l
f04a d60a      sub     $0a
f04c 30fb      jr      nc,$f049         ; (-$05)
f04e c63a      add     a,$3a            ;":" - char after '9'
f050 67        ld      h,a
f051 224eae    ld      ($ae4e),hl       ;Write exponent digits to buffer
f054 e1        pop     hl
f055 c9        ret     

;;=scale no exp needed
f056 cd87f0    call    $f087
f059 cd13f1    call    $f113
f05c 80        add     a,b
f05d b9        cp      c
f05e 3005      jr      nc,$f065         ; (+$05)
f060 cd9af0    call    $f09a
f063 180a      jr      $f06f            ; (+$0a)

f065 fe15      cp      $15
f067 3802      jr      c,$f06b          ; (+$02)
f069 3e14      ld      a,$14
f06b 91        sub     c
f06c c4c2f0    call    nz,$f0c2
f06f 3a52ae    ld      a,($ae52)
f072 b7        or      a
f073 c8        ret     z

;;=poss insert decimal point
f074 0e2e      ld      c,$2e
f076 78        ld      a,b
;;=poss insert char into buffer
f077 c5        push    bc
f078 47        ld      b,a
f079 04        inc     b
f07a 85        add     a,l
f07b 6f        ld      l,a
f07c 8c        adc     a,h
f07d 95        sub     l
f07e 67        ld      h,a
f07f 2b        dec     hl
f080 79        ld      a,c
f081 4e        ld      c,(hl)
f082 77        ld      (hl),a
f083 10fa      djnz    $f07f            ; (-$06)
f085 c1        pop     bc
f086 c9        ret     

;;=prob write zeros to buffer
f087 7b        ld      a,e
f088 81        add     a,c
f089 47        ld      b,a
f08a f0        ret     p

f08b 2f        cpl     
f08c 3c        inc     a
f08d 0614      ld      b,$14
f08f b8        cp      b
f090 3001      jr      nc,$f093         ; (+$01)
f092 47        ld      b,a
f093 2b        dec     hl
f094 3630      ld      (hl),$30         ;'0'
f096 0c        inc     c
f097 10fa      djnz    $f093            ; (-$06)
f099 c9        ret     

;;=prob round last digit
f09a 4f        ld      c,a
f09b 85        add     a,l
f09c 6f        ld      l,a
f09d 8c        adc     a,h
f09e 95        sub     l
f09f 67        ld      h,a
f0a0 e5        push    hl
f0a1 c5        push    bc
f0a2 7e        ld      a,(hl)
f0a3 fe35      cp      $35              ;'5'
f0a5 d4b4f0    call    nc,$f0b4
f0a8 c1        pop     bc
f0a9 3805      jr      c,$f0b0          ; (+$05)
f0ab 2b        dec     hl
f0ac 3631      ld      (hl),$31         ;'1'
f0ae 04        inc     b
f0af 0c        inc     c
f0b0 e1        pop     hl
f0b1 2b        dec     hl
f0b2 1838      jr      $f0ec            ; (+$38)

;;=prob right pad with zeros
f0b4 79        ld      a,c
f0b5 b7        or      a
f0b6 c8        ret     z

f0b7 2b        dec     hl
f0b8 0d        dec     c
f0b9 7e        ld      a,(hl)
f0ba 34        inc     (hl)
f0bb fe39      cp      $39              ;'9'
f0bd d8        ret     c

f0be 3630      ld      (hl),$30         ;'0'
f0c0 18f2      jr      $f0b4            ; (-$0e)

;;=prob copy buffer and right pad with zeros
f0c2 d5        push    de
f0c3 c5        push    bc
f0c4 eb        ex      de,hl
f0c5 47        ld      b,a
f0c6 7b        ld      a,e
f0c7 90        sub     b
f0c8 6f        ld      l,a
f0c9 9f        sbc     a,a
f0ca 82        add     a,d
f0cb 67        ld      h,a
f0cc e5        push    hl
;copy until null loop
f0cd 1a        ld      a,(de)
f0ce 13        inc     de
f0cf 77        ld      (hl),a
f0d0 23        inc     hl
f0d1 b7        or      a
f0d2 20f9      jr      nz,$f0cd         ; (-$07)
f0d4 2b        dec     hl
;write zeros loop
f0d5 3630      ld      (hl),$30         ;'0'
f0d7 23        inc     hl
f0d8 10fb      djnz    $f0d5            ; (-$05)
f0da e1        pop     hl
f0db c1        pop     bc
f0dc d1        pop     de
f0dd c9        ret     

;;=prob remove trailing zeros
f0de 2150ae    ld      hl,$ae4f + 1         ;##LABEL##
;Loop over zeros
f0e1 2b        dec     hl
f0e2 7e        ld      a,(hl)
f0e3 fe30      cp      $30
f0e5 2005      jr      nz,$f0ec         ; (+$05)
f0e7 0d        dec     c
f0e8 04        inc     b
f0e9 20f6      jr      nz,$f0e1         ; (-$0a)

f0eb 2b        dec     hl
f0ec d5        push    de
f0ed c5        push    bc
f0ee 114fae    ld      de,$ae4f         ;##LABEL##
f0f1 0600      ld      b,$00
f0f3 cdf5ff    call    $fff5 ; copy bytes LDDR (BC = count)
f0f6 eb        ex      de,hl
f0f7 23        inc     hl
f0f8 c1        pop     bc
f0f9 d1        pop     de
f0fa c9        ret     

;;=prob test if prefix char needed
f0fb c5        push    bc
f0fc 7a        ld      a,d
f0fd e604      and     $04              ;Currency prefix
f0ff 1f        rra     
f100 1f        rra     
f101 47        ld      b,a
f102 cb62      bit     4,d              ;Sign prefix
f104 2007      jr      nz,$f10d         ; (+$07)
f106 7a        ld      a,d
f107 87        add     a,a
f108 b3        or      e
f109 f20df1    jp      p,$f10d
f10c 04        inc     b
f10d 3a53ae    ld      a,($ae53)
f110 90        sub     b
f111 c1        pop     bc
f112 c9        ret     

;;=get chars before dp
f113 3a52ae    ld      a,($ae52)
f116 b7        or      a
f117 c8        ret     z

f118 3d        dec     a
f119 c9        ret     

;;=insert commas if required
;D=format flags
;B=position of decimal point
f11a cb4a      bit     1,d              ;Bit 1 of flag = insert commas
f11c c8        ret     z

f11d 78        ld      a,b              ;Position of decimal point?
f11e d603      sub     $03              ;Three chars prior
f120 d8        ret     c                ;Return when done
f121 c8        ret     z

f122 f5        push    af               ;Do the insertion
f123 0e2c      ld      c,$2c			; ','
f125 cd77f0    call    $f077
f128 04        inc     b
f129 f1        pop     af
f12a 18f2      jr      $f11e            ; (-$0e) Loop

;;=write zero if required
f12c e5        push    hl
;Loop over chars < '0'
f12d 7e        ld      a,(hl)
f12e 23        inc     hl
f12f 3d        dec     a
f130 fe30      cp      $30              ;'0'
f132 38f9      jr      c,$f12d          ; (-$07)

f134 3c        inc     a
f135 2001      jr      nz,$f138         ; (+$01)
f137 5f        ld      e,a
f138 e1        pop     hl
f139 7a        ld      a,d
f13a ee80      xor     $80
f13c f4fbf0    call    p,$f0fb          ;Formatted number
f13f d8        ret     c

f140 c8        ret     z

f141 3e30      ld      a,$30			; '0'
f143 1806      jr      $f14b            

;;=write currency prefix if required
f145 cb52      bit     2,d
f147 c8        ret     z
f148 3a54ae    ld      a,($ae54)

;;=write prefix char
f14b 04        inc     b
f14c 2b        dec     hl
f14d 77        ld      (hl),a
f14e c9        ret     

;;=prob write sign if needed
;Writes leading or trailing sign (or space) as necessary
;Bit 7 of E is set if number is negative
f14f 7b        ld      a,e
f150 87        add     a,a
f151 3e2d      ld      a,$2d			; '-'
f153 380e      jr      c,$f163          ; Negative number
f155 7a        ld      a,d
f156 e698      and     $98              ;Bits 4 and 3 = sign formatting
f158 ee80      xor     $80              ;Formatted number?
f15a c8        ret     z                ;Exit if not    

f15b e608      and     $08
f15d 3e2b      ld      a,$2b			; '+'
f15f 2002      jr      nz,$f163         ; Positive prefix or any suffix
f161 3e20      ld      a,$20			; ' ' else space prefix
f163 cb62      bit     4,d              ;Suffix if set
f165 28e4      jr      z,$f14b          ; (-$1c) if prefix
f167 3250ae    ld      ($ae50),a        ;Suffix address
f16a af        xor     a                ;Terminate buffer
f16b 3251ae    ld      ($ae51),a
f16e c9        ret     

;;=prob write leading asterisk or space
f16f 7a        ld      a,d
f170 b7        or      a
f171 f0        ret     p

f172 3a53ae    ld      a,($ae53)
f175 90        sub     b
f176 c8        ret     z

f177 380e      jr      c,$f187          ; (+$0e)
f179 47        ld      b,a
f17a cb6a      bit     5,d
f17c 3e2a      ld      a,$2a            ;'*'
f17e 2002      jr      nz,$f182         ; (+$02)
f180 3e20      ld      a,$20            ;' '
f182 2b        dec     hl
f183 77        ld      (hl),a
f184 10fc      djnz    $f182            ; (-$04)
f186 c9        ret     

f187 cbc2      set     0,d
f189 c9        ret     

;;=do input to ascii
;Converts the input number to unformatted ASCII
;HL=last byte of input buffer
;C=number of bytes in buffer: $01 for one byte integer, $02 for 2 byte integer, various for real
;
;Returns:
;HL=addr of first digit of number
;C=Number of digits
f18a 112dae    ld      de,$ae2d
f18d af        xor     a
f18e 47        ld      b,a              ;Count=0

;Loop backwards over buffer to find first non-null value (if any).
;Ie. skip any zero high bytes
;Buffer is C bytes long
f18f b6        or      (hl)
f190 2b        dec     hl
f191 2005      jr      nz,$f198         ; (+$05) Non-null value found
f193 0d        dec     c
f194 20f9      jr      nz,$f18f         ; (-$07)

f196 1828      jr      $f1c0            ; (+$28) End of buffer. Number is zero

;;=binary to ASCII
;Converts the binary number to BCD then falls through to the BCD to ASCII routine
;HL=addr of second most significant byte (penultimate) of number
;C=number of bytes to convert
;B=0
;A=most significant byte
f198 37        scf     
f199 8f        adc     a,a
f19a 30fd      jr      nc,$f199         ; (-$03)
f19c eb        ex      de,hl
f19d d5        push    de
f19e 57        ld      d,a
f19f 1811      jr      $f1b2            ; (+$11)

;Outer loop
f1a1 1a        ld      a,(de)
f1a2 1b        dec     de
f1a3 d5        push    de
f1a4 37        scf     
f1a5 8f        adc     a,a

;Middle loop
f1a6 57        ld      d,a
f1a7 58        ld      e,b

;Inner loop
f1a8 7e        ld      a,(hl)
f1a9 8f        adc     a,a
f1aa 27        daa     
f1ab 77        ld      (hl),a
f1ac 23        inc     hl
f1ad 1d        dec     e
f1ae 20f8      jr      nz,$f1a8         ; (-$08) 
;End of inner loop

f1b0 3003      jr      nc,$f1b5         ; (+$03)

;Entry point
f1b2 04        inc     b
f1b3 3601      ld      (hl),$01
f1b5 212dae    ld      hl,$ae2d
f1b8 7a        ld      a,d
f1b9 87        add     a,a
f1ba 20ea      jr      nz,$f1a6         ; (-$16) 
;End of middle loop

f1bc d1        pop     de
f1bd 0d        dec     c
f1be 20e1      jr      nz,$f1a1         ; (-$1f) 
;End of outer loop


;;=BCD to ASCII
;B=number of bytes to convert, $00 if number is zero
f1c0 eb        ex      de,hl
f1c1 2150ae    ld      hl,$ae4f + 1
f1c4 3600      ld      (hl),$00         ;Zero terminate the buffer
f1c6 78        ld      a,b              
f1c7 87        add     a,a
f1c8 4f        ld      c,a              ;C=number of digits returned, zero if number is zero
f1c9 c8        ret     z           

f1ca 3e30      ld      a,$30			; '0' - Puts 3 into the high nybble of A, 
                                        ;so digits get converted to ASCII numbers
f1cc eb        ex      de,hl

;Loop
;RRD rotates: low nybble of A to high nybble of (HL) to low nybble of (HL) to low nybbe of A
;This code splits the number at (HL) into separate nybbles, writing one to each byte starting at (DE) - 1
;HL increments after each byte. DE decrements for each nybble
;So, we're unpacking a hex number (or a BCD one)
f1cd ed67      rrd                      ;Put low nybble of (HL) into A
f1cf 1b        dec     de
f1d0 12        ld      (de),a           ;And store into (DE)
f1d1 ed67      rrd                      ;Put (what was) high nybble of (HL) into A
f1d3 1b        dec     de
f1d4 12        ld      (de),a           ;And store in (DE)
f1d5 23        inc     hl
f1d6 10f5      djnz    $f1cd            ; (-$0b)
;End of loop

f1d8 eb        ex      de,hl
f1d9 fe30      cp      $30              ;'0'
f1db c0        ret     nz

f1dc 0d        dec     c                ;Step back if leading zero (if there is one)
                                        ;Since we already counted how many bytes to unpack there is a 
                                        ;maximum of one leading zero
f1dd 23        inc     hl
f1de c9        ret     

;;===============================
;;convert based number to string
;HL=number to convert
;C=base (01=binary, 0f=hex)
;B=number of bits per output digit (01 for binary, 04 for hex)
;A: $01 to $80=minimum number of digits to output. I.e. pad with leading zeros. 
;   $81 to $ff or $00=no padding.

;Returns: ASCIIZ string at HL
f1df d5        push    de
f1e0 eb        ex      de,hl
f1e1 213eae    ld      hl,$ae3e
f1e4 3600      ld      (hl),$00         ;Returns a zero terminated string
f1e6 3d        dec     a

;;=convert digit loop
f1e7 f5        push    af
f1e8 7b        ld      a,e              ;A=byte
f1e9 a1        and     c                ;C=mask for bits we're interested in

;These four lines convert nybble to hex ASCII. 
;See 'Analysis of the binary to ASCII hex conversion' below
f1ea f6f0      or      $f0              
f1ec 27        daa     
f1ed c6a0      add     a,$a0
f1ef ce40      adc     a,$40			;; 'A'-1

f1f1 2b        dec     hl
f1f2 77        ld      (hl),a           ;Write to buffer
f1f3 78        ld      a,b              ;Cache bits per digit

;;=convert shift loop
f1f4 cb3a      srl     d                ;DE=number to convert
f1f6 cb1b      rr      e                ;Shift for next digit
f1f8 10fa      djnz    $f1f4            ; (-$06) Next digit

f1fa 47        ld      b,a              ;Restore bits per digit
f1fb f1        pop     af               ;A=minimum width
f1fc 3d        dec     a
f1fd f2e7f1    jp      p,$f1e7          ;If A still > 0 then loop

f200 7a        ld      a,d              ;If A < 0 then check if number is now zero
f201 b3        or      e
f202 3e00      ld      a,$00            ;Force no padding
f204 20e1      jr      nz,$f1e7         ; (-$1f) Not zero? => next digit

f206 d1        pop     de
f207 c9        ret     

;Analysis of the binary to ASCII hex conversion
;----------------------------------------------
;Lower nybble:
;To convert from binary to ASCII we only need to add 7 if value is more than 9:
;or $f0     ;Remains the same
;daa        ;Adds 6 if more than 9
;add a,$a0  ;If DAA added 6 then this will set carry (see high nybble section)
;adc a,$40  ;Adds one to lower nybble if carry set

;High nybble:
;Needs to be $3 (%0011) for number or $4 (%0100) for letter
;or $f0     ;Initialises to $f
;daa        ;If low nybble 0..9, adds 6. If low nybble A to F effectively adds 7.
;           ;Thus high nybble becomes          $5 (%0101) or          $6 ($0110)
;add $a0    ;(%1010) Becomes          No carry,$f ($1111) or 16=Carry,$0 ($0000)
;adc $40    ;(%0110) Becomes                   $3 (%0011) or          $4 ($0110)





;;***PeekPokeIOBarCall.asm
;;<< PEEK, POKE, INP, OUT, WAIT, |BAR commands, CALL
;;========================================================
;; function PEEK
;PEEK(<address expression>)
;Reads the given byte from RAM

f208 cdebfe    call    $feeb        ;Eval address
f20b e7        rst     $20          ;RAM_LAM - read a byte from RAM with all ROMs disabled
f20c c332ff    jp      $ff32

;;========================================================================
;; command POKE
;POKE <address expression>,<integer expression>
;Pokes a byte into RAM at the given location

f20f cdf5ce    call    $cef5        ;Eval address
f212 d5        push    de
f213 cd3ff2    call    $f23f        ;Eval data
f216 d1        pop     de
f217 12        ld      (de),a       ;Poke data
f218 c9        ret     

;;========================================================================
;; function INP
;INP(<port number>)
;Reads a value from the given I/O port

f219 cdb6fe    call    $feb6        ;Eval port
f21c 44        ld      b,h
f21d 4d        ld      c,l
f21e ed78      in      a,(c)        ;Read port
f220 c332ff    jp      $ff32

;;========================================================================
;; command OUT
;OUT <port number>,<integer expression>
;Outputs data to the given I/O port
;Expression must be 0..255

f223 cd3af2    call    $f23a        ;Eval port and data
f226 ed79      out     (c),a        ;Write to port
f228 c9        ret    
 
;;========================================================================
;; command WAIT
;WAIT <port number>,<mask>[,<inversion>]
;Waits for an I/O port to have a specific value.
;XORs the input data with <inversion> then ANDs it with <mask>. Loops until the result
;is non-zero.

f229 cd3af2    call    $f23a        ;Eval port and mask
f22c 57        ld      d,a          ;D=mask
f22d 3e00      ld      a,$00        ;Default inversion
f22f c43ff2    call    nz,$f23f     ;Eval inversion if preset
f232 5f        ld      e,a          ;E=inversion

f233 ed78      in      a,(c)        ;Read port
f235 ab        xor     e            ;Inversion
f236 a2        and     d            ;Mask
f237 28fa      jr      z,$f233          ; (-$06) Loop while zero

f239 c9        ret     

;;========================================================================
;;=eval uint and byte params or error
;evals a UINT parameter into BC and a byte parameter into A
f23a cdf5ce    call    $cef5
f23d 42        ld      b,d
f23e 4b        ld      c,e
;;=eval next param as byte or error
f23f cd15de    call    $de15 ; check for comma
f242 c3b8ce    jp      $ceb8 ; get number and check it's less than 255 

;;=========================================================
;; BAR command
;|<command name>[,<list of: <parameter}>]
;Executes the given RSX (bar) command.
;Parameter passing is as per CALL

;; skip | symbol
f245 23        inc     hl
;; this is the name with last char with bit 7 set
f246 7e        ld      a,(hl)
f247 b7        or      a
f248 23        inc     hl
f249 e5        push    hl
f24a ccd4bc    call    z,$bcd4			; firmware function: KL FIND COMMAND
f24d eb        ex      de,hl
f24e e1        pop     hl
f24f 3007      jr      nc,$f258         ; command not found...?
;; skip name
f251 7e        ld      a,(hl)
f252 23        inc     hl
f253 17        rla     
f254 30fb      jr      nc,$f251         ; (-$05)
f256 1809      jr      $f261            ; (+$09)

f258 cd45cb    call    $cb45
f25b defb $1c                         ;Inline error code: Unknown command

;;==================================================================
;; command CALL
;CALL <address expression>[,<list of: <parameter>>]
;Calls a machine code routine at the given address.
;The routine is called with IX pointing to the list of parameters
;and A containing the number of parameters.
;Parameters are passed in reverse order, ie. (IX+0) is the last parameter supplied.

f25c cdf5ce    call    $cef5			; get address
f25f 0eff      ld      c,$ff
;; store address of function
f261 ed5355ae  ld      ($ae55),de
;; store rom select
f265 79        ld      a,c
f266 3257ae    ld      ($ae57),a
f269 ed735aae  ld      ($ae5a),sp
f26d 0620      ld      b,$20			; max 32 parameters
f26f cd41de    call    $de41
f272 3008      jr      nc,$f27c         ; (+$08)
f274 c5        push    bc
f275 cde3ce    call    $cee3
f278 c1        pop     bc
f279 d5        push    de				; push parameter onto stack
f27a 10f3      djnz    $f26f            ; (-$0d)
f27c cd37de    call    $de37
f27f 2258ae    ld      ($ae58),hl
f282 3e20      ld      a,$20			; max 32 parameters
;; B = $20-number of parameters specified
f284 90        sub     b
;; A = number of parameters
f285 dd210000  ld      ix,$0000         ;##LIT##
f289 dd39      add     ix,sp			; IX points to parameters on stack

;; IX = points to parameters
;; A = number of parameters
;; execute function
f28b df        rst     $18
defw $ae55
f28e ed7b5aae  ld      sp,($ae5a)
f292 cdccfb    call    $fbcc
f295 2a58ae    ld      hl,($ae58)
f298 c9        ret     






;;***TextOutput.asm
;;<< TEXT OUTPUT (ZONE, PRINT, WRITE)
;;=====================================
;;set zone 13
f299 3e0d      ld      a,$0d
f29b 1803      jr      $f2a0            ; (+$03)

;;========================================================================
;; command ZONE
;ZONE <integer expression>
;Sets the print zone width. Values 1..255

f29d cdc3ce    call    $cec3
f2a0 325cae    ld      ($ae5c),a
f2a3 c9        ret     

;;========================================================================
;; command PRINT
;PRINT [#<stream expression>,][<print list>][<using clause>][<separator>]
;where
;<print list>   is: <print item>[<separator><print item>]*
;<print item>   is: <expression>
;               or: SPC(<integer expression>)
;               or: TAB(<integer expression>)
;<using clause> is: USING <string expression>;<using list>
;<using list>   is: <expression>[<separator><expression>]*
;<separator>    is: comma or semi-colon

;* - these items can be repeated zero or more times

;Print items to the specified stream
;SPC(..) prints the given number of spaces
;TAB(..) moves to the given tab position
;A trailing SPC, TAB or separator prevents a new line being printed
;USING:
;   Valid formatting characters:  ! \ & # . + - * $ ^ , _
;   _   prints the following character as a literal
;   String formatting:
;       !   Prints first character of string
;       \  \    Prints n characters where n equals the number of spaces between \ chars
;       &   Prints the entire string
;   Number formatting:
;       #   Specifies a digit position
;       .   Specifies position of decimal point
;       ,   (before .) Digits will be in groups of three separated by commas
;       $$  (Before number): leading $ sign
;       **  (Before number): leading spaces will be replaced by *
;       **$ (Before number): combination of previous two items
;       +   (Before number): print leading + sign if positive
;       +   (After number):  print trailing + if positive
;       -   (After number):  print trailing + or - sign
;       ^^^^ (After number): print exponent

;If the number can't be displayed in the chosen format a leading % is printed

f2a4 cdcfc1    call    $c1cf        
                                    ;This routine evals a stream number (if present),
                                    ;swaps to it,
                                    ;CALLs the following code (popping address of the stack), 
                                    ;swaps back to original stream,
                                    ;returns to the caller

f2a7 cd3dde    call    $de3d
f2aa da98c3    jp      c,$c398      ;No parameters

;;=print item loop
;Loop though each parameter/item
f2ad feed      cp      $ed          ;"USING"
f2af ca7ef3    jp      z,$f37e
f2b2 eb        ex      de,hl
f2b3 21c3f2    ld      hl,$f2c3     ;Look up the routine tom process the item in the following table...
f2b6 cdb4ff    call    $ffb4        ;...or PRINT_do_other for general items
f2b9 eb        ex      de,hl
f2ba cdfeff    call    $fffe			; JP (DE)
f2bd cd3dde    call    $de3d        ;Next item
f2c0 30eb      jr      nc,$f2ad         ; (-$15) Loop if not end of statement/line
f2c2 c9        ret     

;;=PRINT parameters LUT
f2c3 defb $04     ;Count of parameters
defw $f2d2        ;Jump to if not found  ##LABEL##

defb $2c   ;","
defw $f319 ;  ##LABEL##
defb $e5   ;"SPC"
defw $f334 ;  ##LABEL##
defb $ea   ;"TAB"
defw $f33d ;  ##LABEL##
defb $3b   ;";"
defw $de2c ;  ##LABEL##

;;+PRINT do other
;Anything other than comma, semicolon, SPC, TAB or USING
f2d2 cd62cf    call    $cf62
f2d5 f5        push    af
f2d6 e5        push    hl
f2d7 cd66ff    call    $ff66            ;Parameter type
f2da 280f      jr      z,$f2eb          ; (+$0f) String

;Print number
f2dc cd68ef    call    $ef68            ;Convert to string
f2df cd8af8    call    $f88a            ;Put string in accumulator
f2e2 3620      ld      (hl),$20         ;" " - leading space?
f2e4 2aa0b0    ld      hl,($b0a0)       ;Addr of string descriptor
f2e7 34        inc     (hl)             ;inc string length
f2e8 7e        ld      a,(hl)           ;Get string length
f2e9 181f      jr      $f30a            ; (+$1f)

;;=PRINT do string
f2eb 2aa0b0    ld      hl,($b0a0)       ;HL=string descriptor
f2ee 46        ld      b,(hl)           ;B-length
f2ef 0e00      ld      c,$00
f2f1 23        inc     hl
f2f2 7e        ld      a,(hl)           ;HL=string address
f2f3 23        inc     hl
f2f4 66        ld      h,(hl)
f2f5 6f        ld      l,a
f2f6 04        inc     b
f2f7 180e      jr      $f307            ; (+$0e)

;;=PRINT do string wrap loop
;Test for leading control codes to see if we need to wrap to next line and ignore them(?)
f2f9 7e        ld      a,(hl)
f2fa fe20      cp      $20              ;Control code < $20 " "
f2fc 23        inc     hl
f2fd 3007      jr      nc,$f306         ; (+$07) Control code
f2ff 3d        dec     a
f300 2007      jr      nz,$f309         ; (+$07) Not control code $01 - print symbol given by parameter(?)
f302 05        dec     b
f303 2804      jr      z,$f309          ; (+$04) End of string
f305 23        inc     hl
f306 0c        inc     c
;;=PRINT do test string wrap
f307 10f0      djnz    $f2f9            ; (-$10)

;;=PRINT do string skip C chars
f309 79        ld      a,c
;;=PRINT do string skip A chars
f30a cde7c2    call    $c2e7
f30d d498c3    call    nc,$c398      ;Nothing to print?
f310 cdd0f8    call    $f8d0
f313 e1        pop     hl
f314 f1        pop     af
f315 cc98c3    call    z,$c398      ;; new text line
f318 c9        ret     

;;+PRINT do comma
f319 cd2cde    call    $de2c			; get next token skipping space
f31c 3a5cae    ld      a,($ae5c)
f31f 4f        ld      c,a
f320 cdb9c2    call    $c2b9
f323 3d        dec     a

f324 91        sub     c                ;C=chars to next print zone?
f325 30fd      jr      nc,$f324         ; (-$03)

f327 2f        cpl     
f328 3c        inc     a                ;A=current print position
f329 47        ld      b,a
f32a 81        add     a,c              ;A=new print position
f32b cde7c2    call    $c2e7
f32e d298c3    jp      nc,$c398      ;; new text line
f331 78        ld      a,b
f332 181e      jr      $f352            ; (+$1e)

;;+PRINT do SPC
f334 cd5df3    call    $f35d
f337 cd69f3    call    $f369
f33a 7b        ld      a,e
f33b 1815      jr      $f352            ; (+$15)

;;+PRINT do TAB
f33d cd5df3    call    $f35d
f340 1b        dec     de
f341 cd69f3    call    $f369
f344 cdb9c2    call    $c2b9
f347 2f        cpl     
f348 3c        inc     a
f349 1c        inc     e
f34a 83        add     a,e
f34b 3805      jr      c,$f352          ; (+$05)
f34d cd98c3    call    $c398      ;; new text line
f350 1d        dec     e
f351 7b        ld      a,e

;;=PRINT do B minus 1 spaces
f352 47        ld      b,a
f353 04        inc     b
f354 05        dec     b
f355 c8        ret     z

f356 3e20      ld      a,$20			; ' '
f358 cda0c3    call    $c3a0           ;; display text char
f35b 18f7      jr      $f354            ; (-$09) Loop


;;=PRINT do eval SPC TAB parameter
f35d cd2cde    call    $de2c			; get next token skipping space
f360 cd19de    call    $de19 ; check for open bracket
f363 cdd8ce    call    $ced8 ; get number
f366 c31dde    jp      $de1d ; check for close bracket

;;=PRINT do process SPC TAB parameter
;Calc new print position?
f369 7a        ld      a,d
f36a 17        rla     
f36b 3003      jr      nc,$f370         ; (+$03)
f36d 110000    ld      de,$0000         ;##LIT##
f370 cdcfc2    call    $c2cf
f373 d0        ret     nc

f374 e5        push    hl
f375 eb        ex      de,hl
f376 5f        ld      e,a
f377 1600      ld      d,$00
f379 cdaedd    call    $ddae
f37c e1        pop     hl
f37d c9        ret     

;;=PRINT USING
f37e cd2cde    call    $de2c			; get next token skipping space
f381 cd09cf    call    $cf09            ;Format string paramater
f384 cd25de    call    $de25
f387 defb $3b   ;inline token to test ";"
f388 e5        push    hl
f389 2aa0b0    ld      hl,($b0a0)       ;Address of format string descriptor
f38c e3        ex      (sp),hl
f38d cd62cf    call    $cf62            ;Eval first number to format
f390 af        xor     a                ;Flag=We have parameters to insert
f391 325dae    ld      ($ae5d),a    

;;=print using format string loop
;Loops through the format string looking for parameters to format and insert
;If we reach the end of the format string and there are more parameters to insert then
;restart the format string
f394 d1        pop     de               ;Get format string descriptor
f395 d5        push    de
f396 eb        ex      de,hl
f397 46        ld      b,(hl)           ;B=Format string length
f398 23        inc     hl
f399 7e        ld      a,(hl)           ;HL=Format string address
f39a 23        inc     hl
f39b 66        ld      h,(hl)
f39c 6f        ld      l,a
f39d eb        ex      de,hl
f39e cdcdf3    call    $f3cd            ;Print item
f3a1 d2abf4    jp      nc,$f4ab         ;NC if zero length format string or format string contains nothing to substitute

;;=print using expr loop
f3a4 cd3dde    call    $de3d            
f3a7 3811      jr      c,$f3ba          ; (+$11) End of line/statement
f3a9 cdeff3    call    $f3ef
f3ac 280c      jr      z,$f3ba          ; (+$0c) End if not a valid separator
f3ae d5        push    de
f3af cd62cf    call    $cf62            ;Eval next expression to format
f3b2 d1        pop     de
f3b3 cdcdf3    call    $f3cd            ;Print item
f3b6 30dc      jr      nc,$f394         ; (-$24) reached end of format string loop so restart it more following parameters
f3b8 18ea      jr      $f3a4            ; (-$16) Loop for more expressions

;;=print using end of parameters
f3ba f5        push    af
f3bb 3eff      ld      a,$ff            ;Set flag to show there are no more parameters available to insert
f3bd 325dae    ld      ($ae5d),a
f3c0 cdcdf3    call    $f3cd
f3c3 f1        pop     af
f3c4 dc98c3    call    c,$c398      ;; new text line
f3c7 e3        ex      (sp),hl
f3c8 cd03fc    call    $fc03
f3cb e1        pop     hl
f3cc c9        ret     

;;=print using item
;Starting from current position in format string looks for the next item to substitute
;printing any literals it comes across along the way. Ends once an item has been subbed or
;at end of format string
;B=chars remaining in format string
;DE=current position in format string

;Returns Carry set if we subbed an item
;DE=addr of next char in format string
f3cd 78        ld      a,b              ;End of format string
f3ce b7        or      a
f3cf c8        ret     z

f3d0 e5        push    hl

f3d1 1a        ld      a,(de)
f3d2 fe5f      cp      $5f              ;"_" Next char is a literal
f3d4 2007      jr      nz,$f3dd         ; (+$07)
f3d6 13        inc     de
f3d7 100c      djnz    $f3e5            ; (+$0c)
f3d9 04        inc     b
f3da 1b        dec     de
f3db 1808      jr      $f3e5            ; (+$08)

f3dd cdf7f3    call    $f3f7            ;Returns C set if item subbed
f3e0 d431f4    call    nc,$f431         ;Returns C set if item subbed
f3e3 3808      jr      c,$f3ed          ; (+$08) Done once item subbed 
f3e5 1a        ld      a,(de)
f3e6 cda0c3    call    $c3a0           ; display text char
f3e9 13        inc     de
f3ea 10e5      djnz    $f3d1            ; (-$1b)

f3ec b7        or      a
f3ed e1        pop     hl
f3ee c9        ret     

;;=is A print separator
;Is A a ';' or ',' token. Returns Z flag set if either was found
f3ef fe3b      cp      $3b              ;";"
f3f1 ca2cde    jp      z,$de2c			; get next token skipping space
f3f4 c315de    jp      $de15 ; check for comma

;;=print using string item
;Do if format is one for strings, otherwise returns NC
f3f7 1a        ld      a,(de)
f3f8 0e00      ld      c,$00
f3fa fe26      cp      $26              ;"&" Print entire string
f3fc 281e      jr      z,$f41c          ; (+$1e)
f3fe 0c        inc     c
f3ff fe21      cp      $21              ;"!" Print first character only
f401 2819      jr      z,$f41c          ; (+$19)
f403 ee5c      xor     $5c              ;"\" Print number of chars equivalent to number of spaces between \ and \
f405 c0        ret     nz

f406 c5        push    bc
f407 d5        push    de

f408 13        inc     de               ;Count number of chars (spaces) in C
f409 05        dec     b
f40a 280a      jr      z,$f416          ; (+$0a) Premature and of string
f40c 0c        inc     c
f40d 1a        ld      a,(de)
f40e fe5c      cp      $5c              ;"\"
f410 2808      jr      z,$f41a          ; (+$08) End of specifier
f412 fe20      cp      $20              ;" "
f414 28f2      jr      z,$f408          ; (-$0e) Loop

f416 d1        pop     de
f417 c1        pop     bc
f418 b7        or      a
f419 c9        ret     

;;=PRINT USING do string
;C=number of leading chars of string to print. $00=entire string
f41a f1        pop     af
f41b f1        pop     af
f41c 13        inc     de
f41d 05        dec     b
f41e c5        push    bc
f41f d5        push    de
f420 3a5dae    ld      a,($ae5d)        ;Don't print if we've exhausted all the parameters in PRINT statement
f423 b7        or      a
f424 2007      jr      nz,$f42d         ; (+$07)
f426 cddcf8    call    $f8dc
f429 79        ld      a,c              ;If string shorter than format specifier, pad with spaces
f42a cd52f3    call    $f352
f42d d1        pop     de
f42e c1        pop     bc
f42f 37        scf     
f430 c9        ret     

;;=PRINT USING number item
f431 cd48f4    call    $f448
f434 d0        ret     nc

f435 3a5dae    ld      a,($ae5d)        ;Don't print if we've exhausted all the parameters in PRINT statement
f438 b7        or      a
f439 200b      jr      nz,$f446         ; (+$0b)
f43b c5        push    bc
f43c d5        push    de
f43d 79        ld      a,c
f43e cd6aef    call    $ef6a        ;Number to string
f441 cd8bc3    call    $c38b		;and output it
f444 d1        pop     de
f445 c1        pop     bc
f446 37        scf     
f447 c9        ret     

;;===============================================
;;=parse number format template
;DE=addr of format template
;B=length of format template
;Valid chars in format template: + - $ £ * # , . ^

;A returns the number of (printable?) chars in the template
;C returns a bitwise set of flags:
;Bit    Hex
;7      $80 Always set - indicates we have a format 
;            (as opposed to calling the conversion routines without a format)
;6      &40 Exponent ('^^^^' at the end)
;5      $20 Asterisk prefix
;4      $10 If clear then show sign prefix, otherwise sign suffix
;3      $08 If bit 4 set, bit 3 set specifies always show sign prefix, even for positive numbers
;                         bit 3 clear specifies sign prefix only if negative
;                         bit 3 clear specifies sign prefix only if negative
;           If bit 4 clear, bit 3 clear specifies sign suffix of '-' or space
;                           bit 3 set specifies sign suffix of '-' or '+'
;2      &04 Currency symbol prefix (actual symbol is stored at &ae54)
;1      &02 Contains comma(s)
;(Bit zero is used as a flag when doing conversions)

;During processing:
;H=count of the number of chars before the decimal point
;L=the number of chars after the decimal point, including the decimal point (when processing the hash stuff)
;Thus H + L is the total number of chars (when in the hash stuff)

f448 c5        push    bc
f449 d5        push    de
f44a 0e80      ld      c,$80            ;Set bit 7 to show we have a format
f44c 2600      ld      h,$00            ;Init character counter
f44e 1a        ld      a,(de)

f44f fe2b      cp      $2b				; '+' - sign prefix
f451 2007      jr      nz,$f45a         
f453 13        inc     de
f454 05        dec     b
f455 2824      jr      z,$f47b          ; (+$24)
f457 24        inc     h
f458 0e88      ld      c,$88            ;Bit 7 = we have a format, Bit 4=sign prefix

f45a 1a        ld      a,(de)
f45b fe2e      cp      $2e				; '.'
f45d 2820      jr      z,$f47f          
f45f fe23      cp      $23				; '#'
f461 283e      jr      z,$f4a1          
f463 13        inc     de
f464 05        dec     b
f465 2814      jr      z,$f47b          ; (+$14)

f467 eb        ex      de,hl            ;Test for currency symbols or asterisk
f468 be        cp      (hl)
f469 eb        ex      de,hl
f46a 200f      jr      nz,$f47b         ; (+$0f)
f46c 24        inc     h
f46d 24        inc     h
f46e 2e04      ld      l,$04            ;Flags bit 2 = currency symbol
f470 cd02f5    call    $f502
f473 2824      jr      z,$f499          ; (+$24)

f475 2e20      ld      l,$20            ;Flags bit 5 = asterisk
f477 fe2a      cp      $2a              ;'*'
f479 2811      jr      z,$f48c          ; (+$11)

;;=template error
f47b d1        pop     de               ;Possibly just premature end of template?
f47c c1        pop     bc
f47d b7        or      a
f47e c9        ret     

;;=template period
f47f 13        inc     de               ;If the first char (other than sign) is a decimal point
f480 05        dec     b
f481 28f8      jr      z,$f47b          ; (-$08)
f483 1a        ld      a,(de)
f484 fe23      cp      $23				; '#' Leading Period must be followed by a hash
f486 20f3      jr      nz,$f47b         ; (-$0d)
f488 1b        dec     de
f489 04        inc     b
f48a 1815      jr      $f4a1            ; (+$15)

;;=template asterisk
f48c 13        inc     de
f48d 05        dec     b
f48e 280e      jr      z,$f49e          ; (+$0e)
f490 1a        ld      a,(de)
f491 cd02f5    call    $f502            ;Asterisk followed by currency symbol
f494 2008      jr      nz,$f49e         ; (+$08)

f496 24        inc     h
f497 2e24      ld      l,$24            ;Flag bits for 'asterisk' and 'currency symbol' if asterisk + currency symbol
;;=template currency symbol
f499 3254ae    ld      ($ae54),a        ;Set currency symbol
f49c 13        inc     de
f49d 05        dec     b
f49e 79        ld      a,c              ;OR C,L - Put new flags into C
f49f b5        or      l
f4a0 4f        ld      c,a

;;=template hash
f4a1 f1        pop     af               ;Hashes before the decimal point. (Except if first char is decimal point,
                                        ;in which case we arrive here still at the decimal point)
f4a2 f1        pop     af
f4a3 cdaef4    call    $f4ae
f4a6 7c        ld      a,h              ;Chars before decimal point
f4a7 85        add     a,l              ;Chars including and after decimal point
f4a8 fe15      cp      $15
f4aa d8        ret     c

;;=raise Improper Argument error
f4ab c34dcb    jp      $cb4d			; Error: Improper Argument

;;=do template hash
f4ae af        xor     a
f4af 6f        ld      l,a              ;L=0. Number of chars after decimal point
f4b0 b0        or      b
f4b1 c8        ret     z

;;=template hash loop
f4b2 1a        ld      a,(de)           ;Again hashes before the decimal point, unless the first char is a decimal point
f4b3 fe2e      cp      $2e				; '.'
f4b5 280f      jr      z,$f4c6          ; (+$0f)
f4b7 fe23      cp      $23				; '#'
f4b9 2806      jr      z,$f4c1          ; (+$06)
f4bb fe2c      cp      $2c              ;","
f4bd 2010      jr      nz,$f4cf         ; (+$10)

f4bf cbc9      set     1,c              ;Flag bit 1 = Comma
;;=template hash hash
f4c1 24        inc     h                ;Just loop while hashes
f4c2 13        inc     de
f4c3 10ed      djnz    $f4b2            ; (-$13)
f4c5 c9        ret     

;;=template hash period
;Do items after the decimal point
f4c6 2c        inc     l                ;Branch here once we encounter a decimal point, inc after-decimal-point counter
f4c7 13        inc     de
f4c8 05        dec     b
f4c9 c8        ret     z

f4ca 1a        ld      a,(de)
f4cb fe23      cp      $23				; '#'
f4cd 28f7      jr      z,$f4c6          ; (-$09) Loop for hashes after the decimal point

;;=template hash other
;Items at the end of the template
f4cf eb        ex      de,hl            ;Anything else and we're done with the number part
f4d0 e5        push    hl

;Test for four '^' - exponent (Note, if we get past the first test then A contains '^')
f4d1 fe5e      cp      $5e              ;"^"
f4d3 2016      jr      nz,$f4eb         ; (+$16)
f4d5 23        inc     hl
f4d6 be        cp      (hl)
f4d7 2012      jr      nz,$f4eb         ; (+$12)
f4d9 23        inc     hl
f4da be        cp      (hl)
f4db 200e      jr      nz,$f4eb         ; (+$0e)
f4dd 23        inc     hl
f4de be        cp      (hl)
f4df 200a      jr      nz,$f4eb         ; (+$0a)
f4e1 23        inc     hl

;If we got here then we found four '^'
f4e2 78        ld      a,b
f4e3 d604      sub     $04              
f4e5 3804      jr      c,$f4eb          ; (+$04)
f4e7 47        ld      b,a
f4e8 e3        ex      (sp),hl
f4e9 cbf1      set     6,c              ;Flags bit 6 = Exponent

f4eb e1        pop     hl
f4ec eb        ex      de,hl
f4ed 04        inc     b
f4ee 05        dec     b
f4ef c8        ret     z

f4f0 cb59      bit     3,c              ;Exit if we already have a sign prefix
f4f2 c0        ret     nz

f4f3 1a        ld      a,(de)
f4f4 fe2d      cp      $2d				; '-'
f4f6 2805      jr      z,$f4fd          ; 
f4f8 fe2b      cp      $2b				; '+'
f4fa c0        ret     nz

f4fb cbd9      set     3,c              ;'+' suffix gives us bits 3 and 4
f4fd cbe1      set     4,c              ;'-' suffix only gives us bit 4
f4ff 13        inc     de
f500 05        dec     b
f501 c9        ret     

;;=test for currency symbols
;Returns Z if dollar or pound sign
;Patch this is you want another currency - as long as it's a single char prefix.
;Adding Euros might be a fun project?
f502 fe24      cp      $24				; '$'
f504 c8        ret     z

f505 fea3      cp      $a3				; '£' 
f507 c9        ret     

;;========================================================================
;; command WRITE
;WRITE [#<stream expression>,][<write list>]
;where <write list> is <expression>[<separator>]*

;* - means item can be repeated zero or more times
;<separator> can be a comma or semicolon

;Similar to PRINT but:
;- print zones are ignored
;- strings are enclosed in double quotes
;- commas are added between items
;- does not support the trailing separator
;Intended for writing to files in a form that can be read back by INPUT

f508 cdcfc1    call    $c1cf
                                    ;This routine evals a stream number (if present),
                                    ;swaps to it,
                                    ;CALLs the following code (popping address of the stack), 
                                    ;swaps back to original stream,
                                    ;returns to the caller

f50b cd3dde    call    $de3d
f50e da98c3    jp      c,$c398      ;Nothing to print
;;=WRITE do param loop
f511 cd62cf    call    $cf62
f514 f5        push    af
f515 e5        push    hl
f516 cd66ff    call    $ff66
f519 2808      jr      z,$f523          ; (+$08)
f51b cd5aef    call    $ef5a
f51e cd8bc3    call    $c38b		;; display 0 terminated string
f521 180d      jr      $f530            ; (+$0d)

;;=WRITE do string
f523 3e22      ld      a,$22           ;'"'
f525 cda0c3    call    $c3a0           ;; display text char
f528 cdd0f8    call    $f8d0
f52b 3e22      ld      a,$22           ;'"'
f52d cda0c3    call    $c3a0           ;; display text char

;;=WRITE do after parameter
f530 e1        pop     hl
f531 f1        pop     af
f532 ca98c3    jp      z,$c398      ;; new text line
f535 cdeff3    call    $f3ef
f538 3e2c      ld      a,$2c
f53a cda0c3    call    $c3a0           ;; display text char
f53d 18d2      jr      $f511            ; (-$2e)





;;***MemoryAllocation.asm
;;<< MEMORY ALLOCATION FUNCTIONS
;;< Includes MEMORY, SYMBOL (AFTER)
;;=======================================================

;;initialise memory model
;Start of day initialisation

;Values passed from MC_START_PROGRAM
;DE = first byte of available memory
;HL=last byte of memory not used by BASIC
;BC=last byte of memory not used by firmware

;Returns Carry true if failed - I.e. not enough memory

f53f 0100ac    ld      bc,$ac00         ;This appears to be detecting a warm boot.
f542 cddeff    call    $ffde ; HL=BC?
f545 d0        ret     nc

f546 225eae    ld      ($ae5e),hl ; HIMEM
f549 2273b0    ld      ($b073),hl
f54c 2260ae    ld      ($ae60),hl
f54f eb        ex      de,hl
f550 2262ae    ld      ($ae62),hl  ;start of line entry buffer
f553 012f01    ld      bc,$012f    ;length of line entry buffer (plus other stuff?)
f556 09        add     hl,bc
f557 d8        ret     c

f558 2264ae    ld      ($ae64),hl  ;start of program area?
f55b eb        ex      de,hl
f55c 23        inc     hl
f55d ed52      sbc     hl,de
f55f d8        ret     c

f560 7c        ld      a,h
f561 fe04      cp      $04
f563 d8        ret     c

f564 cd7ff7    call    $f77f
f567 326eae    ld      ($ae6e),a
f56a c9        ret     

;;========================================================================
;; command MEMORY
;MEMORY <address expression>
;Specifies the highest byte of memory which is available to BASIC

f56b cdf5ce    call    $cef5            ;eval parameter
f56e e5        push    hl
f56f 2a60ae    ld      hl,($ae60)       ;Address too high?
f572 cdd8ff    call    $ffd8 ; HL=DE?
f575 3831      jr      c,$f5a8          ; (+$31)

f577 13        inc     de
f578 cdecf5    call    $f5ec ; compare DE with HIMEM
f57b dc8af5    call    c,$f58a      ;Move character matrix table?
f57e eb        ex      de,hl
f57f cd08f8    call    $f808        ;Move strings area
f582 2a76b0    ld      hl,($b076)
f585 2278b0    ld      ($b078),hl
f588 e1        pop     hl
f589 c9        ret     

f58a cdaebb    call    $bbae			; firmware function: TXT GET M TABLE
f58d ed4b5eae  ld      bc,($ae5e) ; HIMEM
f591 dce0f5    call    c,$f5e0
f594 3812      jr      c,$f5a8          ; (+$12)
f596 2a76b0    ld      hl,($b076)
f599 2b        dec     hl
f59a cde0f5    call    $f5e0
f59d d0        ret     nc

f59e 3a75b0    ld      a,($b075)
f5a1 b7        or      a
f5a2 c8        ret     z

f5a3 fe04      cp      $04
f5a5 ca7ff7    jp      z,$f77f
;;=raise memory full error
f5a8 c375f8    jp      $f875

;;====================================================
;;=prepare memory for loading binary
f5ab d5        push    de
f5ac eb        ex      de,hl
f5ad 09        add     hl,bc
f5ae 2b        dec     hl
f5af ed4b62ae  ld      bc,($ae62)                  ;input buffer address
f5b3 e3        ex      (sp),hl
f5b4 eb        ex      de,hl
f5b5 2a5eae    ld      hl,($ae5e) ; HIMEM
f5b8 cde0f5    call    $f5e0
f5bb eb        ex      de,hl
f5bc e3        ex      (sp),hl
f5bd eb        ex      de,hl
f5be dce0f5    call    c,$f5e0
f5c1 30e5      jr      nc,$f5a8         ; (-$1b)
f5c3 ed4b76b0  ld      bc,($b076)
f5c7 21ff0f    ld      hl,$0fff
f5ca 09        add     hl,bc
f5cb cde0f5    call    $f5e0
f5ce d1        pop     de
f5cf dce0f5    call    c,$f5e0
f5d2 d8        ret     c

f5d3 eb        ex      de,hl
f5d4 50        ld      d,b
f5d5 59        ld      e,c
f5d6 cdecf5    call    $f5ec ; compare DE with HIMEM
f5d9 c27ff7    jp      nz,$f77f
f5dc 2278b0    ld      ($b078),hl
f5df c9        ret     

;;=========================
;;compare HL minus BC to DE minus BC
f5e0 d5        push    de
f5e1 e5        push    hl
f5e2 b7        or      a
f5e3 ed42      sbc     hl,bc
f5e5 eb        ex      de,hl
f5e6 b7        or      a
f5e7 ed42      sbc     hl,bc
f5e9 eb        ex      de,hl
f5ea 1806      jr      $f5f2            ; (+$06)

;;===========================
;;=compare DE to HIMEM plus 1
f5ec d5        push    de
f5ed e5        push    hl
f5ee 2a5eae    ld      hl,($ae5e) ; HIMEM
f5f1 23        inc     hl
f5f2 cdd8ff    call    $ffd8 ; HL=DE?
f5f5 e1        pop     hl
f5f6 d1        pop     de
f5f7 c9        ret     

;;==========================
;;=get size of strings area in BC
f5f8 d5        push    de
f5f9 e5        push    hl
f5fa 2a71b0    ld      hl,($b071)
f5fd eb        ex      de,hl
f5fe 2a73b0    ld      hl,($b073)
f601 cde4ff    call    $ffe4			; BC = HL-DE
f604 e1        pop     hl
f605 d1        pop     de
f606 c9        ret     

;;==========================
;;=prob grow all program space pointers by BC
f607 2a66ae    ld      hl,($ae66)
f60a 09        add     hl,bc
f60b 2266ae    ld      ($ae66),hl
f60e 3a6eae    ld      a,($ae6e)
f611 b7        or      a
f612 c0        ret     nz

;;=prob grow program space ptrs by BC
;;(but DOESN'T do any memory moving)
f613 2a68ae    ld      hl,($ae68)
f616 09        add     hl,bc
f617 2268ae    ld      ($ae68),hl
;;=prob grow variables space ptrs by BC
f61a 2a6aae    ld      hl,($ae6a)
f61d 09        add     hl,bc
f61e 226aae    ld      ($ae6a),hl
;;=prob grow array space ptrs by BC
f621 2a6cae    ld      hl,($ae6c)
f624 09        add     hl,bc
f625 226cae    ld      ($ae6c),hl
f628 c9        ret     

;;==============================
;;prob move vars and arrays to end of memory
f629 cdfcf6    call    $f6fc
f62c 44        ld      b,h
f62d 4d        ld      c,l
f62e 2a66ae    ld      hl,($ae66)
f631 eb        ex      de,hl
f632 cdb8f6    call    $f6b8
f635 3eff      ld      a,$ff
f637 326eae    ld      ($ae6e),a
f63a 18d7      jr      $f613            ; (-$29)

;;=============================
;;prob move vars and arrays back from end of memory
f63c af        xor     a
f63d 326eae    ld      ($ae6e),a
f640 2a66ae    ld      hl,($ae66)
f643 eb        ex      de,hl
f644 2a68ae    ld      hl,($ae68)
f647 cde4ff    call    $ffe4			; BC = HL-DE
f64a cde5f6    call    $f6e5
f64d 18c4      jr      $f613            ; (-$3c)

;;==============================
;;prob clear execution stack
f64f 216fae    ld      hl,$ae6f
f652 226fb0    ld      ($b06f),hl
f655 3e01      ld      a,$01
f657 cd72f6    call    $f672
f65a 3600      ld      (hl),$00
f65c 23        inc     hl

;;=set execution stack next free ptr and its cache
f65d 2219ae    ld      ($ae19),hl
f660 180c      jr      $f66e            ; (+$0c)

;;======================================
;;probably remove A bytes off execution stack and get address
f662 2a6fb0    ld      hl,($b06f)
f665 2f        cpl     
f666 3c        inc     a
f667 c8        ret     z

f668 85        add     a,l
f669 6f        ld      l,a
f66a 3eff      ld      a,$ff
f66c 8c        adc     a,h
f66d 67        ld      h,a

;;=set execution stack next free ptr
f66e 226fb0    ld      ($b06f),hl
f671 c9        ret     

;;===================================
;;possibly alloc A bytes on execution stack
f672 2a6fb0    ld      hl,($b06f)
f675 e5        push    hl
f676 85        add     a,l          ; HL = HL + A?
f677 6f        ld      l,a
f678 8c        adc     a,h
f679 95        sub     l
f67a 67        ld      h,a
f67b 226fb0    ld      ($b06f),hl
f67e 3e94      ld      a,(2 - &b06e) and $ff  ;was $94 last byte of execution stack - check for stack overflow???   
f680 85        add     a,l
f681 3e4f      ld      a,((2 - &b06e) >> 8) and $ff     ;was $4f
f683 8c        adc     a,h
f684 e1        pop     hl
f685 d0        ret     nc

f686 cd4ff6    call    $f64f
f689 c375f8    jp      $f875

;;==================================
;;empty strings area
f68c 2a73b0    ld      hl,($b073)
f68f 2271b0    ld      ($b071),hl
f692 c9        ret     

;;==============================
;;alloc C bytes in string space
;Alloc C + 2 bytes in the strings area (i.e. to the bottom),
;then writes BC to the two lowest bytes (where B=0)
;Returns the HL=first byte allocated (NOT inlcuding the two extra bytes)
f693 0600      ld      b,$00
;;=alloc loop
f695 2a6cae    ld      hl,($ae6c)
f698 eb        ex      de,hl
f699 2a71b0    ld      hl,($b071)
f69c b7        or      a
f69d ed42      sbc     hl,bc
f69f 2b        dec     hl
f6a0 2b        dec     hl
f6a1 cdd8ff    call    $ffd8 ; HL=DE?
f6a4 3009      jr      nc,$f6af         ; (+$09)
f6a6 cd64fc    call    $fc64
f6a9 38ea      jr      c,$f695          ; (-$16)
f6ab cd45cb    call    $cb45
f6ae defb $0e                         ;Inline error code: String Space Full error

f6af 2271b0        ld ($b071),hl        ;Update end of memory variable
f6b2 23        inc     hl
f6b3 71        ld      (hl),c           ;Write BC to bottom of string space
f6b4 23        inc     hl
f6b5 70        ld      (hl),b
f6b6 23        inc     hl
f6b7 c9        ret     

;;================================
;;move lower memory up
;Moves memory between DE and HL up by BC bytes
f6b8 cd14f7    call    $f714
f6bb c5        push    bc
f6bc d5        push    de
f6bd d5        push    de
f6be e5        push    hl
f6bf 09        add     hl,bc
f6c0 380e      jr      c,$f6d0          ; (+$0e)
f6c2 eb        ex      de,hl
f6c3 cd07f7    call    $f707
f6c6 cdd8ff    call    $ffd8 ; HL=DE?
f6c9 3008      jr      nc,$f6d3         ; (+$08)
f6cb cd64fc    call    $fc64
f6ce 38f3      jr      c,$f6c3          ; (-$0d)
;;=raise Memory Full error
f6d0 c375f8    jp      $f875

;;=do move lower memory up
f6d3 e1        pop     hl
f6d4 c1        pop     bc
f6d5 d5        push    de
f6d6 7d        ld      a,l           ;BC=HL-BC
f6d7 91        sub     c
f6d8 4f        ld      c,a
f6d9 7c        ld      a,h
f6da 98        sbc     a,b
f6db 47        ld      b,a
f6dc 2b        dec     hl
f6dd 1b        dec     de
f6de cdf5ff    call    $fff5 ; copy bytes LDDR (BC = count)
f6e1 e1        pop     hl
f6e2 d1        pop     de
f6e3 c1        pop     bc
f6e4 c9        ret     

;;===================================
;;move lower memory down
f6e5 c5        push    bc
f6e6 d5        push    de
f6e7 eb        ex      de,hl            ;DE=DE+BC
f6e8 09        add     hl,bc
f6e9 eb        ex      de,hl
f6ea cd14f7    call    $f714
f6ed cde4ff    call    $ffe4			; BC = HL-DE
f6f0 eb        ex      de,hl
f6f1 d1        pop     de
f6f2 cdefff    call    $ffef ; copy bytes LDIR (BC = count)
f6f5 d1        pop     de
f6f6 210000    ld      hl,$0000
f6f9 c3e4ff    jp      $ffe4			; BC = HL-DE

;;============================
;;get free space byte count in HL addr in DE
f6fc 2a6cae    ld      hl,($ae6c)
f6ff eb        ex      de,hl
f700 2a71b0    ld      hl,($b071)
f703 b7        or      a
f704 ed52      sbc     hl,de
f706 c9        ret     

;;==============================
;;get end of free space
;Gets the address of the last free byte in the central spare block,
;taking into account whether variables etc are at the bottom of memory or the top.
f707 3a6eae    ld      a,($ae6e)
f70a b7        or      a
f70b 2a71b0    ld      hl,($b071)
f70e c8        ret     z

f70f 2a68ae    ld      hl,($ae68)
f712 2b        dec     hl
f713 c9        ret     

;;==================================
;;get start of free space
;Gets the address of the first free byte in the central spare block,
;taking into account whether variables etc are at the bottom of memory or the top.
f714 3a6eae    ld      a,($ae6e)
f717 b7        or      a
f718 2a6cae    ld      hl,($ae6c)
f71b c8        ret     z

f71c 2a66ae    ld      hl,($ae66)
f71f c9        ret     

;;===================================
;BASIC uses two 2k buffers, one each for read and write. Either both
;are allocated or neither (it never allocates only one). file_buffer_flags
;($b075) bit 2 maintains the 'buffers allocated' status, and if allocated,
;the file_buffer_flags maintains the in-use state of each buffer (bits 1 and 0).
;The 4k buffer will only be released (be the routines below) when neither 2k 
;buffer is in use.

;;=alloc and use file read buffer
;Allocs file buffers if not allocated, 
;marks read buffer as in use
;returns address of 2k read buffer in DE
f720 110100    ld      de,$0001
f723 1808      jr      $f72d            ; (+$08)

;;=alloc and use file write buffer
;Allocs file buffers if not allocated, 
;marks write buffer as in use
;returns address of 2k write buffer in DE
f725 110208    ld      de,$0802
f728 1803      jr      $f72d            ; (+$03)

;;=alloc file write buffer
;Allocs file buffers if not allocated, 
;does NOT mark either buffer as in use (retains previous in use state)
;returns address of 2k write buffer in DE
f72a 110008    ld      de,$0800

;Allocates the 4k file buffer if not allocated, sets the in use state of
;buffer using value of E (bits 1 or 0)
;If D is $00 returns the address of the read buffer in DE,
;If D is $08 returns the address of the write buffer in DE.
f72d c5        push    bc
f72e e5        push    hl
f72f 3a75b0    ld      a,($b075)       
f732 b7        or      a
f733 2018      jr      nz,$f74d         ; (+$18) Buffer already allocated?

f735 d5        push    de               ;Allocate buffer
f736 2a5eae    ld      hl,($ae5e) ; HIMEM
f739 23        inc     hl
f73a 2278b0    ld      ($b078),hl
f73d 1100f0    ld      de,$f000       ;##LIT##
f740 19        add     hl,de
f741 d275f8    jp      nc,$f875
f744 cd08f8    call    $f808
f747 2276b0    ld      ($b076),hl
f74a d1        pop     de
f74b 3e04      ld      a,$04        ;Buffers allocate flag

f74d b3        or      e            ;Update buffer in use flags
f74e 2a76b0    ld      hl,($b076)
f751 1e00      ld      e,$00        ;Get pointer to required buffer based on D
f753 19        add     hl,de
f754 eb        ex      de,hl
f755 e1        pop     hl
f756 c1        pop     bc
f757 1827      jr      $f780            ; (+$27)

;;=unuse file write buffer
;Frees the buffer if neither buffer is in use
f759 3efe      ld      a,$fe
f75b 1806      jr      $f763            ; (+$06)

;;=unuse file read buffer
;Frees the buffer if neither buffer is in use
f75d 3efd      ld      a,$fd
f75f 1802      jr      $f763            ; (+$02)

;;=free file buffer if not used
f761 3eff      ld      a,$ff

;A=mask for bits to retain in file_buffer_flags (i.e inverse of buffer(s) to free)
f763 e5        push    hl
f764 2175b0    ld      hl,$b075
f767 a6        and     (hl)             ;Mask out and update file_buffer_flags
f768 77        ld      (hl),a           
f769 fe04      cp      $04              ;Both buffers free?
f76b 2009      jr      nz,$f776         ; (+$09)

f76d 2a76b0    ld      hl,($b076)       ;Free buffersS
f770 eb        ex      de,hl
f771 cdecf5    call    $f5ec ; compare DE with HIMEM
f774 2802      jr      z,$f778          ; (+$02)
f776 e1        pop     hl
f777 c9        ret     

f778 2a78b0    ld      hl,($b078)
f77b cd08f8    call    $f808
f77e e1        pop     hl

;;=clear file buffer flag
f77f af        xor     a
;;=set file buffer flag
f780 3275b0    ld      ($b075),a
f783 c9        ret     

;;========================================================================
;; command SYMBOL, SYMBOL AFTER
;SYMBOL <character number>,<list of: <row>>
;Defines the character matrix for a symbol (UDG, user defined graphics)
;Row list must contain eight items
;By default symbols after 240 can be defined. Others will need a SYMBOL AFTER command

;SYMBOL AFTER <integer expression>
;Define the first user definable symbol
;Defaults to SYMBOL AFTER 240
;Deletes any already created symbols
;Cannot be used after a HIMEM has been issued since the last SYMBOL AFTER (except SYMBOL AFTER 256)

f784 fe80      cp      $80				; AFTER
f786 2829      jr      z,$f7b1          ; (+$29)

f788 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
f78b 4f        ld      c,a
f78c cd15de    call    $de15 ; check for comma
f78f 0608      ld      b,$08    ;We need 8 values
f791 37        scf     

f792 d441de    call    nc,$de41
f795 9f        sbc     a,a
f796 dcb8ce    call    c,$ceb8 ; get number and check it's less than 255 
f799 f5        push    af
f79a b7        or      a
f79b 10f5      djnz    $f792            ; (-$0b)

f79d eb        ex      de,hl
f79e 79        ld      a,c
f79f cda5bb    call    $bba5			; firmware function: TXT GET MATRIX		
f7a2 d24dcb    jp      nc,$cb4d			; Error: Improper Argument
f7a5 010800    ld      bc,$0008         ;###LIT### 8 bytes to write
f7a8 09        add     hl,bc
f7a9 f1        pop     af
f7aa 2b        dec     hl
f7ab 77        ld      (hl),a
f7ac 0d        dec     c
f7ad 20fa      jr      nz,$f7a9         ; (-$06)
f7af eb        ex      de,hl
f7b0 c9        ret     

;;=do SYMBOL AFTER
f7b1 cd2cde    call    $de2c			; get next token skipping space
f7b4 cdd8ce    call    $ced8 ; get number
f7b7 e5        push    hl
f7b8 210001    ld      hl,$0100
f7bb cdd8ff    call    $ffd8 ; HL=DE?
f7be da4dcb    jp      c,$cb4d			; Error: Improper Argument
f7c1 d5        push    de
f7c2 cdaebb    call    $bbae			; firmware function: TXT GET M TABLE
f7c5 eb        ex      de,hl
f7c6 301b      jr      nc,$f7e3         ; (+$1b)
;; A = first character
;; HL = address of table
f7c8 2f        cpl     
f7c9 6f        ld      l,a
f7ca 2600      ld      h,$00
f7cc 23        inc     hl
f7cd 29        add     hl,hl			; x2
f7ce 29        add     hl,hl			; x4
f7cf 29        add     hl,hl			; x8
f7d0 cdecf5    call    $f5ec ; compare DE with HIMEM
f7d3 c24dcb    jp      nz,$cb4d			; Error: Improper Argument
f7d6 19        add     hl,de
f7d7 cd08f8    call    $f808
f7da cd61f7    call    $f761
										; HL = Address of table
f7dd 110001    ld      de,$0100			; first character in table
f7e0 cdabbb    call    $bbab			; firmware function: TXT SET M TABLE
f7e3 d1        pop     de
f7e4 cde9f7    call    $f7e9			; no defined table
f7e7 e1        pop     hl
f7e8 c9        ret     

;;+-------------
;; SYMBOL AFTER
;; A = number
f7e9 210001    ld      hl,$0100
f7ec b7        or      a
f7ed ed52      sbc     hl,de
f7ef c8        ret     z

f7f0 d5        push    de
f7f1 29        add     hl,hl
f7f2 29        add     hl,hl
f7f3 29        add     hl,hl
f7f4 eb        ex      de,hl
f7f5 2a5eae    ld      hl,($ae5e) ; HIMEM
f7f8 ed52      sbc     hl,de
f7fa 7c        ld      a,h
f7fb fe40      cp      $40
f7fd da75f8    jp      c,$f875
f800 23        inc     hl
f801 cd08f8    call    $f808
f804 d1        pop     de
f805 c3abbb    jp      $bbab				; firmware function: TXT SET M TABLE


;;=move strings area
;Compact the strings area
f808 e5        push    hl
f809 cd64fc    call    $fc64
f80c eb        ex      de,hl

;Calc the number of bytes to move it by
f80d cdf8f5    call    $f5f8
f810 2a6cae    ld      hl,($ae6c)
f813 09        add     hl,bc
f814 3f        ccf     
f815 dcd8ff    call    c,$ffd8 ; HL=DE?
f818 305b      jr      nc,$f875         ; (+$5b)
f81a 2a5eae    ld      hl,($ae5e) ; HIMEM
f81d eb        ex      de,hl
f81e 37        scf     
f81f ed52      sbc     hl,de
f821 227ab0    ld      ($b07a),hl
f824 e5        push    hl

;Iterate every string variable to add the offset to it's address
f825 1165f8    ld      de,$f865           ;  ##LABEL##
f828 cd93da    call    $da93

;Now do the actual moving of the strings area
f82b c1        pop     bc               ;BC=offset
f82c 78        ld      a,b
f82d 07        rlca                     ;High bit set if negative - moving area down
f82e 3814      jr      c,$f844          ; (+$14)
f830 b1        or      c                ;Zero offset?
f831 282b      jr      z,$f85e          ; (+$2b)

;Moving strings area down
f833 2a73b0    ld      hl,($b073)
f836 54        ld      d,h
f837 5d        ld      e,l
f838 09        add     hl,bc
f839 e5        push    hl
f83a cdf8f5    call    $f5f8
f83d eb        ex      de,hl
f83e cdf5ff    call    $fff5 ; copy bytes LDDR (BC = count)
f841 e1        pop     hl
f842 1813      jr      $f857            ; (+$13)

;Moving strings area up
f844 2a71b0    ld      hl,($b071)
f847 54        ld      d,h
f848 5d        ld      e,l
f849 09        add     hl,bc
f84a e5        push    hl
f84b cdf8f5    call    $f5f8
f84e eb        ex      de,hl
f84f 23        inc     hl
f850 13        inc     de
f851 cdefff    call    $ffef ; copy bytes LDIR (BC = count)
f854 eb        ex      de,hl
f855 2b        dec     hl
f856 d1        pop     de

;Done - moved
f857 2273b0    ld      ($b073),hl
f85a eb        ex      de,hl
f85b 2271b0    ld      ($b071),hl

;Done - no move
f85e e1        pop     hl
f85f 2b        dec     hl
f860 225eae    ld      ($ae5e),hl ; HIMEM
f863 23        inc     hl
f864 c9        ret     

;Called by string iterator:
;DE=addr of /last/ byte of string descriptor
;BC=string address
;A=string length
;;=adjust string descriptor address callback
;Adjust the address in a string descriptor by adding &b07a (string move offset) to it.
f865 2a66ae    ld      hl,($ae66)
f868 cddeff    call    $ffde ; HL=BC?
f86b d0        ret     nc

f86c 2a7ab0    ld      hl,($b07a)
f86f 09        add     hl,bc
f870 eb        ex      de,hl
f871 72        ld      (hl),d
f872 2b        dec     hl
f873 73        ld      (hl),e
f874 c9        ret     

;;=raise Memory Full error
f875 cd45cb    call    $cb45
f878 defb $07                         ;Inline error code: Memory full





;;***StringFunctions.asm
;;<< STRING FUNCTIONS
;;<including the string iterator
;;===================================================================
;String parsing routines
;They returns with HL at end of string and B=length of string
;Each uses the iterator at string_getter which takes the following code section as a callback

;;=get quoted string
;String wrapped in double quotes
f879 23        inc     hl
f87a cda7f8    call    $f8a7            ; Uses the following code as a callback (doesn't return to it)

f87d 7e        ld      a,(hl)			; read character
f87e fe22      cp      $22				; double quote
f880 ca2cde    jp      z,$de2c			; get next token skipping space
f883 b7        or      a				; end of line marker
f884 2831      jr      z,$f8b7          
f886 04        inc     b				; increment number of characters
f887 23        inc     hl				; increment pointer
f888 18f3      jr      $f87d            ; 

;;+---------------------------------------------------------------------------
;;get ASCIIZ string
f88a cda7f8    call    $f8a7            ; Uses the following code as a callback (doesn't return to it)

f88d 7e        ld      a,(hl)
f88e b7        or      a
f88f c8        ret     z               ;return directly to string getter

f890 23        inc     hl
f891 04        inc     b
f892 18f9      jr      $f88d            ; (-$07)

;;+-------------------------------------------------------------
;;get string until $00, comma or value in A
;; returns with HL at end of string and B=length
f894 cda7f8    call    $f8a7            ; Uses the following code as a callback (doesn't return to it)

f897 4f        ld      c,a
f898 7e        ld      a,(hl)
f899 b7        or      a
f89a 281b      jr      z,$f8b7          ; (+$1b)
f89c b9        cp      c
f89d 2818      jr      z,$f8b7          ; (+$18)
f89f fe2c      cp      $2c              ;","
f8a1 2814      jr      z,$f8b7          ; (+$14)
f8a3 23        inc     hl
f8a4 04        inc     b
f8a5 18f1      jr      $f898            ; (-$0f)

;;=string getter
;;get string using following code segment as subroutine
;;HL points to data (string)
f8a7 229db0    ld      ($b09d),hl
f8aa d1        pop     de               ; Get address of callback code
f8ab 0600      ld      b,$00            ; B = string length
f8ad cdfeff    call    $fffe			; JP (DE) call get string subroutine
f8b0 78        ld      a,b              ; Only the ASCIIZ variant returns here
f8b1 329cb0    ld      ($b09c),a
f8b4 c3d6fb    jp      $fbd6            ;$b09d = start of string. 
                                        ;$b09c, A and B equal length 
                                        ;HL = next byte after string (and after whitespace)
                                        
;;===================================================
;;=right trim and return
;;remove whitespace from end of string
f8b7 e5        push    hl
f8b8 04        inc     b
;;=right trim loop
f8b9 05        dec     b                ;remove character from end of string
f8ba 2812      jr      z,$f8ce          ; (+$12) length = zero?
f8bc 2b        dec     hl
f8bd 7e        ld      a,(hl)           
f8be fe20      cp      $20              ;" "
f8c0 28f7      jr      z,$f8b9          ; (-$09)
f8c2 fe09      cp      $09              ;TAB
f8c4 28f3      jr      z,$f8b9          ; (-$0d)
f8c6 fe0d      cp      $0d              ; carriage return
f8c8 28ef      jr      z,$f8b9          ; (-$11)
f8ca fe0a      cp      $0a              ; new line
f8cc 28eb      jr      z,$f8b9          ; (-$15)
f8ce e1        pop     hl
f8cf c9        ret                      ; return to string getter

;;=============================================
;; output accumulator string
f8d0 cdf5fb    call    $fbf5
f8d3 c8        ret     z

;;=output string atDE length B
f8d4 1a        ld      a,(de)
f8d5 13        inc     de
f8d6 cdb8c3    call    $c3b8
f8d9 10f9      djnz    $f8d4            ; (-$07)
f8db c9        ret     

;;=================================================
;;=prob output first C chars of accumulator string
f8dc cdf5fb    call    $fbf5
f8df c8        ret     z

f8e0 79        ld      a,c
f8e1 90        sub     b
f8e2 3005      jr      nc,$f8e9         ; (+$05)
f8e4 80        add     a,b
f8e5 2802      jr      z,$f8e9          ; (+$02)
f8e7 47        ld      b,a
f8e8 af        xor     a
f8e9 4f        ld      c,a
f8ea 18e8      jr      $f8d4            ; (-$18)

;;========================================================
;; function LOWER$
;LOWER$(<string expression>)
;Returns a lowercase copy of the parameter.

f8ec 01f1f8    ld      bc,$f8f1         ;##LABEL##
f8ef 180c      jr      $f8fd            ; (+$0c)

;;=convert character to lower case
f8f1 fe41      cp      $41
f8f3 d8        ret     c

f8f4 fe5b      cp      $5b
f8f6 d0        ret     nc

f8f7 c620      add     a,$20
f8f9 c9        ret     

;;========================================================
;; function UPPER$
;UPPER$(<string expression>)
;Returns an upper case copy of the string

f8fa 01abff    ld      bc,$ffab        ;##LABEL##

;;=string iterator
;Copies the string in the accumulator,
;calls the iterator routine for each character,
;thens add the new string back to the accumulator/string stack
;BC = routine to call for each character
f8fd c5        push    bc
f8fe 2aa0b0    ld      hl,($b0a0)
f901 cdf5fb    call    $fbf5
f904 cd41fc    call    $fc41
f907 23        inc     hl
f908 4e        ld      c,(hl)
f909 23        inc     hl
f90a 66        ld      h,(hl)
f90b 69        ld      l,c
f90c c1        pop     bc
f90d 3c        inc     a
f90e 3d        dec     a
f90f cad6fb    jp      z,$fbd6
f912 f5        push    af
f913 7e        ld      a,(hl)
f914 23        inc     hl
f915 cdfcff    call    $fffc			; JP (BC) call callback function
f918 12        ld      (de),a
f919 13        inc     de
f91a f1        pop     af
f91b 18f1      jr      $f90e            ; (-$0f)

;;====================================================
;;=concat two strings
;HL=address of a string descriptor
;Appends the string in the accumulator to the string at HL,
;returns it in the accumulator/string stack
f91d ed5ba0b0  ld      de,($b0a0)
f921 1a        ld      a,(de)
f922 86        add     a,(hl)
f923 3004      jr      nc,$f929         ; (+$04)
f925 cd45cb    call    $cb45
f928 defb $0f                         ;Inline error code: String too long
    
f929 cd41fc    call    $fc41
f92c cd59f9    call    $f959
f92f d5        push    de
f930 c5        push    bc
f931 48        ld      c,b
f932 cdd6fb    call    $fbd6
f935 79        ld      a,c
f936 cdecff    call    $ffec			;; copy bytes (A=count, HL=source, DE=dest)
f939 c1        pop     bc
f93a e1        pop     hl
f93b 79        ld      a,c
f93c c3ecff    jp      $ffec			;; copy bytes (A=count, HL=source, DE=dest)

;;================================================
;;string comparison

f93f cd59f9    call    $f959
f942 af        xor     a
f943 b9        cp      c
f944 280f      jr      z,$f955          ; (+$0f)
f946 b8        cp      b
f947 280a      jr      z,$f953          ; (+$0a)
f949 05        dec     b
f94a 0d        dec     c
f94b 1a        ld      a,(de)
f94c 13        inc     de
f94d 96        sub     (hl)
f94e 23        inc     hl
f94f 28f2      jr      z,$f943          ; (-$0e)
f951 9f        sbc     a,a
f952 c0        ret     nz

f953 3c        inc     a
f954 c9        ret     

f955 b8        cp      b
f956 c8        ret     z

f957 9f        sbc     a,a
f958 c9        ret     

;;=get string stack TOS
f959 cdf5fb    call    $fbf5
f95c 48        ld      c,b
f95d d5        push    de
f95e cd03fc    call    $fc03
f961 eb        ex      de,hl
f962 d1        pop     de
f963 c9        ret     

;;========================================================================
;; function BIN$
;BIN$(<unsigned integer expression>[,<field width>]
;Convert the expression to a binary ASCII string padded to the given width with leading zeros
;Expression can be -32767..65535
;Field width can be 0..16

f964 010101    ld      bc,$0101         ;One bit per digit and mask for one digit
f967 1803      jr      $f96c            ; (+$03)

;;========================================================================
;; function HEX$
;HEX$(<unsigned integer expression>[,<field width>]
;Convert the expression to a hexadecimal ASCII string padded to the given width with leading zeros
;Expression can be -32767..65535
;Field width can be 0..16

f969 010f04    ld      bc,$040f         ;Four bits per digit and mask for one digit

f96c c5        push    bc
f96d cd62cf    call    $cf62            ;Read value
f970 e5        push    hl
f971 cdebfe    call    $feeb            ;Convert to unsigned integer
f974 e3        ex      (sp),hl
f975 cd41de    call    $de41            ;Comma?
f978 9f        sbc     a,a              ;Calc default width and flag
f979 dcb8ce    call    c,$ceb8          ;If so read width parameter
f97c fe11      cp      $11              ;Width must be <= 16
f97e d24dcb    jp      nc,$cb4d			;Error: Improper Argument
f981 47        ld      b,a              ;Preserve width
f982 cd1dde    call    $de1d            ;Check for close bracket
f985 78        ld      a,b              ;Restore width
f986 eb        ex      de,hl
f987 e1        pop     hl
f988 c1        pop     bc
f989 d5        push    de
f98a cddff1    call    $f1df            ;Convert to ASCIIZ string
f98d 1831      jr      $f9c0            ; (+$31)

;;========================================================================
;; function DEC$
;DEC$(<numeric expression>,<format template>)
;Generate a formatted string representation of a number.
;Format templates are as per PRINT USING but only the following characters are allowed:
;   + - $ * # , . ^

f98f cd62cf    call    $cf62
f992 cd15de    call    $de15 ; check for comma
f995 cd74ff    call    $ff74
f998 cd03cf    call    $cf03
f99b cd1dde    call    $de1d ; check for close bracket
f99e e5        push    hl
f99f 79        ld      a,c
f9a0 cd62f6    call    $f662
f9a3 d5        push    de
f9a4 79        ld      a,c
f9a5 cd6cff    call    $ff6c
f9a8 d1        pop     de
f9a9 78        ld      a,b
f9aa b7        or      a
f9ab c448f4    call    nz,$f448
f9ae d24dcb    jp      nc,$cb4d			; Error: Improper Argument
f9b1 78        ld      a,b
f9b2 b7        or      a
f9b3 c24dcb    jp      nz,$cb4d			; Error: Improper Argument
f9b6 79        ld      a,c
f9b7 cd6aef    call    $ef6a
f9ba 1804      jr      $f9c0            ; (+$04)

;;========================================================
;; function STR$
;STR$(<numeric expression>)
;Converts a number to it's string representation

f9bc e5        push    hl
f9bd cd68ef    call    $ef68

;;=copy ASCIIZ string to stack and accumulator
f9c0 e5        push    hl
f9c1 0eff      ld      c,$ff
f9c3 af        xor     a

f9c4 0c        inc     c                ;Count string length (ASCIIZ)
f9c5 be        cp      (hl)
f9c6 23        inc     hl
f9c7 20fb      jr      nz,$f9c4         ; (-$05)

f9c9 e1        pop     hl
f9ca 79        ld      a,c
f9cb cdd3fb    call    $fbd3
f9ce cdecff    call    $ffec			;; copy bytes (A=count, HL=source, DE=dest)
f9d1 e1        pop     hl
f9d2 c9        ret     

;;========================================================================
;; function LEFT$
;LEFT$(<string expression>,<required length>)
;Returns the given number of characters from the left of the string.
;Length can be 0..255

f9d3 cd43fa    call    $fa43
f9d6 1818      jr      $f9f0            ; (+$18)

;;========================================================================
;; function RIGHT$
;RIGHT$(<string expression>,<required length>)
;Returns the given number of characters from the right of a string.
;Length is 0..255

f9d8 cd43fa    call    $fa43
f9db 1a        ld      a,(de)
f9dc 90        sub     b
f9dd 3811      jr      c,$f9f0          ; (+$11)
f9df 4f        ld      c,a
f9e0 180e      jr      $f9f0            ; (+$0e)

;;=======================================================================
;; prefix MID$
;MID$(<string expression>,<start position>[,<sub-string length>])
;Extract substring. (See also command MID$)
;Position and length can be 1..255

f9e2 cd19de    call    $de19 ; check for open bracket
f9e5 cd43fa    call    $fa43
f9e8 ca4dcb    jp      z,$cb4d			; Error: Improper Argument
f9eb 05        dec     b
f9ec 48        ld      c,b
f9ed cd4ffa    call    $fa4f
;;------------------------------------------------------------------------
;;=do extract substring
f9f0 cd1dde    call    $de1d ; check for close bracket
f9f3 e5        push    hl
f9f4 eb        ex      de,hl
f9f5 cd60fa    call    $fa60
f9f8 cd41fc    call    $fc41
f9fb cd03fc    call    $fc03
f9fe eb        ex      de,hl
f9ff cdd6fb    call    $fbd6
fa02 0600      ld      b,$00
fa04 09        add     hl,bc
fa05 1837      jr      $fa3e            ; (+$37)

;;========================================================================
;; command MID$
;MID$(<string variable>,<start position>[,sub-string length])=<string expression>
;Replaces the specified characters within the first string variable with the second string variable.
;See also function MID$

fa07 cd19de    call    $de19 ; check for open bracket
fa0a cdbfd6    call    $d6bf
fa0d cd5eff    call    $ff5e
fa10 e5        push    hl
fa11 eb        ex      de,hl
fa12 cd58fb    call    $fb58
fa15 e3        ex      (sp),hl
fa16 cd55fa    call    $fa55
fa19 ca4dcb    jp      z,$cb4d			; Error: Improper Argument
fa1c 3d        dec     a
fa1d 4f        ld      c,a
fa1e cd4ffa    call    $fa4f
fa21 cd1dde    call    $de1d ; check for close bracket
fa24 cd21de    call    $de21
fa27 c5        push    bc
fa28 cd03cf    call    $cf03
fa2b 78        ld      a,b
fa2c c1        pop     bc
fa2d e3        ex      (sp),hl
fa2e b8        cp      b
fa2f 3001      jr      nc,$fa32         ; (+$01)
fa31 47        ld      b,a
fa32 cd60fa    call    $fa60
fa35 23        inc     hl
fa36 46        ld      b,(hl)
fa37 23        inc     hl
fa38 66        ld      h,(hl)
fa39 68        ld      l,b
fa3a 0600      ld      b,$00
fa3c 09        add     hl,bc
fa3d eb        ex      de,hl
;;=do copy substring
fa3e cdecff    call    $ffec			;; copy bytes (A=count, HL=source, DE=dest)
fa41 e1        pop     hl
fa42 c9        ret     

;;=eval string then byte parameters
;Returns the string in the accumulator,
;and the byte in B
;Zero flag set if the byte is zero.
fa43 cd09cf    call    $cf09
fa46 eb        ex      de,hl
fa47 2aa0b0    ld      hl,($b0a0)
fa4a eb        ex      de,hl
fa4b 0e00      ld      c,$00
fa4d 1806      jr      $fa55            ; (+$06)

;;=eval byte param or ff
;If we have another parameter, return it in B. If no more params return B=$ff
fa4f 06ff      ld      b,$ff
fa51 7e        ld      a,(hl)
fa52 fe29      cp      $29              ;')'
fa54 c8        ret     z

fa55 d5        push    de
fa56 cd15de    call    $de15 ; check for comma
fa59 cdb8ce    call    $ceb8 ; get number and check it's less than 255 
fa5c 47        ld      b,a
fa5d d1        pop     de
fa5e b7        or      a
fa5f c9        ret     

;;=calc substring length
fa60 7e        ld      a,(hl)
fa61 91        sub     c
fa62 3001      jr      nc,$fa65         ; (+$01)
fa64 af        xor     a
fa65 b8        cp      b
fa66 d8        ret     c

fa67 78        ld      a,b
fa68 c9        ret     

;;========================================================
;; function LEN
;LEN(<string expression>)
;Returns the length of the string, or zero if the string is empty.

fa69 cdf5fb    call    $fbf5
fa6c 1803      jr      $fa71            ; (+$03)

;;========================================================
;; function ASC
;ASC(<string expression>)
;Returns the ASCII value of a character (first character of the supplied string)

fa6e cda6fa    call    $faa6
fa71 c332ff    jp      $ff32

;;========================================================
;; function CHR$
;CHR$(<integer expression>)
;Returns the ASCII character with the given value

fa74 cdd9fa    call    $fad9

;;=create single char string
;Creates a string with a single character.
;A=the character
fa77 37        scf     

;;=create single char or null string
;If carry set, creates a single character string,
;if carry clear creates an empty string
;A=character
fa78 4f        ld      c,a
fa79 9f        sbc     a,a
fa7a e601      and     $01
fa7c 1834      jr      $fab2            ; (+$34)

;;=========================================================
;; variable INKEY$
;INKEY$
;Returns the next key, if any, from the keyboard
;If no key is available returns an empty string.

fa7e cd6fc4    call    $c46f			; call to firmware function: km read key			
fa81 30f5      jr      nc,$fa78         ; 
fa83 fefc      cp      $fc				
fa85 28f1      jr      z,$fa78          
fa87 feef      cp      $ef              ;token for '='
fa89 28ed      jr      z,$fa78          ; (-$13)
fa8b 18ea      jr      $fa77            ; (-$16)

;;=========================================================
;; function STRING$
;STRING$(<length>,<character specifier>)
;Creates a string of a specified character.
;Length must be 0..255
;The character specifier may be an integer value or a string.
;Only the first character of the string is repeated

fa8d cdb8ce    call    $ceb8 ; get number and check it's less than 255 
fa90 f5        push    af
fa91 cd15de    call    $de15 ; check for comma
fa94 cd62cf    call    $cf62
fa97 cd1dde    call    $de1d ; check for close bracket
fa9a cda1fa    call    $faa1
fa9d 4f        ld      c,a
fa9e f1        pop     af
fa9f 1811      jr      $fab2            ; (+$11)

;;=get first char from accumulator or error
;If the accumulator is a string returns the first character,
;otherwise raises an error
faa1 cd66ff    call    $ff66
faa4 2033      jr      nz,$fad9         ; (+$33)
;;=get first char of string or error
faa6 cdf5fb    call    $fbf5
faa9 2837      jr      z,$fae2          ; (+$37)
faab 1a        ld      a,(de)
faac c9        ret     

;;========================================================
;; function SPACE$

faad cdd9fa    call    $fad9
fab0 0e20      ld      c,$20

;;=create filled string
;Create a string of length A filled with char/byte C
fab2 47        ld      b,a
fab3 cdd3fb    call    $fbd3
fab6 79        ld      a,c
fab7 04        inc     b
fab8 05        dec     b
fab9 c8        ret     z

faba 12        ld      (de),a
fabb 13        inc     de
fabc 18fa      jr      $fab8            ; (-$06)

;;========================================================
;; function VAL
;VAL(<string expression>)
;Converts a string to a number

fabe cdf5fb    call    $fbf5
fac1 ca32ff    jp      z,$ff32
fac4 eb        ex      de,hl
fac5 e5        push    hl
fac6 5f        ld      e,a
fac7 1600      ld      d,$00
fac9 19        add     hl,de
faca 5e        ld      e,(hl)
facb 72        ld      (hl),d
facc e3        ex      (sp),hl
facd d5        push    de
face cd6fed    call    $ed6f
fad1 d1        pop     de
fad2 e1        pop     hl
fad3 73        ld      (hl),e
fad4 d8        ret     c

fad5 cd45cb    call    $cb45
fad8 defb $0d                         ;Inline error code: Type Mismatch

;;=============================
;;param less than 256 or error
fad9 e5        push    hl
fada cdb6fe    call    $feb6
fadd 7c        ld      a,h
fade b7        or      a
fadf 7d        ld      a,l
fae0 e1        pop     hl
fae1 c8        ret     z

;;=raise Improper argument error
fae2 c34dcb    jp      $cb4d			; Error: Improper Argument

;;========================================================================
;; function INSTR
;INSTR([<start position>,]<searched string>,<searched for string>])
;Searches for a substring within another and returns it's position, or zero if not found.
;Valid start position is 1..255
;If the searched string is empty always returns zero

fae5 cd62cf    call    $cf62
fae8 cd66ff    call    $ff66
faeb 0e01      ld      c,$01
faed 280e      jr      z,$fafd          ; (+$0e)

faef cdd9fa    call    $fad9
faf2 b7        or      a
faf3 ca4dcb    jp      z,$cb4d			; Error: Improper Argument
faf6 4f        ld      c,a
faf7 cd15de    call    $de15 ; check for comma
fafa cd09cf    call    $cf09

;;=instr no start pos parameter
fafd cd15de    call    $de15 ; check for comma
fb00 e5        push    hl
fb01 2aa0b0    ld      hl,($b0a0)
fb04 e3        ex      (sp),hl
fb05 cd03cf    call    $cf03
fb08 cd1dde    call    $de1d ; check for close bracket
fb0b e3        ex      (sp),hl
fb0c 79        ld      a,c
fb0d 48        ld      c,b
fb0e d5        push    de
fb0f f5        push    af
fb10 cd03fc    call    $fc03
fb13 eb        ex      de,hl
fb14 f1        pop     af
fb15 5f        ld      e,a
fb16 1600      ld      d,$00
fb18 19        add     hl,de
fb19 2b        dec     hl
fb1a 78        ld      a,b
fb1b 93        sub     e
fb1c 3c        inc     a
fb1d 47        ld      b,a
fb1e 7b        ld      a,e
fb1f d1        pop     de
fb20 3825      jr      c,$fb47          ; (+$25)
fb22 0c        inc     c
fb23 0d        dec     c
fb24 2822      jr      z,$fb48          ; (+$22)

;;=instr find first loop
;Loop until we find a char which matches the first in the search string
fb26 f5        push    af
fb27 78        ld      a,b
fb28 b9        cp      c
fb29 381b      jr      c,$fb46          ; (+$1b)
fb2b e5        push    hl               ;Save current position in case this is only partial match
fb2c d5        push    de
fb2d c5        push    bc

;;=instr match loop
;Loop while chars match
fb2e 1a        ld      a,(de)
fb2f be        cp      (hl)
fb30 200b      jr      nz,$fb3d         ; (+$0b)
fb32 23        inc     hl
fb33 13        inc     de
fb34 0d        dec     c
fb35 20f7      jr      nz,$fb2e         ; (-$09)

fb37 c1        pop     bc
fb38 d1        pop     de
fb39 e1        pop     hl
fb3a f1        pop     af
fb3b 180b      jr      $fb48            ; (+$0b)

;;=instr chars differ
;Pick up from position after where the first char did match
fb3d c1        pop     bc
fb3e d1        pop     de
fb3f e1        pop     hl
fb40 f1        pop     af
fb41 3c        inc     a
fb42 23        inc     hl
fb43 05        dec     b
fb44 18e0      jr      $fb26            ; (-$20)

;;=instr pop and return zero
fb46 f1        pop     af
;;=instr return zero
fb47 af        xor     a
;;=instr return A
fb48 cd32ff    call    $ff32
fb4b e1        pop     hl
fb4c c9        ret     




;;***StringsArea.asm
;;<<STRINGS AREA
;;<Including the string stack, FRE and the garbage collector
;;==========================================
;;=copy all strings vars to strings area if not in strings area
;See comments for the next routine. Makes sure no strings being referenced within the code.
;Used by immediate mode and before a CHAIN or DELETE modifies the program.
fb4d d5        push    de
fb4e e5        push    hl
fb4f 1165fb    ld      de,$fb65          ;  ##LABEL##
fb52 cd93da    call    $da93
fb55 e1        pop     hl
fb56 d1        pop     de
fb57 c9        ret     

;;==========================
;;copy string to strings area if not in strings area
;Ensures that a string is stored in the strings area. 
;I.e that the string is not a constant in the program.
;This prevent changes to a string from editing the program itself.
;This is used but the statement form of MID$ and the @ operator,
;and also after evaluating a string expression - strings are only ever 
;referenced once, not copying after an expression would leave it being referenced twice
fb58 e5        push    hl
fb59 7e        ld      a,(hl)
fb5a 23        inc     hl
fb5b 4e        ld      c,(hl)
fb5c 23        inc     hl
fb5d 46        ld      b,(hl)
fb5e eb        ex      de,hl
fb5f b7        or      a
fb60 c465fb    call    nz,$fb65
fb63 e1        pop     hl
fb64 c9        ret     

;;=do copy string to strings area if not in strings area
;Called via string variable iterator
;DE=addr of /last/ byte of string descriptor
;BC=string address
;A=string length
fb65 2a71b0    ld      hl,($b071)       ;Checks if BC is withing a strings area and returns if it is
fb68 cddeff    call    $ffde ; HL=BC?
fb6b 3007      jr      nc,$fb74         ; (+$07)
fb6d 2a73b0    ld      hl,($b073)
fb70 cddeff    call    $ffde ; HL=BC?
fb73 d0        ret     nc

fb74 eb        ex      de,hl
fb75 2b        dec     hl
fb76 2b        dec     hl
fb77 e5        push    hl               ;HL=address of string descriptor
fb78 cdb9fb    call    $fbb9            ;Writes allocated address to last-string-used variable
fb7b e1        pop     hl

;;=store last string used (descriptor) to HL
fb7c 3a9cb0    ld      a,($b09c)
fb7f 77        ld      (hl),a
fb80 23        inc     hl
fb81 ed5b9db0  ld      de,($b09d)
fb85 73        ld      (hl),e
fb86 23        inc     hl
fb87 72        ld      (hl),d
fb88 23        inc     hl
fb89 c9        ret     

;;====================================================
;;=push accum to strings stack and strings area if not on string stack
fb8a cd37fc    call    $fc37
fb8d d8        ret     c

fb8e cdb9fb    call    $fbb9
fb91 c3d6fb    jp      $fbd6

;;================================================
;;=prob copy to strings area if not const in program or ROM
fb94 2aa0b0    ld      hl,($b0a0)
fb97 cd1ffc    call    $fc1f
fb9a 78        ld      a,b
fb9b b7        or      a
fb9c c8        ret     z

fb9d e5        push    hl
fb9e 2a64ae    ld      hl,($ae64)
fba1 cdd8ff    call    $ffd8 ; HL=DE?
fba4 2a73b0    ld      hl,($b073)
fba7 eb        ex      de,hl
fba8 dcd8ff    call    c,$ffd8 ; HL=DE?
fbab 300a      jr      nc,$fbb7         ; (+$0a)
fbad ed5b66ae  ld      de,($ae66)
fbb1 cdd8ff    call    $ffd8 ; HL=DE?
fbb4 d437fc    call    nc,$fc37
fbb7 e1        pop     hl
fbb8 d8        ret     c

;;=alloc and copy string atHL to strings area
;HL=address of a string descriptor
fbb9 7e        ld      a,(hl)
fbba cd41fc    call    $fc41
fbbd d5        push    de
fbbe 7e        ld      a,(hl)
fbbf 23        inc     hl
fbc0 4e        ld      c,(hl)
fbc1 23        inc     hl
fbc2 66        ld      h,(hl)
fbc3 69        ld      l,c
fbc4 cdecff    call    $ffec			;; copy bytes (A=count, HL=source, DE=dest)
fbc7 d1        pop     de
fbc8 219cb0    ld      hl,$b09c
fbcb c9        ret     

;;=================
;;clear string stack
fbcc 217eb0    ld      hl,$b07e
fbcf 227cb0    ld      ($b07c),hl
fbd2 c9        ret     

;;=alloc string push on stack and accumulator
fbd3 cd41fc    call    $fc41

;;=push last string descriptor on string stack
;Also puts the address of the pushed descriptor in the accumulator
fbd6 e5        push    hl
fbd7 3e03      ld      a,$03                ;accumulator is a string
fbd9 329fb0    ld      ($b09f),a
fbdc 2a7cb0    ld      hl,($b07c)
fbdf 22a0b0    ld      ($b0a0),hl
fbe2 119cb0    ld      de,$b09b + 1             ;also next byte after end of string stack
fbe5 cdd8ff    call    $ffd8 ; HL=DE?       ;is string stack full
fbe8 3e10      ld      a,$10            ;String expression too complex error
fbea ca55cb    jp      z,$cb55
fbed cd7cfb    call    $fb7c
fbf0 227cb0    ld      ($b07c),hl
fbf3 e1        pop     hl
fbf4 c9        ret     

;;===================================
;;get accumulator string length
fbf5 e5        push    hl
fbf6 cd5eff    call    $ff5e
fbf9 2aa0b0    ld      hl,($b0a0)
fbfc cd03fc    call    $fc03
fbff e1        pop     hl
fc00 78        ld      a,b
fc01 b7        or      a
fc02 c9        ret     

;;===================================
;;pop TOS from string stack and strings area
;Pops the top-most item from the string stack and also from the strings area(?)
fc03 cd1ffc    call    $fc1f
fc06 c0        ret     nz  ;string addr <> HL

fc07 78        ld      a,b
fc08 b7        or      a
fc09 c8        ret     z   ;empty string

fc0a 2a71b0    ld      hl,($b071)  ;we've popped a string off the stack
fc0d 23        inc     hl
fc0e 23        inc     hl
fc0f 23        inc     hl
fc10 cdd8ff    call    $ffd8 ; HL=DE? (DE = address of popped string)
fc13 c0        ret     nz

fc14 2b        dec     hl
fc15 2b        dec     hl
fc16 6e        ld      l,(hl)  ;length of last item?
fc17 2600      ld      h,$00
fc19 19        add     hl,de   ;move to free space?
fc1a 2b        dec     hl
fc1b 2271b0    ld      ($b071),hl
fc1e c9        ret     

;;=pop TOS from string stack
;Pops the top-most item from the string stack but doesn't affect the strings area
;returns HL=addr, B=length
;if HL=address of last item then 'pops' it off the concat stack
fc1f e5        push    hl
fc20 ed5b7cb0  ld      de,($b07c)
fc24 1b        dec     de
fc25 1b        dec     de
fc26 1b        dec     de
fc27 cdd8ff    call    $ffd8 ; HL=DE?
fc2a 2004      jr      nz,$fc30         ; (+$04)
fc2c ed537cb0  ld      ($b07c),de
fc30 46        ld      b,(hl)
fc31 23        inc     hl
fc32 5e        ld      e,(hl)
fc33 23        inc     hl
fc34 56        ld      d,(hl)
fc35 e1        pop     hl
fc36 c9        ret     

;;============================
;;is accumulator address in string stack
;Is the uint in the accumulator in the string stack (or higher - but no strings stored higher)
;NOTE: this used tha accumulator value as a pointer to a string descriptor, NOT a string descriptor
fc37 2aa0b0    ld      hl,($b0a0)
fc3a 3e7d      ld      a,$b07e - 1 and $ff  ; $7d  string stack start - 1 (low byte)
fc3c 95        sub     l
fc3d 3eb0      ld      a,$b07e - 1 >> 8   ; $b0  string stack start - 1 (high byte)
fc3f 9c        sbc     a,h
fc40 c9        ret     

;;==============================
;;alloc space in strings area
;Allocs A + 2 bytes in the strings area (i.e to the bottom)
;Two bottom-most bytes store the number of bytes allocated.
;Address above, and string length, that is written to the last-string-used variable
;Writes the bytes allocated to start of strings area
;A=string length
;HL=string address
;Returns A,HL unmodified
fc41 e5        push    hl
fc42 c5        push    bc
fc43 4f        ld      c,a
fc44 b7        or      a
fc45 c493f6    call    nz,$f693
fc48 79        ld      a,c
fc49 329cb0    ld      ($b09c),a
fc4c 229db0    ld      ($b09d),hl
fc4f eb        ex      de,hl
fc50 c1        pop     bc
fc51 e1        pop     hl
fc52 c9        ret     

;;========================================================
;; function FRE
;FRE(<numeric expression>)
;FRE(<string expression>)
;The value of the arguments is irrelevant, only the type. Thus the preferred forms are:
;FRE(0)
;FRE("")
;FRE with a numeric parameter returns the amount of free space in bytes
;FRE with a string parameter performs a garbage collection before returning the number of free bytes.
;Garbage collection involves removing empty space within the strings allocation area.
;Garbage collection will also happen if BASIC runs out of memory

fc53 cd66ff    call    $ff66
fc56 2006      jr      nz,$fc5e         ; (+$06) Not a string - just return length
fc58 cdf5fb    call    $fbf5
fc5b cd64fc    call    $fc64
fc5e cdfcf6    call    $f6fc
fc61 c389fe    jp      $fe89

;;=strings area garbage collection
fc64 e5        push    hl
fc65 d5        push    de
fc66 c5        push    bc
fc67 217eb0    ld      hl,$b07e
fc6a 180c      jr      $fc78            ; (+$0c)

;Loops over every string in the strings area,
;Swaps the string address in the descriptor with the two bytes preceding the string
;Thus every string is now preceded by it's address
;;=strings gc prepare loop
fc6c 7e        ld      a,(hl)
fc6d 23        inc     hl
fc6e 4e        ld      c,(hl)
fc6f 23        inc     hl
fc70 46        ld      b,(hl)
fc71 eb        ex      de,hl
fc72 b7        or      a
fc73 c4e3fc    call    nz,$fce3
fc76 eb        ex      de,hl
fc77 23        inc     hl

;HL=bottom of string stack
fc78 ed5b7cb0  ld      de,($b07c)       ;Top of string stack
fc7c cdd8ff    call    $ffd8 ; HL=DE?
fc7f 20eb      jr      nz,$fc6c         ; (-$15) 

;Now does the same for every string variable
fc81 11e3fc    ld      de,$fce3         ;  ##LABEL##
fc84 cd93da    call    $da93


fc87 2a73b0    ld      hl,($b073)
fc8a e5        push    hl
fc8b 2a71b0    ld      hl,($b071)
fc8e 23        inc     hl
fc8f 5d        ld      e,l
fc90 54        ld      d,h
fc91 1814      jr      $fca7            ; (+$14)


;Loop through every string in the strings area, starting with the first (lowest address).
;Copies each string to the start of the strings area (after any strings already copied),
;BUT does not copy any free space. Thus all current strings are moved to a single block
;at the start of the strings area.
;;=strings gc compact loop
fc93 4e        ld      c,(hl)           ;BC=address of string descriptor?
fc94 23        inc     hl
fc95 46        ld      b,(hl)
fc96 04        inc     b
fc97 05        dec     b                ;Test for high byte of address = 0 (free space?)
fc98 280b      jr      z,$fca5          ; (+$0b)
fc9a 2b        dec     hl
fc9b 0a        ld      a,(bc)           ;String length from descriptor?
fc9c 4f        ld      c,a
fc9d 0600      ld      b,$00
fc9f 03        inc     bc
fca0 03        inc     bc               ;BC=length+2?
fca1 edb0      ldir                     ;LDIR - copy string
fca3 1802      jr      $fca7            ; (+$02)

fca5 23        inc     hl
fca6 09        add     hl,bc

;HL=DE=start of strings area. TOS=end of strings area
fca7 c1        pop     bc               ;BC=end of strings area
fca8 c5        push    bc
fca9 cddeff    call    $ffde ; HL=BC?
fcac 38e5      jr      c,$fc93          ; (-$1b)


;All strings now compacted. DE=end of compacted strings
;Calc the number of bytes in this block and LDDR copy them to the end of the strings area
fcae 1b        dec     de
fcaf 2a71b0    ld      hl,($b071)
fcb2 eb        ex      de,hl
fcb3 cde4ff    call    $ffe4			; BC = HL-DE
fcb6 d1        pop     de
fcb7 cdd8ff    call    $ffd8 ; HL=DE?
fcba f5        push    af
fcbb d5        push    de
fcbc cdf5ff    call    $fff5 ; copy bytes LDDR (BC = count)

fcbf eb        ex      de,hl
fcc0 2271b0    ld      ($b071),hl       ;Now write the new start of strings area
fcc3 c1        pop     bc
fcc4 23        inc     hl
fcc5 1812      jr      $fcd9            ; (+$12)

;Loops through the strings area and swaps back the address and descriptor info
;;=strings area gc finalise loop
fcc7 5e        ld      e,(hl)           ;DE=(HL) - string descriptor address?
fcc8 23        inc     hl
fcc9 56        ld      d,(hl)
fcca 2b        dec     hl
fccb 1a        ld      a,(de)           ;A=string length?
fccc 77        ld      (hl),a           ;(HL)=length
fccd 23        inc     hl
fcce 3600      ld      (hl),$00
fcd0 23        inc     hl
fcd1 eb        ex      de,hl
fcd2 72        ld      (hl),d           ;String address?
fcd3 2b        dec     hl
fcd4 73        ld      (hl),e
fcd5 6f        ld      l,a              ;HL=length?
fcd6 2600      ld      h,$00
fcd8 19        add     hl,de            

;HL=new last byte of free memory (byte before new strings area)
;DE=address of last byte of strings area
fcd9 cddeff    call    $ffde ; HL=BC?
fcdc 38e9      jr      c,$fcc7          ; (-$17)

fcde f1        pop     af
fcdf c1        pop     bc
fce0 d1        pop     de
fce1 e1        pop     hl
fce2 c9        ret     

;;strings gc prepare string
;DE=addr of /last/ byte of string descriptor passed in A,BC
;BC=string address
;A=string length
fce3 2a6cae    ld      hl,($ae6c)
fce6 cddeff    call    $ffde ; HL=BC?
fce9 d0        ret     nc

;Load DE to (BC-2) and byte what was at (BC-2) to (DE)
;Ie swap the address (of last byte) of string descriptor with the two bytes before the string
;Thus every string is now preceded by the address of it's string descriptor?
fcea 0b        dec     bc           ;BC=byte before string
fceb 7a        ld      a,d          ;A=high byte of descriptor address
fcec 02        ld      (bc),a       ;Byte before string = high byte of descriptor address
fced 0b        dec     bc           ;BC=two bytes before string
fcee 0a        ld      a,(bc)       ;A=??
fcef 12        ld      (de),a       ;
fcf0 7b        ld      a,e
fcf1 02        ld      (bc),a
fcf2 c9        ret     

;;==========================================
;;=prepare accum and regs for word to string
fcf3 cd4fff    call    $ff4f
fcf6 d276bd    jp      nc,$bd76            ; firmware maths??
fcf9 cd2add    call    $dd2a                ;B=H, C=$01, E=$00
fcfc 22a0b0    ld      ($b0a0),hl
fcff 21a1b0    ld      hl,$b0a1
fd02 c9        ret     

;;=============================================
;;=set regs for int to string conv
fd03 cdebfe    call    $feeb
fd06 21a1b0    ld      hl,$b0a1
fd09 c330dd    jp      $dd30




;;***InfixOperators.asm
;;<< INFIX OPERATORS
;;< Infix +, -, *, / etc. including boolean operators
;;=========================================
;; infix plus +
fd0c cd3bfe    call    $fe3b
fd0f 3009      jr      nc,$fd1a         ; (+$09)
fd11 cd4add    call    $dd4a
fd14 da35ff    jp      c,$ff35
fd17 cd78fe    call    $fe78
fd1a cd7cbd    call    $bd7c             ; firmware REAL addition
fd1d d8        ret     c

;;=overflow error
fd1e c3becb    jp      $cbbe

;;==========================================
;; infix minus -
fd21 cd3bfe    call    $fe3b
fd24 3009      jr      nc,$fd2f         ; (+$09)
fd26 cd52dd    call    $dd52
fd29 da35ff    jp      c,$ff35
fd2c cd78fe    call    $fe78
fd2f cd82bd    call    $bd82            ; firmware REAL reverse subtraction
fd32 d8        ret     c

fd33 18e9      jr      $fd1e            ; (-$17)

;;==========================================
;; infix multiply *
fd35 cd3bfe    call    $fe3b
fd38 3009      jr      nc,$fd43         ; (+$09)
fd3a cd5bdd    call    $dd5b
fd3d da35ff    jp      c,$ff35
fd40 cd78fe    call    $fe78
fd43 cd85bd    call    $bd85             ;firmware REAL mltiplication
fd46 d8        ret     c

fd47 18d5      jr      $fd1e            ; (-$2b)

;;===============================================
;; infix comparisons (plural)
fd49 cd3bfe    call    $fe3b
fd4c da02de    jp      c,$de02
fd4f c38ebd    jp      $bd8e      ; firmwware REAL compare

;;=============================================
;;infix divide /
fd52 cd70fe    call    $fe70
fd55 eb        ex      de,hl
fd56 d5        push    de
fd57 cd88bd    call    $bd88           ; firmware REAL division??
fd5a d1        pop     de
fd5b 010500    ld      bc,$0005
fd5e edb0      ldir    
fd60 d8        ret     c

fd61 cab5cb    jp      z,$cbb5
fd64 c3becb    jp      $cbbe

;;=================================================
;;infix integer division
fd67 cdc3fe    call    $fec3
fd6a eb        ex      de,hl
fd6b cd9cdd    call    $dd9c
fd6e da35ff    jp      c,$ff35
fd71 2810      jr      z,$fd83          ; (+$10)
fd73 210080    ld      hl,$8000
fd76 c389fe    jp      $fe89

;;=================================================
;;infix MOD
fd79 cdc3fe    call    $fec3
fd7c eb        ex      de,hl
fd7d cda3dd    call    $dda3
fd80 da35ff    jp      c,$ff35

;;=raise Division by zero error
fd83 cd45cb    call    $cb45
fd86 defb $0b                         ;Inline error code: Division by zero

;;============================================
;; infix AND
fd87 cdc3fe    call    $fec3
fd8a 7b        ld      a,e
fd8b a5        and     l
fd8c 6f        ld      l,a
fd8d 7c        ld      a,h
fd8e a2        and     d

;;=infix logic done
fd8f c334ff    jp      $ff34

;;=============================================
;; infix OR
fd92 cdc3fe    call    $fec3
fd95 7b        ld      a,e
fd96 b5        or      l
fd97 6f        ld      l,a
fd98 7a        ld      a,d
fd99 b4        or      h
fd9a 18f3      jr      $fd8f            ; (-$0d)

;;==============================================
;; infix XOR
fd9c cdc3fe    call    $fec3
fd9f 7b        ld      a,e
fda0 ad        xor     l
fda1 6f        ld      l,a
fda2 7c        ld      a,h
fda3 aa        xor     d
fda4 18e9      jr      $fd8f            ; (-$17)

;;===============================================
;;bitwise complement/invert
fda6 cdb6fe    call    $feb6
fda9 7d        ld      a,l
fdaa 2f        cpl     
fdab 6f        ld      l,a
fdac 7c        ld      a,h
fdad 2f        cpl     
fdae 18df      jr      $fd8f            ; (-$21)





;;***TypeConversions.asm
;;<< TYPE CONVERSIONS AND ROUNDING
;;< (from numbers to numbers)
;;========================================================
;; function ABS
;ABS(<numeric expression>)
;Returns absolute value (i.e. negates if negative)

fdb0 cdc4fd    call    $fdc4
fdb3 f0        ret     p

;;=negate accumulator
fdb4 cd4fff    call    $ff4f
fdb7 d291bd    jp      nc,$bd91             ; firmware REAL negate
fdba cdeddd    call    $dded                ;negate HL
fdbd 22a0b0    ld      ($b0a0),hl
fdc0 d489fe    call    nc,$fe89             ;Not a valid INT so convert to a REAL
fdc3 c9        ret     

;;=get raw abs of accumulator with reg preserve
fdc4 c5        push    bc
fdc5 e5        push    hl
fdc6 cdccfd    call    $fdcc
fdc9 e1        pop     hl
fdca c1        pop     bc
fdcb c9        ret     

;;=get raw abs of accumulator
;returns A = negative, 0 or positive
fdcc cd4fff    call    $ff4f
fdcf daf9dd    jp      c,$ddf9
fdd2 c394bd    jp      $bd94

;;=round accumulator
fdd5 e5        push    hl
fdd6 79        ld      a,c
fdd7 cd6cff    call    $ff6c
fdda d1        pop     de
fddb cd4fff    call    $ff4f
fdde 78        ld      a,b
fddf 300b      jr      nc,$fdec         ; (+$0b)
fde1 b7        or      a
fde2 f0        ret     p

fde3 cd93fe    call    $fe93
fde6 cdf4fd    call    $fdf4
fde9 c3b6fe    jp      $feb6

fdec b7        or      a
fded 2005      jr      nz,$fdf4         ; (+$05)
fdef 116dbd    ld      de,$bd6d        ;firmware REAL to bin
fdf2 1826      jr      $fe1a            ; (+$26)

fdf4 d5        push    de
fdf5 c5        push    bc
fdf6 78        ld      a,b
fdf7 cd79bd    call    $bd79
fdfa dc6dbd    call    c,$bd6d             ;firmware REAL to bin
fdfd 78        ld      a,b
fdfe c1        pop     bc
fdff d1        pop     de
fe00 3008      jr      nc,$fe0a         ; (+$08)
fe02 cd67bd    call    $bd67             ;firmware bin to REAL
fe05 af        xor     a
fe06 90        sub     b
fe07 c379bd    jp      $bd79           ; firmware REAL exp A

fe0a eb        ex      de,hl
fe0b c36fff    jp      $ff6f

;;========================================================
;; function FIX
;FIX(<numeric expression>)
;Truncate value to an integer. Returns a float with no fractional part, rounding towards zero.
fe0e 1170bd    ld      de,$bd70          ;firmware REAL fix
fe11 1803      jr      $fe16            ; (+$03)

;;========================================================
;; function INT
;INT(<numeric expression>)
;Rounds the value to the nearest smaller integer (round towards minus infinity)
;Does not convert to integer, merely removes fractional part

fe13 1173bd    ld      de,$bd73         ;firmware REAL int
fe16 cd4fff    call    $ff4f
fe19 d8        ret     c

fe1a cdfeff    call    $fffe			; JP (DE)
fe1d d0        ret     nc

fe1e 3a9fb0    ld      a,($b09f)
fe21 cd2cfe    call    $fe2c
fe24 d8        ret     c

fe25 cd45ff    call    $ff45
fe28 78        ld      a,b
fe29 c367bd    jp      $bd67           ;firmware BIN to REAL

fe2c 79        ld      a,c
fe2d fe03      cp      $03
fe2f d0        ret     nc

fe30 7e        ld      a,(hl)
fe31 23        inc     hl
fe32 66        ld      h,(hl)
fe33 6f        ld      l,a
fe34 cd37dd    call    $dd37
fe37 d0        ret     nc

fe38 c335ff    jp      $ff35

;;=========================================
;;convert accum and param to same numeric type
;(error if either is string).
;C=type of param
fe3b 79        ld      a,c              ;C contains a type specifier
fe3c fe03      cp      $03
fe3e 282d      jr      z,$fe6d          ; (+$2d) if string?
fe40 3a9fb0    ld      a,($b09f)
fe43 fe03      cp      $03
fe45 2826      jr      z,$fe6d          ; (+$26) if string
fe47 b9        cp      c
fe48 2817      jr      z,$fe61          ; (+$17) if same type as C
fe4a 300c      jr      nc,$fe58         ; (+$0c) accum is real C is int
fe4c e5        push    hl               ;else accum is int, C is real...
fe4d 219fb0    ld      hl,$b09f         ;...so convert accum to real
fe50 71        ld      (hl),c
fe51 23        inc     hl
fe52 cd8cfe    call    $fe8c
fe55 d1        pop     de
fe56 b7        or      a
fe57 c9        ret     

fe58 cd8cfe    call    $fe8c
fe5b b7        or      a
fe5c eb        ex      de,hl
fe5d 21a0b0    ld      hl,$b0a0
fe60 c9        ret     

fe61 ee02      xor     $02
fe63 20f7      jr      nz,$fe5c         ; (-$09)
fe65 5e        ld      e,(hl)
fe66 23        inc     hl
fe67 56        ld      d,(hl)
fe68 2aa0b0    ld      hl,($b0a0)
fe6b 37        scf     
fe6c c9        ret     

;;=raise Type mismatch error
fe6d c362ff    jp      $ff62

;;==================================
;;convert accum and param to REAL
fe70 3a9fb0    ld      a,($b09f)
fe73 b1        or      c
fe74 fe02      cp      $02
fe76 20c3      jr      nz,$fe3b         ; (-$3d)

;;=convert INT accum and INT param to REAL
fe78 2aa0b0    ld      hl,($b0a0)
fe7b cd93fe    call    $fe93
fe7e 2a6fb0    ld      hl,($b06f)
fe81 cd8cfe    call    $fe8c
fe84 eb        ex      de,hl
fe85 21a0b0    ld      hl,$b0a0
fe88 c9        ret     

;;======================================
;;set accumulator as REAL from unsigned INT
fe89 af        xor     a
fe8a 1808      jr      $fe94            ; (+$08)

;;=======================================
;;convert INT atHL to positive REAL atHL
fe8c 5e        ld      e,(hl)
fe8d 23        inc     hl
fe8e 56        ld      d,(hl)
fe8f 2b        dec     hl
fe90 7a        ld      a,d
fe91 1808      jr      $fe9b            ; (+$08)

;;=======================================
;;set accumulator as positive REAL from HL
;HL=int value
fe93 7c        ld      a,h

;;=set accumulator from HL with possible invert
;invert if bit 7 of a is set
fe94 eb        ex      de,hl
fe95 219fb0    ld      hl,$b09f
fe98 3605      ld      (hl),$05
fe9a 23        inc     hl

;;=set atHL from DE with possible invert
;invert if bit 7 of a is set
fe9b eb        ex      de,hl
fe9c f5        push    af
fe9d b7        or      a
fe9e fceddd    call    m,$dded
fea1 f1        pop     af
fea2 c364bd    jp      $bd64                 ;firmware INT to REAL

;;===================================
;;store int to accumulator
fea5 22a0b0    ld      ($b0a0),hl

;;=====================================
;;set accumulator as REAL from BINARY zero or minus one
;binary in HL only. (useful only for -1 and zero??)
fea8 eb        ex      de,hl
fea9 22a2b0    ld      ($b0a2),hl
feac 219fb0    ld      hl,$b09f
feaf 3605      ld      (hl),$05
feb1 23        inc     hl
feb2 af        xor     a
feb3 c367bd    jp      $bd67                    ;firmware BIN to REAL

;;========================================================
;; function CINT
;CINT(<numeric expression>)
;Converts the value to an integer
;Expression must be -32768..+32767

feb6 cdbcfe    call    $febc
feb9 d8        ret     c

feba 183f      jr      $fefb            ; (+$3f)

febc cdcefe    call    $fece
febf 22a0b0    ld      ($b0a0),hl
fec2 c9        ret     

;;-=============================================
;;=convert atHL with type C and accumulator to ints
fec3 79        ld      a,c
fec4 cdd5fe    call    $fed5
fec7 eb        ex      de,hl
fec8 dccefe    call    c,$fece          ;carry here means we had a pointer to an int
fecb d8        ret     c

fecc 182d      jr      $fefb            ; (+$2d)

;;===============================================
;;=convert accumulator to int
fece 219fb0    ld      hl,$b09f
fed1 7e        ld      a,(hl)
fed2 3602      ld      (hl),$02
fed4 23        inc     hl

;;=convert atHL with type C to int
fed5 fe03      cp      $03
fed7 380d      jr      c,$fee6          ; (+$0d) if type is int treat it as a pointer to the actual real and redo
fed9 ca62ff    jp      z,$ff62          ; error if string
fedc c5        push    bc
fedd cd6abd    call    $bd6a                 ; firmware REAL to INT
fee0 47        ld      b,a
fee1 dc37dd    call    c,$dd37
fee4 c1        pop     bc
fee5 c9        ret     

fee6 7e        ld      a,(hl)
fee7 23        inc     hl
fee8 66        ld      h,(hl)
fee9 6f        ld      l,a
feea c9        ret     

;;========================================================
;; function UNT
;UNT(<address expression>)
;Converts to an unsigned integer in the range -32768..32767

feeb cd4fff    call    $ff4f
feee d8        ret     c

feef cd6abd    call    $bd6a
fef2 3007      jr      nc,$fefb         ; (+$07)
fef4 47        ld      b,a
fef5 fc37dd    call    m,$dd37
fef8 da35ff    jp      c,$ff35

;;=raise Overflow error
fefb cd45cb    call    $cb45
fefe defb $06                         ;Inline error code: Overflow

;;=====================================
;;convert accumulator to type in A
;int to real or real to int only
feff e5        push hl
ff00 d5        push    de
ff01 c5        push    bc
ff02 219fb0    ld      hl,$b09f
ff05 be        cp      (hl)
ff06 c40dff    call    nz,$ff0d
ff09 c1        pop     bc
ff0a d1        pop     de
ff0b e1        pop     hl
ff0c c9        ret     

ff0d d603      sub     $03
ff0f 38a5      jr      c,$feb6          ; (-$5b)
ff11 ca5eff    jp      z,$ff5e

;;========================================================
;; function CREAL
;CREAL(<numeric expression>)
;Converts the value to a real

ff14 cd4fff    call    $ff4f
ff17 da93fe    jp      c,$fe93
ff1a c9        ret     

;;========================================
;;zero accumulator
ff1b e5        push    hl                     ;##LIT##
ff1c 210000    ld      hl,$0000
ff1f 22a0b0    ld      ($b0a0),hl
ff22 22a2b0    ld      ($b0a2),hl
ff25 22a3b0    ld      ($b0a3),hl
ff28 e1        pop     hl
ff29 c9        ret     

;;========================================================
;; function SGN
;SGN(<numeric expression>)
;Returns -1 if expression < 0, 0 if expression = 0, +1 if expression > 0

ff2a cdc4fd    call    $fdc4

;;----------------------------------
;;=store sign extended byte in A in accumulator
ff2d 6f        ld      l,a
ff2e 87        add     a,a
ff2f 9f        sbc     a,a
ff30 1802      jr      $ff34            ; (+$02)





;;***Accumulator.asm
;;<< ACCUMULATOR UTILITIES
;;< Store values to accumulator, get values from accumulator,
;;< and accumulator type conversions
;;=========================================================
;;=store A in accumulator as INT
ff32 6f        ld      l,a
ff33 af        xor     a
;;=store AL in accumulator as INT
ff34 67        ld      h,a

;;=store HL in accumulator as INT
ff35 22a0b0    ld      ($b0a0),hl
;;=set accumulator type to int
ff38 3e02      ld      a,$02               ;int
;;=set accumulator data type
ff3a 329fb0    ld      ($b09f),a
ff3d c9        ret     

;;====================================
;;=set accumulator type to real and HL to accumulator addr
ff3e 21a0b0    ld      hl,$b0a0
;;=set accumulator type to real
ff41 3e05      ld      a,$05            ;real
ff43 18f5      jr      $ff3a            ; (-$0b)

;;======================================
;;get accumulator type in c and addr in HL
ff45 219fb0    ld      hl,$b09f
ff48 4e        ld      c,(hl)
ff49 23        inc     hl
ff4a c9        ret     

;;=====================================
;;get accumulator data type
ff4b 3a9fb0    ld      a,($b09f)
ff4e c9        ret     

;;======================================
;;return accumulator value if int or address if real
ff4f 3a9fb0    ld      a,($b09f)
ff52 fe03      cp      $03              ;string
ff54 280c      jr      z,$ff62          ; (+$0c) error if string
ff56 2aa0b0    ld      hl,($b0a0)       
ff59 d8        ret     c

ff5a 21a0b0    ld      hl,$b0a0
ff5d c9        ret     

;;==================================
;;error if accumulator is not a string
ff5e cd66ff    call    $ff66
ff61 c8        ret     z

;;=raise Type Mismatch error
ff62 cd45cb    call    $cb45
ff65 defb $0d                         ;Inline error code: Type mismatch

;;=======================================================
;;is accumulator a string?
ff66 3a9fb0    ld      a,($b09f)      ; accumulator type
ff69 fe03      cp      $03            ;string marker
ff6b c9        ret     

;;================
;;copy atHL to accumulator type A
ff6c 329fb0    ld      ($b09f),a
;;=copy atHL to accumulator using accumulator type
ff6f 11a0b0    ld      de,$b0a0
ff72 1813      jr      $ff87            ; (+$13)

;;================
;;push numeric accumulator on execution stack
ff74 d5        push    de
ff75 e5        push    hl
ff76 3a9fb0    ld      a,($b09f)
ff79 4f        ld      c,a
ff7a cd72f6    call    $f672
ff7d cd83ff    call    $ff83
ff80 e1        pop     hl
ff81 d1        pop     de
ff82 c9        ret     

;;========================================
;;copy numeric accumulator to atHL
ff83 eb        ex      de,hl
ff84 21a0b0    ld      hl,$b0a0

;;=copy value atHL to atDE accumulator type
ff87 c5        push    bc
ff88 3a9fb0    ld      a,($b09f)
ff8b 4f        ld      c,a
ff8c 0600      ld      b,$00
ff8e edb0      ldir    
ff90 c1        pop     bc
ff91 c9        ret     



;;***Utilities.asm
;;<< UTILITY ROUTINES
;;< Assorted memory copies, table lookups etc.
;;=========================================================
;; test if upcase letter
;Returns Carry true if the value is between 'A' and 'Z' inclusive.
;A=value

ff92 cdabff    call    $ffab			;; convert character to upper case

ff95 fe41      cp      $41				;; 'A'
ff97 3f        ccf     
ff98 d0        ret     nc
ff99 fe5b      cp      $5b				;; 'Z'+1
ff9b c9        ret     

;;=========================================
;; test if letter period or digit
;Returns Carry true, Zero false if the value is an ASCII digit between '0' and '9'
;or an ASCII char between 'A' and 'Z' inclusive
;Returns Carry true, Zero true if the value is a '.'
ff9c cd92ff    call    $ff92			
ff9f d8        ret     c

;;+----------------------------------------
;; test if period or digit
;Returns Carry true, Zero false if the value is an ASCII digit between '0' and '9'
;Returns Carry true, Zero true if the value is a '.'
ffa0 fe2e      cp      $2e				; '.'
ffa2 37        scf     
ffa3 c8        ret     z

;;+----------------------------------------
;; test if digit
;Returns Carry true If the value an ASCII digit between '0' and '9' inclusive
;A = character

ffa4 fe30      cp      $30			; '0'
ffa6 3f        ccf     
ffa7 d0        ret     nc
ffa8 fe3a      cp      $3a			; '9'+1
ffaa c9        ret     

;;========================================================
;; convert character to upper case
;Converts an ASCII char to upper case.
;No effect if the value is not an lower case ASCII char
;A=character

ffab fe61      cp      $61          ;'a'
ffad d8        ret     c

ffae fe7b      cp      $7b          ;'z' + 1
ffb0 d0        ret     nc

ffb1 d620      sub     $20
ffb3 c9        ret     

;;=========================================================
;; get address from table
;; HL = address of table
;; A = code to find in table
;;
;; table header:
;; 0: count
;; 1,2: address to return to if not found

;; each entry in table:
;; offset 0: code
;; offset 1,2: address

ffb4 f5        push    af
ffb5 c5        push    bc
ffb6 46        ld      b,(hl)			; count in table
ffb7 23        inc     hl
ffb8 e5        push    hl               ; save ptr to 'not found' routine

ffb9 23        inc     hl				
ffba 23        inc     hl
ffbb be        cp      (hl)				; code = comparison
ffbc 23        inc     hl
ffbd 2803      jr      z,$ffc2          ; code found?
ffbf 10f8      djnz    $ffb9            ; 

;;-----------------------------------------------
;; code not found
;;
;; get address from start of table; putting address of end of table onto stack
ffc1 e3        ex      (sp),hl          ;retrieve ptr to 'not found' routine
;;-----------------------------------------------
;; code found or not found

ffc2 f1        pop     af             ;remove unwanted from stack - either 'not found' routine or junk from prev. instr

;; get address from table
ffc3 7e        ld      a,(hl)
ffc4 23        inc     hl
ffc5 66        ld      h,(hl)
ffc6 6f        ld      l,a
;;-----------------------------------------------
ffc7 c1        pop     bc
ffc8 f1        pop     af
ffc9 c9        ret     

;;=========================================================
;; check if byte exists in table
;;
;; HL = base address of table (table terminated with 0)
;; A = value
;;
;; carry set = byte exists in table
;; carry clear = byte doesn't exist
;; All other registers preserved

ffca c5        push    bc
ffcb 4f        ld      c,a				;; C = byte to compare against

ffcc 7e        ld      a,(hl)			;; get byte from table
;; table terminator?
ffcd b7        or      a
ffce 2805      jr      z,$ffd5          
ffd0 23        inc     hl
;; same as byte we want
ffd1 b9        cp      c
ffd2 20f8      jr      nz,$ffcc         ; (-$08)
;; byte found in table
ffd4 37        scf    
;; byte found or not found 
ffd5 79        ld      a,c
ffd6 c1        pop     bc
ffd7 c9        ret     

;;=========================================================
;; compare HL DE
ffd8 7c        ld      a,h
ffd9 92        sub     d
ffda c0        ret     nz
ffdb 7d        ld      a,l
ffdc 93        sub     e
ffdd c9        ret     

;;=========================================================
;; compare HL BC
ffde 7c        ld      a,h
ffdf 90        sub     b
ffe0 c0        ret     nz
ffe1 7d        ld      a,l
ffe2 91        sub     c
ffe3 c9        ret 
    
;;=========================================================
;; BC equal HL minus DE
;;
;; HL,DE preserved
;; flags corrupt

ffe4 e5        push    hl				;; store HL
ffe5 b7        or      a
ffe6 ed52      sbc     hl,de			;; HL = HL - DE
ffe8 44        ld      b,h				;; BC = HL - DE
ffe9 4d        ld      c,l
ffea e1        pop     hl				;; restore HL
ffeb c9        ret     

;;=========================================================
;; copy bytes LDIR  (A=count, HL=source, DE=dest)
;;
;; HL = source
;; DE = destination
;; A = count

ffec 4f        ld      c,a
ffed 0600      ld      b,$00
;; BC = count

;;+--------------------------------------------------------------
;; copy bytes LDIR (BC=count, HL=source, DE=dest)
;; BC=0?
ffef 78        ld      a,b
fff0 b1        or      c
fff1 c8        ret     z

;; copy if BC<>0
fff2 edb0      ldir    
fff4 c9        ret     

;;=========================================================
;; copy bytes LDDR (BC=count, HL=source, DE=dest)
;; BC=0?
fff5 78        ld      a,b
fff6 b1        or      c
fff7 c8        ret     z
;; copy if BC<>0
fff8 edb8      lddr    
fffa c9        ret     

;;=========================================================
;; JP (HL)
fffb e9        jp      (hl)

;;=========================================================
;; JP (BC)
fffc c5        push    bc
fffd c9        ret     

;;=========================================================
;; JP (DE)
fffe d5        push    de
ffff c9        ret     
;;--------------------------------------------------------------
