0300 33ff 0300 C ... TDL BASIC
; This is the commented BASIC listing of the 
; TDL 12K Extended "Zapple" BASIC, 
; by Roger Amidon and Neil Colvin, May 1977
;
; This was produced by IDA disassembler
; and further modified for readability (macros and long symbols)
; note this is, although it looks like, not correct Z80 assembler
; to be directly fed into an assembler program - mainly because
; many symbols are too long for Z80 assemblers
; use this as reference only, rather use the HEX dump
; to produce a binary.
;
; The HEX dump has been compared with this commented file;
; while commenting, several OCR errors were corrected.
;
; The hex dump was produced from the book
; Rolf-Dieter Klein, Basic-Interpreter, Franzis Verlag Mnchen, 1982;
; in German language, ISBN 3-7723-6941-3
; The book author himself mentions in the book that he published
; the hex dump because "Der Interpreter wurde urspruenglich von
; TDL (Technical Design Labs) entwickelt und ist sehr leistungsfaehig.
; Da die Firma nicht mehr existiert, soll durch den Abdruck des Listings
; dem Leser die Moeglichkeit gegeben werden, Zugang zu diesem Basic zu
; erhalten." (Seite 103) (Translation: the interpreter was developed
; originally by TDL (Technical Design Labs) and is very powerful.
; Because the company is no longer in existance, the reader is given
; the chance, by printing this listing to get access to this Basic).
;
; The work of reverse engineering and commenting was done by Holger Veit,
; 2012 - this whole work is published unter Creative Commons License
; CC-BY-SA http://creativecommons.org/licenses/by-sa/3.0/

;--------------------------------------------------------------------

;****************************************************************
; some macro definitions for readability
CPHL_DE         macro
                ld    a, h
                sub   d
                jr    nz, @@1
                ld    a, l
                sub   e
@@1:
                endm

LDBC_M          macro
                ld    c, (hl)
                inc   hl
                ld    b, (hl)
                endm

LDDE_M          macro
                ld    e, (hl)
                inc   hl
                ld    d, (hl)
                endm

LDHL_M          macro @tmp
                ld    @tmp, (hl)
                inc   hl
                ld    h, (hl)
                ld    l, @tmp
                endm
				
LDM_BC          macro
                ld    (hl), c
                inc   hl
                ld    (hl), b
                endm

LDM_DE          macro
                ld    (hl), e
                inc   hl
                ld    (hl), d
                endm

LDHL_BC         macro
                ld    h, b
                ld    l, c
                endm

LDHL_DE         macro
                ld    h, d
                ld    l, e
                endm

LDBC_HL         macro
                ld    b, h
                ld    c, l
                endm

LDDE_HL         macro
                ld    d, h
                ld    e, l
                endm

POP_FPREG       macro
                pop   bc
                pop   ix
                pop   de
                endm

PUSH_FPREG      macro
                push  bc
                push  ix
                push  de
                endm
				
FPREG_CONST     macro @1, @2, @3
                ld    bc, @1
                ld    ix, @2
                ld    de, @2
                endm

EXPECT          macro @token
                ld    a, @token
                call  expect_char
				endm

TEST_FFFF       macro
                ld    a, h
                and   l
                inc   a                ; is valid (!= ffff)
				endm

TEST_0          macro
                ld    a, h
                or    l
                endm
				
                
; **************************************************************
CHAR_CTRLC     equ   3
CHAR_TAB       equ   9
CHAR_LF        equ   0Ah
CHAR_CR        equ   0Dh
CHAR_CTRLO     equ   0Fh
CHAR_CTRLQ     equ   11h
CHAR_CTRLR     equ   12h
CHAR_CTRLS     equ   13h
CHAR_CTRLT     equ   14h
CHAR_CTRLU     equ   15h
CHAR_CTRLX     equ   18h
CHAR_CTRLZ     equ   1Ah
CHAR_ESC       equ   1Bh
CHAR_RUBOUT    equ   7Fh
CHAR_EXCL      equ   '!'
CHAR_BSLASH    equ   '\'
CHAR_SPACE     equ   ' '
CHAR_COMMA     equ   ','
CHAR_LPAREN    equ   '('
CHAR_RPAREN    equ   ')'
CHAR_QUOTE     equ   22h
CHAR_TIC       equ   27h
CHAR_SEMI      equ   ';'
CHAR_COLON     equ   ':'
CHAR_ZERO      equ   '0'
CHAR_NINE      equ   '9'
CHAR_PERCENT   equ   '%'
CHAR_AMP       equ   '&>'
CHAR_PERIOD    equ   '.'
CHAR_A         equ   'A'
CHAR_E         equ   'E'
CHAR_Z         equ   'Z'
CHAR_PLUS      equ   '+'
CHAR_MINUS     equ   '-'
CHAR_HASH      equ   '#'
CHAR_DOLLAR    equ   '$'
CHAR_STAR      equ   '*'
CHAR_POWER     equ   '^'
CHAR_QUEST     equ   '?'

TOKEN_END       equ   80h
TOKEN_FOR       equ   81h
TOKEN_DATA      equ   83h
TOKEN_INPUT     equ   84h
TOKEN_GOTO      equ   88h
TOKEN_FNEND     equ   89h
TOKEN_IF        equ   8Ah
TOKEN_RESTORE   equ   8Bh
TOKEN_GOSUB     equ   8Ch
TOKEN_REM       equ   8Eh
TOKEN_QUEST     equ   97h
TOKEN_EXCL      equ   9Ch
TOKEN_USING     equ   9Dh
TOKEN_TAB       equ   9Eh
TOKEN_TO        equ   9Fh
TOKEN_FN        equ   0A0h
TOKEN_SPC       equ   0A1h
TOKEN_THEN      equ   0A2h
TOKEN_NOT       equ   0A3h
TOKEN_STEP      equ   0A4h
TOKEN_PLUS      equ   0A5h
TOKEN_MINUS     equ   0A6h
TOKEN_GREATER   equ   0ACh
TOKEN_EQUAL     equ   0ADh
TOKEN_LESS      equ   0AEh
TOKEN_SGN       equ   0AFh
TOKEN_CHRS      equ   0C3h
TOKEN_MIDS      equ   0C6h
TOKEN_LPOS      equ   0C7h
TOKEN_INSTR     equ   0C8h
TOKEN_ELSE      equ   0C9h
TOKEN_REM       equ   0D5h

MASK_7BIT       equ   07Fh
NULL            equ   0                ; 0 as string terminator

; precedence of operations
PREC_OR         equ   46h
PREC_AND        equ   50h
PREC_NOT        equ   5ah
PREC_STRCMP     equ   64h
PREC_RELOP      equ   78h
PREC_ADDSUB     equ   79h
PREC_MULDIV     equ   7Ch
PREC_MINUS      equ   7Dh
PREC_POWER      equ   7Fh


; **************************************************************

; this structure is typically pointed to by IY
; IY is not used otherwise
ioparams        struc
curpos:         db ?                   ; current position
linelength:     db ?                   ; length of output line
last_field:     db ?
padcount:       db ?                   ; # of padding characters
padchar:        db ?                   ; char used for padding after CRLF
                                       ; (typically NUL)
ioparams        ends

; this is the structure of a string descriptor
string_desc     struc
len:            db ?
unused:         db ?
addr:           dw ?
string_desc     ends

; BASIC interpreter variables
                org 0
resetvector:    ds 1                   ; contains a C3h (JP)
reset_addr:     ds 2                   ; point to BASIC warmstart

                org 100h
iosuppress:     ds 1                   ; flag to suppress I/O
dim_flag:       ds 1                   ; used in array declaration
expr_type:      ds 1                   ; type of current expression
                                       ; =0 numeric
                                       ; =1 string
byte_103:       ds 1                   ; used in tokenizing line
memory_top:     ds 2                   ; highest memory address
stringstkptr:   ds 2                   ; ptr to stringstk
stringstk:      ds 60                  ; stack for storing nested string expressions

; String accu, temporary scratchpad for string expression processing
; must be directly after stringstk
straccu:        ds 1                   ; length of string
                ds 1                   ; unused
                ds 2                   ; address of string
string_top:     ds 2                   ; point to end of string area
arrayvalptr:    ds 2                   ; used in calaculating array values
currentlineno:  ds 2                   ; stores current lineno in BASIC execution
subscript_flag: ds 1                   ; subscript flag, used in variable decl. and eval.
                                       ; = 1 (exec_kill)
                                       ; = 0
                                       ; = CHAR_RPAREN
input_read_flag: ds 1                  ; used in INPUT processing
curlineptr:     ds 2                   ; ptr to current line in BASIC execution
lineptrsave:    ds 2                   ; temporary
lineno:         ds 2                   ; temporary
contlineno:     ds 2                   ; lineno for CONT
contlineptr:    ds 2                   ; temporary
string_base:    ds 2                   ; stack grows below this space
                                       ; string data extends from here to memory_top
start_memory:   ds 2                   ; start of BASIC program
prog_end:       ds 2                   ; end of BASIC program, scalar variables start here
end_of_vars:    ds 2                   ; end of scalar variable table, arrays start here
end_arrays:     ds 2                   ; end of array table, start of free space

; memory layout
; start_memory -> BASIC lines
; prog_end     -> start of variable table
; end_of_vars  -> start of array table
; end_arrays   -> end of array table
; ----- free space, will grow downward
;
; temporary expression stack
; string_base  -> start of string space
; string_top   -> end of string space, growing downwards
; memory_top   -> highest memory
;
; format of BASIC line
; xxxx -> link to next line (0000 if end of program)
; nnnn -> lineno (1...65520)
; tokenized basic line
; 00 -> end of line
; link points to here

data_ptr:       ds 2                   ; ptr to next DATA item to be READ

; FP ACCU #1, stores value in packed format
; i.e. mant6-2 (1 only exists in register calculations)
; contain mantissa with    sign bit in mant6, normalized
; with supression of leading 1
; exp =    0 -> accu is 0
; exp =    0x81 ->    number is 0..1
fpaccu_mant32:  ds 2
fpaccu_mant54:  ds 2
fpaccu_mant6:   ds 1
fpaccu_exp:     ds 1
fpaccu_mantsign: ds 1                  ; FPaccu sign

; buf for conversion and formatting of numbers into decimal representation
numberbuf0:     ds 1                   ; unused, but HL is usually initialized when
                                       ; pointing to number buf
numberbuf:      ds 19
                ds 6                   ; used as token buf

rnd_mant23:     ds 2                   ; random init value
rnd_mant45:     ds 2
rndmant6_exp:   ds 2

outputvector:   ds 1                   ; output vector, points to console or printer
                                       ; filled with JP instruction
output_addr:    ds 2                   ; address of current output routine

; parameter table for CONSOLE (pointed to by IY)
conparam:       ds 1                   ; curpos
                ds 1                   ; linelength
                ds 1                   ; last_field
                ds 1                   ; padcount
                ds 1                   ; padchar

; parameter table for PRINTER output (pointed to by IY)
prtparam:       ds 1                   ; curpos
                ds 1                   ; linelength
                ds 1                   ; last_field
                ds 1                   ; padcount
                ds 1                   ; padchar
curlineno:      ds 2                   ; temporary
auto_increment: ds 2                   ; lineno for autoincrement

renum_size:     ds 1                   ; RENUMBER parameters
renum_incr:     ds 2
renum_new:      ds 2

trace_mode:     ds 1                   ; bit 7=1: LTRACE ON
                                       ; bit 6=1: TRACE ON
                            
coldvector:     ds 1                   ; filled with JP instruction
cold_addr:      ds 2                   ; address of coldstart

inputbuf_cnt:   ds 1                   ; cntr for line inputbuf

pos_period:     ds 2                   ; used in number conversion

fmt_flags:      ds 1                   ; flag for formatting number output
                                       ; bit0 = add for digits for exponent (E+XX)
                                       ; bit1 = unused?
                                       ; bit2 = print SPACE for positive sign
                                       ; bit3 = add leading '+' sign
                                       ; bit4 = add leading '$'
                                       ; bit5 = replace empty positions with '*'
                                       ; bit6 = add commas each 3 digits
                                       ; bit7 = percent format
prompt_flag:    ds 1                   ; =0 : direct mode
                                       ; =1 : prompt auto lineno
renum_start:    ds 2                   ; used in RENUMBER
div_ovf:        ds 1                   ; flag division overflow
precision:      ds 1                   ; number PRECISION
byte_1B0:       ds 1                   ; filled with comma
inputbuf:       ds 14Fh                ; inputbuf for enter, edit, and convert input

; ------------------------------------------------------------------------------

; program code starts here
;
; Jump table, modify these to point to own routines

                org 300h
COLDSTART:      jp    coldstart
WARMSTART:      jp    recovered_msg
math_usr:       jp    illfunc_error

; wait for console character available, return in A
CONSOLEIN:      jp    0F003h

; read a character from paper tape reader, return in A, return C=1 if EOF
READERIN:       jp    0F006h

; write a character in C to CONSOLE, no wait
CONSOLEOUT:     jp    0F009h

; write a character in C to paper tape punch, no wait
PUNCHOUT:       jp    0F00Ch

; write a character in C to printer, no wait
LISTOUT:        jp    0F00Fh

; check if a character is present from CONSOLE, A=0: no, A=FF: yes
; char can be obtained with CONSOLEIN then
CONSOLESTAT:    jp    0F012h

; get IObyte of (Zapple) monitor in A
IOCHECK:        jp    0F015h

; set IObyte of (Zapple) monitor in C
IOSET:          jp    0F018h

; get memory size in BA (B=high, A=low)
MEMSIZE:        jp    0F01Bh

; return to monitor
TRAP:           jp    0F01Eh

; helper functions for USR() programmer
                jp    fpaccu_to_16
                jp    AB_to_fpaccu

; BASIC function dispatch table
func_tbl:       dw    math_sgn
                dw    math_int
                dw    math_abs
                dw    math_usr         ; call USR vector
                dw    math_fre
                dw    math_inp
                dw    math_pos
                dw    math_sqr
                dw    math_rnd
                dw    math_log
                dw    math_exp
                dw    math_cos
                dw    math_sin
                dw    math_tan
                dw    math_atn
                dw    math_peek
                dw    math_len
                dw    math_strs
                dw    math_val
                dw    math_asc
                dw    math_chrs
                dw    math_lefts
                dw    math_rights
                dw    math_mids
                dw    math_lpos
                dw    math_instr
                
; operand dispatch table (first byte of each entry is precedence)
oper_tbl:       db    PREC_ADDSUB 
                dw    pop_fpreg_and_add
                db    PREC_ADDSUB
                dw    pop_fpreg_and_sub
                db    PREC_MULDIV
                dw    pop_fpreg_and_mult
                db    PREC_MULDIV
                dw    pop_fpreg_and_div
                db    PREC_POWER
                dw    pop_fpreg_and_power
                db    PREC_AND
                dw    pop_fpreg_and_booland
                db    PREC_OR
                dw    pop_fpreg_and_boolor

; basic cmd dispatch table                
token2_dispatch:
                dw    exec_end
                dw    exec_for
                dw    exec_next
                dw    exec_data
                dw    exec_input
                dw    exec_dim
                dw    exec_read
                dw    exec_let
                dw    exec_goto
                dw    exec_fnend
                dw    exec_if
                dw    exec_restore
                dw    exec_gosub
                dw    exec_return
                dw    advance_to_eoln  ; REM statement
                dw    exec_stop
                dw    exec_out
                dw    exec_on
                dw    exec_null
                dw    exec_wait
                dw    exec_def
                dw    exec_poke
                dw    exec_print
                dw    exec_print
                dw    exec_input
                dw    exec_clear
                dw    exec_fnend       ; fnreturn
                dw    exec_save
                dw    advance_to_eoln  ; ! statement

; special BASIC token dispatch table
token1_dispatch:
                dw    advance_to_eoln ; ELSE
                dw    exec_lprint
                dw    exec_trace
                dw    exec_ltrace
                dw    exec_randomize
                dw exec_switch
                dw exec_lwidth
                dw exec_lnull
                dw exec_width
                dw exec_lvar
                dw exec_llvar
                dw exec_print
                dw syntax_error        ; tic alternative REM, not processed here
                dw exec_precision
                dw exec_call
                dw exec_kill
                dw exec_exchange
                dw exec_lineinput
                dw exec_loadgo
                dw exec_run
                dw exec_load
                dw exec_new
                dw exec_auto
                dw exec_copy
                dw exec_aloadc
                dw exec_amergec
                dw exec_aload
                dw exec_amerge
                dw exec_asave
                dw exec_list
                dw exec_llist
                dw exec_renumber
                dw exec_delete
                dw exec_edit
                dw exec_cont
                
; discard the last pending FOR loops
; DE = FFxx -> discard all open levels,
;         point to first non-FOR loop level
; DE = 00 -> point to last open level
; DE = var ptr -> discard all open levels
;         and point to correct level
;
; Note: the stack is used for storing various structures,
; such as FOR loop, GOSUB, and expressions
; each structure has a marker at the end which
; is usually the originating token.
; the marker is two levels above (stack mark and process
; routine of BASIC command)
discard_open_forloops:
                ld    hl, 4            ; skip over 2 levels of calls
                add   hl, sp
                ld    bc, 11h
loop3FD:        ld    a, (hl)          ;<+ get stack marker
                inc   hl               ; | advance
                cp    TOKEN_FOR        ; | is it FOR token?
                ret   nz               ; | no, return
                                       ; |
; discard pending for loops              |
                ld    a, (hl)          ; | get next byte of FOR structure
                inc   hl               ; | advance
                push  hl               ; | save it
                ld    h, (hl)          ; | get next byte of FOR structure
                ld    l, a             ; | pack pair into HL
                ld    a, d             ; | get variable to match
                or    e                ; |
                ex    de, hl           ; | save variable name
                jr    z, loc_413       ; | variable zero? NEXT without variable name
                                       ; | matches unconditionally
                ex    de, hl           ; | restore variable
                CPHL_DE                ; | compare with FOR variable name
loc_413:        pop   hl               ; | reload ptr into FOR structure
                inc   hl               ; | point to payload after variable name
                ret   z                ; | return if correct level found
                add   hl, bc           ; | skip over payload
                jr    loop3FD          ;-+ loop

; HL = new end address
; BC = old end address
; DE = start address
make_space:     call  check_memfree    ; validate enough space available
                push  bc
                ex    (sp), hl         ; swap oldend and newend
                pop   bc               ; BC is newend
loc_41F:        or    a                ; clear CY
                push  hl               ; save oldend
                sbc   hl, de           ; calculate bytes to move
                push  bc
                ex    (sp), hl         ; swap newend and bytes to move
                pop   bc               ; BC is move count, HL is newend
                ex    de, hl           ; DE is newend, HL is start
                ex    (sp), hl         ; stack is start, HL is oldend
                inc   bc               ; one more byte to move
                lddr                   ; move data
                inc   hl               ; HL points to end of freed space
                inc   de               ; DE points to start of space
                ld    b, d             ; move DE -> BC
                ld    c, e
                pop   de               ; DE is start of free space
                ret

; verify that 2*C bytes are still free in memory
verify_space:   push  hl               ; save HL
                ld    hl, (end_arrays) ; get start of free space
                ld    b, 0             ; make C 16bit
                add   hl, bc           ; add to free space
                add   hl, bc           ; add to free space
                call  check_memfree    ; check if not overlapping with string space
                pop   hl
                ret

check_memfree:  push  de               ; save DE
                ex    de, hl           ; save HL
                ld    hl, -40          ; subtract 40 from stack
                add   hl, sp
                CPHL_DE                ; subtract memory base
                ex    de, hl
                pop   de
                ret   nc               ; enough space free
out_of_memory_error:
                ld    e, 7
                jr    print_error

; expect the char in A in the inputbuf, otherwise error
expect_char:    cp    (hl)
                jp    z, nextchar
                jr    syntax_error

invalid_input:  ld    a, (input_read_flag) ; get input/read flag
                or    a
                jr    nz, loc_467      ; in READ?
                pop   bc               ; no, drop curlineptr
                ld    hl, a_invalid_input ; message "*invalid input"
                call  print_string     ; error
                jp    loc_5F4          ; restore curlineptr and exit
loc_467:        ld    hl, (currentlineno) ; copy lineno into error lineno
                ld    (lineno), hl     ; otherwise (in READ), 
                                       ; notify a syntax error in data line

; error print routines
syntax_error:
                ld    e, 2
                db    1                ; LD BC, xxxx to skip over next code
div_by_zero_error:
                ld    e, 11
                db    1                ; LD BC, xxxx to skip over next code
recovered_msg:  ld    e, 22
                db    1                ; LD BC, xxxx to skip over next code
redim_array_error:
                ld    e, 10
                db    1                ; LD BC, xxxx to skip over next code
usercall_error: ld    e, 18
                db    1                ; LD BC, xxxx to skip over next code
next_wo_for_error:
                ld    e, 1

; print an error message in E
print_error:    call  reset_stack_warm ; correct stack ptr
                call  enable_output    ; enable output again, if it was suppressed
                call  print_crlf       ; do a CRLF
                ld    hl, e_next_wo_for ; load start of error table
loop48A:        dec   e                ;<--+ decrement error number
                jr    z, loc_494       ;   | if zero, found
loop48D:        bit   7, (hl)          ;<+ | test high bit
                inc   hl               ; | | advance ptr
                jr    z, loop48D       ;-+ | loop to end of string
                jr    loop48A          ;---+ loop until error string found
loc_494:        call  print_string     ; emit the message string
                ld    hl, (lineno)     ; get lineno
                TEST_FFFF              ;  check if != ffff
                call  nz, print_at_lineno ; is valid, print " @ line "
                                       ; if line is printed: A    != 0

; enters here to print ready prompt
; according to flag in A (print if A=0)
print_prompt:
                call  enable_output    ; enable output if it was suppressed
                ld    (prompt_flag), a ; A is 0, clear prompt flag
                call  print_ready_prompt ; print "READY"
loop4A9:        ld    hl, 0FFFFh       ;<+ reset lineno
                ld    (lineno), hl     ; | 
                ld    a, (prompt_flag) ; | prompting?
                or    a                ; | 
                jr    z, loc_4DA       ; | no, go to direct mode
                ld    hl, (curlineno)  ; | get current lineno
                jp    m, sub_1DD5      ; | prompt flag=FF?, yes coming from aload/amerge
                ld    de, (auto_increment) ; in auto mode, get increment
                add   hl, de           ; | make new lineno
                jp    c, subscript_range_error ; too large, error
                                       ; |
; do auto mode                           | 
auto:           ld    (curlineno), hl  ; | store as new lineno
                push  hl               ; | save it
                call  print_HL         ; | print lineno
                call  print_space      ; | print a space
                call  get_inputline    ; | process a whole input line
                call  nextchar         ; | get next char
                pop   de               ; | restore auto lineno
                or    a                ; | line was empty?
                jr    z, print_prompt  ; | yes, continue with next line
                scf                    ; | set flag C=1: digit seen
                jr    loc_4E4          ; | process line, assuming a lineno
                                       ; | has been already found
loc_4DA:        call  get_inputline    ; | get a line
                call  nextchar         ; | read char
                inc   a                ; | set flags
                dec   a                ; |
                jr    z, loop4A9       ;-+ empty line, loop
loc_4E4:        push  af               ; save char and C flag (C=1: digit seen)
                cp    CHAR_CTRLC       ; is it CTRL-C?
                jp    z, has_break     ; yes, skip
                exx                    ; save all regs
                ld    hl, prompt_flag  ; check prompt flag
                inc   (hl)
                dec   (hl)
                exx                    ; restore all regs
loc_4F1:                               ; is in direct mode? try finding a lineno
                call  z, parse_lineno  ; DE contains lineno or 0
                                       ; otherwise: DE contains the AUTO lineno
                cp    CHAR_SPACE       ; is char space?
                jr    nz, loc_4F9      ; no, regular char
                inc   hl               ; advance to next (a space after a lineno)
loc_4F9:        push  de               ; save potential lineno
                call  tokenize_line    ; compress line by tokenizing it
                ld    b, a             ; B = 0 (A returned with 0)
                pop   de               ; restore lineno
                pop   af               ; restore char read
                jp    nc, execute_command ; was not a number?

; a line starting with a statement number was entered
                push  de               ; save potential lineno
                push  bc               ; length of line in C, B is 0
loop505:        inc   hl               ;<+ get first char of line
                ld    a, (hl)          ; | 
                or    a                ; | is zero?
                jr    z, loc_516       ; | flush buf to memory
                cp    CHAR_SPACE       ; | is space?
                jr    z, loop505       ;>+ yes ignore and loop
                cp    CHAR_TAB         ; | is tab?
                jr    z, loop505       ;>+ yes ignore and loop
                cp    CHAR_LF          ; | is LF?
                jr    z, loop505       ;-+ yes ignore and loop
loc_516:        push  af               ; save char seen for future
                call  find_line        ; find the line in program memory
                push  bc               ; save previous link
                jr    nc, loc_531      ; must be inserted before
; must replace line
                ex    de, hl           ; save nextlink in DE
                ld    hl, (prog_end)   ; get end of program
loop521:        ld    a, (de)          ;<+ get data from nextlink
                ld    (bc), a          ; | copy into previous
                inc   bc               ; | advance
                inc   de               ; | 
                CPHL_DE                ; | end of program reached?
                jr    nz, loop521      ;-+ no loop (delete the matching line)
                ld    (prog_end), bc   ; save new end of program
loc_531:        pop   de               ; restore previous link in DE
                pop   af               ; restore char
                jr    z, rebuild_nextchain ; was zero? yes, we just had to 
				                       ; delete the line
                ld    bc, (prog_end)   ; get end of program
                pop   hl               ; get line length to insert
                add   hl, bc           ; add to end of program
                push  hl               ; save new end
                call  make_space       ; shift program up to make a space for line
                pop   hl               ; save new end of program
                ld    (prog_end), hl
                ex    de, hl           ; get link to new line in HL
                ld    (hl), h          ; ensure that line link is not zero
                inc   hl               ; advance to lineno position
                inc   hl
                pop   de               ; restore lineno
                LDM_DE                 ; save it into new line
                inc   hl
                ld    de, inputbuf     ; get inputbuf
loop54F:        ld    a, (de)          ;<+ move line into program space
                ld    (hl), a          ; | 
                inc   hl               ; | 
                inc   de               ; | 
                or    a                ; | until line terminator seen
                jr    nz, loop54F      ;-+
rebuild_nextchain:                     
                call  init_from_start  ; clear variables
                inc   hl               ; HL points to start of program now
                ex    de, hl           ; into DE
                ld    hl, loop4A9      ; set new return address
                push  hl
rebuild_nextchain1:                    ;<--+
                LDHL_DE                ;   | DE is ptr to nextlink, copy into HL
                ld    a, (hl)          ;   | get current nextlink
                inc   hl               ;   | 
                or    (hl)             ;   | 
                ret   z                ;   | return if zero -> finished with
				                       ;   | adjustment of program
                inc   hl               ;   | advance beyond lineno
                inc   hl               ;   | 
                inc   hl               ;   | 
                xor   a                ;   | clear A
loop569:        cp    (hl)             ;<+ | find the line terminator
                inc   hl               ; | | advance
                jr    nz, loop569      ;-+ | loop until found
                ex    de, hl           ;   | HL = previous nextlink, DE = start of next line
                LDM_DE                 ;   | save line position into previous nextlink
                jr    rebuild_nextchain1 ;-+ loop until end of program

; get a range of linenos
; find the first line, set HL, BC as in find_line
; end of range is on stack when returning
get_lineno_range:
                ld    de, 0            ; preload starting lineno
                push  de
                jr    z, loc_585       ; no more arguments, set 0-65535
                pop   de               ; discard start value
                call  read_lineno      ; read a lineno in DE
                push  de               ; save it for later
                jr    z, loc_58E       ; end of command, only delete a single line
                EXPECT TOKEN_MINUS     ; otherweise expect token '-'
loc_585:        ld    de, 0FFFFh       ; preload 65535 as end of range
                call  nz, read_lineno  ; if not end of line yet, get the end of range
                jp    nz, syntax_error ; error, if more characters follow
loc_58E:        ex    de, hl           ; HL is end of range
                pop   de               ; DE is start lineno range
                ex    (sp), hl         ; insert it on stack
                push  hl               ; push old return address

; DE is lineno to search
; return address of nextlink of HL
; return nextlink of previous line in BC
; Z=1 if line matched or nextlink=0
; C=0 if line has to be    inserted here
find_line:      ld    hl, (start_memory) ; load start of program
find_line_from_current: 
                LDBC_HL                ; ptr to nextlink: copy into BC
                ld    a, (hl)          ; check link
                inc   hl
                or    (hl)             ; was it 0000?
                dec   hl               ; HL points to nextlink 0000 (end of program)
                ret   z                ; yes, exit
                inc   hl               ; skip over nextlink
                inc   hl
                LDHL_M A               ; read lineno into HL
                sbc   hl, de           ; compare with lineno to be entered in DE
                LDHL_BC                ; restore nextlink
                LDHL_M A               ; read nextlink into HL
                ccf
                ret   z                ; matched line exactly
                                       ; return nextlink of this line
                ccf
                ret   nc               ; must insert before this line
                exx                    ; fragment of exec_copy:
                                       ; increment cntr of lines to copy
                add   hl, de
                exx
                jr    find_line_from_current ; loop through program
; process NEW command
exec_new:       ret   nz               ; return if arguments follow

new_memory:     ld    hl, (start_memory) ; get lowest memory
                xor   a                ; clear A
                ld    (trace_mode), a  ; clear flag
                ld    (hl), a          ; clear first memory cells
                inc   hl
                ld    (hl), a
                inc   hl
                ld    (prog_end), hl   ; save endofbasic

; initialize program ptrs, clear variables
init_from_start:
                ld    hl, (start_memory)
                dec   hl               ; point to start of memory - 1

; initialize from current position
init_from_current:
                ld    (curlineptr), hl ; save it
                ld    hl, (memory_top) ; copy top ptr
                ld    (string_top), hl
                call  reset_dataptr    ; set program ptr
                ld    hl, (prog_end)   ; end of program text
                ld    (end_of_vars), hl ; start of vars
                ld    (end_arrays), hl ; end of variables

reset_stack_warm:
                pop   bc               ; get return address
                ld    sp, (string_base) ; reset stack
                ld    hl, stringstk    ; HL is  ptr to exprstack
                ld    (stringstkptr), hl ; save ptr
                xor   a                ; clear A
                ld    h, a
                ld    l, a
                ld    (contlineptr), hl ; clear CONT ptr
                ld    (subscript_flag), a ; clear subscript flag
                ld    (inputbuf_cnt), a ; clear cntr of input chars
                push  hl               ; push zero into stacktop
                                       ;  = fallback to reset vector = WARMSTART
                push  bc               ; push return address
loc_5F4:        ld    hl, (curlineptr) ; load ptr to current line
                ret

; clear IOSUPPRESS flag, enabling output again
enable_output:
                xor   a
                ld    (iosuppress), a  ; clear IOSUPPRESS flag

; select console for output
select_console:
                ld    iy, CONSOLEOUT   ; get address of CONSOLEOUT routine
                ld    (output_addr), iy ; put into output vector
                ld    iy, conparam     ; load console parameter set
                ret

tokenize_line:  xor   a                ; clear A
                ld    (byte_103), a
                ld    c, 5             ; load cntr
                ld    de, inputbuf     ; inputbuf, used to compact the inputbuf
                                       ; by replacing keywords with tokens
loop612:        ld    a, (hl)          ; get char
                ld    b, a             ; into B (remember start of string)
                or    a                ; end of buf?
                jp    z, loc_6AD       ; yes exit
                cp    CHAR_EXCL
                jr    c, loc_66B       ; less than "!" ?, skip
                cp    CHAR_QUOTE       ; is it " ?
                jr    z, loc_69B       ; yes, skip
                ld    a, (byte_103)    ; get flag
                or    a                ; is set?
                ld    b, a             ; save in B
                ld    a, (hl)          ; get char
                jr    nz, loc_66B      ; flag is set, accumulate mode
                cp    CHAR_ZERO        ; is char >= '0'?
                jr    c, loc_630       ; no, continue
                cp    CHAR_NINE+1      ; is it <= '9'?
                jr    c, loc_66B       ; yes, accumulate
loc_630:        push  de               ; save DE
                ld    de, token_tbl    ; start of token table
                push  hl               ; ptr to potential keyword
                jr    loop639          ; process token table
loop637:        inc   hl               ;<--+ next char in keyword
                inc   de               ;   | next char in token tbl
loop639:        ld    a, (de)          ;<----+ get char from token table
                or    a                ;   | | end of table?
                jr    z, loc_662       ;   | | yes, exit
                cp    CHAR_SPACE       ;   | | is it a space?
                jr    nz, loc_64A      ;   | | no, skip
                inc   de               ;   | | skip space
loop642:        ld    a, (hl)          ;<+ | | char from input line
                cp    CHAR_SPACE       ; | | | is it a space?
                jr    nz, loc_64A      ; | | | no skip
                inc   hl               ; | | | ignore space
                jr    loop642          ;-+ | | and get next char
loc_64A:        ex    de, hl           ;   | | token table in HL, buf in DE
                ld    a, (de)          ;   | | get buf char
                cp    60h              ;   | | alphabetic?
                jr    c, loc_652       ;   | | no, skip
                and   5Fh              ;   | | make upper case
loc_652:        xor   (hl)             ;   | | compare with token table
                and   MASK_7BIT        ;   | | mask 7 bits only
                ex    de, hl           ;   | | buf in HL, token table in DE
                jr    nz, loc_6A1      ;   | | did not match
                ld    a, (de)          ;   | | get char from token table
                rla                    ;   | |  
                jr    nc, loop637      ;---+ | not yet end of token? loop
                pop   af               ;     | we have a match, discard HL
                ld    a, b             ;     | get token count
                or    80h              ;     | mark as token
                jr    loc_66A          ;     | token  value in A
loc_662:        pop   hl               ;     | end of table reached, restore ptr to keyword
                ld    a, (hl)          ;     | get char
                cp    60h              ;     | > 0x60
                jr    c, loc_66A       ;     | no skip
                and   5Fh              ;     | make upper case
loc_66A:        pop   de               ;     | restore bufptr
loc_66B:        ex    de, hl           ;     | get target buf
                cp    TOKEN_ELSE       ;     | is it token ELSE?
                ld    (hl), CHAR_COLON ;     | put colon in buf
                jr    nz, loc_674      ;     | no, skip
                inc   c                ;     | yes, advance
                inc   hl               ;     | 
loc_674:        ex    de, hl           ;     | restore target buf in DE
                inc   hl               ;     | advance to next char
                ld    (de), a          ;     | accumulate char in buf
                inc   de               ;     | to next position
                inc   c                ;     | 
                sub   CHAR_COLON       ;     | is char ':'?
                jr    z, loc_687       ;     | yes, delimiter
                cp    CHAR_TIC-CHAR_COLON ;  | is it "tic"? (D5)
                ld    b, CHAR_COLON    ;     | put colon in buf
                jr    z, loc_694       ;     | yes, was D5
                cp    CHAR_DATA-CHAR_COLON ; | is token 83 (DATA)?
                jr    nz, loc_68A      ;     | no skip
loc_687:        ld    (byte_103), a    ;     | save flag
loc_68A:        sub   TOKEN_REM-CHAR_COLON ; | is token 8E (REM)?
                jr    z, loc_693       ;     | yes skip
                sub   TOKEN_EXCL-TOKEN_REM ; | is token ! (REM)?
                jp    nz, loop612      ;     | no, loop
loc_693:                               ;     | store zero in B
                ld    b, a             ;     | disable tokenizer until end of line
loc_694:        ld    a, (hl)          ;     | get char
                or    a                ;     | is 0?
                jr    z, loc_6AD       ;     | yes, done
                cp    b                ;     | same as start char?
                jr    z, loc_66B       ;     | yes, done
loc_69B:        inc   hl               ;     | advance to next char
                ld    (de), a          ;     | put char in buf
                inc   c                ;     | increment cntr
                inc   de               ;     | increment targetbufptr
                jr    loc_694          ;     | disable tokenizer until next " is seen, or 0
loc_6A1:        pop   hl               ;     | restore ptr to potential keyword
                push  hl               ;     | save it again
                inc   b                ;     | increment token cntr
                ex    de, hl           ;     | keyword in DE, tokentable in HL
loop6A5:        bit   7, (hl)          ;<+   | test bit of token tbl entry
                inc   hl               ; |   | advance
                jr    z, loop6A5       ;-+   | loop as long as end of token not reached
                ex    de, hl           ;     | keyword in HL, tokentbl in DE
                jr    loop639          ;-----+ loop
loc_6AD:        ld    hl, inputbuf-1   ; point to start of inputbuf -1
                ld    (de), a          ; save three 0 bytes at the end of buf
                inc   de               ; 1st byte = end of line
                                       ; 2nd,3rd = link to next line
                                       ; is 0000 because this is a single
                                       ; line in inputbuf
                ld    (de), a
                inc   de
                ld    (de), a
                ret

ctrl_7f:        ld    a, b             ; get current char count of input line
                dec   a                ; decrement
                or    (iy+ioparams.curpos) ; get current position
                jr    z, get_inputline ; at beginning of line? yes, restart get_inputline
                call  print_backslash  ; no, print a backslash
loop6C0:        djnz  loc_6CA          ;<+ skip if count not zero
                call  print_backslash  ; | two backslahes
                call  print_backslash  ; |
                jr    loc_704          ; | restart get_inputline in new line
loc_6CA:        dec   hl               ; | decrement line ptr
                ld    a, (hl)          ; | get last char
                call  print_char       ; | print it
                call  read_conchar     ; | get a character
                cp    CHAR_RUBOUT      ; | is RUBOUT?
                jr    z, loop6C0       ;-+ yes, loop
                push  af               ; save char entered
                call  print_backslash  ; final backslash
                pop   af               ; restore
                jr    loc_713          ; back with entering data in buf

; print ?? to get more input
; read a new inputbuf, return start of buf in HL
get_moreinput:
                ld    a, CHAR_QUEST
                call  write_char
; prompt ?, get an inputbuf, Z=1 if CTRL-C entered,
; HL points to inputbuf-1
get_input:      ld    a, CHAR_QUEST    ; print a question mark
                call  write_char
                call  print_space      ; print a space
                call  get_inputline    ; get a buf
                inc   hl               ; point to inputbuf
                ld    a, (hl)          ; get char in buf
                dec   hl               ; point to inputbuf-1
                cp    3                ; check for CTRL-C
                ret                    ; exit

con_emit_ctrl_char:
                call  select_console   ; select console for I/O
emit_ctrl_char:
                push  af               ; save char for output
                ld    a, '^'           ; prefix ^ for CTRL char
                call  write_char       ; output it
                pop   af               ; restore char
                or    40h              ; convert to A-Z
                jr    write_char       ; emit it

ctrlu:          call  emit_ctrl_char   ; emit CTRL-U
loc_704:        call  prompt_edit_lineno ; emit the lineno,if any

; read input line in inputbuf
; return inputbuf-1, B = # characters entered,
; buf terminated with 0
get_inputline:
                ld    hl, inputbuf     ; get bufptr
                ld    b, 1             ; initialize count
                ld    a, b
                ld    (inputbuf_cnt), a
loop710:        call  read_conchar     ;<+ read a character
loc_713:        cp    7                ; | is it BEL?
                jr    z, loc_753       ; | yes, skip
                cp    CHAR_CR          ; | is it CR?
                jp    z, loc_CE9       ; | yes, do CRLF and exit
                cp    3                ; | is it CTRL-C?
                jp    z, loc_CE1       ; | yes, store CTRL-C and exit
                cp    CHAR_CTRLU       ; | is CTRL-U?
                jr    z, ctrlu         ; | yes, discard line
                cp    CHAR_RUBOUT      ; | is it RUBOUT?
                jr    z, ctrl_7f       ; | yes, skip
                cp    CHAR_CTRLR       ; | is CTRL-R?
                jr    nz, loc_741      ; | no, skip
                call  emit_ctrl_char   ; | emit CTRL-R
                call  prompt_edit_lineno ; do CRLF and edit prompt, if any
                ld    hl, inputbuf     ; | get current inputbuf
                ld    c, b             ; | copy current line count in C
loop737:        dec   c                ;<--+ pre decrement char cntr
                jr    z, loop710       ;-+ | no more chars? continue with input
                ld    a, (hl)          ;   | get char from buf
                inc   hl               ;   | advance ptr
                call  print_char       ;   | print it
                jr    loop737          ;---+ loop
loc_741:        cp    CHAR_TAB         ; is TAB?
                jr    z, loc_753       ; yes, accept as normal char
                cp    CHAR_LF          ; is LF?
                jr    nz, loc_74F      ; no, skip
                dec   b                ; decrement cntr
                jr    z, get_inputline ; if at beginning, restart get_inputline
                inc   b                ; restore buf cnt
                jr    loc_753          ; accept as normal character
loc_74F:        cp    CHAR_SPACE       ; is another control character?
                jr    c, loop710       ; yes, ignore
loc_753:        ld    c, a             ; save entered char
                ld    a, b             ; get current buf count
                cp    253              ; still space in buf?
                ld    a, 7             ; preload BEL
                jr    nc, loc_75F      ; no space, ring bell
                ld    a, c             ; restore entered char
                ld    (hl), a          ; store it in buf
                inc   hl               ; advance bufptr
                inc   b                ; advance buf ocunt
loc_75F:        call  print_char       ; emit character
                jr    loop710          ; loop

;print a SPACE on current output device
print_space:
                ld    a, CHAR_SPACE

; print char in A on the current output device,
; interpret LF (emit CR+LF+NUL...)
print_char:     cp    CHAR_LF          ; is LF?
                jr    nz, write_char   ; no, emit char
                call  print_crlf       ; do a CRLF
                ld    a, CHAR_LF       ; reload char (LF)
                ret                    ; exit

print_backslash:
                ld    a, CHAR_BSLASH   ; print a backslash (for DEL)

; print out a char in A at the current output device
write_char:     push  bc               ; print_char
                ld    c, a             ; save char
                ld    a, (iosuppress)  ; get IO suppress flag
                or    a
                jr    nz, loc_7B9      ; is set, exit
                ld    a, c             ; get char
                cp    CHAR_TAB         ; is a TAB?
                jr    nz, loc_7A6      ; no, skip
                ld    a, (iy+ioparams.linelength) ; get line length
                and   0F8h ; '?'       ; adjust to multiple of 8
                dec   a                ; -1
                cp    (iy+ioparams)    ; compare to current pos
                jr    c, loc_7A1       ; would TAB skip to next line?, then do CRLF
                ld    a, (iy+ioparams) ; no get current pos
loc_78D:        and   7                ; get # of chars printed in current tab column
                cpl                    ; calculate number of chars still to print
                add   a, 9
                ld    b, a             ; into cntr
                ld    c, CHAR_SPACE    ; load SPACE
loop795:        call  outputvector     ;<----+ emit it
                inc   (iy+ioparams.curpos) ; | advance next position
                djnz  loop795          ;-----+ loop
loc_79D:        ld    c, CHAR_TAB      ; restore char
                jr    loc_7B9          ; exit
loc_7A1:        call  print_crlf       ; advance to next line
                jr    loc_79D          
loc_7A6:        cp    CHAR_SPACE       ; is it a CTRL?
                jr    c, loc_7B6       ; no, skip
                ld    a, (iy+ioparams.curpos) ; get current pos
                cp    (iy+ioparams.linelength) ; compare with line length
                call  z, print_crlf    ; if end of line reached, do CRLF
                inc   (iy+ioparams.curpos) ; advance position
loc_7B6:        call  outputvector ; emit it
loc_7B9:        ld    a, c             ; restore registers, return char in A
                pop   bc
                or    a
                ret

; print a string pointed to by HL, delimited by character with high byte set
print_string:   ld    a, (hl)          ; get character
                res   7, a             ; reset bit 7
                call  print_char       ; emit
                bit   7, (hl)          ; test bit 7
                ret   nz               ; exit if set
                inc   hl               ; advance to next char
                jr    print_string     ; loop

; read a char from console, return in A
read_conchar:   call  CONSOLEIN        ; read a character
                and   MASK_7BIT        ; mask out parity bit
                cp    CHAR_CTRLX       ; is it CTRL-X?
                jr    z, loc_7E1       ; yes, skip
                cp    CHAR_CTRLO       ; is it CTRL-O?
                ret   nz               ; no, return with character read
                call  con_emit_ctrl_char ; print char as ^O
                ld    a, (iosuppress)  ; complement IOSUPPRESS flag
                cpl
                ld    (iosuppress), a
                xor   a                ; return A =0
                ret
loc_7E1:        call  con_emit_ctrl_char
                call  print_crlf       ; print a CRLF
                call  TRAP             ; return to monitor
                xor   a                ; hopefully return here back to BASIC
                ret                    ; with A = 0

exec_llist:     call  select_printer   ; select printer for output
exec_list:      pop   bc               ; drop return address
                call  get_lineno_range ; get a lineno range
                                       ; HL, BC point to first line
                                       ; stack contains end of range
                push  bc               ; save nextlink of first line
list1:          call  print_crlf       ; new line
                pop   hl               ; get nextlink of line in HL
                pop   de               ; DE is lastlineno to list
                LDBC_M                 ; get nextlink into BC
                inc   hl
                ld    a, b             ; is it zero, ie end of program?
                add   a, c
                jr    z, loc_834       ; yes, done, return to interpreter
                call  check_break      ; check for break, exit if CTRL-C
                push  bc               ; save nextlink
                LDBC_M                 ; get current lineno in BC
                inc   hl
                push  bc               ; save it
                ex    (sp), hl         ; stack is ptr to line
                                       ; HL is current lineno
                ex    de, hl           ; swap with lastlineno
                CPHL_DE                ; compare this lineno with lastlineno
                pop   bc               ; restore ptr to line
                jr    c, sub_833       ; end reached, clean up and return to interpreter
                ex    (sp), hl         ; stack is lastlineneo
                                       ; HL is nextlink
                push  hl               ; save
                push  bc               ; save ptr to line
                ex    de, hl           ; HL becomes current lineno
                call  print_HL         ; print it
                pop   hl               ; restore ptr to line
                call  print_space      ; print a space
                call  detokenize       ; detokenize line
                ld    hl, inputbuf     ; load inputbuf
                ld    bc, list1        ; recurse LIST/LLIST
                push  bc               ; on return

sub_82A:        dec   hl               ; point to position before buf
                ld    b, NULL          ; set terminator character
                call  copy_0string     ; copy 0-terminated string to expression stack
                jp    straccu_print    ; print the string

sub_833:        pop   bc
loc_834:        jp    print_prompt

; HL points to program line
; expand tokens  to keywords and copy expanded line into inputbuf
detokenize:     ld    bc, inputbuf-1   ; ptr to inputbuf - 1
                db    3Eh              ; LD A, xx to skip next instruction
                                       ; masks POP HL. LD A is uncritical because
                                       ; A will be overwritten
loop83B:        pop   hl               ; restore ptr to program line again
loop83C:        ld    a, (hl)          ; get char from program line
                inc   bc               ; advance inputbuf
                or    a                ; set flags
                inc   hl               ; advance program line
                ld    (bc), a          ; store char in inputbuf
                ret   z                ; exit if terminating 0 byte
                jp    p, loop83C       ; if character not a token, loop
                cp    TOKEN_ELSE       ; is it an ELSE?
                jr    nz, loc_84A      ; no skip
                dec   bc               ; decrement ptr
                                       ; tokenizer has inserted a ':' before ELSE to
                                       ; improve parsing -> discard this
loc_84A:        sub   80h              ; convert to 0...N
                push  hl               ; save ptr to program line
                ld    hl, token_tbl    ; get token table
                jr    z, kwd_found     ; if zero, found correct keyword
loop852:        bit   7, (hl)          ;<+ test high bit of keyword
                inc   hl               ; | advance token ptr
                jr    z, loop852       ;>+ not at end of keyword, loop
                dec   a                ; | decrement token to find
                jr    nz, loop852      ;-+ correct keyword not yet reached
kwd_found:      ld    a, (hl)          ; get char from keyword
                cp    CHAR_SPACE       ; ignore space, as in GO SUB and GO TO
                jr    z, loc_867
                or    a                ; set sign of character
                res   7, a             ; make positive
                ld    (bc), a          ; put into inputbuf
                jp    m, loop83B       ; was end of keyword? yes, continue
                inc   bc               ; advance inputbufptr
loc_867:        inc   hl               ; advance to next char, skip space
                jr    kwd_found        ; loop

; process FOR/TO/STEP
exec_for:       ld    a, CHAR_RPAREN
                ld    (subscript_flag), a ; this won't match a '(' in find_var,
                                       ; so effectively prevents array variables
                                       ; as FOR variables -> will result in a syntax
                                       ; error when attempting so
                call  exec_let         ; initialize loop variable
                                       ; DE = target address
                                       ; note: this is ensured to be a scalar variable
                ex    (sp), hl         ; HL = return address
                                       ; stack    = curlineptr
                call  discard_open_forloops
                pop   de               ; DE = curlineptr after loop init
                jr    nz, loc_87B      ; some levels discarded?
                add   hl, bc           ; BC = 17 (sizeof FOR structure)
                ld    sp, hl           ; store as new stack position
loc_87B:        ex    de, hl           ; HL = curlineptr after loop init
                ld    c, 0Ah           ; verify we have enough space
                call  verify_space
                push  hl               ; save curlineptr
                call  exec_data        ; advance to end of line or next statement
                ex    (sp), hl         ; HL = curlineptr after loop init
                                       ; stack = curlineptr of loop body
                push  hl               ; push it on stack
                ld    hl, (lineno)     ; FORSTRUCT: replace with current lineno
                ex    (sp), hl         ; curlineptr points to TO

loc_88B:        EXPECT TOKEN_TO        ; expect a TO
                call  assert_numeric   ; require loop variable numeric
                call  expression       ; get TO expression
                push  hl               ; save curlineptr
                call  fpaccu_to_fpreg  ; convert end value into FPREG
                pop   hl               ; restore curlineptr
                PUSH_FPREG             ; FORSTRUCT: push 6 bytes end value
                ld    bc, 8100h        ; load constant 1.0 into FPreg
                ld    ix, 0
                ld    d, c
                ld    e, c
                ld    a, (hl)          ; get next char
                cp    TOKEN_STEP       ; is it STEP token?
                ld    a, 1             ; sign flag: positive
                jr    nz, loc_8BD      ; no, skip
                call  nextchar         ; get STEP expression
                call  expression
                push  hl               ; save curlineptr
                call  fpaccu_to_fpreg  ; put into FPreg
                call  fpaccu_sgn       ; get sign flag 1=positive, ff=negative
                pop   hl               ; restore curlineptr
loc_8BD:        PUSH_FPREG             ; FORSTRUCT: push 6 bytes of STEPsize
                push  af               ; FORSTRUCT: push upward or downward flag
                inc   sp               ; discard flag byte
                push  hl
                ld    hl, (curlineptr) ; FORSTRUCT: push address of target variable
                ex    (sp), hl
loc_8C8:        ld    b, TOKEN_FOR     ; push FOR marker
                push  bc
                inc   sp               ; single byte only
                                       ; no subroutines to discard, so
                                       ; not returning with RET
; enters here after having processed a complete command, i.e. accept either
; EOLN or command separator ':' test for break here
command_done:   call  CONSOLESTAT      ; get console status
                inc   a                ; has a char?
                call  z, con_get_char  ; yes, get the char
                                       ; will accept CTRL-C, XON, XOFF,
                                       ; other chars get lost
                ld    (curlineptr), hl ; save current line ptr
                ld    a, (hl)          ; get current char in process
                cp    CHAR_COLON       ; is it a colon?
                jr    z, execute_command ; yes, process it
                or    a                ; is end of line?
                jp    nz, syntax_error ; no, error
                inc   hl               ; was end of line, advance
                ld    a, (hl)          ; get link to next line H
                inc   hl               ; advance
                or    (hl)             ; get link to next line L
                inc   hl               ; advance
                jp    z, end_program   ; lineno is zero?, end of program
                LDDE_M                 ; get lineno in DE
                ld    (lineno), de     ; store it a new current lineno
                ld    a, (trace_mode)  ; is trace mode on?
                or    a
                jr    z, execute_command ; no, execute the command
loc_8F4:        push  af               ; save trace flag
                call  m, select_printer ; if bit7=1, select printer for output
                push  de               ; save regs
                push  hl
                ld    a, '<'           ; print a '<'
                call  write_char
                ex    de, hl           ; get lineno in HL
                call  print_HL         ; print it out
                ld    a, '>'           ; print '>'
                call  write_char
                pop   hl               ; restore regs
                pop   de
                pop   af               ; restore trace flag
                add   a, a             ; shift left
                jr    nc, execute_command ; was LTRACE? no, execute the command
                call  select_console   ; select console output again
                add   a, a             ; was ALSO bit 6 set?
                jr    c, loc_8F4       ; yes also trace on console
execute_command:            
                call  nextchar         ; get next char/token
                ld    de, command_done ; push return address to call
                                       ; when command is finished
                push  de
loc_91B:        ret   z                ; line was empty, then loop to command_done
execute_token:  sub   80h              ; has a token or a single ASCII
                jp    c, do_assignment ; is not a token, skip
                cp    TOKEN_MIDS-80h   ; is token MID$?
                jp    z, do_lh_mids    ; yes process left-hand-side MID$
                cp    TOKEN_USING-80h  ; is token TAB( ?
                jr    c, loc_939       ; less than this, skip
                sub   TOKEN_ELSE-80h   ; token 9D to C6 are functions that 
                                       ; can't be used in direct mode
                jp    c, syntax_error  ; invalid instruction
                cp    TOKEN_DELETE-TOKEN_ELSE ; token larger than E9 are syntax errors
                jp    nc, syntax_error
                ld    de, token1_dispatch ; obviously a valid token, load jump table
                jr    loc_93C
loc_939:        ld    de, token2_dispatch ; load jump table
loc_93C:        rlca                   ; token * 2 (word index)
                ld    c, a             ; put as index into BC
                ld    b, 0             ; make 16 bit
                ex    de, hl           ; save curlineptr
                                       ; load token_dispatch table into HL
                add   hl, bc           ; point to command entry
                LDBC_N                 ; get command address into BC
                push  bc               ; push it on stack, will be called on
                                       ; return of nextchar
                ex    de, hl           ; restore curlineptr

; get next char    from inputbuf, set CY if digit seen
nextchar:       inc   hl               ; point to next char in buf
skipspace:      ld    a, (hl)          ; get char from    buf
                cp    TOKEN_REM        ; is it "tic" (REM, token D5)?
                jr    nz, loc_955      ; no, skip
loc_94D:        inc   hl               ; next char
                ld    a, (hl)          ; get next char
                cp    CHAR_COLON       ; is it ':'?
                ret   z                ; yes, exit
                or    a
                jr    nz, loc_94D
loc_955:        cp    CHAR_NINE+1      ; is it > '9'? 
                ret   nc               ; yes, exit
                cp    CHAR_SPACE       ; is it space?
                jr    z, nextchar      ; skip space
                cp    CHAR_TAB         ; is it TAB?
                jr    z, nextchar      ; yes skip white space
                cp    CHAR_LF          ; is it LF?
                jr    z, nextchar      ; yes, skip whitespace
                cp    CHAR_ZERO        ; compare with '0'
                ccf                    ; complement CY
                inc   a                ; set flags
                dec   a
                ret                    ; exit

; process RESTORE
exec_restore:   jr    z, reset_dataptr ; no arg, reset DATA ptr to start of program
                call  read_lineno      ; get a lineno
                push  hl               ; save curlineptr
                call  find_line        ; find line
                pop   de               ; restore curlineptr into DE
                jp    nc, undef_stmt_error ; error if line does not exist
                LDHL_BC                ; copy ptr to LINE into HL
                jr    set_dataptr      ; set the data ptr
                                       ; will restore the curlineptr again into HL

; set the ptr to next DATA
reset_dataptr:  ex    de, hl           ; save HL
                ld    hl, (start_memory) ; get memory start
set_dataptr:    dec   hl
set_dataptr1:   ld    (data_ptr), hl   ; save next position to interpret
                ex    de, hl           ; restore HL
                ret

; read a lineno into DE (may be missing -> DE=0)
read_lineno:    dec   hl               ; point to begin of expression
read_lineno_here:            
                call  nextchar         ; get next char
                call  parse_lineno     ; read a lineno into DE
                jr    skipspace        ; skip spaces

input_ctrlc:    pop   bc               ; drop address of variable
input_ctrlc1:   pop   bc               ; drop curlineptr
has_break:      or    a                ; enters here with ctrl-C seen
                jr    break_entry      ; jump into END for break processing

check_break:    call  CONSOLESTAT      ; get console status
                inc   a                ; if A=FF, character present
                ret   nz               ; no char present: exit

con_get_char:   call  read_conchar     ; read a character
                cp    CHAR_CTRLT       ; is it CTRL-T?
                jr    nz, loc_9AB      ; no, skip
                push  hl               ; save HL
                ld    hl, (lineno)     ; get lineno
				TEST_FFFF              ; is valid (!= ffff)
                call  nz, trace_lineno ; yes, emit it
                pop   hl               ; restore
                ret
loc_9AB:        cp    CHAR_CTRLS       ; is it CTRL-S (XOFF)?
                jr    nz, loc_9BA      ; no skip
loop9AF:        call  read_conchar     ;<+ read a char
                cp    CHAR_CTRLC       ; | is it CTRL-C (break)?
                jr    z, loc_9BA       ; | yes exit
                cp    CHAR_CTRLQ       ; | is it CTRL-Q (XON)?
                jr    nz, loop9AF      ;-+ no loop, until XON or break
loc_9BA:        cp    CHAR_CTRLC       ; if not break, return
                ret   nz
                call  con_emit_ctrl_char ; emit ^C
                                       ; and skip to exec_end
                db    3Eh              ; LD A, xxxx to skip next instructions
exec_stop:      ret   nz               ;* more instructions follow?, exit
                db    0F6h             ;* OR xxxx to skip next instruction
                                       ; ensures that A is non zero
exec_end:                              ; ignore unless at end of line
                ret   nz               ; note: when entered through END, A=0
                                       ; when entered through STOP, A = 0xC0
                ld    (curlineptr), hl ; save last position for CONT
break_entry:    pop   bc               ; discard return address
                                       ; will leave interpreter loop on return
end_program:    push  af               ; save token (C0 if stop)
                ld    hl, (lineno)     ; get lineno
                TEST_FFFF              ; is FFFF?
                jr    z, loc_9DA       ; yes, not in program mode
                ld    (contlineno), hl ; save last lineno for continue
                ld    hl, (curlineptr)
                ld    (contlineptr), hl ; save lineptr for continue
loc_9DA:        call  enable_output    ; reenable console out if suppressed
                pop   af               ; restore STOP/END flag
                ld    hl, a_break      ; load break message
                jp    nz, loc_494      ; was a break/STOP, do print BREAK @ LINE ...
                jp    print_prompt     ; display READY prompt and return to interpreter

; process CONT
exec_cont:      ld    e, 11h           ; preload error message "CAN'T CONTINUE"
                ld    hl, (contlineptr) ; get ptr to continue line
                TEST_0
                jr    z, loc_A46       ; is zero: error
                ex    de, hl           ; save continue    line
                ld    hl, (contlineno) ; set current lineno
                ld    (lineno), hl
                ex    de, hl           ; restore line ptr
                ret                    ; return to interpreter, will continue processing

; process LNULL, NULL commands
exec_lnull:     call  temporary_select_printer
exec_null:      call  expression_u8_ae ; get 8 bit expression
                cp    50               ; more than 50?
                jr    nc, illfunc_error ; yes, error
                ld    (iy+ioparams.padcount), a ; store in pad count
                ld    a, CHAR_COMMA    ; get a comma
                cp    (hl)             ; does a comma follow in buf?
                ret   nz               ; no, return
                call  nextchar         ; get next char
                call  expression_u8_ae ; and get the pad character
                ld    (iy+ioparams.padchar), a ; put into PAD field
                ret

; return CY clear, if character is alphabetic
check_alpha:    ld    a, (hl)          ; get char
                cp    CHAR_A           ; is < 'A'?
                ret   c                ; yes return CY set
                cp    CHAR_Z+1         ; is less than '['?
                ccf                    ; complement CY
                ret                    ; return CY clear, if alphabetic

sub_A1C:        call  assert_numeric
                jr    fpaccu_to_16

; read next char andparse following expression
getnext_expression_U16:
                call  nextchar

; has first char of expression in A, parse 16 bit expression
expression_u16: call  expression

; convert fpaccu to a 16 bit number in DE
fpaccu_to_u16:  call  fpaccu_sgn       ; get sign
                jp    m, illfunc_error ; error, if negative

; convert fpaccu to u16
fpaccu_to_16:   ld    a, (fpaccu_exp)  ; load exponent
                cp    91h              ; less than 65536?
                jp    c, fpreg_fix     ; yes, convert
                FPREG_CONST 9180h, 0, 8000h ; constant 65536
                call  fpaccu_compare   ; compare it
loc_A42:        ld    d, c
                ret   z                ; less than this?, okay return
illfunc_error:  ld    e, 5             ; load illegal function error
loc_A46:        jp    print_error

; parse a lineno and return it in DE
parse_lineno:   dec    hl              ; adjust bufptr to point 
                                       ; to previous char
                ld    de, 0            ; set cntr = 0
loopA4D:        inc   hl               ; point to next char
                ld    a, (hl)          ; get char from buf
                or    a                ; empty line?
                ret   z                ; yes exit
                cp    CHAR_ZERO        ; less than '0'?
                ccf
                ret   nc               ; yes exit
                cp    CHAR_NINE+1      ; greater than '9'?
                ret   nc               ; yes exit
                push  hl               ; save bufptr
                ld    hl, 6552         ; maximum lineno 65529 before
                                       ; calculating * 10 + digit
                add   a, a             ; multiply digit with 2
                sbc   hl, de           ; subtract DE from constant
                jp    c, syntax_error  ; lineno too large
                LDHL_DE                ; DE -> HL
                add   hl, de           ; * 2
                add   hl, hl           ; * 4
                add   hl, de           ; * 5
                add   hl, hl           ; * 10
                sub   CHAR_ZERO        ; convert ASCII to digit
                ld    e, a             ; add digit
                ld    d, 0
                add   hl, de
                ex    de, hl           ; into number
                pop   hl               ; restore buf
                jr    loopA4D          ; loop

; process CLEAR
exec_clear:     jr    z, loc_A9A       ; no argument, go directly to clear
                call  expression_u16   ; get argument
                call  skipspace        ; advance beyond expression
                ret   nz               ; return if more arguments
                push  hl               ; save bufptr
                ld    hl, (memory_top) ; get memory top
                sbc   hl, de           ; subtract space for strings
                ex    de, hl           ; DE is start of reserved space
                jp    c, syntax_error  ; more space requested than available memory?
                ld    hl, (prog_end)   ; get ptr to end of program
                ld    bc, 40           ; reserve space for stack
                add   hl, bc
                CPHL_DE                ; subtract string base?
                                       ; do program and string area overlap?
                jp    nc, out_of_memory_error ; yes error
                ex    de, hl           ; HL is start of reserved space
                ld    (string_base), hl ; store it
                pop   hl
loc_A9A:        jp    init_from_current ; interpreter loop

exec_run:       jp    z, init_from_start ; initialize ptrs, clear variables
                call  init_from_current ; init again
                ; will push WARMSTART return twice on stack
                ; this is possibly to mark stack that no GOSUB is pending
                ld    bc, command_done ; get command_done entry point
                jr    pre_goto         ; push entry anddo a GOTO

; process a GOSUB
; this pushes the following structure on the stack
; TOS -> 0x8C inputbufcnt
;     current lineno
;     current line ptr
exec_gosub:     ld    c, 3
                call  verify_space     ; assert 3 words are free
                pop   bc               ; pop return address
                push  hl               ; GOSUB push curlineptr
                ld    de, (lineno)
                push  de               ; GOSUB push current lineno
                ld    a, d             ; is lineno ffff?
                or    e
                inc   a
                ld    a, (inputbuf_cnt) ; get inputbuf count
                ld    d, a             ; save it
                jr    nz, loc_AC1      ; was not in direct mode, skip
                xor    a               ; gosub called from direct mode
                                       ; clear inputbuf cntr
                ld    (inputbuf_cnt), a
loc_AC1:        ld    e, TOKEN_GOSUB   ; gosub marker
                push  de               ; GOSUB push gosubmarker
pre_goto:       push  bc               ; push return address

exec_goto:      call  parse_lineno     ; get a lineno in DE
                call  advance_to_eoln  ; advance to end of line
                push  hl               ; save ptr to next line
                                       ; (points to line terminator)
                ld    hl, (lineno)     ; get current lineno
                CPHL_DE                ; compare this lineno and target lineno
                pop   hl               ; restore line ptr
                inc   hl               ; advance to nextlink
                call  c, find_line_from_current ; must move forward, jump into
                                       ; find_line at current position
loc_ADA:        call  nc, find_line    ; anyway, find the line
                LDHL_BC                ; become new position
                dec   hl
                ret   c                ; if line was found, exit
undef_stmt_error:
                ld    e, 8
loc_AE3:        jp    print_error

exec_return:    ret   nz               ; more cmds follow?, exit
                ld    d, 0FFh          ; do not match any variable
                call  discard_open_forloops ; clean stack from pending open FOR loop
                ld    d, (hl)          ; get inputbuf cntr
                inc   hl               ; advance
                ld    sp, hl           ; remove token word
                cp    TOKEN_GOSUB      ; check whether it is a GOSUB token
                ld    e, 3             ; error "RETURN W/O GOSUB"
                jr    nz, loc_AE3      ; not a GOSUB token: error
                pop   hl               ; restore lineno
                ld    (lineno), hl     ; set Z=1 if lineno is FFFF
                TEST_FFFF 
                ld    hl, inputbuf_cnt ; get current inputbuf cntr
                ld    a, (hl)          ; load it
                ld    (hl), d          ; store the old cntr from GOSUB
                jr    nz, loc_B07      ; skip if called in program context
                or    a                ; inputbuf was overwritten sinc e?
                jp    nz, ill_direct_error ; yes, error
loc_B07:        ld    hl, command_done
                ex    (sp), hl         ; return through command_done

; process DATA
; which is effectively the same as a REM to the program
; exception: will not advance to end of line but to next colon only
; this routine is also called from elsewhere, e.g. IF to advance to the ELSE
exec_data:      db    1                ; LD BC, 0E3Ah to skip next instruction
                                       ; skips the LD C,0 instruction,
                                       ; with NOP remaining
                                       ; loads C with 3A (colon), i.e. stop when
                                       ; EOLN or next colon found
                db    3Ah              ; ** LDA xxxx to skip next instruction
advance_to_eoln:            
                ld    c, NULL          ; ** skipped
                ld    b, NULL
loopB11:        ld    a, c             ;<--+ swap C and B
                ld    c, b             ;   |
                ld    b, a             ;   |
loopB14:        ld    a, (hl)          ;<+ | get next char
                or    a                ; | | end of line?
                ret   z                ; | | yes exit
                cp    b                ; | | is it same as B?
                ret   z                ; | | yes exit
                inc   hl               ; | | advance
                cp    CHAR_QUOTE       ; | | is it a begin of string
                jr    z, loopB11       ;---+ 1st time: B becomes ", C becomes 0
                                       ; | 2nd time: B becomes 0, C becomes "
                                       ; | i.e. wait until end of string or EOLN
                sub   TOKEN_IF         ; | subtract 8A (token IF)
                jr    nz, loopB14      ;-+ no loop
                ; we found an IF here: this routine is also called
                ; by exec_if to find the position of an ELSE, but we have
                ; a nesting of IFs here
                cp    b                ; C=1 if pending ", C=0 if not in string
                adc   a, d             ; increment level of nesting
                ld    d, a             ; into D
                jr    loopB14          ; loop

exec_let:       cp    TOKEN_MIDS       ; is MID$ token?
                jr    z, do_lh_mids    ; yes, LET MID$(xx,y,z) = expression

;entry here for assigment without LET
do_assignment:  call  find_var         ; get address of variable value into DE
                EXPECT TOKEN_EQUAL     ; expect a '=' token
                push  de               ; HL = curlineptr
                                       ; DE save var address
                ld    a, (expr_type)   ; save required    expression type
                push  af
                call  expression1      ; evaluate an expression inro fpaccu
                pop   af
                ex    (sp), hl         ; HL = address of variable
                                       ; stack = curlineptr
                ld    (curlineptr), hl ; save address in curlineptr
                rra                    ; expressiontype expected into CY
                call  verify_exprtype
                jr    nz, store_string ; must store a string
                push  hl               ; target address
                call  fpaccu_to_mem    ; store result
                pop   de               ; DE = target address
                pop   hl               ; restore curlineptr
                ret

store_string:   push  hl               ; save target address
                ld    hl, (fpaccu_mant32) ; get address of string descriptor
                push  hl               ; save it
                inc   hl               ; advance to string length
                inc   hl
                LDDE_M                 ; get string address into DE
                ld    hl, inputbuf+255 ; load end of input line buf
                CPHL_DE                ; check whether string in inputbuf
                jr    nc, loc_B7A      ; is below, skip
                ld    hl, (string_base) ; get base of string
                CPHL_DE                ; is below string base?
                pop   de               ; restore string descriptor in DE
                jr    nc, loc_B82      ; is below string base, skip
                ld    hl, (prog_end)   ; check for constant in program
                CPHL_DE
                jr    nc, loc_B82      ; is in program, skip
                db 3Eh                 ; LD A, xx to skip next instruction
loc_B7A:
                pop   de               ; restore string descriptor
                call  peekpop_str_stringstk ; get off string stack
                ex    de, hl
                call  string_dup       ; make a copy 
loc_B82:
                call  peekpop_str_stringstk ; get off string stack
                pop   hl               ; restore target address
                call  move_to_var      ; move to variable
                pop   hl               ; restore curlineptr 
                ret

; lefthand-side MID$
do_lh_mids:     call  nextchar         ; get next char
                EXPECT CHAR_LPAREN     ; expect left paren
                call  find_var         ; get variable into DE
                call  assert_string    ; verify it is a string
                EXPECT CHAR_COMMA      ; expect a start value for string
                push  de               ; save variable ptr
                call  expression_u8_ae ; get an 8 bit expression
                or    a                ; is zero?
                jp    z, illfunc_error ; yes, error
                push  af               ; save start pos
                ld    e, 0FFh          ; preload maximum position
                ld    a, (hl)          ; get char
                cp    CHAR_RPAREN      ; is it right paren?
                jr    z, loc_BB6       ; yes, skip
                EXPECT CHAR_COMMA      ; expect a comma
                call  expression_u8_ae ; get length expression
loc_BB6:        EXPECT CHAR_RPAREN     ; expect a right paren now
                EXPECT TOKEN_EQUAL     ; expect assignment now
                pop   af               ; restore start position
                ex    (sp), hl         ; get variable ptr in HL
                dec   a                ; adjust start position to 0-based
                cp    (hl)             ; compare with string length in var
                ld    b, 0
                jr    nc, loc_BD0
                ld    c, a             ; start position in C
                ld    a, (hl)          ; get string length in A
                sub   c
                cp    e
                ld    b, a
                jr    c, loc_BD0
                ld    b, e
loc_BD0:        push  bc
                inc   hl
                inc   hl
                LDHL_M B     
                ld    b, 0
                add   hl, bc
                pop   bc
                ex    (sp), hl
                push  bc
                call  string_expression1
                pop   bc
                pop   de
                push  hl
                ld    hl, (fpaccu_mant32)
                ld    a, b
                sub   (hl)
                push  af
                ld    a, b
                jr    c, loc_BED
                ld    a, (hl)
loc_BED:        inc   hl
                inc   hl
                LDBC_M       
                call  copy_string
                pop   af
                jr    c, loc_C01
                jr    z, loc_C01
                ex    de, hl
loopBFB:        ld    (hl), CHAR_SPACE ;<+
                inc   hl               ; |
                dec   a                ; |
                jr    nz, loopBFB      ;-+
loc_C01:        call  fpaccu_getstr
                pop   hl
                ret

; process ON GOTO/GOSUB
exec_on:
                call  expression_u8_ae ; get selector expression
                ld    a, (hl)          ; get next char
                ld    b, a             ; put into b
                cp    TOKEN_GOSUB      ; is it gosub?
                jr    z, process_on    ; ok
                EXPECT TOKEN_GOTO      ; must be goto
                dec   hl               ; point before goto/gosubtoken
process_on:     ld    c, e             ; get expression result into C
loopC16:        dec   c                ;<+ decrement
                ld    a, b             ; | get current token
                jp    z, execute_token ; | correct lineno found,
                                       ; | continue instruction processing
                                       ; | note: the token is either GOTO or GOSUB
                                       ; | in A, ready to parsed, the curlineptr
                                       ; | points directly to the position of
                                       ; | the matching lineno
                call  read_lineno_here ; | parse a line number
                cp    CHAR_COMMA       ; | does a comma follow?
                ret   nz               ; | no, exit
                jr    loopC16          ;-+ loop

; process IF/THEN/ELSE
exec_if:        call  expression1      ; get expression into fpaccu
                ld    a, (hl)          ; get token
                cp    CHAR_COMMA       ; is it comma? ???
                call  z, nextchar      ; yes ignore
                cp    TOKEN_GOTO       ; GOTO token?
                jr    z, loc_C36       ; yes, IF x THEN nnn case
                EXPECT TOKEN_THEN      ; expect a THEN
                dec   hl               ; point to token before
loc_C36:        push  hl               ; save it
                call  fpaccu_sgn       ; get sign of expression
                pop   hl               ; restore curlineptr
                jr    z, loc_C46       ; was condition false?
loopC3D:        call  nextchar         ;<+ get the current token again
                jp    c, exec_goto     ; | if number follows, do a GOTO
                jp    loc_91B          ; | otherwise do the instructions after THEN
loc_C46:        ld    d, 1             ; | load flag for skipping next instructions
loc_C48:        call  exec_data        ; | advance to next colon, using the
                                       ; | DATA skip routine
                or    a                ; | is end of line?
                ret   z                ; | yes done
                call  nextchar         ; | no get next char
                cp    TOKEN_ELSE       ; | is it ELSE?
                jr    nz, loc_C48      ; | no, loop
                dec   d                ; | decrement nesting level
                jr    nz, loc_C48      ; | not zero, find matching ELSE
                jr    loopC3D          ;-+ okay, found the right ELSE, 
                                       ; do GOTO or instruction

exec_lprint:    call  temporary_select_printer
exec_print:     jp    z, print_crlf    ; end of statement, i.e. empty PRINT?
				                       ; just do a CRLF and exit
                cp    TOKEN_USING      ; token USING?
                jp    z, printusing
                cp    TOKEN_TAB        ; token TAB( ?
                jr    z, printtab      ; advance to given position
                cp    TOKEN_SPC        ; token SPC( ?
                jr    z, printspc      ; sprint a given number of spaces
                push  hl               ; save curlinepos
                cp    CHAR_COMMA       ; check for COMMA
                jr    z, printcomma    ; advance to next field
                cp    CHAR_SEMI        ; check for semicolon
                jr    z, printsemi     ; advance to next argument
                pop   bc               ; discard curlinepos from stack
                call  expression1      ; evaluate next field expression
                push  hl               ; save curlinepos
                ld    a, (expr_type)   ; get expression type
                or    a
                jr    nz, loc_C9A      ; not zero, is a string
                call  format_number    ; is a number, do raw formatting
                call  straccu_copy     ; copy string pointed to by HL into straccu
                ld    hl, (fpaccu_mant32) ; point to string length
                ld    a, (iy+ioparams.curpos) ; get current cursor position
                add   a, (hl)          ; addstring length
                cp    (iy+ioparams.linelength) ; is string longer than rest of line?
                call  nc, print_crlf   ; yes, do a CRLF first
                call  straccu_print    ; print out string
                call  print_space      ; print a SPACE
                xor    a               ; skip next instruction  (Z=1)
loc_C9A:        call  nz, straccu_print ; print string
                pop   hl               ; restore curlinepos
                call  skipspace        ; advance to next non-whitespace
                jr    exec_print       ; loop in PRINT until end of line
printcomma:     ld    a, (iy+ioparams.curpos) ; get current print position
                cp    (iy+ioparams.last_field) ; is beyond last field position?
                call  nc, print_crlf   ; yes new line
                jr    nc, printsemi    ; continue printing argument
loopCAE:        sub   14               ;<+ current pos modulo field width (14)
                jr    nc, loopCAE      ;-+ modulo by subtracting
                cpl                    ; complement (became negative)
                                       ; -> number of spaces to print to advance
                jr    loc_CCD          ; print as much spaces to advance to next field
printspc:       scf                    ; set CY flag for SPC(
                                       ; comparison for TAB cleared CY
printtab:       push  af               ; save flag
                call  next_fpaccu_u8   ; get 8 bit expression
                EXPECT CHAR_RPAREN     ; expect a closing ')'
                dec   hl               ; curlineptr to point back to ')'
                pop   af               ; restore flag
                push  hl               ; save curlineptr
                ld    a, 0FFh          ; load maximum possible line position
                jr    c, loc_CCA       ; was SPC( ? skip
                ld    a, (iy+ioparams.curpos) ; get current cursor position
                cpl                    ; complement for subtraction
loc_CCA:        add   a, e             ; add argument
                jr    nc, printsemi    ; position already reached? yes exit
loc_CCD:        inc   a                ; adjust
                ld    b, a             ; store as cntr in B
loopCCF:        call  print_space      ;<+ print space to advance print position
                djnz    loopCCF        ;-+ loop until done
printsemi:      pop   hl               ; restore curlineptr
                call  nextchar         ; get next char/token
                ret   z                ; end of statement? yes exit
                jr    exec_print       ; otherwise loop in PRINT

print_ready_prompt:
                ld    hl, a_ready
                jp    coldvector

loc_CE1:        ld    hl, inputbuf     ; get start of buf
                ld    (hl), a          ; store control char at beginning
                inc   hl               ; advance
                call  emit_ctrl_char   ; emit control character
loc_CE9:        ld    (hl), NULL       ; store NULL as end of buf
                ld    hl, inputbuf-1   ; load inputbuf - 1

; print a CRLF including delaying padding bytes
print_crlf:     ld    a, CHAR_CR       ; load CR
                ld    (iy+ioparams.curpos), a  ; set char position to anything
                call  write_char       ; emit byte
                ld    a, CHAR_LF       ; load LF
                call  write_char       ; emit

print_nul_delay:
                ld    a, (iy+ioparams.padcount) ; get NUL byte cntr
                inc   a                ; +1
loopCFF:        dec   a                ;<-------+ predecrement
                ld    (iy+ioparams.curpos), a ; |  clear charpos (A is 0 on exit)
                ret   z                ;        | exit if finished
                push  af               ;        | save cntr
                ld    a, (iy+ioparams.padchar) ;| get NUL byte
                call  write_char       ;        | emit
                pop   af               ;        | restore cntr
                jr    loopCFF          ;--------+ loop

prompt_edit_lineno:
                call  print_crlf       ; do a CRLF
                ld    a, (prompt_flag) ; print PROMPT?
                or    a
                ret   z                ; no, exit
                push  hl               ; save registers
                push  bc
                ld    hl, (curlineno)  ; get the current EDIT lineno
                call  print_HL         ; emit it
                call  print_space      ; emit a space
                pop   bc               ; exit
                pop   hl
                ret

; process AUTO
exec_auto:      pop   de               ; discard resturn address
                ld    de, 10           ; load default start value
                push  de               ; push it for later
                call  c, read_lineno   ; get a lineno into DE
                ex    de, hl           ; save curlineptr into DE
                                       ; number read into DL
                ex    (sp), hl         ; set new start value, HL=10
                ex    de, hl           ; HL = curlineptr
                                       ; DE = 10 (increment unless second arg follows)
                cp    CHAR_COMMA       ; another arg follows?
                jr    nz, loc_D39      ; no, skip, assume increment=10 (DE)
                call  nextchar         ; advance
                call  c, read_lineno   ; read stepping value into DE
loc_D39:        or    a                ; now EOLN?
                jp    nz, syntax_error ; no, error
                ld    (auto_increment), de ; save as auto increment
                ld    a, d             ; if zero, error
                or    e
                jp    z, syntax_error
                ld    a, 1             ; set AUTO mode
                ld    (prompt_flag), a
                pop   hl               ; restore step width
                jp    auto

exec_lineinput: EXPECT TOKEN_INPUT     ; expect following input token
                db    0F6h             ; OR xxxx to skip next instruction
                                       ; also ensure A != 0 for string input

exec_input:     xor    a               ;** set flag=numeric
                push  af
                ld    a, (hl)          ; get current char
                cp    CHAR_QUOTE       ; is it a string?, e.g. INPUT "Enter data";A,B
                ld    a, 0             ; enable I/O
                ld    (iosuppress), a
                jr    nz, loc_D6E      ; no, skip
                call  copy_strconst    ; get the string to output
                EXPECT CHAR_SEMI       ; expect a semicolon
                push  hl               ; save curlineptr
                call  straccu_print    ; print the string message
                pop   hl               ; restore curlineptr
loc_D6E:        ex    (sp), hl         ; insert curlineptr on stack
                                       ; top of stack is cntr
                push  hl
                call  assert_run_program ; trigger ILLEGAL DIRECT error, 
                                       ; unless in program
                call  get_input        ; print a ? and request an inputbuf
                jp    z, input_ctrlc   ; CTRL-C? yes exit
                pop   af               ; restore type flag
                jr    z, read_input    ; if coming from INPUT, use READ
                                       ; routine to request input
loopD7C:        ex    (sp), hl         ;<+ no, this comes from LINEINPUT
				                       ; | HL is curlineptr
                call  find_var         ; | get a variable
                call  assert_string    ; | verify it is a string variable
                ex    (sp), hl         ; | put curlineptr on stack again
                push  de               ; | save variable address
                ld    b, 0             ; | string terminator (0), i.e. until 
                                       ; | end of buf
                call  copy_0string     ; | copy a string
                ex    de, hl           ; | save ptr to inputbuf
                ld    hl, loc_D93      ; | push handler
                ex    (sp), hl         ; | HL is curlineptr
                push  de               ; | save inputbufptr
                jp    store_string     ; | 
loc_D93:        pop   hl               ; | restore curlineptr
                call  skipspace        ; | advance
                ret   z                ; | end of line? exit
                EXPECT CHAR_COMMA      ; | require a comma
                push  hl               ; | save curlineptr
                call  get_moreinput    ; | print ?? andget an inputbuf
                jp    z, input_ctrlc1  ; | exit if CTRL-C
                jr    loopD7C          ;-+ loop

exec_read:      push  hl               ; save curlineptr
                ld    hl, (data_ptr)   ; get ptr to current data item to read
                db    0F6h             ; OR xxxx to skip next instruction
read_input:     xor   a                ; ** skipped, enters here from exec_input
                ld    (input_read_flag), a ; flag: != 0 if coming from READ,
                                       ; = 0 if coming from INPUT
                ex    (sp), hl         ; stack is data_ptr
                                       ; HL is    curlineptr
                jr    loc_DB7          ; skip
loc_DB2:        EXPECT CHAR_COMMA      ; expect a comma
loc_DB7:        call  find_var         ; get variable name, payload address in DE
                ex    (sp), hl         ; stack is curlineptr
                                       ; HL is data_ptr
                push  de               ; save address of variable
                ld    a, (hl)          ; get char from data_ptr
                cp    CHAR_COMMA       ; is it comma?
                jr    z, get_next_dataitem ; yes, advance
                ld    a, (input_read_flag) ; get input/read flag
                or    a
                jr    nz, find_next_DATA ; comes from READ, skip
                call  get_moreinput    ; INPUT: not enough data, query    more
                jp    z, input_ctrlc   ; if CTRL-C, leave
get_next_dataitem:            
                ld    a, (expr_type)   ; get required expression
                add   a, a             ; make 0 or 2
                jr    z, get_numeric_data ; is numeric, skip
                call  nextchar         ; advance in DATA/INPUT    buf
                ld    d, a             ; save as delimiters
                ld    b, a
                cp    CHAR_QUOTE       ; is it a dbl quote?
                jr    z, loc_DE1       ; yes, skip
                ld    d, CHAR_COLON    ; no, set line delimiter (:) and comma delimiter
                ld    b, CHAR_COMMA
                dec   hl               ; point to start of string
loc_DE1:        call  copy_string1     ; copy a string into straccu
                ex    de, hl           ; save ptr to data/input
                ld    hl, data_handler ; insert DATA/INPUT handler return
                ex    (sp), hl         ; stack is handler
                                       ; HL is address of variable
                push  de               ; save data/input ptr
                jp    store_string     ; copy string to payload address in HL
                                       ; and continue at data_handler
get_numeric_data:            
                call  nextchar         ; get next char
                call  parse_number_fpaccu ; get a number into fpaccu
                ex    (sp), hl         ; stack is data ptr
                                       ; HL is address of variable
                call  fpaccu_to_mem    ; save number read
                pop   hl               ; restore data ptr
data_handler:                          ; advance to next input data
                call  skipspace
                jr    z, loc_E02       ; end of input, skip
                cp    CHAR_COMMA       ; comma follows?
                jp    nz, invalid_input ; no, notify invalid input (INPUT)
                                       ; or syntax error (READ)
loc_E02:        ex    (sp), hl         ; stack is data_ptr
				                       ; HL is curlineptr
                call  skipspace        ; advance to next READ/INPUT variable
                jr    nz, loc_DB2      ; if not end of line, loop
                pop   de               ; restore data ptr
                ld    a, (input_read_flag) ; get mode flag
                or    a
                ex    de, hl           ; HL is input line ptr
                                       ; DE is curlineptr
                jp    nz, set_dataptr1 ; is data, save new data_ptr andexit
                add   a, (hl)          ; A is 0, add char from input line to set flags
                ld    hl, a_extralost  ; load EXTRA LOST message
                push  de               ; save curlineptr
                call  nz, print_string ; if more chars in input line,
                                       ; print *EXTRA_LOST*
                pop   hl               ; restore curlineptr
                ret                    ; done

; HL is data_ptr, find the next DATA statement
find_next_DATA:
                call  exec_data        ; end of DATA line, advance to next DATA
                or    a                ; end of line?
                jr    nz, loc_E31      ; no, advance
                inc   hl               ; at end of line, go to next char
                ld    a, (hl)          ; is the link 0?
                inc   hl
                or    (hl)
                ld    e, 4             ; load OUT OF DATA error code
                jr    z, loc_E92       ; link, is 0, error
                inc   hl               ; advance and get current lineno
                LDDE_M       
                ld    (currentlineno), de ; save it
loc_E31:        call  nextchar         ; get next char
                cp    TOKEN_DATA       ; is it a DATA token?
                jr    nz, find_next_DATA ; no, advance until found
                jp    get_next_dataitem ; yes, found one, continue READ

; process NEXT
exec_next:      ld    de, 0            ; preload zero variable name
sub_E3E:        call  nz, find_var     ; if not EOLN, find the named variable
                ld    (curlineptr), hl ; save curlineptr
                call  discard_open_forloops ; discard loops
                jp    nz, next_wo_for_error ; didn't find a FORSTRUCT? error
                ld    sp, hl           ; correct stack level
                push  de               ; push address of var
                ld    a, (hl)          ; load UP/DOWN marker
                inc   hl               ; advance, point to step value now
                push  af               ; save up/down
                push  de               ; push address of var
                call  mem_to_fpaccu    ; load step value in fpaccu, add6 to HL
                ex    (sp), hl         ; HL = address of var
                                       ; STACK = address of end value
                push  hl               ; push var
                call  load_and_add_fpaccu ; add step to variable
                pop   hl               ; restore address of var
                call  fpaccu_to_mem    ; move result back into for variable
                pop   hl               ; load variable in fpreg
                call  load_fpreg
                push  hl               ; save address of end value
                call  fpaccu_compare
                pop   hl               ; restore ptr to end value
                pop   bc               ; restore UP/DOWN flag in B
                sub   b
                call  restore_de_bc    ; DE = lineno, BC = curlineptr
                jr    z, loc_E75       ; loop ended, continue
                ex    de, hl           ; save new line number
                ld    (lineno), hl
                LDHL_BC                ; load curlineptr
                jp    loc_8C8          ; put up FOR marker again, set SP and
                                       ; continue processing
loc_E75:        ld    sp, hl           ; adjust stack (discard this loop)
                ld    hl, (curlineptr) ; restore curlineptr
                ld    a, (hl)          ; get char
                cp    CHAR_COMMA       ; a NEXT X,Y ?
                jp    nz, command_done ; no, continue processing
                call  nextchar         ; get next char
                call  sub_E3E          ; recurse into NEXT processing

; evaluate an expression, result in fpaccu
expression:     call  expression1

assert_numeric: db    0F6h             ; OR xx to skip next instruction
                                       ; clears CY
assert_string:  scf                    ;** set CY for string type

; CY = 0 for numeric, 1 for string type required
verify_exprtype:
                ld    a, (expr_type)   ; get expression type of last expression
                adc   a, a             ; add CY
                or    a                ; test result
                ret   pe               ; okay?
type_mismatch_error:                   ; no, types don't match
                ld    e, 13
loc_E92:        jp    print_error

string_expression1:
                call  expression1
                jr    assert_string

; evaluate expression
expression1:    dec   hl               ; point to char before expression
                ld    d, 0             ; precedence
; highly recursive expression handler
expresssion2:   push  de               ; save precedence
                ld    c, 1
                call  verify_space     ; verify still 2 bytes free
                call  expr             ; calculate an expression
                ld    (lineptrsave), hl
loc_EA9:        ld    hl, (lineptrsave)
loc_EAC:        pop   bc               ; restore precedence
                ld    a, b             ; into A
                cp    PREC_RELOP
                call  nc, assert_numeric ; result must be numeric
                ld    a, (hl)          ; get current char in line
                ld    d, 0             ; initialize relation flag
loopEB6:                               ;<+ subtract token '>'
                sub   TOKEN_GREATER    ; | '<' is 0
                                       ; | '=' is 1
                                       ; | '>' is 2
                jr    c, loc_ECF       ; | is it lower?
                cp    3                ; | is it above token '<'?
                jr    nc, loc_ECF      ; | no not comparison
                cp    1                ; | is it '='? set CY if less
                rla                    ; | and shift
                                       ; | '<' is 001
                                       ; | '=' is 010
                                       ; | '>' is 100
                xor    d               ; | xor with previous comparison value
                                       ; | <> or >< is 101
                                       ; | <= or =< is 011
                                       ; | >= or => is 110
                cp    d                ; | compare with previous
                ld    d, a             ; | and store as new compare value
                jp    c, syntax_error  ; | did the value decrease, e.g. by
                                       ; | invalid '=' '='?
                                       ; | yes, error
                ld    (arrayvalptr), hl ;| save curlineptr
                call  nextchar         ; | get next char
                jr    loopEB6          ;-+ loop comparison operator
; has expression and a relational operator in D
loc_ECF:        ld    a, d             ; get compare operator
                or    a                ; was zero, not a relational operator
                jp    nz, expr_compare
                ld    a, (hl)          ; store end of relational operator
                ld    (arrayvalptr), hl
                sub   TOKEN_PLUS       ; subtract '+' token
                ret   c                ; exit if less than '+'
                cp    7                ; check if '+', '-', '*', '/', '^', 'AND', 'OR'
                ret   nc               ; no, above or equal, exit
                ld    e, a             ; store dyadic operator in E
                                       ; '+' is 0
                                       ; '-' is 1
                                       ; '*' is 2
                                       ; '/' is 3
                                       ; '^' is 4
                                       ; AND is 5
                                       ; OR  is 6
                ld    a, (expr_type)   ; get expression type
                dec   a                ; FF=numeric, 0=string
                or    e                ; becomes 0 for string addition, FF otherwise
                ld    a, e             ; get operator
                jp    z, string_add    ; handle string addition
                rlca
                add   a, e             ; multiply with 3
                ld    e, a             ; into E
                                       ; note: D=0 because it was no relational operator
                ld    hl, oper_tbl     ; load operator table
                add   hl, de           ; add index
                ld    a, b             ; get current precedence
                ld    d, (hl)          ; get precedence of new operator
                cp    d                ; compare curprec - newprec
                ret   nc               ; above or equal, exit
                inc   hl               ; advance to next char
                call  assert_numeric   ; require current subexpression is numeric
loc_EF7:        push  bc               ; save precedence
                ld    bc, loc_EA9      ; push expression loop
                push  bc               ; as return
                ld    bc, fpaccu_mant32 ; push current accu on stack
                push  bc
                ld    bc, fpaccu_mant54
                push  bc
                ld    bc, fpaccu_mant6
                push  bc
                LDBC_M                 ; get operator handler
                push  bc               ; push it, to be called at the end of expression
                ld    hl, (arrayvalptr) ; restore ptr to start
                                       ; of second operandexpression
                jr    expresssion2

; process single expression
; including functions
;
; precedence:
; 0x46:    OR
; 0x50:    AND
; 0x5a:    NOT
; 0x78:    relational ops
; 0x79:    dyadic '+', '-'
; 0x7c:    '*', '/'
; 0x7d:    monadic    '-'
; 0x7f:    '^'
expr:           xor    a               ; set expression type = numeric
                ld    (expr_type), a
                call  nextchar         ; get char
                jp    c, expr_numeric  ; is numeric?, yes skip
                call  check_alpha
                jr    nc, expr_alpha   ; yes is letter
                cp    TOKEN_PLUS       ; is token '+' ?
                jr    z, expr          ; yes, ignore it
                cp    CHAR_PERIOD      ; is a minus?
                jp    z, expr_numeric
                cp    TOKEN_MINUS      ; is token '-'?
                jr    z, expr_minus
                cp    CHAR_QUOTE       ; is string delimiter?
                jp    z, copy_strconst
                cp    TOKEN_NOT        ; is token NOT
                jp    z, expr_not
                cp    TOKEN_FN         ; is token FN?
                jp    z, expr_fn
                cp    CHAR_AMP         ; is &> ?
                jp    z, expr_hex
                sub   TOKEN_SGN        ; subtract token SGN
                jr    nc, expr_function ; is above or equal, i.e. a function
expr_paren:
                EXPECT CHAR_LPAREN     ; expect an opening parenthesis
                call  expression1      ; evaluate expression
                EXPECT CHAR_RPAREN     ; expect closing parenthesis
                ret                    ; exit, result is in fpaccu

expr_minus:
                ld    d, PREC_MINUS    ; set precedence
                call  expresssion2     ; recurse evaluator
                ld    hl, (lineptrsave)
                push  hl
                call  fpaccu_changesign
loc_F62:        call  assert_numeric   ; verify numeric result
                pop   hl
                ret

expr_alpha:     call  find_var         ; locate variable, return address
                                       ; of value/descriptor
loc_F6A:        push  hl               ; save curlineptr
                ex    de, hl           ; get payload address in DE
                ld    (fpaccu_mant32), hl ; store string descriptor in accu
                ld    a, (expr_type)   ; get type of variable
                or    a
                call  z, mem_to_fpaccu ; if numeric, copy value into FPaccu
                pop   hl               ; restore curlineptr
                ret

expr_function:  ld    b, 0             ; high value
                rlca                   ; multiply function token (minus TOKEN_SGN) with 2
                ld    c, a             ; make 16 bit
                push  bc               ; save offset to func table
                call  nextchar         ; get next char
                ld    a, c
                cp    2*(TOKEN_CHRS-TOKEN_SGN) ; less than CHR$()?
                jr    c, loc_FAB       ; yes, handle single parenthesis
                cp    2*(TOKEN_LPOS-TOKEN_SGN) ; is LPOS?
                jr    z, loc_FAB       ; yes, handle single parenthesis
                cp    2*(TOKEN_INSTR-TOKEN_SGN) ; is INSTR?
                jr    z, loc_FA8       ; yes, skip
                jp    nc, illfunc_error ; above or equal? not a function token
                                       ; here we have string functions
                                       ; with more than one argument
                EXPECT CHAR_LPAREN    ; expect opening parenthesis
                call  string_expression1 ; get a string expression
                EXPECT CHAR_COMMA      ; expect a second argument
                ex    de, hl           ; save curlineptr in DE
                ld    hl, (fpaccu_mant32) ; get string descriptor in fpaccu
                ex    (sp), hl         ; insert on stack
                push  hl
                ex    de, hl           ; restore curlineptr
                call  expression_u8_ae ; get an 8 bit expression in E
                ex    de, hl           ; into HL
loc_FA8:        ex    (sp), hl         ; stack is 2nd arg of function
				                       ; HL is offset to function table
                jr    loc_FB3
loc_FAB:        call  expr_paren       ; get single argument expression into fpaccu
                ex    (sp), hl         ; stack is curlineptr
                                       ; HL is offset to function table
                ld    de, loc_F62      ; insert checker that result is numeric
                push  de
loc_FB3:        ld    bc, func_tbl     ; get function offset
                add   hl, bc           ; add to function table
                LDHL_M C               ; get function handler address into HL
                jp    (hl)             ; jump to it

pop_fpreg_and_boolor:
                db    0F6h             ; OR xxxx to skip next instruction
                                       ; ensure A is not zero
pop_fpreg_and_booland:
                xor    a               ;** skipped, clears A
                push  af               ; Z = 1 for AND, 0 for OR
                call  sub_A1C          ; get value from fpaccu
                pop   af               ; restore AF
                ex    de, hl           ; get 1st result in HL
                pop   bc               ; restore operandon stack in BC, IX, DE
                pop   ix
                ex    (sp), hl         ; put 1st result on stack
                ex    de, hl           ; restore rest of fpreg
                call  store_fpaccu     ; save in FPaccu
                push  af               ; save A
                call  fpaccu_to_16     ; get value from fpaccu into DE
                pop   af               ; restore A
                pop   bc               ; restore 1st result
                ld    a, c             ; get first result low
                ld    hl, AC_to_fpaccu ; load routine of result copy routine
                jr    nz, boolor       ; was not zero, to OR operation
                and   e                ; and of low part
                ld    c, a             ; into C
                ld    a, b             ; and of high part
                and   d
                jp    (hl)             ; copy result (AC_to_fpaccu)
boolor:         or    e                ; or of low part
                ld    c, a             ; save
                ld    a, b             ; get high part
                or    d                ; or of high part
                jp    (hl)             ; copy result (AC_to_fpaccu)

; has compare operator in D:
; 001 <
; 010 =
; 011 <=
; 100 >
; 101 <>
; 110 >=
expr_compare:   ld    hl, compare_tbl  ; load handler
                ld    a, (expr_type)   ; get type of expression
                rra                    ; set CY for string
                ld    a, d             ; get condition
                rla                    ; shift in CY
                ld    e, a             ; save in E
                ld    d, PREC_STRCMP   ; set precedence
                ld    a, b
                cp    d                ; compare with current precedence
                ret   nc               ; don't handle yet
                jp    loc_EF7          ; push on stack and get second operand

compare_tbl:    dw    compare_handler  ; routine to handle comparison

compare_handler:            
                ld    a, c             ; get operation
                or    a                ; ensure CY = 0
                rra                    ; discard lowest bit, i.e. convert back
                                       ; to operation code
                POP_FPREG              ; pop 1st operand off stack
                push  af
                call  verify_exprtype  ; check that types match
                ld    hl, exit_compare ; push routine to call on exit
                push  hl
                jp    z, fpaccu_compare ; do comparison of numerics
                                       ; will go to exit_compare on ret
                xor    a               ; string comparison
                ld    (expr_type), a   ; set expression result type numeric
                push  de               ; descriptor of second operand
                call  fpaccu_getstr    ; get 2nd string descr in HL
                pop   de               ; restore 2nd descriptor
                LDBC_M                 ; get string length into BC
                inc   hl
                push  bc               ; save
                LDBC_M                 ; get string address into BC
                push  bc               ; save
                call  peek_str_stringstk ; discard 1st string
                call  restore_de_bc    ; restore 1st string descr in
                                       ; E=length / BC = string addr
                pop   hl               ; pop string address
                ex    (sp), hl         ; stack is string addr
                                       ; HL is string length
                ld    d, l             ; get length into D
                pop   hl               ; HL is string addr
loop1024:       ld    a, e             ;<+ both strings are empty? yes return Z=1
                or    d                ; | 
                ret   z                ; | yes exit with A=0
                ld    a, d             ; | subtract 1 from length of 1st string
                sub   1                ; | 
                ret   c                ; | cntr negative?
                xor    a               ; | clear A
                cp    e                ; | is other length also 0?
                inc   a                ; | set A = 1
                ret   nc               ; | exit if 1st is longer
                dec   d                ; | decrement string lengths
                dec   e                ; |
                ld    a, (bc)          ; | compare strings
                cp    (hl)             ; |
                inc   hl               ; | advance to next string positions
                inc   bc               ; |
                jr    z, loop1024      ;-+ still same? yes loop
                ccf                    ; complement CY
                jp    loc_22CA         ; set A = FF or 1, depending on CY result
exit_compare:   inc   a                ; adjust result to 0, 1, 2
                adc   a, a             ; to 0, 2, 4
                pop   bc               ; restore compare operation
                and   b                ; mask result (will produce 1 <, 2 =, 4    >
                add   a, 0FFh          ; adjust to 0, 1, 3
                sbc   a, a             ; subtract CY -> -1,    0, 2
                jp    s8_to_fp         ; convert into numeric result

expr_not:       ld    d, PREC_NOT      ; set precedence
                call  expresssion2     ; get expression
                call  assert_numeric   ; require it to be numeric
                call  fpaccu_to_16     ; convert to 16 bit
                ld    a, e             ; complement
                cpl                    ; E is low value
                ld    c, a
                ld    a, d
                cpl                    ; A is high value
                call  AC_to_fpaccu     ; convert to numeric
                pop   bc               ; discard caller
                jp    loc_EA9          ; jump back into expression

dim_loop:       call  skipspace        ; skip white space
                ret   z                ; end of line, exit
                EXPECT CHAR_COMMA      ; expect a comma

exec_dim:       ld    bc, dim_loop     ; stay in DIM
                push  bc
                db    0F6h             ; OR 0AFh instruction, sets dim_flag
                                       ; for DIM to non-zero

; find anddefine variable pointed to by HL
; return payload address in DE
find_var:       xor    a               ; clear dim_flag (non-zero if declaring arrays)
                ld    (dim_flag), a    ; set by exec_dim
                ld    b, (hl)          ; get 1st char of variable
loc_106F:       call  check_alpha      ; error, if not alpha
                jp    c, syntax_error
                xor   a                ; preload 2nd letter
                ld    c, a             ; clear expression type
                ld    (expr_type), a
                call  nextchar         ; get a char
                jr    c, loc_1084      ; numeric, skip
                call  check_alpha      ; second letter alpha?
                jr    c, loc_108F      ; no, skip
loc_1084:       ld    c, a             ; store second letter
loop1085:                              ;<+ ignore following variable characters
                call  nextchar         ; | only two are significant
                jr    c, loop1085      ;>+ numeric, ignore
                call  check_alpha      ; | alpha, ignore
                jr    nc, loop1085     ;-+
loc_108F:                
                sub   CHAR_DOLLAR      ; is it a string variable?
                jr    nz, loc_109C     ; no, numeric
                inc   a                ; set expression type = string (1)
                ld    (expr_type), a
                set    7, c            ; set bit 7 to mark string variable
                call  nextchar         ; get next character

; subscript flag is 0 in normal    processing
; ie will here go to var_subscript to evaluate an
; array or FN expression
; flag is 1 for processing exec_kill
; flag is CHAR_RPAREN to locate and create variable/FN
; return ptr to payload in DE
loc_109C:                ; get subscript    flag
                ld    a, (subscript_flag)
                dec   a
                jp    z, kill_matrix   ; subscript flag is 1 (exec_kill), set number of indices = 0
                add   a, (hl)          ; addnext char
                                       ; if it was '(', result will be 0x27
                sub   CHAR_LPAREN-1    ; subtract 0x27
                jr    z, var_subscript ; we found a subscript and are in an expression
                                       ; evaluate the whole item
                xor    a               ; not in var evaluation or func definition
                                       ; clear subscript flag
                ld    (subscript_flag), a
                push  hl               ; save curlineptr
                ld    hl, (end_of_vars)
                ex    de, hl           ; DE = end of vars
                ld    hl, (prog_end)   ; HL = prog_end
find_var1:      CPHL_DE                ; compare with end
                jr    z, var_not_found ; end of variables found?
                ld    a, c             ; compare variable name with name in var table
                sub   (hl)
                inc   hl
                jr    nz, loc_10C3
                ld    a, b
                sub   (hl)
loc_10C3:       inc   hl
                jr    z, var_found     ; found variable, return address of payload in DE
                inc   hl               ; advance to next variable
                                       ; (skip over the floating point/string value)
                inc   hl
                inc   hl
                inc   hl
                inc   hl
                inc   hl
                jr    find_var1        ; loop
var_not_found:  pop   hl               ; restore curlineptr
                ex    (sp), hl         ; stack: curlineptr
                                       ; HL: return address
                push  de               ; save DE
                ld    de, loc_F6A      ; came from expression handler?
                CPHL_DE   
                pop   de               ; restore DE
                jr    z, fpaccu_clear  ; yes, called out of expression handler
                                       ; clear fpaccu
                ex    (sp), hl         ; restore return address, HL = curlineptr
                push  hl               ; save curlineptr
                push  bc               ; save variable name
                ld    bc, 8            ; require space for 8 bytes
                ld    hl, (end_arrays) ; get start of arrays
                push  hl               ; save it
                add   hl, bc           ; calculate new end address
                pop   bc               ; old end address
                push  hl               ; new end address
                                       ; DE is start address
                call  make_space       ; copy area 8 bytes up
                pop   hl
                ld    (end_arrays), hl ; save new end address
                LDHL_BC                ; get end of free space
                ld    (end_of_vars), hl ; new end of variables
loop10F6:       dec   hl               ;<+ clear free space
                ld    (hl), NULL       ; |
                CPHL_DE                ; |
                jr    nz, loop10F6     ;-+ loop
                pop   de               ; get variable name
                LDM_DE                 ; save it in variable
                inc   hl
var_found:      ex    de, hl           ; address of payload of variable in DE
                pop   hl               ; curlineptr in HL
                ret                    ; exit

fpaccu_clear:   ld    (fpaccu_exp), a  ; A is 0
                ld    hl, 2FFh         ; should be irrelevant, as exp=0
                ld    (fpaccu_mant32), hl ; mark newly initialized variable
                pop   hl
                ret

; called to evaluate a var expression for an
; already declared array
var_subscript:  push  hl               ; save curlineptr
                ld    hl, (dim_flag)   ; load dim_flag and expression type
                ex    (sp), hl         ; save it, restore curlineptr
                ld    d, a             ; clear D, A was 0
loop111A:       push  de               ;<+ save registers
                push  bc               ; | 
                call  getnext_expression_U16 ; get index in DE
                pop   bc               ; | restore reg
                pop   af               ; | restore cntr of indices
                ex    de, hl           ; | index in HL
                ex    (sp), hl         ; | push on stack
                push  hl               ; | 
                ex    de, hl           ; | get current line ptr again
                inc   a                ; | increment # of indices
                ld    d, a             ; | into D
                ld    a, (hl)          ; | get next char
                cp    CHAR_COMMA       ; | is it comma?
                jr    z, loop111A      ;-+ yes, loop
                EXPECT CHAR_RPAREN     ; must be end of subscript
                ld    (lineptrsave), hl ; save line ptr
                pop   hl               ; restore expression/var types
                ld    (dim_flag), hl
                ld    e, 0             ; D is # indices, E = 0
                push  de               ; save
                db    11h              ; LD DE, xxxx to skip next 2 instructions
kill_matrix:    push  hl               ;** save curlineptr
                push  af               ;** number of indices
                                       ; is 0 if coming from exec_kill
; var_subscript skips here
                ld    hl, (end_of_vars) ; HL = end_of_vars = start_arrays
                db    3Eh              ; LD A, xx to skip next instruction
loop1142:       add   hl, de           ;**
                ld    de, (end_arrays) ;<+ is end_of_arrays reached?
                CPHL_DE                ; | 
                jr    z, array_declare ; | end of table, not found, go declare it
                ld    a, (hl)          ; | compare with name
                cp    c                ; | 
                inc   hl               ; | 
                jr    nz, loc_1156     ; | 
                ld    a, (hl)          ; | 
                cp    b                ; | 
loc_1156:       inc   hl               ; | 
                LDDE_M                 ; | DE = size of array in bytes
                inc   hl               ; |
                jr    nz, loop1142     ;-+ array not found, loop
                                       ; the array is found
                ld    a, (dim_flag)    ; was it from DIM?
                or    a
                jp    nz, redim_array_error ; yes, and it already exists
                                       ; otherwise error!
                pop   af               ; restore number of indices
                jp    z, kill_array    ; zero, ie comes from exec_kill
                sub   (hl)             ; subtract from #indices of declared array
                jr    z, find_arrayvar ; both match

subscript_range_error:            
                ld    e, 9             ; no, error 
                jp    print_error
array_declare:  ld    de, 6            ; sizeof element
                pop   af               ; restore #indices
                jp    z, loc_1F19      ; zero?
                LDM_BC                 ; store variable name
                inc   hl
                ld    c, a             ; reserve space for index words
                call  verify_space
                inc   hl               ; advance 2 bytes (for total size)
                inc   hl
                ld    (arrayvalptr), hl ; save index table ptr
                ld    (hl), c          ; save #index bytes
                inc   hl
                ld    a, (dim_flag)    ; get dimension flag
                rla                    ; put flag in CY
                ld    a, c             ; load index count
loop118B:       ld    bc, 0Bh          ;<+ load default value for index
                jr    nc, loc_1192     ; | not DIM, skip
                pop   bc               ; | get index
                inc   bc               ; | +1 (zero based)
loc_1192:       LDM_BC                 ; | store index
                inc   hl               ; | 
                push  af               ; | save count
                push  hl               ; | save ptr to index tbl
                call  umultiply16      ; | calculate total size
                ex    de, hl           ; | result in DE
                pop   hl               ; | restore ptr
                pop   af               ; | restore #indices
                dec   a                ; | decrement
                jr    nz, loop118B     ;-+ loop over all indices
                push  af               ; A = 0, save
                ld    b, d             ; get total size in BC
                ld    c, e
                ex    de, hl           ; HL = end of index table
                add   hl, de           ; add total size
                jr    c, subscript_range_error ; overflow? error
                call  check_memfree    ; enough space free?
                ld    (end_arrays), hl ; store new end of array
loop11AE:       dec   hl               ;<+ clear array
                ld    (hl), NULL       ; |
                CPHL_DE                ; |
                jr    nz, loop11AE     ;-+ loop
                inc   bc               ; total size +1
                ld    d, a             ; D = 0, because A is 0
                ld    hl, (arrayvalptr) ; get ptr to array index table
                ld    e, (hl)
                ex    de, hl           ; HL = # indices
                add   hl, hl           ;  HL * 2
                add   hl, bc           ; add size of payload
                ex    de, hl           ; into DE
                dec   hl               ; point to total size field
                dec   hl
                LDM_DE                 ; store array length
                inc   hl
                pop   af               ; restore CY = dimflag
                jr    c, loc_11F2      ; restore curlineptr and exit
find_arrayvar:  ld    b, a             ; clear BC
                ld    c, a
                ld    a, (hl)          ; load #indices of declared array
                inc   hl               ; advance to index list
                db    16h              ; LD D, xx to skip next instruction
                                       ; is uncritical because D is loaded 3 instrs
                                       ; later again
loop11D1:       pop   hl               ;<+ ** pop requested index
                LDDE_M                 ; | load requested subscript in DE
                inc   hl               ; | 
                ex    (sp), hl         ; | get next index dimension
                push  af               ; | save #indices
                CPHL_DE                ; | reqd index to large?
                jr    nc, subscript_range_error ; yes, error
                push  hl               ; | save dimension
                call  umultiply16      ; | HL = DE * BC
                pop   de               ; | restore dimension
                add   hl, de           ; | add dimension size
                pop   af               ; | restore #indices
                dec   a                ; | decrement
                LDBC_HL                ; | move to new position
                jr    nz, loop11D1     ;-+ loop over all indices
                add   hl, hl           ; HL * 2
                add   hl, bc           ; HL + BC
                add   hl, hl           ; HL * 2
                                       ; -> multiply with 6 (element size)
                pop   bc               ; add base
                add   hl, bc
                ex    de, hl           ; address of variable in DE
loc_11F2:       ld    hl, (lineptrsave) ; restore curlineptr
                ret

math_fre:       ld    hl, (end_arrays) ; get end of array space
                ex    de, hl           ; into DE
                ld    hl, 0            ; get SP
                add   hl, sp
                ld    a, (expr_type)   ; check expression type of FRE
                or    a
                jr    z, loc_1211      ; is numeric? skip
                call  fpaccu_getstr    ; put string on expr stack
                                       ; to allow it to be disposed directly
                call  gc               ; do garbage collection
                ld    hl, (string_base) ; get current base of strings
                ex    de, hl           ; into DE
loc_120E:       ld    hl, (string_top) ; get end of strings
loc_1211:       xor    a               ; set expression type to numeric
                ld    (expr_type), a
                sbc   hl, de           ; subtract start of range from end of range
                                       ; => used space by strings

hl_to_fpaccu:   ex    de, hl           ; copy number in DE

; convert unsigned 16 bit DE number into FPACCU
uDE_to_fpaccu:  xor    a               ; sign is 0
                ld    b, 98h           ; preload exponent with 0x98
                jr    loc_1227         ; go convert 16 bit

; convert C into FP, A is sign
AC_to_fpaccu:   ld    b, c

; convert B into FP, A is sign
AB_to_fpaccu:   ld    d, b
                ld    e, 0
                ld    hl, expr_type
                ld    (hl), e          ; clear cell
                ld    b, 90h           ; exponent = 0x90 (16 bit)
loc_1227:       jp    s24_to_fp

; process LPOS()
math_lpos:      ld    a, (prtparam.curpos) ; get printer position
                jr    uA_to_fpaccu

; process POS()
math_pos:       ld    a, (conparam.curpos) ; load current cursor position

; convert unsigned 8 bit in A into FP
uA_to_fpaccu:   ld    b, a             ; put into B
                xor    a               ; clear sign
                jr    AB_to_fpaccu     ; convert into FP

exec_def:       call  locate_fn_info   ; define or read a variable for FN
                                       ; ptr to payload in DE
                call  assert_run_program ; only allowed in program
                ex    de, hl           ; payload to function in HL
                LDM_DE                 ; save current line ptr in function
                ex    de, hl           ; DE = payload, FL = curlineptr
                dec   hl               ; point to previous char
loop1242:       call  nextchar         ;<+ get next char
                jr    z, fn_program    ; | EOLN or end of statement?
                                       ; | yes function subprogram
                cp    TOKEN_EQUAL      ; | token '=' ?
                jr    nz, loop1242     ;-+ no possibly argument list, skip over it
loop124B:       jp    exec_data        ;<+ one-line function, ignore until EOLN or ':'
fn_program:     or    a                ; | is a real EOLN?
                jr    nz, loc_1260     ; | no, something follows
                inc   hl               ; | multiline FN definition at the end of program?
                ld    a, (hl)          ; | 
                inc   hl               ; | 
                or    (hl)             ; | 
                jp    z, syntax_error  ; | yes, not terminated with FNEND
                inc   hl               ; | get new lineno
                LDDE_M                 ; | 
                ld    (lineno), de     ; | and store it
loop1260:       call  nextchar         ;<--+ get next char (argument list or function body)
                jr    z, fn_program    ; | | EOLN or end statement, go loop
                cp    TOKEN_FNEND      ; | | an FNEND found?
                jr    z, loop124B      ;-+ | yes, advance until end 
                                       ;   | of statement (return expression)
                jp    loop1260         ;---+ no, skip over it

expr_fn:        call  locate_fn_info
                ld    a, (expr_type)
                or    a
                push  af
                ld    (lineptrsave), hl
                ex    de, hl
                LDHL_M A     
                or    h
                jp    z, usercall_error
                ld    a, (hl)
                cp    CHAR_SPACE
                jr    nz, loc_12F6
                call  nextchar
                ld    (arrayvalptr), hl
                jr    loc_1292
loop128D:       EXPECT CHAR_COMMA      ;<+
loc_1292:       ld    c, 5             ; |
                call  verify_space     ; |
                ld    a, CHAR_RPAREN   ; |
                ld    (subscript_flag), a
                call  find_var         ; |
                ex    de, hl           ; |
                ld    a, (expr_type)   ; |
                or    a                ; |
                scf                    ; |
                jr    nz, loc_12B7     ; |
                LDBC_M                 ; |
                push  bc               ; |
                inc   hl               ; |
                LDBC_M                 ; |
                push  bc               ; |
                inc   hl               ; |
                LDBC_M                 ; |
                push  bc               ; |
                jr    loc_12BF         ; |
loc_12B7:       push  af               ; |
                push  de               ; |
                ex    de, hl           ; |
                call  de_push_stringstk ;|
                pop   de               ; |
                pop   af               ; |
loc_12BF:       push  hl               ; |
                push  af               ; |
                ex    de, hl           ; |
                ld    a, (hl)          ; |
                cp    CHAR_RPAREN      ; | 
                jr    nz, loop128D     ;-+
                ld    hl, (lineptrsave)
                EXPECT CHAR_LPAREN
                push  hl
                ld    hl, (arrayvalptr)
loop12D3:       call  find_var         ;<+
                ex    (sp), hl         ; |
                call  sub_833          ; |
                ld    a, (hl)          ; |
                cp    CHAR_RPAREN      ; |
                jr    z, loc_12EC      ; |
                EXPECT CHAR_COMMA      ; |
                ex    (sp), hl         ; |
                EXPECT CHAR_COMMA      ; |
                jr    loop12D3         ;-+
loc_12EC:       call  nextchar
                ex    (sp), hl
                EXPECT CHAR_RPAREN
                db    3Eh              ; LD A, xx to skip next instruction
                                       ; LD A is uncritical because	skipspace_buf
                                       ; will destroy A
loc_12F6:       push  de               ;* skipped
                call  skipspace
                jr    z, loc_130C
                EXPECT TOKEN_EQUAL
                call  expression1
                call  skipspace
                jp    nz, syntax_error
                jr    loc_1346
loc_130C:       ld    c, 2
                call  verify_space
                ld    de, (lineno)
                push  de
                ld    d, TOKEN_FN
                push  de
                inc   sp
                jp    command_done

exec_fnend:     jr    nz, has_fnreturn ; return expression follows?
                call  fpaccu_zero      ; no, return value is zero
                ld    (straccu.len), a ; set to 0
                cpl
                ld    (expr_type), a   ; set to FF
                jr    loc_1334         ; continue
has_fnreturn:   call  expression1      ; parse result expression
                call  skipspace        ; advance
                jp    nz, syntax_error ; is not EOLN? error
loc_1334:       ld    d, 0FFh          ; destroy any FOR loops that were in function
                call  discard_open_forloops
                ld    sp, hl           ; store new stack top
                cp    TOKEN_FN         ; is a FN structure on stack?
fnreturn_error: ld    e, 23            ; no, FNRETURN W/O FUNCTION error
                jp    nz, print_error
                pop   de               ; restore old lineno
                ld    (lineno), de

loc_1346:       ld    a, (expr_type)
                inc   a
                jr    z, loc_134F
                dec   a
                jr    nz, loc_137D
loop134F:       pop   de               ;<---+
loop1350:       pop   af               ;<-+ |
                jr    nc, loc_1366     ;  | |
                jr    nz, loc_138C     ;  | |
                pop   hl               ;  | |
                pop   bc               ;  | |
                ld    (hl), b          ;  | |
                dec   hl               ;  | |
                ld    (hl), c          ;  | |
                dec   hl               ;  | |
                pop   bc               ;  | |
                ld    (hl), b          ;  | |
                dec   hl               ;  | |
                ld    (hl), c          ;  | |
                dec   hl               ;  | |
                pop   bc               ;  | |
                ld    (hl), b          ;  | |
                dec   hl               ;  | |
                ld    (hl), c          ;  | |
                jr    loop1350         ;--+ |
loc_1366:       push  af               ;  | |    
                push  de               ;  | |    
                ld    hl, expr_type    ;  | |    
                bit    7, (hl)         ;  | |    
                jr    z, loc_1370      ;  | |    
                ld    (hl), a          ;  | |    
loc_1370:       or    a                ;  | |    
                ld    de, straccu      ;  | |    
                call  nz, de_push_stringstk
                pop   hl               ;  | |    
                pop   af               ;  | |    
                rra                    ;  | |    
                jp    verify_exprtype  ;  | |    
loc_137D:       ld    de, fpaccu_mant32 ; | |    
                call  peekpop_str_exprstk ; |    
                ld    hl, straccu      ;  | |    
                call  move_to_var      ;  | |    
                jr    loop134F         ;--|-+
loc_138C:       call  peekpop_str_stringstk
                ld    a, (hl)          ;  |
                ld    (stringstkptr), hl ;|
                pop   hl               ;  |
                ld    (hl), a          ;  |
                inc   hl               ;  |
                inc   hl               ;  |
                LDM_BC                 ;  |
                jr    loop1350         ;--+

; check if function is called while program is running
assert_run_program:
                push  hl               ; save curlineptr
                ld    hl, (lineno)     ; get lineno
                inc   hl
                TEST_0
                pop   hl
                ret   nz               ; if not zero, return
ill_direct_error:                      
                ld    e, 12            ; illegal direct error
                jp    print_error

locate_fn_info: EXPECT TOKEN_FN        ; expect FN
                or    80h              ; set bit7 of first character of func name
                ld    b, a             ; store in B
                ld    a, CHAR_RPAREN   ; set subscript flag
                ld    (subscript_flag), a
                jp    loc_106F         ; jump into find_var

math_strs:
                call  assert_numeric   ; require argument to be numeric
                call  format_number    ; format it into scratchpad
                call  straccu_copy     ; copy it into straccu
                call  fpaccu_getstr    ; get it
                ld    bc, loc_15C2     ; push result on exprstack later
                push  bc

; reserve space for string (descr at HL) and copy it to this area
string_dup:     ld    a, (hl)          ; get length of string
                inc   hl               ; point to address of string
                inc   hl
                push  hl
                call  reserve_strspace ; reserve space on stack
                pop   hl
                LDBC_M                 ; get string address into BC
                call  straccu_store    ; store string descr in straccu
                push  hl               ; save descriptor
                call  copy_string      ; copy string to reserved space
                pop   de
                ret

; reserve space for A bytes and store descriptor in straccu
straccu_reserve_strspace:
                call  reserve_strspace ; reserve space for A bytes

; store A=len, DE=addr into string accu
straccu_store:  ld    hl, straccu      ; point to current string descriptor
                push  hl               ; save it
                ld    (hl), a          ; save string length
                inc   hl               ; skip a cell
                inc   hl
                LDM_DE                 ; save current address of string
                pop   hl
                ret

straccu_copy:   dec   hl               ; position to double quote character

; enters here with double quote 8") seen
; copy a string constant into straccu, and push on stringstk
; set expr_type to string
copy_strconst:  ld    b, CHAR_QUOTE    ; load constant string terminator

; entered here with terminator 0 as well
copy_0string:   ld    d, b             ; store terminator
copy_string1:   push  hl               ; save ptr to string
                ld    c, 0FFh          ; set char cntr to -1
loop13F4:       inc   hl               ;<+ advance to next string char
                ld    a, (hl)          ; | get string char
                inc   c                ; | increment length
                or    a                ; | is it zero?
                jr    z, string_end    ; | yes, done
                cp    d                ; | is it terminator in D?
                jr    z, string_end    ; | yes, done
                cp    b                ; | is it terminator in B?
                jr    nz, loop13F4     ;-+ no, loop
string_end:     cp    CHAR_QUOTE       ; if terminator was ", advance
                call  z, nextchar
                ex    (sp), hl         ; stack is current position
                                       ; HL is start of string
                inc   hl               ; skip over the starting "
                ex    de, hl           ; put into DE
                ld    a, c             ; get length in A
                call  straccu_store    ; store in string accu

straccu_push_exprstack:                ; get string accu
                ld    de, straccu
                db    3Eh              ; LD A, xx to skip instruction
                                       ; is uncritical, because A is loaded later again
de_push_stringstk:
                push  de
                ld    hl, (stringstkptr) ; HL points to exprstack
                ld    (fpaccu_mant32), hl ; store exprstackptr in fpaccu
                ld    a, 1
                ld    (expr_type), a   ; set expression type to string
                call  move_to_var      ; put into exypression stack
                                       ; HL points to next position
                                       ; DE = stringaccu+6
                CPHL_DE                ; check if exprstack full
                                       ; assume DE was stringaccu
                                       ; on 11th call level, this will
                                       ; copy stringaccu -> stringaccu
                                       ; and will result in overflow
                ld    (stringstkptr), hl ; store new exprstack ptr
                pop   hl               ; restore stringaccu
                ld    a, (hl)          ; get length of string
                ret   nz               ; return if no stack overflow
                ld    e, 16            ; error code "too complex"

print_error1:   jp    print_error      ; exit error

loc_1430:       inc   hl
straccu_copy_print:
                call  straccu_copy

; print string pointed to by fpaccu
straccu_print:  call  fpaccu_getstr    ; get the string pointed to by fpaccu
                call  restore_de_bc    ; restore string descriptor into DE andBC
                                       ; E is length, BC is address
                inc   e                ; preincrement for loop
loop143B:       dec   e                ;<+ decrement length
                ret   z                ; | return if zero
                ld    a, (bc)          ; | get char of string
                call  print_char       ; | print it
                cp    CHAR_CR          ; | was it a CR?
                call  z, print_nul_delay ; yes, print padding characters
                inc   bc               ; | advance to next position
                jr    loop143B         ;-+ loop

; reserve space on string scratchpad
; A=requested size
; DE = start of string space
; HL = string_base
reserve_strspace:
                or    a                ; set flags of requested length
                db    0Eh              ; LD C, xx to skip next instruction
                                       ; is uncritical because C is loaded later again

; will arrive here twice, first coming from reserve_strspace
; and second, if string scratchpad space overflows
reserve_strspace1:            
                pop   af               ; ** skipped
                push  af               ; save A
                ld    hl, (string_base) ; get stringbase into DE
                ex    de, hl
                ld    hl, (string_top) ; get start of strings
                ld    c, a             ; get requested length
                xor    a               ; extend to 16 bit in BC, clear CY
                ld    b, a
                sbc   hl, bc           ; subtract from string start
                CPHL_DE                ; compare with base of strings
                jr    c, loc_1468      ; overflow?, error
                ld    (string_top), hl ; store as new string start
                inc   hl               ; point to string
                ex    de, hl           ; into DE
                pop   af               ; restore requested length
                ret

; on first call, Z is never 1
; on second call, Z is forced to be 1
; to fall thru to no-memory error
loc_1468:       pop   af               ; drop length
                ld    e, 14            ; error "no string space"
                jr    z, print_error1  ; if Z flag == 1, error
                                       ; note comment above
                cp    a                ; enforce Z=1
                push  af               ; save requested size andZ=1
                ld    bc, reserve_strspace1 ; schedule reserve_space again
                push  bc

; try garbage collection
;
; GC algorithm:
; set string_top = memory_top
; while not at string_base do
;   for each string in system
;     find xstring with highest address
;     copy xstring below string_top
;     set string_top = start of xstring
;     correct string descriptor of xstring
;   end for
; end while
;
gc:             ld    hl, (memory_top) ; get highest memory address
gc_outer_while: ld    (string_top), hl ; set as new start of string area
; run the following entirely in the alternative register set
                xor   a                ; clear A' and F' (CY=0)
                ex    af, af'
                ld    de, (string_base) ; DE = loop variable for traversing
                                        ; strings to find the currently upmost one
                                        ; initialized with lowest string in system,
                                        ; so any string above it this will override it
                exx                     ; swap to alternative set
                ld    hl, stringstk     ; HL' = exprstack

; garbage collection of string expression stack
;
; loop to handle scalar vars and expr stack
gc_inner_scalar:            
                ld    de, (stringstkptr) ; DE' = current exprstackptr
                CPHL_DE                ; compare
                ld    bc, gc_inner_scalar ; BC' is addr to return to outer loop
                jr    nz, gc_inner_find_xstring ; stack is not empty,
                                       ; do garbage collection

; garbage collection for string variable list
                ld    hl, (prog_end)   ; get end_of_prog (start_of_vars table)
loop1495:       ld    de, (end_of_vars) ;<+ get end_of_vars ptr
                CPHL_DE                ;  | compare
                jr    z, loc_14AB      ;  | end of vars reached? yes, to array processing
                bit    7, (hl)         ;  | test bit 7 of 1st char of variable name
                                       ;  | is set for string variable
                inc   hl               ;  | point to payload (string descriptor)
                inc   hl               ;  |
                call  gc_inner_find_xstring1 ; check if this is highest (no outer loop)
                jr    loop1495         ;--+ loop until all variables have been traversed

; garbage collection for string arrays
loop14AA:       pop   bc               ;<+ drop saved ptr to array declaration
loc_14AB:       ex    de, hl           ; | HL' is current string descriptor
                ld    hl, (end_arrays) ; | compare with end of end of array ptr
                sbc   hl, de           ; |
                ex    de, hl           ; | HL' is again current string descriptor
                jr    z, loc_14F8      ; | is it at the end of array space? yes, skip
                call  restore_de_bc    ; | DE' is variable name
                                       ; | BC' is total size
                bit    7, e            ; | check variable name bit7=1: string var
                push  hl               ; | save ptr to array declaration
                add   hl, bc           ; | advance to next array element
                jr    z, loop14AA      ;-+ is it not a string array? loop
                ex    (sp), hl         ; stack is ptr to next array element
                                       ; HL' is ptr to declaration
                ld    c, (hl)          ; load # of array indices
                ld    b, 0             ; make 16 bit
                add   hl, bc           ; skip over space for indices
                add   hl, bc
                inc   hl               ; +1 for #indices
                                       ; HL' points to list of array elements
                                       ; note: even for a multidimensional array,
                                       ; these are sequential, and the actual element
                                       ; subscripts are irrelevant

; loop to handle string arrays
gc_inner_array: pop   de               ; DE' is ptr to next array element
                CPHL_DE                ; compare ptr to curr. element with end of array
                jr    z, loc_14AB      ; end reached? loop
                push  de               ; restore end of element list of array
                ld    bc, gc_inner_array ; setup outer loop to find highest string

; find xstring (string with highest address below string_top)
; IX is ptr to descriptor for this
gc_inner_find_xstring:            
                push  bc               ; push address for loop

; HL points to current string descriptor
gc_inner_find_xstring1:            
                ld    a, (hl)          ; A' = length of string
                inc   hl
                inc   hl
                LDDE_M                 ; DE' is addr of potential xstring
                inc   hl               ; advance to next entry
                inc   hl
                inc   hl
                ret   z                ; Z was 1? yes return to inner loop
                                       ; note: on call of gc_inner_find_xstring, Z=0
                                       ; when entering through gc_inner_find_xstring1,
                                       ; Z depends on whether entered
                                       ; with a string var name (bit7=1)
                or    a                ; is string length = 0?
                ret   z                ; yes, return to inner loop
                push  de               ; transfer string address into std reg set
                exx                    ; back to std register set
                pop   bc               ; restore string address
                ld    hl, (string_top) ; get current top of string set
                sbc   hl, bc           ; subtract string address
                exx                    ; alternate register set
                ret   c                ; is above string_top, already GC'd
                exx                    ; back to standard set
                LDHL_DE                ; DE is currently highest string
                sbc   hl, bc           ; subtract curr_high_string - stringaddr
                exx                    ; alternate set
                ret   nc               ; is below curr_high_string
                                       ; don't handle now, and return
                exx                    ; standard set
                ld    d, b             ; DE = new curr_high_string
                ld    e, c
                exx                    ; alternate set
                ex    af, af'          ; restore string length requested
                                       ; and set CY=1 in std set: found a descriptor
                push  hl               ; put descr of curr_high_string into IX
                pop   ix
                ret                    ; return to inner loop

; we have found the string descriptor of xstring in IX
loc_14F8:       ex    af, af'          ; check std set CY flag: IX contains a descriptor
                ret   nc               ; no, we haven't found one,
                                       ; -> terminate garbage collection.
                exx                    ; switch back to std set
                ld    hl, (string_top) ; get start of string space
                ex    de, hl           ; into DE
                ld    c, a             ; get string length of xstring
                ld    b, 0             ; make 16 bit in BC
                add   hl, bc
                dec   hl               ; move string below string_top area
                lddr
                LDHL_DE                ; HL is new string_top
                inc   de               ; DE is new start of string
                ld    (ix-3), d        ; adjust ptr to string in descriptor
                ld    (ix-4), e        ; IX points to end of 6 byte string descriptor
                jp    gc_outer_while   ; loop again with next string

string_add:     push  bc
                push  hl
                ld    hl, (fpaccu_mant32)
                ex    (sp), hl
                call  expr
                ex    (sp), hl
                call  assert_string
                ld    a, (hl)
                push  hl
                ld    hl, (fpaccu_mant32)
                push  hl
                add   a, (hl)
                ld    e, 0Fh        ; error    code
                jp    c, print_error    ; "string to long error"
                call  straccu_reserve_strspace
                pop   de
                call  peek_str_stringstk
                ex    (sp), hl
                call  pop_str_stringstk
                push  hl
                ld    hl, (straccu.addr)
                ex    de, hl
                call  sub_1549
                call  sub_1549
                ld    hl, loc_EAC
                ex    (sp), hl
                push  hl
                jp    straccu_push_exprstack

sub_1549:       pop   hl
                ex    (sp), hl
                LDBC_M       
                inc   hl
                LDHL_M A    
loc_1553:       ld    a, b
                or    c
                ret   z
                ldir
                ret

; copy a string in BC of length A to DE
copy_string:    LDHL_BC                ; get source length into HL
                ld    c, a             ; get length into BC
                ld    b, 0
                jr    loc_1553         ; move string to DE space

; get string, descriptor in fpaccu, HL points to descriptor
string_expression:
                call  assert_string    ; verify that fpaccu contains a string result

; get string from stringstk, pointed to by fpaccu
fpaccu_getstr:  ld    hl, (fpaccu_mant32) ; point to string on exprstack

; popstring descr from exprstack, and discard it from string space, if easily
; possible
pop_str_stringstk:
                ex    de, hl           ; move to DE, i.e. pop
; discard string from exprstack, and also discard it from string space, if at
; the beginning of area
peek_str_stringstk:
                call  peekpop_str_stringstk ; popstring descr from stringstk
                ex    de, hl           ; DE is current stkptr
                                       ; HL is previous stkptr
                ret   nz               ; exit if not popped
                push  de               ; save stkptr
                ld    d, b             ; DE is address of string
                ld    e, c
                dec   de               ; decrement stringptr
                ld    c, (hl)          ; get string length into C
                ld    hl, (string_top) ; get top of strings ptr
                CPHL_DE                ; is at string space?
                jr    nz, loc_1581     ; no, some other string, restore stringstkptr
                ld    b, a             ; clear B (A is zero)
                add   hl, bc           ; yes, discard string from string space
                ld    (string_top), hl
loc_1581:       pop   hl
                ret

; peek or pop a value from expr stack
; if DE == (stringstk-6) pop, else peek
peekpop_str_stringstk:
                ld    hl, (stringstkptr) ; point to exprstack
                dec   hl               ; skip 2 unused bytes in exprstack
                dec   hl
                dec   hl
                ld    b, (hl)          ; get string address into BC
                dec   hl
                ld    c, (hl)
                dec   hl               ; skip unused byte
                dec   hl               ; skip string length
                CPHL_DE                ; compare ptr with DE value
                                       ; something strange happened, don't pop
                ret   nz               ; but exit with NZ
                ld    (stringstkptr), hl ; store ptr
                ret

math_len:       ld    bc, uA_to_fpaccu ; push function convert A to fpaccu
                push  bc

; parse a string argument
; HL = fpaccu
; A = string length
fpaccu_get_string:
                call  string_expression ; get a string expression
                xor   a                ; clear D
                ld    d, a
                ld    (expr_type), a   ; set resulting exprtype to numeric
                ld    a, (hl)          ; get string length
                or    a                ; set flags
                ret

math_asc:       call  fpaccu_get_string ; get string
                jr    z, error_illfunc ; is length zero? error
                inc   hl               ; advance to string address
                inc   hl
                LDDE_M                 ; get address into DE
                ld    a, (de)          ; get first char
                jp    uA_to_fpaccu     ; convert to FPaccu

math_chrs:      ld    a, 1             ; set request size
                call  straccu_reserve_strspace ; reserve space for 1 byte of string
                call  fpaccu_u8        ; Get a single byte
                ld    hl, (straccu.addr) ; load address of reserved string
                ld    (hl), e          ; store char into string space
loc_15C2:       pop   bc               ; drop caller
                jp    straccu_push_exprstack ; push result on exprstack

math_lefts:     call  get_numarg_stack ; get the numeric argument in B
                xor   a                ; starting position is 0
loc_15CA:       ex    (sp), hl         ; HL is string descriptor
                ld    c, a             ; copy starting position
                db    3Eh              ; LD A, xx to skip next instruction
loc_15CD:       push  hl               ; ** skipped, save descriptor
loc_15CE:       push  hl               ; save string descriptor
                ld    a, (hl)          ; get length of string
                cp    b                ; compare with LEFT$ arg
                jr    c, loc_15D5      ; is less?, yes skip
                ld    a, b             ; B = minimum length
                db    11h              ; LD DE, xxxx to skip next instruction
                                       ; is uncritical because next call will destroy DE
loc_15D5:       ld    c, 0             ; ** skipped
                push  bc               ; save B, C
                call  reserve_strspace ; reserve space for result string
                pop   bc
                pop   hl               ; reload descriptor
                push  hl
                inc   hl               ; point to string addr
                inc   hl
                LDHL_M B               ; get string address into HL
                ld    b, 0             ; make C 16 bit
                add   hl, bc           ; add starting position
                LDBC_HL                ; into BC
                call  straccu_store    ; setup target string descriptor (A, DE)
                call  copy_string      ; copy string
                pop   de               ; restore original string descr
                call  peek_str_stringstk ; discard original string, if possible
                jp    straccu_push_exprstack ; put result on expr stack

math_rights:    call  get_numarg_stack ; get numeric argument
                pop   de               ; reload original string descriptor
                push  de
                ld    a, (de)          ; get string length
                sub   b                ; subtract right position to be copied
                jr    loc_15CA         ; use LEFT$ code to copy substring

math_mids:      ex    de, hl           ; HL is string descriptor
                ld    a, (hl)          ; get string length
                pop   de               ; restore first argument
                ld    b, e             ; into B
                inc   b                ; set flags
                dec   b
error_illfunc:  jp    z, illfunc_error ; 1st arg is zero?, error
                push  bc               ; save starting position
                ld    e, 0FFh          ; preload maximum length
                cp    CHAR_RPAREN      ; no third argument?
                jr    z, loc_1617      ; no, don't have it, skip
                EXPECT CHAR_COMMA      ; expect a comma
                call  expression_u8_ae ; get an 8 bit expression in E
loc_1617:       EXPECT CHAR_RPAREN     ; now really expect closing parenthesis
                pop   af               ; restore starting position in A
                ex    (sp), hl         ; stack is curlineptr
                                       ; HL is string descriptor
                dec   a                ; adjust starting pos to 0-justified
                cp    (hl)             ; compare with string pos
                ld    b, 0
                jr    nc, loc_15CE
                ld    c, a             ; starting pos, save in C
                ld    a, (hl)          ; get length again
                sub   c                ; subtract start
                cp    e                ; compare with length to copy
                ld    b, a
                jr    c, loc_15CE
                ld    b, e             ; calculate minimum value
                jr    loc_15CE         ; and use LEFT$ to copy B chars from position C

math_instr:     pop   hl               ; restore curlineptr
                EXPECT CHAR_LPAREN     ; require '('
                call  string_expression1 ; get first argument
                ld    de, (fpaccu_mant32)
                push  de               ; save ptr to string
                EXPECT CHAR_COMMA      ; require comma
                call  string_expression1 ; get second argument
                ld    de, (fpaccu_mant32) ; save ptr to second string
                push  de
                ld    bc, 0FFh         ; preload start B=0, length C=FF
                ld    a, (hl)          ; get next char
                cp    CHAR_COMMA       ; does a start position follow?
                jr    nz, loc_1666     ; no, search from beginning to end
                push  bc               ; save BC
                call  next_fpaccu_u8   ; get a starting position
                pop   bc               ; restore BC
                dec   e                ; adjust start position 0-based
                ld    b, e             ; put into B (starting position)
                inc   e                ; check if it was 255
                jr    z, error_illfunc ; yes error
                ld    a, (hl)          ; get next char
                cp    CHAR_COMMA       ; is it a comma?
                jr    nz, loc_1666     ; no, search from given start position to end
                push  bc               ; save BC
                call  next_fpaccu_u8   ; get length argument
                pop   bc               ; restore start/length
                ld    c, e             ; put length argument
loc_1666:       EXPECT CHAR_RPAREN     ; require closing paren
                ex    (sp), hl         ; stack is curlineptr
                                       ; DE is second string
                push  bc               ; save start/length
                call  pop_str_stringstk ; discard second string
                pop   bc               ; restore start/length
                ex    de, hl           ; DE is second string
                pop   hl               ; restore curlineptr
                ex    (sp), hl         ; stack is curlineptr
                                       ; HL is first string
                push  de               ; save second string
                push  bc               ; save start/length
                call  pop_str_stringstk ; discard first string
                pop   bc               ; restore start/length
                pop   de               ; restore second string
                ld    a, b             ; get start position
                sub   (hl)             ; get length of first string
                jp    nc, loc_16D1     ; check beyond end of string? exit - no match
                neg                    ; length - start
                cp    c                ; compare with length to search
                jr    nc, loc_1686
                ld    c, a             ; set minimum of both
loc_1686:       inc   hl               ; advance to string address
                inc   hl
                LDHL_M A               ; into HL
                push  hl               ; save 1st address
                push  bc               ; save start/length
                ld    c, b             ; start as 16 bit
                ld    b, 0
                add   hl, bc           ; build string start poisiton
                pop   bc               ; restore start/lengh
                ex    de, hl           ; DE is first string address
                                       ; HL is second string descriptor
                ld    a, c             ; get search length
                sub   (hl)             ; subtract length of 2nd string
                jr    c, loc_16D0      ; is less, cannot match in this range, exit
                inc   a                ; add 1 to compare length
                ld    c, a             ; length to check in C
                ld    b, (hl)          ; get length of 2nd string in B
                inc   hl               ; advance to string address
                inc   hl
                LDHL_M A               ; get string address in HL
                ex    de, hl           ; DE is addr of 2nd string
                                       ; HL is addr of 1st string
                ld    a, b             ; get length of 2nd string
                or    a
                jr    z, loc_16C3      ; is zero?, skip
loc_16A6:       push  bc               ; save B = 2nd length, C = compare width
                ld    b, 0             ; make 16 bit comparison length
                ld    a, (de)          ; get first char to search
                cpir                   ; find position of first char of
                                       ; 2nd string in 1st string
                ld    a, c             ; save position
                pop   bc               ; restore length, compare width
                jr    nz, loc_16D0     ; not found
                ld    c, a             ; set new compare length
                push  bc               ; save regs
                push  de
                push  hl
                jr    loc_16BC         ; found first char in 1st string, skip
loop16B6:       inc   de               ;<+ advance ptr to char in 2nd string
                ld    a, (de)          ; | get char
                cp    (hl)             ; | does it match 1st string?
                jr    nz, loc_16BE     ; | no, leave loop
                inc   hl               ; | yes, advance to next position in 1st string
loc_16BC:       djnz  loop16B6         ;-+ end of 2nd string reached? no loop
loc_16BE:       pop   hl               ; restore regs
                pop   de
                pop   bc
                jr    nz, loc_16CC     ; no match, skip
loc_16C3:       pop   de               ; drop 2nd string descr
                sbc   hl, de           ; subtract string positions
                ld    a, l             ; get difference into A -> returned position
loc_16C7:       call  uA_to_fpaccu     ; convert position to FP
                pop   hl               ; restore curlineptr
                ret                    ; done
loc_16CC:       ld    a, c             ; at end of range to search?
                or    a
                jr    nz, loc_16A6     ; no, try again
loc_16D0:       pop   de               ; drop saved 2nd string descr
loc_16D1:       xor    a               ; return position 0 (not found)
                jr    loc_16C7         ; return result

; process INP(port)
math_inp:       call  fpaccu_u8        ; get port number in A
                ld    c, a             ; move into C
                in    a, (c)           ; read from port into A
                jp    uA_to_fpaccu     ; convert to fpaccu

; process OUT command
exec_out:       call  expression_2u8   ; get port in C, data in A
                out    (c), a          ; do out port
                ret

; process WAIT command
exec_wait:      call  expression_2u8   ; get port in C, mask in A
                ld    b, a             ; save mask in B
                push  bc               ; save mask
                ld    e, 0             ; exor argument
                call  skipspace        ; advance
                jr    z, loc_16F7      ; end of line?, no exor
                EXPECT CHAR_COMMA      ; expect a comma
                call  expression_u8_ae ; get exxor expression in E
loc_16F7:       pop   bc               ; restore mask
loop16F8:       in    a, (c)           ;<+ read port
                xor   e                ; | exor with arg
                and   b                ; | mask out bits
                jr    z, loop16F8      ;-+ wait as long port remains zero
                                       ; DANGEROUS: if port bit never changes,
                                       ; program will hang forever, need RESET
                ret

; get numeric second arg off stack, which was
; pushed there by function evaluator
get_numarg_stack:
                ex    de, hl           ; HL = curlineptr
                EXPECT CHAR_RPAREN     ; expect closing paren
                pop   bc               ; restore caller
                pop   de               ; restore 2nd arg of LEFT$/RIGHT$ off stack
                push  bc               ; push caller
                ld    b, e             ; get argument in B
                ret

; get 2 u8 expressions, return first in C, second in E
expression_2u8: call  expression_u8_ae ; get an 8 bit expression
                push  de               ; save it
                EXPECT CHAR_COMMA      ; expect a comma
                call  expression_u8_ae ; get an 8 bit expression in A and E
                pop   bc               ; return 1st arg in C
                ret                    ; return 2nd in A and E

; get next char and parse a 8 bit expression
next_fpaccu_u8: call  nextchar

; evaluate an unsigned 8 bit expression, return in A or E
expression_u8_ae:
                call  expression
fpaccu_u8:      call  fpaccu_to_u16
                ld    a, d             ; larger than 8 bit?
                or    a
                jp    nz, illfunc_error ; yes, error
                call  skipspace        ; advance to non-whitespace
                ld    a, e             ; get result in A and E
                ret

math_val:       call  fpaccu_get_string ; evaluate string expression
                                       ; set exprtype to numeric
                jp    z, fpaccu_zero   ; length of string zero?
                                       ; yes, return 0
                ld    e, a             ; store string length
                                       ; note: D is 0
                inc   hl
                inc   hl
                LDHL_M A               ; get string address into HL
                push  hl               ; save start of string
                add   hl, de           ; get end of string
                ld    b, (hl)          ; save original value
                ld    (hl), d          ; make 0-terminated
                ex    (sp), hl         ; save end of string, HL is start of string
                push  bc               ; save BC
                ld    a, (hl)          ; load first char of number
                call  parse_number_fpaccu ; convert string to number
                pop   bc               ; restore BC
                pop   hl               ; restore end of string
                ld    (hl), b          ; restore original value
                ret                    ; done

; process SWITCH command
exec_switch:    jr    c, loc_1751      ; has an argument?
                call  IOCHECK          ; get IO byte of Zapple monitor
                xor   3                ; invert (why that?)
loc_174D:       ld    c, a             ; put into C
                jp    IOSET            ; set it
loc_1751:       call  expression_u8_ae ; get an 8 bit expression
                cp    4                ; is it >= 4?
                jp    nc, syntax_error ; yes, error
                ld    b, a             ; save it
                call  IOCHECK          ; get IO byte from Zapple monitor
                and   0FCh             ; mask out lowest bits
                or    b                ; put in new console switch
                jr    loc_174D         ; set IO byte

; process LWIDTH, WIDTH commands
exec_lwidth:    call  temporary_select_printer
exec_width:     call  expression_u8_ae ; get an 8 bit expression
                cp    14               ; less or equal 14?
                jp    c, illfunc_error ; invalid
                ld    (iy+ioparams.linelength), a ; store as line width
                ld    c, a             ; get width again
loop1771:       sub   14               ;<+ subtract 14
                jr    nc, loop1771     ;-+ loop until negative
                add   a, 28            ; make a number between 14 and 27
                neg                    ; invert
                add   a, c             ; length of last printout field
                ld    (iy+ioparams.last_field), a
                ret

sub_177E:       call  check_alpha      ; check for alpha character
                jp    c, syntax_error  ; no, return error
                ld    c, a             ; save program name to load
loop1785:       ld    b, 3             ;<+ cntr for chars
loop1787:       call  READERIN         ;<--+ get a char from reader
                jr    c, loc_17A7      ; | | error, exit
                inc   a                ; | | expect at least 3 * FF chars
                jr    nz, loop1785     ;-+ |
                djnz  loop1787         ;---+ wait for three FF
loop1791:       call  READERIN         ;<+ get a char from reader
                jr    c, loc_17A7      ; | error, exit
                inc   a                ; | expect a FF
                jr    z, loop1791      ;-+ loop as long as FF
                dec   a                ; regenerate char
                cp    c                ; compare with file name
                jr    z, loc_17A2      ; yes, correct program found
                call  read_reader_zero ; wait for 00 or EOF
                jr    loop1787         ; redo load
loc_17A2:       ld    c, 7             ; load BEL char
                jp    CONSOLEOUT       ; emit it to console
loc_17A7:       ld    e, 19            ; error code "file not found"
                jr    loc_17BC         ; print error

read_reader_zero:
                ld    b, 3
loop17AD:       call  read_reader      ;<---+ get char
                or    a                ;    | wait for three 00
                jr    nz, read_reader_zero ;|
                djnz  loop17AD         ;----+
                ret                    ; got them

read_reader:    call  READERIN         ; get a char from reader
                ret   nc               ; return if char found
loc_17BA:       ld    e, 20            ; error code "illegal EOF error"
loc_17BC:       jp    print_error
loc_17BF:       inc   d
                call  nz, new_memory
                jr    loc_17BA

; process binary SAVE
exec_save:      call  check_alpha      ; get program name character
                jp    c, syntax_error  ; not found, error
                ld    c, a             ; save in C
                call  nextchar         ; get next char
                jp    nz, syntax_error ; error if not end of line
                push  hl               ; save buf address
                push  bc               ; save program name
loop17D4:       ld    bc, 8FFh         ;<+ load char FF and cntr 8
                call  PUNCHOUT         ; | punch tape
                djnz  loop17D4         ;-+ loop to emit 8 * FF
                pop   bc               ; restore program name
                call  PUNCHOUT         ; write program name
                ld    hl, (prog_end)   ; load end of program
                ex    de, hl           ; into DE
                ld    hl, (start_memory) ; load start of program
loop17E7:       ld    c, (hl)          ;<+ get byte to write
                inc   hl               ; | advance ptr
                call  PUNCHOUT         ; | punch it
                CPHL_DE                ; | compare with end
                jr    nz, loop17E7     ;-+ loop until at end
                ld    bc, 8FFh         ; load byte FF and cntr 8
loop17F7:       call  PUNCHOUT         ;<+ punch trailer
                djnz  loop17F7         ;-+ loop to emit 8 * FF
                pop   hl               ; restore bufptr
                ret                    ; exit

; process LOAD, LOAD?
exec_load:      cp    TOKEN_QUEST      ; "LOAD?"
                ld    d, 0FFh          ; set flag verify
                jr    z, loc_180F      ; yes, skip verify
                ld    (fpaccu_mant32), a ; save argument of LOAD
loc_1807:       call  new_memory       ; clear memory
                ld    d, 0             ; set flag load
                ld    hl, (data_ptr+1) ; ***** this is possibly a bug, it should
                                       ; have been data_ptr+0
loc_180F:       call  nextchar         ; reload char
                call  sub_177E         ; read program name
                ld    hl, (start_memory) ; get start of memory
loop1818:       ld    b, 3             ;<--+
loop181A:       call  READERIN         ;<+ | get a char
                jr    c, loc_17BF      ; | | EOF?
                ld    e, a             ; | | put into E
                sub   (hl)             ; | | compare with memory
                and   d                ; | | and with LOAD=0, VERIFY=FF
                jr    nz, loc_183C     ; | | if not zero, does not match
                ld    (hl), e          ; | | store data
                call  check_memfree    ; | | check whether there is still space
                ld    a, (hl)          ; | | get current character
                or    a                ; | | set flags
                inc   hl               ; | | next cell
                jr    nz, loop1818     ;---+ loop until three consecutive zeros
                djnz  loop181A         ;-+
                ld    (prog_end), hl   ; save end address
                ld    a, (prompt_flag) ; print prompt if flag is zero
                or    a
                call  z, print_ready_prompt
                jp    rebuild_nextchain ; go execute
loc_183C:       ld    e, 21            ; error code "files different"
                jp    print_error

; process ASAVE command
exec_asave:     ret   nz               ; exit if argument follows
                pop   hl               ; discard return address
                ld    bc, 8FFh         ; B=8, C=FF
loop1846:       call  PUNCHOUT         ;<+ write FF to punch device
                djnz    loop1846       ;-+ loop 8 times
                ld    hl, (start_memory) ; get start of program
loop184E:       ld    a, (hl)          ;<+ get next link
                inc   hl               ; |
                or    (hl)             ; |
                inc   hl               ; |
                jr    z, loc_1885      ; | is it zero? end of program
                LDDE_M                 ; | get lineno into DE
                inc   hl               ; |
                push  hl               ; | save position in line
                call  uDE_to_fpaccu    ; | put into FPaccu
                call  format_number    ; | format as number
                inc   hl               ; | advance to number (no sign)
                call  punch_asciz      ; | write number
                pop   hl               ; | restore line ptr
                ld    a, (hl)          ; | get character
                cp    9                ; | is TAB?
                jr    z, loc_186E      ; | yes, ignore
                ld    c, CHAR_SPACE    ; | punch a space
                call  PUNCHOUT         ; |
loc_186E:       call  detokenize       ; | convert line decoded into inputbuf
                push  hl               ; | save current position
                ld    hl, inputbuf     ; | get inputbuf
                call  punch_asciz      ; | dump it
                pop   hl               ; | restore line position
                ld    c, CHAR_CR       ; | punch a CRLF
                call  PUNCHOUT         ; |
                ld    c, CHAR_LF       ; |
                call  PUNCHOUT         ; |
                jr    loop184E         ;-+ loop
loc_1885:       ld    c, CHAR_CTRLZ    ; punch a CTRL-Z
                call  PUNCHOUT
                ld    bc, 8FFh         ; B=8 C=FF
loop188D:       call  PUNCHOUT         ;<+ send a FF to punch
                djnz  loop188D         ;-+ 8 times
                jp    print_prompt     ; return to interpreter loop

; send a 0-terminated string in    HL to PUNCH device
punch_asciz:    ld    a, (hl)          ;<+ get character
                or    a                ; | is 0?
                ret   z                ; | yes exit
                ld    c, a             ; | put int C
                call  PUNCHOUT         ; | and punch
                inc   hl               ; | advance to next position
                jr    punch_asciz      ;-+ loop

temporary_select_printer:
                ex    de, hl           ; save HL
                ld    hl, select_console
                ex    (sp), hl         ; insert into stack
                push  hl
                ex    de, hl           ; restore HL

select_printer: ld    iy, LISTOUT
                ld    (output_addr), iy
                ld    iy, prtparam
                ret

exec_renumber:  ex    af, af'          ; save flags (following arguments?)
                ex    de, hl           ; save curlineptr
                ld    hl, (lineno)     ; get lineno
                TEST_FFFF              ; is it FFFF?
                jp    nz, illfunc_error ; no, error, not in  direct mode
                ld    hl, (start_memory) ; start of program
                ld    a, (hl)          ; get nextlink
                inc   hl
                or    (hl)
                ex    de, hl           ; restore curlineptr
                jp    z, advance_to_eoln ; no program? ignore the whole junk
                ld    de, 10           ; preload starting line
                push  de
                ex    af, af'          ; restore flags
                call  c, read_lineno   ; number follows?, yes get a lineno
                                       ; otherwise reuse the preloaded number
                ld    (renum_new), de  ; save it
                pop   de               ; drop preload
                cp    CHAR_COMMA       ; comma follows?
                jr    nz, loc_18DF     ; no, skip
                call  nextchar         ; get next char
                call  c, read_lineno   ; and read increment
loc_18DF:       ld    (renum_incr), de ; save increment (if not given, DE was 10)
                push  hl               ; save curlineptr
                ld    hl, (start_memory) ; get program start
                inc   hl               ; skip over nextlink
                inc   hl
                LDDE_M                 ; get first line
                pop   hl
                cp    CHAR_COMMA       ; another comma follows?
                jr    nz, loc_18FF     ; no, skip
                call  nextchar         ; get the lineno to start
                call  c, read_lineno
                ld    hl, (renum_new)  ; new lineno to set
                sbc   hl, de           ; subtract the line where to start
                jp    c, syntax_error  ; error if start > new
loc_18FF:       ld    (renum_start), de ; save line to start
                or    a                ; more arguments follow?
                jp    nz, syntax_error ; yes, error
                call  find_line        ; find starting line
                jp    nc, undef_stmt_error ; not found, error
                LDHL_BC                ; ptr to start of line into HL
                exx                    ; alt set
                ld    de, 1            ; initialize cntr of lines
                                       ; DE' is increment
                ld    hl, 0            ; HL' is initial count
                exx
                ld    de, 0FFFFh       ; search for highest line
                call  find_line_from_current ; and count number of lines to renumber
                exx                    ; from now on, ignore reg set, only HL = count of
                                       ; lines is interesting
                dec   hl               ; one less
                ex    de, hl           ; put nmber of lines in DE
                ld    bc, (renum_incr) ; get increment
                ld    a, b             ; increment is zero?
                or    c
                jp    z, syntax_error  ; yes error
                call  umultiply16      ; HL is increment * number of lines
                ld    de, (renum_new)  ; get start of renumbering
                add   hl, de           ; add, to find the highest number to expect
                jp    c, subscript_range_error ; overflow? error
                ld    hl, (start_memory) ; start of program
renum_doline:   inc   hl               ; skip over nextlink
                inc   hl
                LDBC_M                 ; get current lineno in BC
                ex    de, hl           ; save curlineptr
                ld    hl, (renum_start) ; check if renumbering starts?
                sbc   hl, bc           ; is above the lower margin?
                jr    c, loc_194A      ; yes, skip
                jr    z, loc_1954      ; is exactly the starting position
                LDHL_BC                ; no, put lineno in HL
                jr    loc_1957         ; skip
loc_194A:       ld    bc, (renum_incr) ; get increment
                ld    hl, (curlineno)  ; get current line cntr
                add   hl, bc           ; and add, to get the new lineno to set
                jr    loc_1957
loc_1954:       ld    hl, (renum_new)  ; set base of new line
loc_1957:       ld    (curlineno), hl  ; store as the current line handled
                ex    de, hl           ; reload curlineptr
renum_search:   call  nextchar         ;<+ advance to next char in line
renum_search1:  or    a                ; | end of line?
                jp    z, renum_eoln    ; | yes, skip
                cp    TOKEN_GOTO       ; | is GOTO?
                jr    z, renum_target  ; | yes, handle jump target
                cp    TOKEN_GOSUB      ; | is GOSUB?
                jr    z, renum_target  ; | yes, handle
                cp    TOKEN_THEN       ; | is THEN?
                jr    z, renum_target  ; | yes, handle
                cp    TOKEN_ELSE       ; | is ELSE?
                jr    z, renum_target  ; | yes handle
                cp    TOKEN_USING      ; | is USING?
                jr    z, renum_target  ; | yes handle
                cp    TOKEN_RESTORE    ; | is RESTORE?
                jr    nz, renum_search ;-+ no, continue searching
renum_target:   call  nextchar         ; found token with a lineno following?
                jr    nc, renum_search1 ; no, none following, continue searching
                ld    (auto_increment), hl ; save curlineptr
                dec   hl               ; to first char of line
                ld    de, 0            ; initialize number store
                ld    c, 0             ; number of chars in number
loop1988:       call  nextchar         ;<--+ get char
                jr    nc, loc_19B8     ;   | no digit
                push  hl               ;   | save curlineptr
                or    a                ;   | clear CY
                ld    hl, 6552         ;   | maximum lineno before adding last digit
                sbc   hl, de           ;   | would result in too large number?
                jr    nc, loc_19A7     ;   | no, skip
loc_1996:       ld    hl, e_subscr_range ; | print error message
                call  print_string     ;   |
                call  trace_curlineno  ;   | print lineno currently handled
                pop   hl               ;   | restore curlineno
loop19A0:       call  nextchar         ;<+ | advance to next
                jr    c, loop19A0      ;-+ | still a number? advance
                jr    renum_search1    ;   | continue
loc_19A7:       LDHL_DE                ;   | save current number value in HL
                add   hl, hl           ;   | multiply with 10
                add   hl, hl           ;   |
                add   hl, de           ;   |
                add   hl, hl           ;   |
                sub   CHAR_ZERO        ;   | subtract '0' from digit
                ld    e, a             ;   | make 16 bit
                ld    d, 0             ;   |
                add   hl, de           ;   | add to number store
                ex    de, hl           ;   | put number back into DE
                pop   hl               ;   | restore curlineptr
                inc   c                ;   | increment digit count
                jr    loop1988         ;---+ loop
loc_19B8:       ld    a, c             ; save the length of number
                ld    (renum_size), a
                push  hl               ; save curlineptr
                ld    hl, (renum_start) ; get starting position to renumber
                ex    de, hl           ; DE is starting line to renumber
                                       ; HL is lineno found in text
                push  hl               ; save found number
                sbc   hl, de           ; subtract
                jr    c, loc_19F0      ; is below the range to renumber
                call  find_line        ; find the line where to start renumbering
                LDHL_BC                ; ptr to nextlink in HL
                pop   de               ; restore GOTO etc. target
                exx
                ld    hl, (renum_new)  ; initialize cntr for renumbered lines
                                       ; HL' is starting count
                                       ; DE' is increment
                ld    de, (renum_incr)
                exx
                call  find_line_from_current ; find the target
                jr    c, loc_19ED      ; got it
                ld    hl, e_undef_stmt ; otherwise, notify undefined statement error
                push  de               ; save target
                call  print_string
                pop   hl
                call  print_HL         ; print target
                call  trace_curlineno  ; print lineno where found
                pop   hl               ; restore curlineptr
                ld    a, (hl)          ; load current char
                jp    renum_search1    ; continue searching
loc_19ED:       exx                    ; get the calculated new target lineno
                                       ; out of alt set
                push  hl
                exx
loc_19F0:       pop   de               ; into DE
                pop   hl               ; restore old target number
                xor    a               ; positive sign
                ld    b, 98h           ; convert into a FP number
                call  s24_to_fp
                call  format_number    ; format it
                ld    b, 0             ; initialize digit cntr
                inc   hl               ; point to next char in number buf
                push  hl               ; save start of number buf
loop19FF:       ld    a, (hl)          ;<+ get char
                or    a                ; | 
                jr    z, loc_1A07      ; | end of number? yes exit loop
                inc   b                ; | incr digit count
                inc   hl               ; | advance
                jr    loop19FF         ;-+ loop
loc_1A07:       ld    a, (renum_size)  ; get size of old target
                sub   b                ; compare with size of new target
                jr    z, loc_1A49      ; same? great, skip
                jr    c, loc_1A2B      ; new target is larger
                ld    c, a             ; new target is smaller
                ld    b, 0             ; make 16 bit
                ld    hl, (auto_increment) ; get position of old target
                LDDE_HL                ; into DE
                add   hl, bc           ; addsize of new target
                push  hl               ; save end position
                ld    hl, (prog_end)   ; end of program
                sbc   hl, de           ; subtract old target pos
                sbc   hl, bc           ; subtract size of new target
                LDBC_HL                ; count of bytes to move
                pop   hl               ; restore end position
                ldir                   ; move data
                ld    (prog_end), de   ; adjust new end of program
                jr    loc_1A49         ; now has correct space for new target
loc_1A2B:       neg                    ; difference was negative, negate
                ld    c, a             ; make 16 bit, number of bytes to expand
                ld    b, 0
                ld    hl, (prog_end)   ; get end of program
                LDDE_HL                ; into DE
                add   hl, bc           ; calculate new end
                call  check_memfree    ; validate enough free space
                ld    (prog_end), hl   ; store as new end
                ex    de, hl           ; put into DE
                push  hl               ; save old end of program
                ld    bc, (auto_increment) ; get position of old target
                sbc   hl, bc           ; subtract -> number of bytes to move
                LDBC_HL                ; into BC
                pop   hl
                lddr                   ; move bytes to open gap
; now gap is exactly as large to fit the new target number
loc_1A49:       pop   de               ; start of number buf
                ld    hl, (auto_increment) ; position of old target
loop1A4D:       ld    a, (de)          ;<+ get digit from number buf
                or    a                ; | 
                jr    z, loc_1A56      ; | at end? yes leave loop
                ld    (hl), a          ; | put into gap
                inc   hl               ; | advance ptrs
                inc   de               ; |
                jr    loop1A4D         ;-+ loop
loc_1A56:       push  hl               ; save next position
                ld    hl, (start_memory) ; get start of program into DE
                ex    de, hl
                call  rebuild_nextchain1 ; fix next chain
                pop   hl               ; restore curlineptr
                ld    a, (hl)          ; get next char
                cp    CHAR_COMMA       ; is it a comma? ON GOTO case
                jp    z, renum_target  ; yes, stay in loop to fix a potential target
                jp    renum_search1    ; continue line processing
renum_eoln:     inc   hl               ; at end of line, skip over 0 byte
                or    (hl)             ; check  nextlink (A is 0)
                inc   hl
                or    (hl)
                dec   hl
                jp    nz, renum_doline ; not at end of program yet, continue
                ld    de, (renum_start) ; find start line to renumber
                call  find_line
                LDHL_BC                ; put ptr to nextlink in HL
                ld    bc, (renum_incr) ; get increment
                ld    de, (renum_new)  ; get new value
                inc   hl               ; skip over nextlink
loop1A82:       inc   hl               ;<--+
                LDM_DE                 ;   | put new lineno into line
loop1A86:       inc   hl               ;<+ | advance
                ld    a, (hl)          ; | | advance to end of line
                or    a                ; | | 
                jr    nz, loop1A86     ;-+ | 
                ex    de, hl           ;   | save curlineptr
                add   hl, bc           ;   | increment the new lineno
                ex    de, hl           ;   | restore curlineptr
                inc   hl               ;   | check if end of program
                or    (hl)             ;   | 
                inc   hl               ;   | 
                or    (hl)             ;   | 
                jr    nz, loop1A82     ;---+ no, loop, setting next lineno
                call  init_from_current ; clear all variables
                jp    print_prompt     ; return to interpreter loop

trace_curlineno:
                ld    hl, (curlineno)
trace_lineno:   call  print_at_lineno
                jp    print_crlf

; process DELETE
exec_delete:    call  get_lineno_range ; obtain lineno range
                                       ; HL is address of nextlink
                                       ; BC is address of previous nextlink
                pop   de               ; restore ending lineno
                push  bc               ; save starting position
                call  find_line        ; find the ending line from current position
                jp    nc, illfunc_error ; not matched, error
                LDDE_HL                ; DE = start of lines to delete
                ex    (sp), hl         ; insert it in stack
                push  hl
                CPHL_DE                ; subtract address range
                jp    nc, illfunc_error ; negative? yes error
                call  print_ready_prompt ; print READY
                pop   bc               ; restore starting position
                ld    hl, rebuild_nextchain ; return via rebuild_nextchain
                ex    (sp), hl
                ex    de, hl           ; DE = end to delete
                ld    hl, (prog_end)   ; HL = prog_end
                                       ; BC = start to delete
loop1AC7:       ld    a, (de)          ;<+ get byte from range end
                ld    (bc), a          ; | move to range start
                inc   bc               ; | advance ptrs
                inc   de               ; | 
                CPHL_DE                ; | loop until end of program
                jr    nz, loop1AC7     ;-+
                ld    (prog_end), bc   ; save new end of program
                ret

exec_ltrace:    ld    a, 7Fh           ; load flag for LTRACE
                db    1                ; LD BC, xxxx to skip next instruction

; process TRACE/LTRACE
exec_trace:     ld    a, 0BFh          ;** load flag for TRACE
                push  af               ; save LTRACE/TRACE flag
                call  expression1      ; evaluate an expression
                call  skipspace        ; continue
                jr    nz, loc_1AFA     ; if not EOLN, error
                call  fpaccu_sgn       ; get value (0,1)
                dec   a                ; convert to 0/FF
                cpl
                ld    b, a             ; save
                pop   af               ; restore flag
                ld    c, a             ; save
                cpl                    ; complement: LTRACE = 0x80, TRACE = 0x40
                and   b                ; mask bit
                ld    b, a             ; result into B
                ld    a, (trace_mode)  ; get trace mode
                and   c                ; mask out relevant bit
                or    b                ; inject trace flag
                ld    (trace_mode), a  ; save it
                ret
loc_1AFA:       pop   af
                jp    syntax_error

exec_edit:      call  read_lineno      ; read the line number
                ret   nz               ; exit if more arguments follow
                pop   hl               ; drop return address
loc_1B03:       call  find_line        ; find the line to be edited
                jp    nc, illfunc_error ; not found, error
                LDHL_BC                ; put start of line into HL
                inc   hl               ; skip over next link
                inc   hl
                LDBC_M                 ; get lineno into BC
                inc   hl
                push  bc               ; save lineno
                call  detokenize       ; move line into inputbuf
loc_1B15:       pop   hl               ; restore lineno
                push  hl               ; save again
                call  print_HL         ; print lineno
                call  print_space      ; print blank
                ld    hl, inputbuf     ; ptr to inputbuf
                push  hl
                ld    e, 0FFh          ; E = -1
loop1B23:       inc   e                ;<+ increment
                ld    a, (hl)          ; | get char
                and   MASK_7BIT        ; | discard parity bit
                ld    (hl), a          ; | 
                inc   hl               ; | advance
                jr    nz, loop1B23     ;-+ loop until end of buf
                                       ; E is length of line
                pop   hl               ; restore start of buf
                ld    d, a             ; clear D (A is 0)
edit_loop:      ld    b, 0             ; clear count
loop1B2F:       call  read_conchar     ;<+ get char from console
                cp    ':'              ; | between 0-9?
                jr    nc, loc_1B46     ; | 
                cp    CHAR_ZERO        ; | 
                jr    c, loc_1B46      ; | no, skip
                sub   CHAR_ZERO        ; | make digit
                ld    c, a             ; | into C
                ld    a, b             ; | get count
                rlca                   ; | multiply with 10
                rlca                   ; | 
                add   a, b             ; | 
                rlca                   ; | 
                add   a, c             ; | add digit
                ld    b, a             ; | new count
                jr    loop1B2F         ;-+ loop
loc_1B46:       push  hl               ; save bufptr
                ld    hl, edit_loop
                ex    (sp), hl         ; put edit_loop on stack
                                       ; HL is bufptr
                dec   b                ; check if count is 0
                inc   b
                jr    nz, loc_1B50
                inc   b                ; yes, set to 1
loc_1B50:       exx                    ; alt register set
loop1B51:       ld    hl, edit_tbl     ;<--+ HL' is edit_tbl
loop1B54:       cp    (hl)             ;<+ | compare entered character with table entry
                inc   hl               ; | | advance
                LDBC_M                 ; | | get handler address into BC'
                inc   hl               ; | | 
                push  bc               ; | | save on stack
                exx                    ; | | std set
                ret   z                ; | | if command found, return to handler routine
                exx                    ; | | to alt set
                pop   bc               ; | | drop handler address
                inc   (hl)             ; | | check for terminating 0 byte
                dec   (hl)             ; | | 
                jr    nz, loop1B54     ;-+ | no loop
                cp    60h              ;   | is it a lower case letter?
                jr    c, loc_1B6B      ;   | no, ring bell for error
                and   5Fh              ;   | make it upper case
                jr    loop1B51         ;---+ and try again
loc_1B6B:       exx                    ; return to std set
                ld    a, 7             ; ring BEL
                jp    write_char       ; and return to edit_loop
edit_tbl:       db    CHAR_SPACE
                dw    edit_right
                db    'Q'
                dw    break_entry
                db    'L'
                dw    edit_list
                db    'F'
                dw    edit_find
                db    'I'
                dw    edit_insert
                db    'D'
                dw    edit_delete
                db    CHAR_CR
                dw    edit_end
                db    'R'
                dw    edit_replace
                db    'E'
                dw    edit_save
                db    'X'
                dw    edit_append
                db    'K'
                dw    edit_kill
                db    'H'
                dw    edit_deleoln
                db    CHAR_RUBOUT
                dw    edit_left
                db    'A'
                dw    edit_reload
                db    0

edit_reload:    pop   bc               ; drop argument
                pop   de               ; restore current line to edit
                call  print_crlf       ; print CRLF
                jp    loc_1B03         ; find and reload line in DE

edit_right:     ld    a, (hl)          ;<+ get current char
                or    a                ; | at end of line?
                ret   z                ; | yes, exit to edit_loop
                inc   d                ; | increment pos
                call  print_char       ; | print character
                inc   hl               ; | advance ptr
                djnz    edit_right     ;-+ loop N times
                ret                    ; exit to edit_loop

edit_kill:      push  hl               ; save position
                ld    hl, print_backslash1 ; print a backslash
                ex    (sp), hl         ; put on stack, HL is position
                scf                    ; set CY
edit_find:      push  af               ; save flags
                call  read_conchar     ; get character
                ld    c, a             ; save in C
                pop   af               ; restore flags
                dec   (hl)             ; at end of line?
                inc   (hl)
                ret   z                ; yes, exit to print_backslash1
                push  af               ; save flags
                call  c, print_backslash1 ; if in kill mode, print char X as "\X"
                ld    a, (hl)
loop1BC3:       call  print_char       ;<+
                pop   af               ; | restore flags
                push  af               ; | save again
                jr    nc, loc_1BCF     ; | if not in kill mode, skip
                call  del_char_from_buf ;| delete char from buf
                djnz  loc_1BD1         ; | loop for count
loc_1BCF:       inc   hl               ; | advance to next position
                inc   d                ; | advance char cntr
loc_1BD1:       ld    a, (hl)          ; | get character
                or    a                ; | 
                jr    z, loc_1BDA      ; | end of line? yes skip
                cp    c                ; | is it the char to find
                jr    nz, loop1BC3     ;>+ no loop
                djnz  loop1BC3         ;-+ loop N times
loc_1BDA:       pop   af               ; drop flags
                ret                    ; return to edit_loop

edit_list:      call  sub_82A          ; print buf
                call  print_crlf       ; do CRLF
                pop   bc               ; cleanup stack
                jp    loc_1B15         ; loop to EDIT print line

edit_delete:    ld    a, (hl)          ; get char
                or    a                ; is it end of line?
                ret   z                ; yes, exit to edit_loop
                ld    a, CHAR_BSLASH   ; print a backslash
                call  write_char       ;<+
loop1BEE:       ld    a, (hl)          ; | print char
                or    a                ; | 
                jr    z, print_backslash1 ; unless it is end of line
                call  print_char       ; | 
                call  del_char_from_buf ;| delete char from buf
                djnz    loop1BEE       ;-+ loop N times

print_backslash1:
                ld    a, CHAR_BSLASH
                jp    write_char

edit_replace:   ld    a, (hl)          ;<+ get char
                or    a                ; | 
                ret   z                ; | if end of line, exit to edit_loop
                call  read_conchar     ; | get character
                call  print_char       ; | print it
                ld    (hl), a          ; | put into buf
                inc   hl               ; | advance bufptr
                inc   d                ; | advance buf count
                djnz    edit_replace   ;-+ loop N times
                ret

edit_deleoln:   ld    (hl), 0          ; set end of buf here
                ld    e, d             ; store buf count
edit_append:    ld    b, 0FFh          ; go as much right as possible
                call  edit_right
edit_insert:    call  read_conchar     ;<+ get char from console
                cp    CHAR_CR          ; | is it CR?
                jr    z, edit_end      ; | yes, done
                cp    CHAR_ESC         ; | is it ESCAPE?
                ret   z                ; | yes, leave edit mode
                cp    CHAR_RUBOUT      ; | is it RUBOUT?
                jr    nz, loc_1C33     ; | no, skip
                dec   d                ; | check position
                inc   d                ; | 
                jr    z, loc_1C3A      ; | at the start of buf
                dec   hl               ; | no, decrement bufptr
                dec   d                ; | and cntr
                ld    a, (hl)          ; | get the char
                call  print_char       ; | print it
                call  del_char_from_buf ;| and delete it from buf
                jr    edit_insert      ;-+ loop
loc_1C33:       push  af               ; save character
                ld    a, e             ; get edit count
                cp    0FFh             ; is it 255?
                jr    c, loc_1C41      ; no, not yet, go insert the char
                pop   af               ; drop character
loc_1C3A:       ld    a, 7             ; ring bell (end of buf)
                call  write_char
                jr    edit_insert      ; loop
loc_1C41:       sub   d                ; edit count - buf position
                inc   e                ; increment both
                inc   d
                push  de               ; save DE
                ex    de, hl           ; bufptr
                ld    l, a             ; make 16 bit
                ld    h, 0
                add   hl, de           ; bufptr + insertion length
                LDBC_HL                ; into BC
                inc   bc               ; add 1
                call  loc_41F          ; reserve space
                pop   de               ; restore DE
                pop   af               ; restore char inserted
                call  print_char       ; print it
                ld    (hl), a          ; put into buf
                inc   hl
                jr    edit_insert      ; loop

edit_left:      ld    a, d             ;<+ get buf pos
                or    a                ; | already at the beginning?
                ret   z                ; | yes ignore
                dec   d                ; | move pos andptr to left
                dec   hl               ; | 
                ld    a, (hl)          ; | print char
                call  print_char       ; | 
                djnz  edit_left        ;-+ loop N times
                ret

edit_end:       call  sub_82A          ; print the whole line
edit_save:      call  print_crlf       ; print a CRLF
                pop   bc               ; cleanup stack
                pop   de               ; restore lineno
                scf                    ; set CY
                push  af               ; save it
                ld    hl, inputbuf     ; load inputbuf
                jp    loc_4F9          ; enter into line insertion routine

del_char_from_buf:
                push  hl               ; save buf position
                dec   e                ; decrement count
loop1C77:       ld    a, (hl)          ;<+ get character
                or    a                ; | end of buf reached
                jr    z, loc_1C82      ; | 
                inc   hl               ; | advance to next position
                ld    a, (hl)          ; | delete char from buf
                dec   hl               ; | 
                ld    (hl), a          ; | 
                inc   hl               ; | 
                jr    loop1C77         ;-+ loop
loc_1C82:       pop   hl               ; restore position
                ret

; get a random init value from refresh register
; BAD code: this only gets 256 different random values
exec_randomize: ret   nz               ; exit if argument follows
                ex    de, hl           ; save HL
                ld    hl, rnd_mant23
                ld    a, r             ; get refresh register (256 values)
                ld    (hl), a          ; save mant2
                inc   hl
                ld    (hl), a          ; save mant3
                inc   hl
                ld    (hl), a          ; save mant4
                inc   hl
                ld    (hl), a          ; save mant5
                inc   hl
                and   7Fh              ; make positive (suppressed MSB)
                ld    (hl), a          ; save mant6
                inc   hl
                ld    (hl), 80h        ; make expenent
                ex    de, hl
                ret

; handle LVAR/LLVAR
; anachronism: does not print arrays
exec_llvar:     call  temporary_select_printer ; select printer for output
exec_lvar:      ret   nz               ; exit, if arguments follow
                push  hl               ; save curlineptr
                ld    hl, (prog_end)   ; get start of variables
loop1CA3:       call  print_crlf       ;<+ print a CRLF
                call  check_break      ; | check for break
                ld    de, (end_of_vars) ;| load end of variables
                CPHL_DE                ; | 
                jr    z, loc_1CF0      ; | is end of vars already reached? yes exit
                ld    c, (hl)          ; | get variable name in C
                inc   hl               ; | 
                ld    a, (hl)          ; | and A
                inc   hl               ; | 
                bit   7, a             ; | test bit 7
                jr    nz, loc_1CE8     ; | advance to next, is a function
                call  write_char       ; | write 1st character
                ld    a, c             ; | get second character
                and   MASK_7BIT        ; | mask high bit
                call  nz, write_char   ; | print if character is not 0
                ld    a, CHAR_DOLLAR   ; | preload $
                bit    7, c            ; | check bit 7 if 2nd char
                call  nz, write_char   ; | print $ (string) if bit 7 set
                ld    a, '='           ; | print a '='
                call  write_char       ; | 
                ld    a, c             ; | get 2nd char
                rla                    ; | put bit 7 into CY
                sbc   a, a             ; | set flag = FF if string
                ld    (fpaccu_mant32), hl ; save address of string descriptor in fpaccu
                push  hl               ; | save var ptr
                jr    nz, loc_1CE4     ; | was a string? yes, skip
                call  mem_to_fpaccu    ; | load numeric value info FPaccu
                call  format_number    ; | format as number
                call  straccu_copy     ; | copy formatted number to straccu
loc_1CE4:       call  straccu_print    ; | print the string
                pop   hl               ; | restore ptr to variable
loc_1CE8:       inc   hl               ; | advance to next position
                inc   hl               ; | 
                inc   hl               ; | 
                inc   hl               ; | 
                inc   hl               ; | 
                inc   hl               ; | 
                jp    loop1CA3         ;-+ loop
loc_1CF0:       pop   hl               ; done
                ret
				
exec_aload:     call  new_memory       ; clear memory
exec_amerge:    ld    hl, (prog_end)   ; load current end of program
                dec   hl
loop1CF9:       call  get_RDR          ;<+ get char from reader
                jr    c, loc_1D25      ; | CY set?, end of file, skip
loc_1CFE:       jr    z, loop1CF9      ;>+ zero byte, ignore
                cp    CHAR_RUBOUT      ; | is RUBOUT marker?
                jr    z, loop1CF9      ;-+ yes ignore
                inc   hl               ; advance ptr
                ld    (hl), a          ; save it
                call  check_memfree    ; validate still memory available
                ld    a, (hl)          ; load char
                sub   CHAR_CR          ; is it a CR?
                jr    nz, loc_1D21     ; no continue
                ld    (hl), a          ; save 0 byte at line end
                inc   hl               ; leave space for following nextlink andlineno
                ld    (hl), a
                inc   hl
                ld    (hl), a
                inc   hl
                ld    (hl), a
                call  get_RDR          ; get char from reader
                jr    c, loc_1D25      ; end of file? skip
                cp    CHAR_LF          ; is it a following LF?
                jr    z, loop1CF9      ; yes, ignore
                or    a                ; set flags
                jr    loc_1CFE         ; and process normally
loc_1D21:       cp    CHAR_CR          ; is it 0d+0d == 1a == CTRL-Z?
                jr    nz, loop1CF9     ; no process normally
; end of file encntred
loc_1D25:       ld    (hl), NULL       ; store terminating 0
                inc   hl
                ld    (hl), CHAR_CTRLZ ; store terminating CTRL-Z
                ld    hl, (prog_end)   ; begin at program end again
loc_1D2D:       push  hl               ; save current line ptr
                ld    a, (hl)          ; get current char
                sub   CHAR_CTRLZ       ; is it CTRL-Z?
                jr    nz, loop1D3C     ; no, skip
                ld    (prompt_flag), a ; yes, finished
                call  init_from_start  ; reinitialize
                jp    print_prompt     ; return to interpreter    loop
loop1D3C:       ld    a, (hl)          ;<+ get current char
                inc   hl               ; | advance
                or    a                ; | set flags
                jr    nz, loop1D3C     ;-+ loop until end of line
; has found a 0 byte                     
loop1D41:       ld    a, (hl)          ;<+ get current char
                inc   hl               ; |
                or    a                ; |
                jr    z, loop1D41      ;-+ loop until non-null byte
                dec   hl               ; point to next line
                ld    (curlineno), hl  ; save position in curlineno
                pop   hl               ; restore start of line
                ld    a, 0FFh          ; set prompt flag = FF
                ld    (prompt_flag), a
                call  skipspace        ; advance in buf to non-empty
                inc   a                ; check char read
                dec   a
                jp    z, loc_4A9       ; char is zero?, clear line
amerge_enter_line:            
                jr    nc, loc_1D5F     ; no lineno found from skipspace?
                push  af               ; save char
                xor    a               ; clear char
                jp    loc_4F1          ; jump into line parser to insert the
                                       ; line HL points to.
                                       ; Note: this, in theory, could overwrite
                                       ; the text that AMERGE read in, but this won't
                                       ; happen, because a tokenized line is always
                                       ; shorter than the plain text line. So it will
                                       ; enter a line and then continue with
                                       ; the next line of RDR.
loc_1D5F:       ld    e, 24            ; error code "missing statement number"
                jp    print_error

get_RDR:        call  READERIN         ; get char from reader
                ret   c                ; return if end of file
                and   MASK_7BIT        ; discard parity bit
                ret

exec_aloadc:    call  new_memory       ; clear memory
exec_amergec:   ld    hl, inputbuf-1   ; point to inputbuf
                ld    b, 0             ; init char per line cntr
loop1D73:       call  get_RDR          ;<+ get char from reader
                jr    c, loc_1DAA      ; | end of file?, exit done
                jr    z, loop1D73      ;>+ ignore zero bytes
                cp    CHAR_RUBOUT      ; | is it a RUBOUT?
                jr    z, loop1D73      ;-+ yes ignore
                cp    CHAR_CTRLZ       ; is it CTRL-Z?
                jr    z, loc_1DAA      ; yes end of file, done
                cp    CHAR_LF          ; is it an LF?
                jr    nz, loc_1D8A     ; no, skip
                inc   b                ; test char count
                dec   b                
                jr    z, loop1D73      ; was empty, ignore
loc_1D8A:       ld    c, a             ; save char
                ld    a, b             ; get char cntr
                cp    0FFh             ; is it 255?
                ld    a, c             ; restore char
                jr    z, loc_1D93      ; yes, ignore more characters
                inc   hl               ; advance bufptr
                inc   b                ; advance char cnt
loc_1D93:       ld    (hl), a          ; put char into buf
                sub   CHAR_CR          ; check if CR
                jr    nz, loop1D73     ; no loop
                ld    (hl), a          ; store 9 byte in buf
                ld    a, 0FEh          ; set prompt flag = FE
                ld    (prompt_flag), a
                ld    hl, inputbuf-1   ; point to inputbuf
                call  nextchar         ; get next char
                inc   a                ; end of line?
                dec   a
                jr    z, exec_amergec  ; yes, loop
                jr    amerge_enter_line ; jump into AMERGE to process line
loc_1DAA:       call  init_from_start  ; clear variables
                jp    print_prompt     ; and return to interpreter loop

; process LOADGO
exec_loadgo:    ld    (fpaccu_mant32), a ; save program name
                call  nextchar         ; get next char
                ld    de, 0FFFFh       ; DE = ffff
                jr    z, loc_1DC9      ; end of command, no start lineno given
                EXPECT CHAR_COMMA      ; expect a comma
                jp    nc, syntax_error
                call  read_lineno      ; get a lineno,
                                       ; not using expression here!
                                       ; only accept a numeric value.
                jp    nz, syntax_error ; invalid, error
loc_1DC9:                
                ld    (curlineno), de  ; store into next line to execute
                ld    a, 0FDh          ; set prompt flag to -3
                ld    (prompt_flag), a
                jp    loc_1807         ; load program

sub_1DD5:       inc   a                ; prompting flag in A
                jp    z, loc_1D2D      ; was it FF?, yes skip
                inc   a                ; was it FE?
                jr    z, exec_amergec  ; yes, continue with AMERGEC
                call  init_from_start  ; clear variables
                xor    a
                ld    (prompt_flag), a ; clear prompt flag
                ld    de, (curlineno)  ; is lineno FFFF?
                ld    a, d
                and   e
                inc   a
                ld    bc, command_done
                push  bc
                ret   z                ; yes, go back into command_done loop
                jp    loc_ADA

; COPY newstart,increment=startrange-endrange
exec_copy:      ret   z                ; exit if end of statement
                jp    nc, illfunc_error ; no number follows? error
                call  read_lineno      ; get lineno
                ld    (curlineno), de  ; save as newstart
                ld    de, 10           ; preload increment of 10
                cp    CHAR_COMMA       ; does a comma follow?
                jr    nz, loc_1E0A     ; no, skip
                call  nextchar         ; get an increment
                call  c, read_lineno
loc_1E0A:       ld    (auto_increment), de ; store in autoincrement
                EXPECT TOKEN_EQUAL     ; expect a '='
                call  get_lineno_range ; get a range (endrange on stack),
                                       ; BC = nextlink of startrange
                pop   de               ; DE = endrange lineno (passed through stack)
                push  bc               ; save nextlink of startrange
                LDHL_BC                ; put as startrange lineno to search for
                                       ; endrange lineno into HL
                exx                    ; alt set
                ld    de, 1            ; preload cntr for counting the lines to move
                                       ; DE' = 1 (increment)
                ld    hl, 0            ; HL' = 0 (initial value)
                exx                    ; std set
                call  find_line_from_current ; find nextlink of endrange
                                       ; and count the number of lines to move in HL'
                jp    nc, illfunc_error ; not found, error
                push  hl               ; save nextlink of endrange
                exx                    ; alt set
                ex    de, hl           ; DE' is count of lines between current position
                                       ; and line to copy
                                       ; ** from here we are no longer interested
                                       ; in data in other set, so no longer marking
                                       ; alt registers and no bothering to switch
                                       ; back set
                ld    bc, (auto_increment) ; BC = increment
                ld    a, b             ; if zero, error
                or    c
                jp    z, syntax_error
                call  umultiply16      ; HL = increment * DE
                                       ; = numbering span to expect
                ld    de, (curlineno)  ; add newstart lineno
                add   hl, de           ; to find the highest new number to expect
                jp    c, subscript_range_error ; overflow, error
                push  hl               ; save as newend lineno
                ld    de, (curlineno)  ; find nextlink of newstart
                call  find_line
                jp    c, illfunc_error ; does the newend lineno exist?
                                       ; yes error
                pop   de               ; DE = newend lineno
                push  bc               ; newstart was not there, but we have
                                       ; a nextlink position where it would go to
                LDHL_BC                ; put into HL
                ld    a, (hl)          ; get nextlink of position where to put
                                       ; newstart to
                inc   hl
                or    (hl)
                jr    z, loc_1E5D      ; if zero, skip (we are at end)
                inc   hl               ; get the lineno of this line into HL
                LDHL_M A
                sbc   hl, de           ; subtract newend lineno
                jp    c, subscript_range_error ; overlapping? error
loc_1E5D:       pop   bc               ; restore ptr of newstart
                pop   hl               ; restore ptr of endrange
                pop   de               ; restore ptr of startrange
                push  hl               ; save ptr of endrange
                sbc   hl, de           ; subtract ptr of startrange
                ex    (sp), hl         ; stack is bytes between endrange andstartrange
                                       ; HL is endrange ptr
                dec   hl               ; decrement
                sbc   hl, bc           ; layout:
                                       ; ....
                                       ; startrange---+--+
                                       ; ...          |  |stack (bytes in range)
                                       ; endrange+-------+
                                       ; ...     |    |
                                       ; ...     |DE  |HL
                                       ; newstart+----+
                                       ; ...
                                       ;
                                       ; HL = bytes from endrange to newstart
                ex    de, hl           ; DE is bytes between endrange andnewstart
                                       ; HL is startrange ptr
                jr    c, loc_1E74      ; newstart is above endrange, i.e.
                                       ; append behind range
                                       ; (as in diagram above)
                sbc   hl, bc           ; bytes from startrange to newstart
                jp    c, illfunc_error ; negative result?
                add   hl, bc           ; undo
                ex    de, hl           ; DE is startrange ptr
                pop   hl               ; restore bytes in range
                push  hl               ; save bytes in range
                add   hl, de           ; HL is startrange+bytes in range
loc_1E74:       ex    (sp), hl         ; insert on stack
                push  hl               ; HL is bytes in range
                ld    d, b             ; DE is newstart ptr
                ld    e, c
                ld    bc, (prog_end)   ; end of program ptr
                add   hl, bc           ; add bytes in range
                push  hl               ; save
                call  make_space       ; DE=start, BC=old end, HL=new end
                                       ; reserve space
                pop   hl               ; set new end of range
                ld    (prog_end), hl
                LDHL_BC                ; HL is old end of program
                pop   bc               ; BC is bytes to copy
                ex    (sp), hl         ; HL is ptr to start of range to copy
                push  de               ; DE is newstart save it
                ldir                   ; copy the lines
                pop   hl               ; restore ptr to nextlink of newstart
                ld    bc, (curlineno)  ; get the newstart lineno
loop1E91:       inc   hl               ;<--+ skip over nextlink
                inc   hl               ;   | 
                LDM_BC                 ;   | put new lineno in line
loop1E96:       inc   hl               ;<+ | advance to end of line
                ld    a, (hl)          ; | | 
                or    a                ; | | 
                jr    nz, loop1E96     ;-+ | loop
                inc   hl               ;   | skip over 0 byte, pointing to 
                                       ;   | nextlink of following line
                pop   de               ;   | restore endrange ptr
                CPHL_DE                ;   | end reached?
                jr    z, loc_1EB0      ;   | yes, we're finished, cleanup
                push  de               ;   | save endrange ptr
                ex    de, hl           ;   | save ptr to line
                ld    hl, (auto_increment) ; get increment
                add   hl, bc           ;   | add current lineno
                LDBC_HL                ;   | put into BC for next round
                ex    de, hl           ;   | restore ptr to line
                jr    loop1E91         ;---+ process next line
loc_1EB0:       call  print_ready_prompt ; print OK
                jp    rebuild_nextchain ; fixup the nextlink chain

exec_exchange:
                call  find_var         ; find first variable
                push  de               ; save addr of 1st var
                push  hl               ; save curlineptr
                ld    hl, numberbuf0   ; move first var into a temporary save
                call  move_to_var
                ld    hl, (end_of_vars) ; get variable end
                ex    (sp), hl         ; stack is end_of_vars
                    ; HL is    curlineptr
                ld    a, (expr_type)   ; save type of variable
                push  af
                EXPECT CHAR_COMMA      ; expect a comma
                call  find_var         ; get second var
                pop   bc               ; DE is addr of 2nd var
                                       ; restore type into B
                ld    a, (expr_type)   ; get type of variable
                xor    b               ; compare with type of 1st var
                rra                    ; result into CY
                jp    c, type_mismatch_error ; error if types don't match
                ex    (sp), hl         ; stack = curlineptr
                                       ; HL = end_of_vars
                ex    de, hl           ; DE = end_of_vars
                                       ; HL = address of 2nd var
                push  hl               ; save it
                ld    hl, (end_of_vars) ; compare end_of_vars with old value
                CPHL_DE                 was second variable newly declared?
                jp    nz, illfunc_error ; yes, error
                pop   de               ; DE = addr of 2nd var
                pop   hl               ; HL = curlineptr
                ex    (sp), hl         ; stack is curlineptr
                                       ; HL is addr of 1st var
                push  de               ; save 2nd var
                call  move_to_var      ; move 1st var -> 2nd var
                pop   hl               ; restore 2nd var
                ld    de, numberbuf0   ; move scratchpad to 2nd var
                call  move_to_var
                pop   hl               ; restore curlineptr
                ret

exec_kill:      ld    a, 1             ; set subscript flag to 1, i.e. 
                                       ; to search for arrays without subscript
                ld    (subscript_flag), a
                jp    find_var

kill_array:                            ; HL points to #indices in array
                push  hl               ; DE is total size of array
                add   hl, de           ; calculate end of array
                ex    de, hl           ; save it in DE
                ld    hl, (end_arrays) ; get end_array ptr
                or    a                ; set CY
                sbc   hl, de           ; calculate size of range to move
                ex    (sp), hl         ; stack = size to move
                                       ; HL = ptr to indices
                pop   bc               ; BC = move size
                ex    de, hl           ; HL = ptr to new end of arrays
                                       ; DE = ptr to start of array
                dec   de               ; adjust (total size and variable name)
                dec   de
                dec   de
                dec   de
                jr    z, loc_1F15      ; unless empty, move data
                ldir
loc_1F15:       ld    (end_arrays), de ; store new end of array
loc_1F19:       ld    (subscript_flag), a ; (A was 0) clear subscript flag
                pop   hl               ; restore curlineptr
                ld    a, (hl)          ; get next char
                cp    CHAR_COMMA       ; was comma?
                ret   nz               ; no, exit
                call  nextchar         ; yes, get next char
                jr    exec_kill        ; and continue in kill
exec_call:      ret   z                ; no arguments follow? exit
                ld    (curlineno), sp  ; save stack to curlineno
                push  hl               ; save curlineptr
                ld    de, hlrestore    ; push HL restore to return stack
                push  de
                call  expression_u16   ; get address expression
                ld    c, 0             ; count number of arguments
loop1F35:       push  de               ;<+ push call address on stack
                call  skipspace        ; | advance
                jr    z, call2         ; | end of statement? done with arguments
                EXPECT CHAR_COMMA      ; | expect a comma
                inc   c                ; | increment argument count
                push  bc               ; | save argument count
                call  expression_u16   ; | get argument
                pop   bc               ; | 
                ex    de, hl           ; | DE is curlineptr
                                       ; | HL is argument
                ex    (sp), hl         ; | stack is argument
                                       ; | HL is call address
                ex    de, hl           ; | DE is call address
                                       ; | HL is curlineptr
                jr    loop1F35         ;-+ loop over all arguments

call2:          push  de               ; push caller address
                ex    de, hl           ; DE is curlineptr
                                       ; HL is caller address
                ld    hl, (curlineno)  ; get initial stack ptr
                                       ; is location where call address
                                       ; was pushed initially
                dec   hl               ; put curlineptr in it
                ld    (hl), d
                dec   hl
                ld    (hl), e
                dec   hl               ; point to HL restore routine
                dec   hl
                ret                    ; return to call address

; calling convention:
                    ; C contains number of 16bit arguments
                    ; Stack    -> argumentN
                    ;       argumentN-1
                    ;       ...
                    ;       argument1
                    ; HL contains return address
                    ; return from caller via JP (HL)
                    ;
                    ; will jump on HLrestore which will
                    ; restore the curlineptr andthen exit
                    ; int interpreter loop
                    ;
hlrestore:      pop   hl               ; pop pending HL value (curlineptr?) from stack
                ret

; process PRECISION
exec_precision: ld    a, 0             ; get precision 0
                call  nz, expression_u8_ae ; if argument, get expression
                ret   nz               ; exit if more arguments
                cp    0Bh              ; is it exactly 11?, then set precision  0
                jr    z, exec_precision
                jp    nc, illfunc_error ; is it larger? error
                ld    (precision), a   ; save precision value
                ret

; process PEEK()
math_peek:      call  fpaccu_to_u16    ; get 16 bit argument in DE
                ld    a, (de)          ; get value from memory at DE
                jp    uA_to_fpaccu     ; put result

; process POKE command
exec_poke:      call  expression_u16   ; get a 16 bit expression in DE
                push  de               ; save address
                EXPECT CHAR_COMMA      ; expect a comma
                call  expression_u8_ae ; get 8 bit expression
                pop   de               ; restore address
                ld    (de), a          ; save data
                ret

; addconstant 0.5
add_0_5:        ld    hl, const0_5     ; constant 0.5
load_and_add_fpaccu:
                call  load_fpreg
                jr    add_fpreg_fpaccu

load_fpreg_and_subtr:
                call  load_fpreg
                jr    subtr_fpreg_fpaccu

pop_fpreg_and_sub:
                POP_FPREG

; subtract fpreg - fpaccu => fpaccu
subtr_fpreg_fpaccu:
                call  fpaccu_changesign ; change sign of fpaccu

; add fpaccu andFPreg, result in fpaccu
add_fpreg_fpaccu:
                ld    a, b             ; get fpreg exponent
                or    a
                ret   z                ; if zero, then done
                ld    a, (fpaccu_exp)  ; get fpaccu exponent
                or    a                ; is zero?
                jp    z, store_fpaccu  ; yes, just store FPreg into fpaccu
                sub   b                ; subtract fpreg exp from fpaccu exp
                jr    nc, loc_1FB2
                neg
                exx                    ; save fpreg temporarily
                                       ; FPREG in alternative regs
                push  ix               ; including ix
                call  fpaccu_to_fpreg  ; copy fpaccu to fpreg
                exx                    ; restore fpreg
                                       ; fpaccu in alternative regs
                ex    (sp), ix         ; including ix
                call  store_fpaccu     ; store in fpaccu
                exx                    ; fpaccu in these registers
                pop   ix
loc_1FB2:       cp    29h              ; do exponents differ too much?
                ret   nc               ; yes, ignore (adding a large number
                                       ; and a very small one) and exit
                push  af               ; save difference of exponent
                call  fpaccu_restoresign ; restore the sign of mantissa
                ld    h, a             ; save sign in H
                pop   af               ; restore shift count
                call  fpreg_shiftmant  ; adjust fpreg to same exponent as fpaccu
                or    h                ; was positive sign?
                ld    hl, fpaccu_mant32 ; load address of fpaccu
                jp    p, subtr_mantissa ; go subtract mantissas
                call  add_mantissas    ; add mantissas
                jr    nc, round_store_fpreg ; overflow?
                inc   hl               ; yes
                inc   (hl)             ; increment exponent
                jp    z, e_overflow    ; too bad, exponent overflow, error
                ld    l, 1
                call  mant_shiftright1 ; shift mantissa 1 bit
                                       ; (because exponent was incremented)
                jr    round_store_fpreg ; round fpreg and store in fpaccu
subtr_mantissa: xor   a                ; subtract adjusted mantissas
                sub   b
                ld    b, a
                ld    a, (hl)
                sbc   a, e
                ld    e, a
                inc   hl
                ld    a, (hl)
                sbc   a, d
                ld    d, a
                inc   hl
                ld    a, (hl)
                sbc   a, xl
                ld    xl, a
                inc   hl
                ld    a, (hl)
                sbc   a, xh
                ld    xh, a
                inc   hl
                ld    a, (hl)
                sbc   a, c
                ld    c, a
				
; normalize and round a number in FPreg, and store in fpaccu
; if CY, complement mantissa
; mant6-mant1 = C,XH,XL,D,H,L
; exponent = B

fpreg_normalize:            
                call  c, fpreg_complement ; complement FPaccu in registers
loc_1FF3:       ld    l, b             ; copy BE -> HL
                ld    h, e
                xor   a                ; clear lower mantissa
                ld    b, a
                ld    a, c             ; get highest mantissa
                or    a
loop1FF9:       jr    nz, loc_2022     ;<+ not zero, shift single
                ld    c, xh            ; | high mantissa is 0, shift mantissa a byte
                                       ; | XH -> C
                ld    a, xl            ; | XL -> XH
                ld    xh, a            ; | 
                ld    xl, d            ; | D -> XL
                xor    a               ; | 
                ld    d, h             ; | H -> D
                ld    h, l             ; | L -> H
                ld    l, a             ; | 0 -> L
                ld    a, b             ; | get exponent
                sub   8                ; | subtract 8
                cp    0D0h             ; | 
                jr    nz, loop1FF9     ;-+ not yet zero? loop

; load zero in fpaccu
fpaccu_zero:    xor   a                ; accu is zero
loc_200F:       ld    (fpaccu_exp), a
                ret

; part of normalizing FPreg:
; B = binary exponent
; C = high mantissa (6)
; IXH =    mantissa (5)
; IXL =    mantissa (4)
; D = mantissa (3)
; H = mantissa (2)
; L = lowest mantissa (1)
loop2013:       dec   b                ;<+ decrement exponent
                add   hl, hl           ; | shift HL left
                rl    d                ; | rotate into D
                ex    af, af'          ; | save flags
                add   ix, ix           ; | shift IX left
                ex    af, af'          ; | restore flags, CY from IX is in AF'
                jr    nc, loc_201F     ; | no CY from D? skip
                inc   ix               ; | move CY from D into IX
loc_201F:       ex    af, af'          ; | get CY from IX
                rl    c                ; | rotate into C
loc_2022:       jp    p, loop2013      ;-+ highest mantissa still positive?, yes skip
                ld    a, b             ; get exponent
                ld    e, h             ; save HL -> EB
                ld    b, l
                or    a                ; exponent zero?
                jr    z, round_store_fpreg ; yes, skip
                ld    hl, fpaccu_exp   ; get binary shift
                add   a, (hl)          ; addit to exponent
                ld    (hl), a          ; store it
                jr    nc, fpaccu_zero  ; underflow?, mark as zero
                ret   z                ; exit zero
round_store_fpreg:                     ; get lowest mantissa
                ld    a, b
loc_2034:       ld    hl, fpaccu_exp   ; get shift
                rlca                   ; shift bit 6 into sign
                call  m, mant_inc r    ; if negative, round FPreg up
                ld    b, (hl)          ; B = adjustment
                inc   hl               ; point to sign mantissa
                ld    a, (hl)          ; mask out sign bit
                and   80h
                xor    c               ; merge into high mantissa (suppressed MSB)
                ld    c, a
                jp    store_fpaccu     ; store it in accu1

mant_inc r:     inc   e                ; increment mantissa 2
                ret   nz               ; exit unless carry
                inc   d                ; increment mantissa 3
                ret   nz
                inc   xl               ; increment mantissa 4
                ret   nz
                inc   xh
                ret   nz               ; exit unless carry
                inc   c                ; increment mantissa 6
                ret   nz
                ld    c, 80h           ; highest mantissa became 0
                                       ; make 0x80 again
                inc   (hl)             ; needs adjustment again
                ret   nz               ; oops, this also overflowed?
e_overflow:     ld    e, 6             ; error code "arithmetic overflow"
                jp    print_error

add_mantissas:  ld    a, (hl)          ; add adjusted mantissas
                add   a, e
                ld    e, a
                inc   hl
                ld    a, (hl)
                adc   a, d
                ld    d, a
                inc   hl
                ld    a, (hl)
                adc   a, xl
                ld    xl, a
                inc   hl
                ld    a, (hl)
                adc   a, xh
                ld    xh, a
                inc   hl
                ld    a, (hl)
                adc   a, c
                ld    c, a
                ret

fpreg_complement:
                ld    hl, fpaccu_mantsign
                ld    a, (hl)          ; complement sign of mantissa
                cpl
                ld    (hl), a
                xor    a
                ld    l, a             ; clear HL
                ld    h, a
                sub   b                ; complement B
                ld    b, a
                ld    a, l             ; A = 0
                sbc   hl, de           ; complement DE
                ex    de, hl
                ld    l, a             ; L = 0
                sbc   a, xl            ; complement XL
                ld    xl, a
                ld    a, l             ; A = 0
                sbc   a, xh            ; complement XH
                ld    xh, a
                ld    a, l             ; A = 0
                sbc   a, c             ; complement C
                ld    c, a
                ret

fpreg_shiftmant:
                ld    b, 0             ; load zero
mant_shift8:    sub   8                ; subtract 8 from exponent
                jr    c, loc_20A5      ; borrow, skip
                ld    b, e             ; E -> B
                ld    e, d             ; D -> E
                ld    d, xl            ; XL -> D
                ex    af, af'
                ld    a, xh
                ld    xl, a            ; XH -> XL
                ex    af, af'
                ld    xh, c            ; C -> XH
                ld    c, 0             ; 0 -> C
                jr    mant_shift8      ; loop
loc_20A5:       add   a, 9             ; correct exponent again
                ld    l, a             ; save exp in l
mant_shift1:    xor   a                ; clear    a
                dec   l                ; decrement exp
                ret   z                ; exit if zero
				ld    a, c             ; get mant6
mant_shiftright1:            
                rra
				ld    c,a              ; shift right C
                ld    a, xh            ; shift right XH
                rra
                ld    xh, a            ; A -> XH
loc_20B3:       ld    a, xl            ; shift right XL
                rra
                ld    xl, a
                rr    d                ; shift right D
                rr    e                ; shift right E
                rr    b                ; shift right B
                jr    mant_shift1      ; loop

const1:         db    0, 0, 0, 0, 0, 81h ; 1.0
LOG_poly_tbl:   db    6
                db    23h, 85h, 0ACh, 0C3h, 11h, 7Fh ; 0.28469600
                db    53h, 0CBh, 9Eh, 0B7h, 23h, 7Fh ; 0.31976029
                db    0CCh, 0FEh, 0A6h, 0Dh, 53h, 7Fh ; 0.41221353
                db    0CBh, 5Ch, 60h, 8Bh, 13h, 80h ; 0.57634547
                db    0DDh, 0E3h, 4Eh, 38h, 76h, 80h ; 0.96179669
                db    5Ch, 29h, 3Bh, 0AAh, 38h, 82h ; 2.88539008

math_log:       call  fpaccu_sgn       ; get sign
                or    a
                jp    pe, illfunc_error ; negative? yes error
                ld    hl, fpaccu_exp
                ld    a, (hl)          ; get exponent
                FPREG_CONST 8035h, 4F3h, 33FAh ; constant 1/SQR(2)
                sub   b                ; normalize exponent
                                       ; reuse 0x80 from constant
                push  af               ; save it for later
                ld    (hl), b          ; put it into fpaccu
                PUSH_FPREG             ; save constant
                call  add_fpreg_fpaccu ; add constant
                POP_FPREG
                inc   b                ; convert constant to SQR(2)
                                       ; 2*(1/SQR(2)) == SQR(2)
                call  div_fpreg_fpaccu ; divide SQR(2) / argument
                ld    hl, const1
                call  load_fpreg_and_subtr ; subtract 1.0 - argument
                ld    hl, LOG_poly_tbl ; load coefficient table
                call  fpaccu_polyeval_sqr ; evaluate polynomial
                FPREG_CONST 8080h,0,0  ; add -0.5
                call  add_fpreg_fpaccu
                pop   af
                call  fpaccu_add_u8    ; adjust exponent
                FPREG_CONST 8031h,7217h,0F7D2 ; constant LOG(2)
                jr    multiply_fpreg_fpaccu ; multiply with it

; pop fpreg from stack and multiply with fpaccu
pop_fpreg_and_mult:
                POP_FPREG              ; pop fpreg from stack
; multiply fpreg * fpaccu => fpaccu
multiply_fpreg_fpaccu:
                call  fpaccu_sgn       ; get sign of fpaccu
                ret   z                ; is zero?, exit (result is zero)
                ld    l, 0
                call  mult_div_calcexponent ; calculate new exponent
                ld    a, c             ; get mantissa6
                push  de               ; push mant32 fpreg
                exx                    ; alternative registers
                ld    c, a             ; mant6 -> C'
                pop   de               ; mant32 -> DE'
                push  ix               ; mant54 -> HL'
                pop   hl
                exx                    ; back to std set
                ld    bc, 0            ; clear BC (mant61)
                ld    d, b             ; clear DE (mant32)
                ld    e, b
                ld    ix, 0            ; clear IX (mant54)
                ld    hl, loc_1FF3     ; call normalize on return
                push  hl
                ld    hl, loc_2168     ; call restore altregs on return
                push  hl               ; four times
                push  hl               ; will calculate partial
                                       ; multiplication for 8 bits
                push  hl
                push  hl
                ld    hl, fpaccu_mant32 ; get fpaccu
loc_2168:       ld    a, (hl)          ; get factor byte
                inc   hl               ; advance
                or    a                ; is zero?
                jr    nz, loc_217B     ; no, must do bitwise partial multiply
                ld    b, e             ; shift 8 bits
                                       ; mant2 -> mant1
                ld    e, d             ; mant3 -> mant2
                ld    d, xl            ; mant4 -> mant3
                ex    af, af'
                ld    a, xh            ; mant5 -> mant4
                ld    xl, a
                ex    af, af'
                ld    xh, c            ; mant6 -> mant5
                ld    c, a             ; 0 -> mant6
                ret
loc_217B:       push  hl               ; save ptr to fpaccu
                ex    de, hl           ; mant32 -> HL
                ld    e, 8             ; cntr for 8 bits
loop217F:       rra                    ;<+ next bit of factor
                ld    d, a             ; | save factor
                ld    a, c             ; | mant6 -> C
                jr    nc, loc_2196     ; | bit is zero, only shift
                push  hl               ; | push mant32
                exx                    ; | alternative set
                ex    (sp), hl         ; | stack is mant54', HL' is mant32
                add   hl, de           ; | DE is mant32'
                                       ; | mant32 + mant32' -> HL'
                ex    (sp), hl         ; | HL' is mant54', stack is mant32
                ex    de, hl           ; | HL' is mant32', DE' is mant54'
                push  ix               ; | push mant54
                ex    (sp), hl         ; | stack is mant32', HL' is mant54
                adc   hl, de           ; | CY + mant54' + mant54 -> HL'
                ex    (sp), hl         ; | stack is mant54, HL is mant32'
                pop   ix               ; | restore mant54
                ex    de, hl           ; | HL' is mant54', DE is mant32'
                adc   a, c             ; | CY + mant6' + mant6 -> A
                exx                    ; | std set
                pop   hl               ; | restore mant32
loc_2196:       rra                    ; | shift right mant6
                ld    c, a             ; | 
                ld    a, xh            ; | shift right mant5
                rra                    ; | 
                ld    xh, a            ; | 
                ld    a, xl            ; | shift right mant4
                rra                    ; | 
                ld    xl, a            ; | 
                rr    h                ; | shift right mant3
                rr    l                ; | shift right mant2
                rr    b                ; | shift right mant1
                dec   e                ; | decrement bit count
                ld    a, d             ; | restore factor
                jr    nz, loop217F     ;-+ not yet done? loop
                ex    de, hl           ; mant32 -> DE
loc_21AD:       pop   hl               ; restore ptr to fpaccu
                ret

; divide fpaccu by 10
fpaccu_div10:   call  push_fpaccu      ; push fpaccu
                FPREG_CONST 8420h,0,0  ; constant 10.0
                call  store_fpaccu     ; put in fpaccu

; popfpreg from stack anddivide by fpaccu
pop_fpreg_and_div:
                POP_FPREG
; divide fpreg / fpaccu => fpaccu
div_fpreg_fpaccu:
                call  fpaccu_sgn       ; check fpaccu is 0?
                jp    z, div_by_zero_error ; yes division by zero error
                ld    l, 0FFh          ; for complement of exponent
                call  mult_div_calcexponent ; calculate exponent
                push  iy               ; save IY
                inc   (hl)             ; adjust exponent (2's complement)
                inc   (hl)
                dec   hl
                push  hl               ; ptr to fpaccu mant6
                exx                    ; alt set
                pop   hl               ; get ptr
                ld    c, (hl)          ; mant6' -> C'
                dec   hl
                ld    d, (hl)          ; mant54' -> DE'
                dec   hl
                ld    e, (hl)
                dec   hl
                ld    a, (hl)          ; mant32' -> HL'
                dec   hl
                ld    l, (hl)
                ld    h, a
                ex    de, hl           ; mant54' -> HL'
                                       ; mant32' -> DE'
                exx                    ; std set
                ld    b, c             ; mant6 -> B
                ex    de, hl           ; mant32 -> HL
                push  ix               ; mant54 -> IY
                pop   iy
                xor    a               ; extent registers
                ld    c, a
                ld    d, a
                ld    e, a
                ld    ix, 0
                ld    (div_ovf), a
loop21F3:       push  hl               ;<+ push mant6...mant2
                push  iy               ; | 
                push  bc               ; | 
                push  hl               ; | push mant32
                ld    a, b             ; | mant6 -> A
                exx                    ; | alt set
                ex    (sp), hl         ; | stack is mant54', HL' is mant32
                or    a                ; | set CY
                sbc   hl, de           ; | mant32 - mant32' -> HL'
                ex    (sp), hl         ; | stack is mant32, HL' is mant54'
                ex    de, hl           ; | DE' is mant54', HL' is mant32'
                push  iy               ; | push mant54
                ex    (sp), hl         ; | stack is mant32', HL' is mant54
                sbc   hl, de           ; | mant54 - mant54' -> HL'
                ex    (sp), hl         ; | stack is mant54, HL' is mant32'
                pop   iy               ; | restore mant54
                ex    de, hl           ; | DE' is mant32', HL' is mant54'
                sbc   a, c             ; | C' is mant6
                                       ; | mant6 - mant6' -> A
                exx                    ; | std set
                pop   hl               ; | restore mant32
                ld    b, a             ; | store mant6
                ld    a, (div_ovf)     ; | get overflow?
                sbc   a, 0             ; | subtract remainying CY
                ccf                    ; | complement it
                jr    nc, loc_221E     ; | this failed, undo subtract
                ld    (div_ovf), a     ; | store overflow
                pop   af               ; | discard mant6...2
                pop   af               ; | 
                pop   af               ; | 
                scf                    ; | set CY
                jr    loc_2222         ; | skip
loc_221E:       pop   bc               ; | restore old mantissa
                pop   iy               ; | 
                pop   hl               ; | CY is 0, coming from here
loc_2222:       inc   c                ; | get sign of mant6
                dec   c                ; | 
                rra                    ; | set CY into bit7
                jp    m, loc_225E      ; | are we done?, yes, skip
                rla                    ; | shift in the CY bit
                rl    e                ; | shift mant32 left
                rl    d                ; | 
                ex    af, af'          ; | save flags
                add   ix, ix           ; | shift mant54 left
                ex    af, af'          ; | save flags
                jr    nc, loc_2235     ; | adjust for CY in
                inc   ix               ; | 
loc_2235:       ex    af, af'          ; | save flags
                rl    c                ; | shift left mant6
                add   hl, hl           ; | shift left extent HL
                ex    af, af'          ; | 
                add   iy, iy           ; | shift left extent IY
                ex    af, af'          ; | restore flags
                jr    nc, loc_2241     ; | adjust for CY
                inc   iy               ; | 
loc_2241:       ex    af, af'          ; | 
                rl    b                ; | shift left B
                ld    a, (div_ovf)     ; | shift left extent
                rla                    ; |
                ld    (div_ovf), a     ; |
                ld    a, c             ; | still bits left to shift?
                or    d                ; | 
                or    e                ; | 
                or    xh               ; | 
                or    xl               ; | 
                jr    nz, loc_21F3     ;-+ yes, loop
                push  hl               ; save HL
                ld    hl, fpaccu_exp   ; get exponent
                dec   (hl)             ; decrement (left shift == exp-1)
                pop   hl               ; restore HL
                jr    nz, loop21F3     ; not zero?
                jr    e_overflow1      ; exponent overflow
loc_225E:       pop   iy               ; restore IY
                jp    loc_2034         ; round and store result

mult_div_calcexponent:
                ld    a, b             ; get fpreg exponent
                or    a
                jr    z, loc_2287      ; is zero? yes, result is zero
                ld    a, l             ; multiply: l=0, divide: l=ff
                ld    hl, fpaccu_exp   ; get exponent
                xor    (hl)            ; do 1's complement for division
                add   a, b             ; add exponents
                ld    b, a             ; resulting exponent in fpreg
                rra                    ; test overflow (bit 6 shift into bit 7)
                xor    b               ; check overflow
                ld    a, b             ; get resulting exponent
                jp    p, loc_2286      ; if positive, skip
                add   a, 80h           ; adjust exponent again
                ld    (hl), a          ; store as new exponent in fpaccu
                jp    z, loc_21AD      ; exponent is 0, exit
                call  fpaccu_restoresign ; restore sign of mantissa
                ld    (hl), a          ; store sign
                dec   hl
                ret
loc_2280:       call  fpaccu_sgn       ; get sign of fpaccu
                cpl                    ; complement
                or    a                ; set flags (redundant, because CPL
                                       ; already sets sign)
                db    21h              ; LD HL, xxxx to skip next 2 instructions
loc_2286:       or    a                ;** set flags
loc_2287:       pop   hl               ;** discard caller
                jp    p, fpaccu_zero   ; if positive, return zero
e_overflow1:    jp    e_overflow       ; overflow error

fpaccu_mult10:  call  fpaccu_to_fpreg  ; copy fpaccu into registers
                ld     a, b            ; get exponent
                or    a
                ret   z                ; is zero? yes exit
                add   a, 2             ; multiply fpreg with 4
                jr    c, e_overflow1   ; check for overflow
                ld    b, a             ; store fpreg exponent
                call  add_fpreg_fpaccu ; add 4*X + X -> 5*X
                ld    hl, fpaccu_exp   ; get fpaccu exponent
                inc   (hl)             ; multiply with 2
                ret   nz               ; not zero? okay
                jr    e_overflow1      ; overflow error

; process SGN()
math_sgn:       call  fpaccu_sgn       ; get sign of FPACCU in    A

; convert signed byte in A into fpaccu
s8_to_fp:       ld    b, 88h           ; preload exponent with 8
                ld    de, 0            ; low mantissa = 0

; entry point used to also convert signed 16 bit
; and unsigned 16 bit numbers in A,D,E
s24_to_fp:      ld    hl, fpaccu_exp   ; address of FPaccu
                ld    c, a             ; put sign into C
                push  de               ; put upper mantissa in IX
                pop   ix
                ld    de, 0            ; lower mantissa = 0
                ld    (hl), b          ; store exponent
                ld    b, 0             ; clear B
                inc   hl
                ld    (hl), 80h
                rla
                jp    fpreg_normalize

; return SGN(fpaccu) in A (ff,0,1)
fpaccu_sgn:     ld    a, (fpaccu_exp)  ; is exponent 0?
                or    a
                ret   z                ; yes, return A = 0
                ld    a, (fpaccu_mant6) ; get highest mantissa
                db    0FEh             ; CP xx to skip following instruction
loc_22C8:       cpl                    ;** skipped
                rla                    ; sign of mantissa into CY
loc_22CA:       sbc   a, a             ; A = FF if negative
                ret   nz               ;  exit
                inc   a                ; A = 1, if positive
                ret

; process ABS()
math_abs:       call  fpaccu_sgn       ; get sign of fpaccu
                ret   p                ; is already positive? yes exit

; toggle sign in fpaccu
fpaccu_changesign:
                ld    hl, fpaccu_mant6 ; get sign bit of mantissa
                ld    a, (hl)
                xor    80h             ; complement
                ld    (hl), a
                ret

; push fpaccu on stack
push_fpaccu:    ex    de, hl           ; save old HL

; push fpaccu on stack, exchange DE,HL
push_fpaccu_ex: ld    hl, (fpaccu_mant32)
                ex    (sp), hl
                push  hl
                ld    hl, (fpaccu_mant54)
                ex    (sp), hl
                push  hl
                ld    hl, (fpaccu_mant6)
                ex    (sp), hl
                push  hl
                ex    de, hl        ; restore old HL
                ret

; copy value in memory at HL into fpaccu
mem_to_fpaccu:  ld    de, fpaccu_mant32
                ld    bc, 6
                ldir
                ret

store_fpaccu:   ld    (fpaccu_mant32), de
                ld    (fpaccu_mant54), ix
                ld    (fpaccu_mant6), bc
                ret

fpaccu_to_fpreg:
                ld    hl, fpaccu_mant32 ; get mantissa32
load_fpreg:     LDDE_M                 ; load mant32 into DE
                inc   hl
                ld    c, (hl)          ; load mant4 into IXL
                ld    xl, c
                inc   hl
                ld    c, (hl)          ; load mant5 into IXH
                ld    xh, c
                inc   hl
                LDBC_M                 ; load mant6 into C
                                       ; load exp into B
                inc   hl
                ret

; store fpaccu into memory, pointed to by HL
fpaccu_to_mem:  ld    de, fpaccu_mant32

; move 6 byte value at addr in DE to  addr in HL
move_to_var:    ld    bc, 6
                ex    de, hl
                ldir
                ex    de, hl
                ret

; restore sign of mantissa, return sign    in A
fpaccu_restoresign:
                ld    hl, fpaccu_mant6 ; get mantissa with suppressed leading 1
                ld    a, (hl)          ; A = S6543210
                rlca                   ; A = 6543210S, CY=S
                scf                    ; CY=H
                rra                    ; A = H6543210, CY=S
                ld    (hl), a          ; store correct mantissa in fpaccu_mant6
                ccf                    ; CY=-S
                rra                    ; A = -S7654321, CY=0
                inc   hl
                inc   hl               ; point to separate sign bit
                ld    (hl), a          ; save A=-S6543210
                ld    a, c             ; A=S6543210
                rlca                   ; A = 6543210S, CY=S
                scf                    ; CY=H
                rra                    ; A = H6543210, CY=S
                ld    c, a             ; store correct mant6 in C
                rra                    ; A = SH654321, CY=0
                xor   (hl)             ; A = Sxxxxxxx
                ret

; compare a number in fpaccu with B,C,IXH,IXL,D,E
; return ff,0,1  n A
fpaccu_compare: ld    a, b             ; get exponent of number in regs
                or    a
                jr    z, fpaccu_sgn    ; if zero, return zero in A
                call  fpaccu_sgn       ; set sign of fpaccu in Z
                ld    a, c             ; get high mantissa
                jr    z, loc_22C8      ; if zero, go complement
                ld    hl, fpaccu_mant6 ; get fpaccu mantissa
                xor   (hl)             ; complement with number in regs
                ld    a, c             ; get high mantissa again
                jp    m, loc_22C8      ; return result sign
                call  fp_compare1      ; compare fpaccu
                rra                    ; build correct compare sign
                xor   c
                jp    loc_22C8         ; exit compare status

fp_compare1:    inc   hl               ; point to fpexp
                ld    a, b             ; get exponent
                cp    (hl)             ; compare exponents
                ret   nz               ; exit if not same
                dec   hl               ; point to mant6
                ld    a, c             ; compare mantissa
                cp    (hl)
                ret   nz               ; exit not same
                dec   hl               ; compare mant5
                ld    a, xh
                cp    (hl)
                ret   nz               ; exit not same
                dec   hl               ; compare mant4
                ld    a, xl
                cp    (hl)
                ret   nz               ; exit not same
                dec   hl
                ld    a, d
                cp    (hl)             ; compare mant3
                ret   nz               ; exit not same
                dec   hl
                ld    a, e
                sub   (hl)             ; compare mant2
                ret   nz               ; exit not same
                pop   hl               ; leave subroutine level of fpaccu_compare
                                       ; directly
                ret                    ; return to fpaccu_compare

; load next 4 bytes at HL into DE,BC
restore_de_bc:  LDDE_M                 ; load 4 bytes into DE, BC
                inc   hl
                LDBC_M
                inc   hl
                ret

fpreg_fix:      ld    b, a             ; store A into FPreg
                ld    c, a
                ld    d, a
                ld    e, a
                ld    xh, a
                ld    xl, a
                or    a                ; was it zero?, yes, exit
                ret   z
                push  hl               ; save HL
                call  fpaccu_to_fpreg  ; load current fpaccu
                call  fpaccu_restoresign
                xor    (hl)            ; complement sign
                ld    h, a             ; save in H
                jp    p, loc_239B      ; positive? skip, else decrement for
                                       ; 2's complement
                dec   de               ; decrement mantissa
                ld    a, d             ; is borrow?
                and   e
                inc   a
                jr    nz, loc_239B     ; no skip
                dec   ix               ; decrement next part of mantissa
                ld    a, xh
                and   xl               ; more borrow?
                inc   a
                jr    nz, loc_239B
                dec   c                ; decrement highest mantissa part
loc_239B:       ld    a, 0A8h          ; exponent for overflow
                sub   b
                call  fpreg_shiftmant  ; do 8 bit shifts
                ld    a, h             ; restore mantissa sign
                rla                    ; move into CY
                call  c, mant_inc r    ; increment for 2s complement
                ld    b, 0             ; mant1
                call  c, fpreg_complement ; complement mantissa
                pop   hl               ; restore HL
                ret

; process INT()
math_int:       ld    hl, fpaccu_exp   ; load exponent
                ld    a, (hl)
                cp    0A8h             ; exponent more than 2^40?
                                       ; no fractional bits available
                ld    a, (fpaccu_mant32)
                ret   nc               ; exit
                ld    a, (hl)          ; clip fractional bits
                call  fpreg_fix
                ld    (hl), 0A8h
                ld    a, b
                push  af
                ld    a, c
                rla
                call  fpreg_normalize  ; normalize number again
                pop   af
                ret

; HL = BC * DE
umultiply16:    ld    hl, 0            ; clear HL
                ld    a, b             ; is index 0?
                or    c
                ret   z                ; return
                ld    a, 11h           ; 17 rounds
loop23CE:       dec   a                ;<+
                ret   z                ; | 
                add   hl, hl           ; | HL * 2
                jr    c, loc_23DB      ; | overflow?, error
                ex    de, hl           ; | get sizeof element
                add   hl, hl           ; | DE * 2
                ex    de, hl           ; | 
                jr    nc, loop23CE     ;>+ overflow?
                add   hl, bc           ; | add index
                jr    nc, loop23CE     ;-+
loc_23DB:       jp    subscript_range_error

; HL=buf, read a 16 bit number
; A= current char read
; returns packed number    in fpaccu
parse_number_fpaccu:
                cp    CHAR_AMP         ; potentially a hex number?
                jp    z, expr_hex
expr_numeric:   cp    CHAR_MINUS       ; negative sign?
                push  af               ; save it
                jr    z, loc_23ED      ; skip
                cp    CHAR_PLUS        ; positive sign?
                jr    z, loc_23ED      ; yes
                dec   hl               ; go back to current char, should be a digit
loc_23ED:       call  fpaccu_zero      ; A = 0
                ld    b, a             ; B = 0
                ld    d, a             ; D = 0
                ld    e, a             ; E = 0
                cpl
                ld    c, a             ; C = FF
loop23F5:       call  nextchar         ;<+ get next from buf
                jr    c, do_mantissapart ; is number? process
                cp    CHAR_PERIOD      ; | is a period?
                jr    z, do_period     ; | yes, process period
                cp    'E'              ; | is exponent?
                jr    nz, number_done  ; | no skip
                call  nextchar         ; | get next char
                dec   d                ; | D = exponent sign
                cp    TOKEN_MINUS      ; | is '-' as token?
                jr    z, do_exponent   ; | yes, advance
                cp    CHAR_MINUS       ; | is '-' as ASCII?
                jr    z, do_exponent   ; | yes advance
                inc   d                ; | positive exponent sign
                cp    CHAR_PLUS        ; | is positive?
                jr    z, do_exponent   ; | yes advance
                cp    TOKEN_PLUS       ; | '+' sign as token?
                jr    z, do_exponent   ; | yes, advance
                dec   hl               ; | no sign found, reread this char
; process exponent                       | 
do_exponent:    call  nextchar         ; | get char of exponent
                jr    c, add_expdigit  ; | is number?, process
                inc   d                ; | exponent sign: was negative?
                jr    nz, number_done  ; | no, done with number
                xor    a               ; | complement exponent
                sub   e                ; | 
                ld    e, a             ; | E = exponent
                inc   c                ; | disable processing part after decimal point
; process mantissa after decimal point   |
; now count each fractional digit (C = 0) in B
; this is the decrement    value for exponent
do_period:      inc   c                ; | was there already a decimal point?
                jr    z, loc_23F5      ;>+ no, loop to read more digits
; has complete number                  ; |
number_done:    push  hl               ; | save curlineptr
                ld    a, e             ; | get exponent
                sub   b                ; | subtract fractional digits
                jp    p, loc_2439      ; | positive? skip
                call  push_fpaccu      ; | push fpaccu
                neg                    ; | make positive
                ld    hl, const1       ; | load constant 1 into fpaccu
                call  mem_to_fpaccu    ; | 
                scf                    ; | set CY
loc_2439:       push  af               ; | save CY and exponent
loop243A:       call  mult10_and_dec   ;<|-+ multiply by 10 and decrement exponent cntr
                jr    nz, loop243A     ;---+ loop until count is zero
                pop   af               ; | restore C flag (negative)
                jr    nc, loc_2449     ; | was positive
                POP_FPREG              ; | pop FPaccu
                call  div_fpreg_fpaccu ; | divide (10*exponent) / mantissa
loc_2449:       pop   de               ; | restore registers
                pop   af               ; | restore sign of mantissa
                call  z, fpaccu_changesign ; change sign if negative
                ex    de, hl           ; | restore curlineptr
                ret                    ; | exit
; process mantissa before decimal point  | 
do_mantissapart:                       ; | 
                push  de               ; | save DE
                ld    d, a             ; | put char in D
                ld    a, b             ; | add C to B
                adc   a, c             ; | CY is set
                                       ; | will add 0 to B for each  digit
                                       ; | before decimal point, and add 1 for each
                                       ; | in fractional part
                ld    b, a             ; | 
                push  bc               ; | save registers
                push  hl               ; | 
                push  de               ; | save character in D
                call  fpaccu_mult10    ; | 
                pop   af               ; | restore character in A
                sub   CHAR_ZERO        ; | convert to digit 0-9
                call  fpaccu_add_u8    ; | add the digit
                pop   hl               ; | restore registers
                pop   bc               ; | 
                pop   de               ; | restore DE
                jr    loop23F5         ;-+ loop next digit
; process exponent digit
add_expdigit:                          ; get exponent
                ld    a, e
                add   a, a             ; multiply with 10
                add   a, a
                add   a, e
                add   a, a
                add   a, (hl)          ; addexponent digit
                sub   CHAR_ZERO        ; convert to digit
                ld    e, a             ; store exponent
                jr    do_exponent      ; loop

expr_hex:       ld    de, 0            ; initialize number buf
loop2474:       call  nextchar         ;<+ get char
                jr    z, loc_249B      ; | end of buf?, exit
                jr    c, loc_2487      ; | is a digit? yes, skip
                sub   'A'              ; | no digit andless than 'A'?
                jr    c, loc_249B      ; | yes, exit
                cp    6                ; | more than 'F'?
                jr    nc, loc_249B     ; | yes, exit
                add   a, 10            ; | adjust to hex digit 0a...0f
                jr    loc_2489         ; | input into number buf
loc_2487:       sub   CHAR_ZERO        ; | was digit, convert to 0...9
loc_2489:       ex    af, af'          ; | save digit
                ld    a, d             ; | get overflow word
                cp    16               ; | is DE already>0xfff? yes reject another digit
                jp    nc, e_overflow   ; | yes, arithmetic overflow
                ex    af, af'          ; | restore digit
                ex    de, hl           ; | save HL
                add   hl, hl           ; | shift HL 4 bit left
                add   hl, hl           ; | 
                add   hl, hl           ; | 
                add   hl, hl           ; | 
                or    l                ; | mask in digit at lowest position
                ld    l, a             ; | back into L
                ex    de, hl           ; | number back into DE
                jr    loop2474         ;-+ loop
loc_249B:       push  hl               ; save HL
                call  uDE_to_fpaccu    ; convert DE to    floating point
                pop   hl        ; restore HL
                ret

fpaccu_add_u8:  call  push_fpaccu      ; push fpaccu
                call  s8_to_fp         ; convert 8 bit into FP
pop_fpreg_and_add:
                POP_FPREG
                jp    add_fpreg_fpaccu

mult10_and_dec: ret   z

fpaccu_mult10_and_dec1:
                push  af
                call  fpaccu_mult10
                pop   af
                dec   a                ; decrement exponent count
                ret

fpaccu_div10_and_inc :
                push  de               ; save registers
                push  hl
                push  af
                call  fpaccu_div10     ; divide fpaccu by 10
                pop   af               ; restore registers
                pop   hl
                pop   de
                inc   a                ; and increment exponent cntr
                ret

; print string " @ line ", for error/stop output,
; print lineno in HL
print_at_lineno:
                push  hl               ; save HL
                ld    hl, a_at_line    ; print " @ line "
                call  print_string
                pop   hl               ; restore it

; print    u16 number in HL
print_HL:       call  hl_to_fpaccu     ; put 16 bit number in fpaccu
                ld    hl, precision    ; save precision
                ld    a, (hl)          ; adjust to maximum precision
                ld    (hl), 0
                push  af
                call  format_number    ; format number
                pop   af               ; restore precision
                ld    (precision), a
                jp    loc_1430

format_number:  xor   a                ; fmt unconditionally

; format number  with format flags in A
format_number_fmt:
                ld    (fmt_flags), a
                ld    hl, numberbuf    ; scratchpad for formatting number
                ld    (hl), CHAR_SPACE ; store a leading space
                and   8                ; check bit 3: put leading '+' sign
                jr    z, loc_24EC      ; no leading '+'
                ld    (hl), CHAR_PLUS  ; stor leading +
loc_24EC:       call  fpaccu_sgn       ; get sign of fpaccu
                jp    p, loc_24FA      ; positive?, yes, dont change sign
                                       ; note: if result is 0, Z is 1
                ld    (hl), CHAR_MINUS ; store leading '-'
                push  hl               ; save print position
                call  fpaccu_changesign ; make accu positive
                pop   hl               ; restore print position
                or    h                ; HL is 01xx, this way ensure that Z=0
loc_24FA:       inc   hl               ; next print position 
                ld    (hl), CHAR_ZERO  ; store a '0'
                ld    a, (fmt_flags)   ; get flags
                ld    d, a             ; into D
                rla                    ; check bit 7 (shifted into CY)
                                       ; note: RLC does not affect Z flag, so this
                                       ; is preserved from checking for accu==zero
                jp    c, format_percent ; do percent format? yes, skip
                jp    z, end_format    ; is accu zero? yes, finished, exit
                                       ; no is not set, continue
                push  hl               ; save print position
                call  adjust_number_1e10 ; adjust number to be in range
                                       ; 1E10-1E11 or larger
                                       ; A contains exponent of adjustment factor
                                       ; 10 ^ -A.
                ld    hl, precision    ; get precision
                inc   (hl)             ; check if zero
                dec   (hl)
                jr    z, loc_2564      ; yes, skip
; assume for example here
; Number N=12.3456789, precision=4
; number in fpaccu is now 1234567800
                ld    d, a             ; D = negative adjustment exponent (-8)
                add   a, 0Bh           ; add 11 (+3)
                jp    m, loc_2555      ; still negative? skip: number is less than 0.01
                cp    (hl)             ; compare with precision (4)
                jr    z, loc_251E      ; same? yes continue
                jr    nc, loc_2555     ; larger than precision, no rounding
                                       ; here: 3-4 -> no skip
loc_251E:       ld    b, a             ; put adjustment into B (+3)
                ld    a, (hl)          ; get precision (4)
                sub   b                ; subtract adjustment (+1)
                inc   a                ; plus 1 (+2)
                ld    c, a             ; into C (+2)
                inc   b                ; adjustment plus 1 (+4)
                ld    a, d             ; exponent into A (-8)
                ld    d, 0Bh           ; D = 11
                pop   hl               ; restore print position
                inc   hl               ; advance to next position
                call  format_numinbuf  ; format the number
                push  hl               ; save current buf position
                xor    a               ; clear A
                ld    bc, 0            ; load maximum cntr
                cpir                   ; find zero byte
                dec   hl               ; one before
                ld    bc, loc_253C     ; inject continuation routine
                push  bc
                xor    a               ; clear A, push  on stack
                push  af               ; exponent to add (0=none)
                jr    loc_2583         ; skip: put exponent if any and exit
loc_253C:                              ; return here after formatting buf
                pop   hl               ; restore the buf position
                ld    a, (hl)          ; get character from buf
                cp    CHAR_MINUS       ; is negative sign?
                ret   z                ; yes, exit
                cp    CHAR_SPACE       ; is space?
                ret   z                ; yes, exit
                cp    CHAR_ZERO        ; is zero?
                jr    z, loc_2552      ; yes, skip
                cp    CHAR_PERCENT     ; is percent?
                jr    nz, loc_2551     ; no, skip
                inc   hl               ; yes, it is
                    ; advance to next
                ld    a, (hl)          ; get next character
                cp    CHAR_MINUS       ; is negative sign?
                ret   z                ; yes, skip
loc_2551:       dec   hl               ; no replace with space
loc_2552:       ld    (hl), CHAR_SPACE
                ret                    ; exit
loc_2555:       ld    c, (hl)          ; get precision again
                dec   c                ; decrement
                jr    z, loc_255A      ; was 1?
                inc   c                ; no, add 1 more digit
loc_255A:       ld    b, 2             ; load cntr = 2
                pop   hl               ; restore print position
                inc   hl               ; advance to next position
                ld    a, d             ; load adjustment exponent
                ld    d, 0             ; cntr = 0
; A = adjustment exponent
; D = 0
                jp    loc_26D7
; precision is 0
; A is adjustment exponent (positive or negative)
loc_2564:       ld    bc, 300h         ; B = 3, C = 0
                add   a, 0Ch           ; add 12
                jp    m, loc_2574      ; still negative, i.e. less than 0.01
                cp    0Dh              ; is it even less than 0.001?
                jr    nc, loc_2574
                inc   a                ; increment
                ld    b, a             ; set exponent = 2
                ld    a, 2
loc_2574:       sub   2
                pop   hl
                push  af
                call  set_comma
                ld    (hl), CHAR_ZERO
                jr    nz, loc_2580
                inc   hl
loc_2580:       call  output_num_digits ; put digits of number into buf
loc_2583:       dec   hl               ; point to previous buf position
                ld    a, (hl)          ; load char
                cp    CHAR_ZERO        ; is zero?
                jr    z, loc_2583      ; yes, loop
                cp    CHAR_PERIOD      ; is decimal point?
                jr    z, loc_258E      ; yes, skip
                inc   hl               ; point to last non-zero fractional digit
loc_258E:       pop   af               ; restore exponent
                jr    z, end_format1   ; terminate if 0 (none)

sub_2591:       ld    (hl), CHAR_E     ; put E for exponent in buf
                inc   hl               ; next position
                ld    (hl), CHAR_PLUS  ; put positive sign
                jp    p, loc_259D      ; was exponent positive?
                ld    (hl), CHAR_MINUS ; no, put negative sign
                neg                    ; negate exponent
loc_259D:       ld    b, CHAR_ZERO-1   ; preload '0'-1
loc_259F:       inc   b                ; increment digit count
                sub   10               ; subtract 10 from exponent
                jr    nc, loc_259F     ; loop until negative
                add   a, CHAR_NINE+1   ; add10 again andconvert to digit (+'0')
                inc   hl               ; put tenth digit into buf
                ld    (hl), b
                inc   hl               ; put remainder digit into buf
                ld    (hl), a
end_format:     inc   hl               ; advance 
end_format1:    ld    (hl), 0          ; store terminating zero byte
                ex    de, hl           ; DE is end of number
                ld    hl, numberbuf    ; HL is start of number
                ret

format_percent: inc   hl               ; advance to next position
                push  bc               ; save format, buf position
                push  hl
                ld    a, d             ; load format flags
                rra                    ; bit 0 into CY (digits for exponent)
                jp    c, loc_26CE      ; must do an exponent? yes, skip
                FPREG_CONST 0B60Eh, 1BC9h, 0BF04h ; constant 1E16
                call  fpaccu_compare   ; compare value with 1E16
                jp    m, loc_25D3      ; larger?
                pop   hl               ; restore regs
                pop   bc
                call  format_number    ; just format number
                dec   hl               ; and add a percent sign afterwards
                ld    (hl), CHAR_PERCENT
                ret                    ; exit
loc_25D3:       ld    d, 11            ; length of field
                call  fpaccu_sgn       ; check number zero
                call  nz, adjust_number_1e10 ; no adjust into range 1E10-1E11
                pop   hl               ; restore regs
                pop   bc
                jp    m, format_numinbuf ; format number
                push  bc               ; save format to use
                ld    e, a             ; save precision
                ld    a, b
                sub   d                ; subtract field width
                sub   e                ; subtract precision
                call  p, add_zeros     ; addleading zeros
                call  check_1000s_marker ; calculate position of next comma if any, in C
                call  output_num_digits ; format the digits to emit
                or    e                ; more digits before decimal point?
                call  nz, pad_zeros    ; yes, pad with zeros, A=0
                add   a, e             ; put E in A, set flags
                call  nz, set_comma    ; add comma, if neeeded
                pop   de               ; restore format
                ld    a, e             ; load C (precision)
                or    a                ; is zero?
                jr    nz, loc_25FC     ; no, skip
                dec   hl               ; preceding position
loc_25FC:       dec   a
                call  p, add_zeros
loc_2600:       push  hl               ; save HL
                ld    hl, numberbuf    ; get number buf
                ld    b, (hl)          ; get first char
                ld    c, CHAR_SPACE    ; preload space
                ld    a, (fmt_flags)   ; get format flags
                ld    e, a             ; into E
                and   20h              ; test bit 6 (replace leading ' ' with '*')
                jr    z, loc_2616      ; do not replace
                ld    a, b             ; put char in A
                cp    c                ; is space?
                ld    c, CHAR_STAR     ; preload '*'
                jr    nz, loc_2616     ; was not space, skip
                ld    b, c             ; was space, replace with '*'
loop2616:       ld    (hl), c          ;<+ put space or '*' in buf
                call  nextchar         ; | get next char from buf
                jr    z, loc_262C      ; | end of buf, skip
                cp    CHAR_E           ; | is E?
                jr    z, loc_262C      ; | yes, skip
                cp    CHAR_ZERO        ; | is '0'?
                jr    z, loop2616      ;>+ yes, advance
                cp    CHAR_COMMA       ; | is comma?
                jr    z, loop2616      ;-+ yes, advance
                cp    CHAR_PERIOD      ; is decimal point?
                jr    nz, loc_262F     ; no skip
loc_262C:       dec   hl               ; preceding position
                ld    (hl), CHAR_ZERO  ; put '0' here
loc_262F:       bit    4, e            ; add leading '$'?
                jr    z, loc_2636      ; no, skip
                dec   hl               ; preceding position
                ld    (hl), CHAR_DOLLAR ; put '$' in buf
loc_2636:       bit    2, e            ; space for positive sign?
                jr    nz, loc_263C     ; yes, skip
                dec   hl               ; preceding position
                ld    (hl), b          ; put space or '*' in position
loc_263C:       pop   hl               ; restore end of bufptr
                jr    z, loc_2641      ; was not space for positive
                ld    (hl), b          ; put trailing '*' or space
                inc   hl               ; next position
loc_2641:       ld    (hl), 0          ; put zero byte delimiter
                ld    hl, numberbuf0   ; load one position before buf
loop2646:       inc   hl               ;<+ advance position
loop2647:       ld    a, (pos_period)  ;<--+ get low address val of position of period
                sub   l                ; | | subtract buf begin
                sub   d                ; | | subtract field length
                ret   z                ; | | correct size?    return
                ld    a, (hl)          ; | | load character
                cp    CHAR_SPACE       ; | | is space?
                jr    z, loop2646      ;>+ | 
                cp    CHAR_STAR        ; | | or '*'?
                jr    z, loop2646      ;>+ | yes, advance
                dec   hl               ;   | preceding position
                push  hl               ;   | digits start here, save
loop2658:       push  af               ;<+ | save current character
                call  nextchar         ; | | next char
                cp    CHAR_MINUS       ; | | is negative sign?
                jr    z, loop2658      ;>+ | save and advance
                cp    CHAR_PLUS        ; | | is positive sign?
                jr    z, loop2658      ;>+ | yes, save and advance
                cp    CHAR_DOLLAR      ; | | is '$'?
                jr    z, loop2658      ;>+ | yes save andadvance
                cp    CHAR_ZERO        ;   | is leading zero?
                jr    nz, loc_267C     ;   | no, non-zero digits start here
; discard leading zeroes to fit number into buf
                inc   hl               ;   | advance to next
                call  nextchar         ;   | get next char
                jr    nc, loc_267C     ;   | not digit, skip
                dec   hl               ;   | position to previous
                db    1                ;   | LD BC, xxxx to skip over next two instrs
loop2674:       dec   hl               ;<+ | ** position to previous
                ld    (hl), a          ; | | ** store character here
                pop   af               ; | | restore the char before leading zeros
                jr    z, loop2674      ;-+ | not at end? loop
                pop   bc               ;   | drop saved digit position
                jr    loop2647         ;---+ loop fitting number into field
loop267C:       pop   af               ;<+ drop characters until end of buf
                jr    z, loop267C      ;-+
                pop   hl               ; restore buf position
                ld    (hl), CHAR_PERCENT ; add a percent sign
                ret                    ; done

; has number in FPaccu, adjusted to range 1E10-1E11
; again in example:
; Number=12.2345678 precision 4
; fpaccu=1234567800
format_numinbuf:
                ld    e, a             ; save exponent in E (-8)
                ld    a, c             ; adjustment in A (+2)
                or    a                ; does not need correction?
                jr    z, loc_2689      ; no, skip
                dec   a                ; decrement required adjustment (+1)
loc_2689:       add   a, e             ; target exponent (-7)
                jp    m, loc_268E      ; is negative?, skip
                xor   a                ; target exponent=0
loc_268E:       push  bc               ; save BC (B=+4, C=+2)
                push  af               ; save target exponent
loop2690:       call  m, fpaccu_div10_and_inc ;<+ divide FPaccu/10 andincrement A
                jr    nz, loop2690     ;--------+ target exponent is not yet 0, loop
                                       ; fpaccu now 123.4567800
                pop   bc               ; restore exponent in B (-7)
                ld    a, e             ; get exponent (-8)
                sub   b                ; subtract (-1)
                pop   bc               ; restore BC (+4, +2)
                ld    e, a             ; save further exponent correction (-1)
                add   a, d             ; add field width (10)
                ld    a, b             ; get B again (+4)
                jp    m, loc_26AA      ; too large for field?, skip
                sub   d                ; subtract (-7)
                sub   e                ; subtract (-8)
                call  p, add_zeros     ; positive: add leading zeros
                push  bc               ; save BC (+4, +2)
                call  check_1000s_marker ; get modulo for 1000s comma
                jr    loc_26BB         ; skip
loc_26AA:       call  add_zeros        ; add leading zeros
                ld    a, c             ; save C
                call  set_period       ; store decimal point in buf
                ld    c, a             ; restore C
                xor   a                ; calculate number of trailing zeros
                sub   d
                sub   e
                call  add_zeros        ; add trailing zeros
                push  bc               ; save B, C (+4,+2)
                ld    b, a             ; clear B,C
                ld    c, a
loc_26BB:       call  output_num_digits ; (B+C digits)
                pop   bc               ; restore BC
                or    c                ; A was 0, check if C is also 0
                jr    nz, loc_26C5     ; no, still digits to add(after decimal  point)
                ld    hl, (pos_period) ; get position of period
loc_26C5:       add   a, e             ; calculate remaining field width
                dec   a                ; add trailing zeros to fill field width
                call  p, add_zeros
                ld    d, b             ; get number digits after decimal point
                jp    loc_2600         ; jump to final corrections
loc_26CE:       call  fpaccu_sgn
                scf
                call  nz, adjust_number_1e10
                pop   hl
                pop   bc
loc_26D7:       push  af               ; save adjustment
                ld    a, c             ; get precision
                add   a, a             ; * 2
                push  af               ; save
                jr    z, loc_26DE      ; was zero, skip
                dec   a                ; one less
loc_26DE:       add   a, b
                ld    c, a
                ld    a, d
                and   4
                cp    1
                sbc   a, a
                ld    d, a
                add   a, c
                ld    c, a
                sub   0Bh
                push  af
                push  bc
loop26ED:       call  m, fpaccu_div10_and_inc ;<+
                jp    m, loop26ED      ;--------+
                pop   bc
                pop   af
                push  bc
                push  af
                jp    m, loc_26FB
                xor    a
loc_26FB:       neg
                add   a, b
                inc   a
                add   a, d
                ld    b, a
                ld    c, 0
                call  output_num_digits
                pop   af
                call  p, sub_2815
                pop   bc
                pop   af
                jr    nz, loc_270F
                dec   hl
loc_270F:       pop   af
                jr    c, loc_2716
                add   a, 0Bh
                sub   b
                sub   d
loc_2716:       push  bc
                call  sub_2591
                ex    de, hl
                pop   de
                jp    loc_2600

; routine to adjust number so it is between 1E10 and1E11
; return correction exponent in A
; A is negative when number had to be multiplied, i.e. was <1E10
; e.g. number =    1.00 ->    A = -9
adjust_number_1e10:
                push  de               ; save registers
                xor    a               ; clear adjustment factor
                push  af               ; save it
                call  sub_2748
loop2725:       FPREG_CONST 0A215h, 2F8h, 0FFFDh ; constant 9 999 999 999.9
                call  fpaccu_compare   ; compare accu with constant
                jp    p, loc_2745      ; is larger, exit
                pop   af               ; restore exponent count
                call  fpaccu_mult10_and_dec1 ; multiply with 10 and decrement exponent
                push  af
                jp    loop2725         ; loop
loop273D:       pop   af               ;<---+ restore exponent count
                call  fpaccu_div10_and_inc ;| divide by 10 and adjust exponent count
                push  af               ;    | save exponent count again
                call  sub_2748         ;    | is still too large?
loc_2745:       pop   af               ;    | 
                pop   de               ;    | 
                ret                    ;    | 
sub_2748:       FPREG_CONST 0A53Ah, 43B7h, 3FFCh ; constant 99 999 999 999.5
                call  fpaccu_compare   ;    | compare accu with constant
                pop   hl               ;    | get return value
                jp    p, loop273D      ;----+ if larger, divide by 10
                jp    (hl)

; set a 1000s marker (comma), if needed
; (still digits to emit before decimal point)
; B is digits before decimal point
set_comma:      dec   b                ; decrement count of digits before period
                jr    nz, loc_2765     ; not yet zero, emit more

; put a decimal point into number buf, clear C if called from set_comma
set_period:     ld    (hl), CHAR_PERIOD ; store a period
                ld    (pos_period), hl ; save period position
                inc   hl               ; advance to next position
                ld    c, b             ; clear C, when coming from set_comma
                ret                    ; exit
loc_2765:       dec   c                ; decrement comma cntr
                ret   nz               ; not yet zero, exit
                ld    (hl), CHAR_COMMA ; put a comma marker into buf
                inc   hl
                ld    c, 3             ; reload comma cntr
                ret                    ; exit

output_num_digits:
                push  de               ; save registers
                push  bc
                push  hl
                call  add_0_5          ; add 0.5 for rounding
                inc   a                ; add 1 to FPaccu exponent
                call  fpreg_fix        ; clip fractional digits
                call  store_fpaccu     ; save result again
                pop   hl               ; restore HL, BC registers
                pop   bc
                ld    de, powers10     ; get powers of 10 table
                ld    a, 0Bh           ; loop count
; B is number of digits before decimal point
; C cntr for comma positions
loop2781:                              ;<--+ set a 1000s marker if needed,
                                       ;   | or a period, unless
                call  set_comma        ;   | more digits to emit
                push  bc               ;   | save regs
                push  af               ;   | 
                push  hl               ;   | 
                push  de               ;   | 
                call  fpaccu_to_fpreg  ;   | copy fpaccu to fpreg
                pop   hl               ;   | HL = powers of 10 table
                ld    b, CHAR_ZERO-1   ;   | preload '0'-1
loop278E:       inc   b                ;<+ | increment (accumulator of current digit)
                ld    a, e             ; | | subtract current power of 10
                sub   (hl)             ; | | 
                ld    e, a             ; | | 
                inc   hl               ; | | 
                ld    a, d             ; | | 
                sbc   a, (hl)          ; | | 
                ld    d, a             ; | | 
                inc   hl               ; | | 
                ld    a, xl            ; | | 
                sbc   a, (hl)          ; | | 
                ld    xl, a            ; | | 
                inc   hl               ; | | 
                ld    a, xh            ; | | 
                sbc   a, (hl)          ; | | 
                ld    xh, a            ; | | 
                inc   hl               ; | | 
                ld    a, c             ; | | 
                sbc   a, (hl)          ; | | 
                ld    c, a             ; | | 
                dec   hl               ; | | point back to current power
                dec   hl               ; | | 
                dec   hl               ; | | 
                dec   hl               ; | | 
                jr    nc, loop278E     ;-+ | still positive, loop
                call  add_mantissas    ;   | became negative, addcurrent power again
                inc   hl               ;   | advance to next position
                call  store_fpaccu     ;   | save the current result again
                ex    de, hl           ;   | DE is ptr to powers of 10, now next power
                pop   hl               ;   | restore ptr to number buf
                ld    (hl), b          ;   | save calculated digit
                inc   hl               ;   | advance to next buf position
                pop   af               ;   | restore A
                pop   bc               ;   | restore BC
                dec   a                ;   | decrement loop
                jr    nz, loop2781     ;---+ loop for 11 digits
                call  set_comma        ; set comma if needed
                ld    (hl), a          ; store terminating zero in buf
                pop   de               ; restore DE
                ret

powers10:       db    0, 0E4h, 0Bh, 54h, 2 ; constant 10000000000
                db    0, 0CAh, 9Ah, 3Bh, 0 ; constant 1000000000
                db    0, 0E1h, 0F5h, 5, 0  ; constant 100000000
                db    80h, 96h, 98h, 0, 0  ; constant 10000000
                db    40h, 42h, 0Fh, 0, 0  ; constant 1000000
                db    0A0h, 86h, 1, 0, 0   ; constant 100000
                db    10h, 27h, 0, 0, 0    ; constant 10000
                db    0E8h, 3, 0, 0, 0     ; constant 1000
                db    64h, 0, 0, 0, 0      ; constant 100
                db    0Ah, 0, 0, 0, 0      ; constant 10
                db    1, 0, 0, 0, 0        ; constant 1

add_zeros:      or    a                ; is cntr for zeros = 0?
                ret   z                ; yes exit
                dec   a                ; decrement count
                ld    (hl), CHAR_ZERO  ; put '0' in buf
                inc   hl               ; advance to next
                jr    add_zeros        ; loop

check_1000s_marker:
                ld    a, e             ; get E (-1)
                add   a, d             ; add field width (10)
                inc   a                ; add 1 for period (11)
                ld    b, a             ; put into B
                inc   a                ; add 1 (12)
loop2806:       sub   3                ;<+ calculate modulo 3
                jr    nc, loop2806     ;-+
                add   a, 5             ; add 5 to modulo
                ld    c, a             ; store into C (+5)
                ld    a, (fmt_flags)   ; get format flags
                and   40h              ; check comma flag
                ret   nz               ; exit with modulus+5 if set
                ld    c, a             ; return zero if not set
                ret

sub_2815:       jr    nz, pad_zeros
loop2817:       ret   z                ;<+
                call  set_comma        ; | 
pad_zeros:      ld    (hl), CHAR_ZERO  ; | put trailing zero in buf
                inc   hl               ; | advance
                dec   a                ; | decrement cntr
                jr    loop2817         ;-+ loop

; has seen PRINT USING...
printusing:     call  nextchar         ; get next token
                jr    nc, loc_2844     ; is not a digit, skip
                call  read_lineno      ; get lineno of USING statement ("!...")
                push  hl               ; save curlineptr
                call  find_line        ; search for USING line
                jp    nc, undef_stmt_error ; not found, error
                LDHL_BC                ; get position into HL
                inc   hl               ; advance to line body, skip lineno
                inc   hl
                inc   hl
                call  nextchar         ; get first char of line
                sub   9Ch              ; must be a ! token
                jp    nz, illfunc_error ; otherwise error
                ld    b, a             ; B is 0, store string terminator
                                       ; USING is only statement in line
                call  copy_0string     ; copy 0 terminated string in stringaccu
                pop   hl               ; restore curlineptr of PRINT statement
                jr    loc_2847         ; skip
loc_2844:       call  string_expression1 ; get a string expression
loc_2847:       call  skipspace        ; advance to next non-whitespace
                scf                    ; set CY
                jr    z, loc_2859      ; end of statement? skip
                cp    CHAR_COMMA       ; expect either comma or semicolon
                jr    z, loc_2856
                cp    CHAR_SEMI
                jp    nz, syntax_error ; otherwise syntax error
loc_2856:       call  nextchar         ; skip over delimiter
loc_2859:       ex    de, hl           ; save curlineptr
                ld    hl, (fpaccu_mant32) ; load string descriptor of USING
                db    1                ; LD BC, xxxx to skip next 2 instructions
                                       ; is uncritical because BC will be overwritten
loc_285E:       pop   de               ; **
                ex    de, hl           ; **
                push  hl               ; save ptr to USING string
                push  af               ; save nextchar after expression
                push  de               ; save DE
                ld    b, (hl)          ; get string length
                or    b
                jp    z, illfunc_error ; empty? error
                inc   hl               ; point to address of USING format
                inc   hl
                LDHL_M C               ; get USING format into HL
                jp    loc_2877         ; skip
loc_2871:       call  plus_if_D        ; print leading '+' if requested
                call  write_char       ; print the char in A
loc_2877:
                xor   a
                ld    e, a             ; numeric digits before decimal point
                                       ; (C will become digits after DP)
                ld    d, a             ; stores fmt_flag, initially 0
loop287A:       call  plus_if_D        ;<+ print leading '+' if D != 0
                ld    d, a             ; | store fmt_flag
                ld    a, (hl)          ; | get char from USING format
                inc   hl               ; | next position
                cp    CHAR_HASH        ; | is it a numeric digit?
                jp    z, using_numeric ; | 
                cp    CHAR_TIC         ; | TIC, is it a string field?
                jp    z, using_string  ; | 
                dec   b                ; | decrement length of format
                jp    z, using_end     ; | end of format? yes skip
                cp    CHAR_PLUS        ; | no, is it a '+'?
                ld    a, 8             ; | yes set bit3 in format flag (leading '+')
                jr    z, loop287A      ;-+ loop
                dec   hl               ; no wasn't a '+', reget the last format character
                ld    a, (hl)
                inc   hl
                cp    CHAR_PERIOD      ; a leading decimal point?
                jp    z, using_dp1     ; yes, count digits after DP
                cp    (hl)             ; duplicate characters?
                jr    nz, loc_2871     ; print non-format char
                cp    CHAR_DOLLAR      ; was the duplicate char a '$'?
                jr    z, using_dollar  ; yes, skip
                cp    CHAR_STAR        ; is '*'?
                jr    nz, loc_2871     ; no, print the non-format character
                ld    a, b             ; get format string length
                cp    2                ; at least more than 2 chars in format?
                inc   hl               ; advance to next format pos
                jr    c, loc_28B0      ; no, skip
                ld    a, (hl)          ; get next format char
                cp    CHAR_DOLLAR      ; is it a '$', i.e. sequence '**$'?
loc_28B0:       ld    a, 20h           ; set bit 5 of fmt_flag
                jr    nz, loc_28BB     ; not '**$', skip
                dec   b                ; decrement remaining format length
                inc   e                ; add one more digit before decimal point
                db    0FEh             ; CP AF to skip next instruction
using_dollar:   xor   a                ; ** clear fmt_flag
                add   a, 10h           ; set flag 4 of fmt_flag
                inc   hl               ; advance to next format character
loc_28BB:       inc   e                ; increment numeric digit count (for '*')
                add   a, d             ; set bits into fmt_flag
                ld    d, a
using_numeric:  inc   e                ; increment cntr for numeric digits
                ld    c, 0             ; clear cntr of digits after DP
                dec   b                ; decrement format length
                jr    z, loc_290A      ; end of format? skip
                ld    a, (hl)          ; get next char of format
                inc   hl               ; advance format ptr
                cp    CHAR_PERIOD      ; is it a decimal point?
                jr    z, using_dp      ; yes decimal
                cp    CHAR_HASH        ; is it another numeric digit?
                jr    z, using_numeric ; yes loop
                cp    CHAR_COMMA       ; is it a comma?
                jr    nz, loc_28EB
                set    6, d            ; set fmt_flag bit 6 (addcommas for 1000's)
                jr    using_numeric    ; loop
using_dp1:                             ; handle leading decimal point
                ld    a, (hl)          ; get next format char
                cp    CHAR_HASH        ; is it numeric?
                ld    a, CHAR_PERIOD   ; load decimal point
                jp    nz, loc_2871     ; not numeric, go, print the decimal point
                ld    c, 1             ; set count of digits after decimal point
                inc   hl               ; advance to next format position
using_dp:       inc   c                ; increment count of digits after decimal point
                dec   b                ; decrement format ptr
                jr    z, loc_290A      ; exit if zero
                ld    a, (hl)          ; get next format character
                inc   hl               ; advance format ptr
                cp    CHAR_HASH        ; is it '#'?
                jr    z, using_dp      ; continue counting digits after DP
                                       ; a non-# format char
loc_28EB:       push  de               ; save fmt_flag and digit count
                LDDE_HL                ; save current format pos into DE
                cp    CHAR_POWER       ; is it a ^ (exponent marker)
                jr    nz, loc_2908     ; no, skip
                cp    (hl)             ; check with next pos
                jr    nz, loc_2908     ; not a second ^, skip
                inc   hl
                cp    (hl)             ; check third pos
                jr    nz, loc_2908     ; no, not a third ^
                inc   hl
                cp    (hl)             ; check fourth pos
                jr    nz, loc_2908     ; no, not a fourth ^
                inc   hl
                ld    a, b             ; subtract 4 from string length
                sub   4
                jr    c, loc_2908      ; not enough chars left in format?
                pop   de               ; restore format flag and digit count
                ld    b, a             ; save string length back to B
                inc   d                ; set flag 0 in fmt
                inc   hl               ; advance to next position
                db    0CAh             ; JP Z, xxxx to skip next 2 instructions
                                       ; is uncritical because Z is never set here
loc_2908:       ex    de, hl           ;** restore old position of format ptr
                pop   de               ;** restore saved flags
loc_290A:       dec   hl               ; skip back to last char of format
                inc   e                ; reserve a digit for a potential sign
                bit   3, d             ; check sign flag
                jr    nz, loc_2923     ; is sign bit set
                dec   e                ; have a reserved sign position
                                       ; therefore don't reserve another one
                ld    a, b             ; get remaining format string length
                or    a
                jr    z, loc_2923      ; now at end? yes, skip
                ld    a, (hl)          ; no, is it a '-'?
                sub   CHAR_MINUS
                jr    z, using_minus   ; yes, skip
loc_291A:       cp    -2               ; was it a '+'?
                jr    nz, loc_2923     ; no, skip
                set   3, d             ; yes, it was, set BIT 3
using_minus:    set   2, d             ; set bit 2: print minus sign, but space for '+'
                dec   b                ; decrement format string length
loc_2923:       pop   hl               ; restore curlineptr
                pop   af               ; restore nextchar
                jr    z, loc_2978      ; is EOLN? yes skip
                push  bc               ; save format
                push  de               ; D = fmt_flag
                                       ; E = digits before DP
                                       ; C = digits after DP
                call  expression1      ; get expression to print
                pop   de               ; restore format
                pop   bc
                push  bc               ; save BC
                push  hl               ; save curlineptr
                ld    b, e             ; get digits before DP into E
                ld    a, b             ; calculate total length of field
                add   a, c
                cp    25               ; longer than 25? -> accuracy problem,
                                       ; we don't have that many significant digits
                jp    nc, illfunc_error ; yes, error
                ld    a, d             ; get format flag
                or    80h              ; set bit 7
                call  format_number_fmt ; format number in buf
                call  straccu_copy_print ; copy to straccu andprint it
print_mainloop: pop   hl               ; restore curlineptr
                call  skipspace        ; advance to next non-whitespace
                scf
                jr    z, loc_2954      ; end of line? yes, exit
                cp    CHAR_SEMI        ; semicolon follwing?
                jr    z, loc_2951      ; yes advance
                cp    CHAR_COMMA       ; comma following?
                jp    nz, syntax_error ; no, error
loc_2951:       call  nextchar         ; advance
loc_2954:       pop   bc               ; restore BC
                ex    de, hl           ; save curlinepos -> DE
                pop   hl               ; restore string descriptor to format
                push  hl               ; save it again
                push  af
                push  de               ; save curlineptr
                ld    a, (hl)          ; get string length
                sub   b                ; subtract format length
                inc   hl               ; advance to string ptr
                inc   hl
                LDHL_M C               ; get string address into HL
                ld    d, 0
                ld    e, a
                add   hl, de           ; advance to remaining format part
                ld    a, b             ; still chars in format string?
                or    a
                jp    nz, loc_2877     ; yes, do another formatting
                jr    loc_2973         ; otherwise exit
using_end:      call  plus_if_D
                call  write_char
loc_2973:       pop   hl               ; restore curlineptr
                pop   af               ; restore last char seen
                jp    nz, loc_285E     ; loop
loc_2978:       call  c, print_crlf    ; print new line
                ex    (sp), hl         ; save curlineptr to stack, restore
                                       ; string stack ptr
                call  pop_str_stringstk ; discard format/scratchpad from string stack
                pop   hl               ; restore curlineptr
                ret                    ; exit

; has seen a tic (') for a string field
using_string:   ld    c, 1             ; initialize field size cntr
                ld    e, 'L'           ; left justified
                dec   b                ; nothing left?, exit
                jr    z, loc_29A4
                ld    a, (hl)          ; get char after tic
                inc   hl               ; advance
                cp    'E'              ; is it an 'E' (left justify with extension)
                jr    z, loc_299A      ; yes, put into reg E
                cp    'R'              ; is it a 'R' (right justified)?
                jr    z, loc_299A      ; yes, put into reg E
                cp    'L'              ; is it an 'L' (left justified)?
                jr    z, loc_299A      ; yes, put into reg E
                cp    'C'              ; is it a 'C' (centered)?
                jr    nz, loc_29A4     ; no, skip, default reg E is 'L')
loc_299A:       ld    e, a             ; store the justification key in E
loc_299B:       inc   c                ; increment field size cntr
                dec   b                ; at end of line?
                jr    z, loc_29A4      ; yes, exit loop
                ld    a, (hl)          ; get next char
                inc   hl               ; advance
                cp    e                ; is it the same as previous one?
                jr    z, loc_299B      ; yes, loop
; end of USING string
;
; start here to emit string corresponding to format
loc_29A4:       call  plus_if_D        ; emit start of field
                pop   hl               ; restore curlineptr
                pop   af               ; and last char seen
                jr    z, loc_2978      ; EOLN? yes exit
                push  bc
                push  de
                call  string_expression1 ; get a string expression
                pop   de
                pop   bc
                push  bc               ; B = remaining format length
                                       ; C = field length
                                       ; E = justification
                push  hl               ; save curlineptr
                ld    hl, (fpaccu_mant32) ; get string descriptor in FPaccu
                ld    b, c             ; get field length
                ld    c, 0             ; cntr for trailing spaces
                ld    a, e             ; get justification
                cp    'E'              ; left with extension?
                jr    z, loc_29EA      ; yes, skip
                                       ; effectively just print the string as is
                push  de               ; save regs
                push  bc
                call  loc_15CD
                pop   bc
                pop   de
                ld    a, b
                sub   (hl)
                ld    b, a
                ld    a, e
                cp    'L'
                jr    z, loc_29DC
                cp    'R'
                jr    z, loc_29E7
                ld    a, b
                srl    b
                sub   b

; B = cnt for leading spaces
; A = cnt for trailing spaces
print_lead_field_trail:            
                ex    af, af'          ; save count for trailing spaces
                call  print_b_spaces   ; print spaces, count in B
                ex    af, af'          ; restore
print_field_and_trailing:
                ld    b, a             ; put cnt for trailing in B
loc_29DC:       push  bc
                call  straccu_print    ; print the string
                pop   bc
                call  print_b_spaces   ; print trailing spaces
                jp    print_mainloop   ; continue with print
loc_29E7:       xor   a                ; cntr for trailing spaces = 0
                jr    print_lead_field_trail ; enter printing loop
loc_29EA:       ld    a, b             ; get field length
                sub   (hl)             ; subtract string length
                jr    nc, print_field_and_trailing ; if less, store difference
                                       ; as cntr for trailing spaces
                xor    a               ; otherwise set trailing count = 0
                jr    print_field_and_trailing ; print the field

print_b_spaces: inc   b
loop29F2:       dec   b                ;<+
                ret   z                ; | 
                call  print_space      ; | 
                jr    loop29F2         ;-+

; in USING, print a leading or trailing '+' if D is non-zero
plus_if_D:      push  af               ; save A
                ld    a, d             ; get SIGN flag
                or    a
                ld    a, CHAR_PLUS     ; if set, print a '+'
                call  nz, write_char
                pop   af               ; restore A
                ret

; insert a change sign into return stack
; to be called when calling routine returns (for ATN)
push_changesign:
                ld    hl, fpaccu_changesign
                ex    (sp), hl
                jp    (hl)

const0_5:       db    0, 0, 0, 0, 0, 80h ; constant 0.5

; process SQR()
math_sqr:       call  push_fpaccu      ; push fpaccu
                ld    hl, const0_5     ; get constant
                call  mem_to_fpaccu    ; into fpaccu

; pop fpreg off stack and calc power of fpaccu
pop_fpreg_and_power:
                POP_FPREG              ; pop fpreg
; calculate fpreg ^ fpaccu => fpaccu
fpaccu_power:   call  fpaccu_sgn       ; get sign of powerexp
                jr    z, math_exp      ; is zero, then calculate exp(0) == 1
                                       ; note: this is inefficient
                ld    a, b             ; get exponent of base
                or    a
                jp    z, loc_200F      ; is zero? => result is zero
                PUSH_FPREG             ; push base again
                ld    a, c             ; get base
                or    7Fh
                call  fpaccu_to_fpreg  ; copy powerexp to fpreg
                jp    p, loc_2A44      ; is positive, skip
                PUSH_FPREG             ; push powerexp
                call  math_int         ; calculate int(powerexp)
                POP_FPREG              ; restore powerexp
                push  af               ; save base sign
                call  fpaccu_compare   ; compare INT(powerexp) with powerexp()
                pop   hl               ; restore base sign
                ld    a, h
                rra                    ; into CY
loc_2A44:       pop   hl               ; pop base into fpaccu
                ld    (fpaccu_mant6), hl
                pop   hl
                ld    (fpaccu_mant54), hl
                pop   hl
                ld    (fpaccu_mant32), hl
                call  c, push_changesign ; change sign afterwards
                call  z, fpaccu_changesign ; change sign now
                PUSH_FPREG             ; pop powerexp in to fpreg
                call  math_log         ; calculate LOG(base)
                POP_FPREG
                call  multiply_fpreg_fpaccu ; LOG(base)*powerexp

; process EXP()
math_exp:       FPREG_CONST 8138h, 0AA3Bh, 295Ch ; get constant 1/LOG(2)
                call  multiply_fpreg_fpaccu ; multiply with fpaccu
                ld    a, (fpaccu_exp)
                cp    88h
                jp    nc, loc_2280     ; exponent too large?
                                       ; if sign is negative, then result
                                       ; is zero, otherwise overflow error
                call  push_fpaccu      ; push arg
                call  math_int         ; do INT(arg)
                POP_FPREG              ; pop fpreg
                push  af               ; save sign
                call  subtr_fpreg_fpaccu ; calculate arg - INT(arg)
                ld    hl, EXP_poly_tbl ; load coefficient table
                call  fpaccu_polyeval  ; do polynomial eval
                ld    hl, fpaccu_exp   ; get exponent
                pop   af               ; restore
                or    a                ; check for exponent value
                jp    m, loc_2A97      ; negative, potential overflow
                add   a, (hl)          ; add exponent
                db 1                   ; LD BC, xxxx to skip next 2 instructions
                                       ; is uncritical because BC will be overwritten
loc_2A97:       add   a, (hl)          ;** 
                ccf                    ;** 
                ld    (hl), a          ; store resulting exponent
                ret   nc               ; return result if not overflow
                jp    loc_2280         ; overflow

EXP_poly_tbl:   db    0Ah
                db    0CCh, 0D5h, 45h, 56h, 15h, 6Ah   ; 0.00000014
                db    0CFh, 37h, 0A0h, 92h, 27h, 6Dh   ; 0.00000125
                db    0F5h, 95h, 0EEh, 93h, 0, 71h     ; 0.00001533
                db    0D0h, 0FCh, 0A7h, 78h, 21h, 74h  ; 0.00015399
                db    0B1h, 21h, 82h, 0C4h, 2Eh, 77h   ; 0.00133337
                db    82h, 58h, 58h, 95h, 1Dh, 7Ah     ; 0.00961813
                db    6Dh, 0CBh, 46h, 58h, 63h, 7Ch    ; 0.05550411
                db    0E9h, 0FBh, 0EFh, 0FDh, 75h, 7Eh ; 0.24022651
                db    0D2h, 0F7h, 17h, 72h, 31h, 80h   ; 0.69314718
                db    0, 0, 0, 0, 0, 81h               ; 1.0

; calculate X^2 first and then evaluate
; polynomial a0*X + a1*X^2 + a2*x^3 + a3*x^4 ...
fpaccu_polyeval_sqr:
                call  push_fpaccu      ; push fpaccu
                ld    de, pop_fpreg_and_mult ; push routine to multiply at the end
                push  de
                push  hl               ; save HL
                call  fpaccu_to_fpreg  ; copy to fpreg
                call  multiply_fpreg_fpaccu ; calculate square(fpaccu)
                pop   hl               ; restore hl
; calculate polynomial evaluation
; a0 + a1*X + a2*X^2 + a3*X^3 ...
; by Horner's evaluation:
; ((..a3)*X + a2)*X + a1) * X) + a0
fpaccu_polyeval:            
                call  push_fpaccu      ; push accu1 again
                ld    a, (hl)          ; get number of coefficients in table
                inc   hl               ; point to innermost coefficient
                call  mem_to_fpaccu    ; load into fpaccu
                db    0FEh             ; CP xx to skip next instruction
                                       ; uncritical because flags are never checked
                                       ; restore number of factors
loop2AF3:       pop   af               ;<+ ** only popped on second and following calls
                POP_FPREG              ; | pop fpreg
                dec   a                ; | complete factors done?
                ret   z                ; | yes, exit
                PUSH_FPREG             ; | push X again
                push  af               ; | 
                push  hl               ; | save HL
                call  multiply_fpreg_fpaccu ; multiply partial product
                                       ; | ((.(an*X+an-1)*X + an-k) with X
                pop   hl               ; | restore HL
                call  load_fpreg       ; | get next factor an-k-1
                push  hl               ; | save HL
                call  add_fpreg_fpaccu ; | add coefficient
                pop   hl               ; | restore HL
                jr    loop2AF3         ;-+ loop over all coefficients

math_rnd:       call  fpaccu_sgn       ; get sign of argument
                jp    m, loc_2B35      ; negative, dont calc 
                                       ; RND*11879546+0.000392... first
                ld    hl, rnd_mant23   ; get current random number into fpaccu
                call  mem_to_fpaccu
                ret   z                ; if argument is 0, return last random number
                FPREG_CONST 9835h, 447Ah, 0 ; constant 11879546
                call  multiply_fpreg_fpaccu ; multiply with random number
                FPREG_CONST 6828h, 0B146h, 0 ; constant 3.92767774E-4
                call  add_fpreg_fpaccu ; add to number
loc_2B35:       call  fpaccu_to_fpreg  ; copy to fpreg
                ld    a, e             ; rotate digits
                ld    e, c
                ld    c, a
                ld    (hl), 80h        ; HL points to exponent
                                       ; set exponent to range 0...1
                dec   hl
                ld    b, (hl)          ; get highest bit of mantissa
                ld    (hl), 80h        ; ensure high bit
                call  loc_1FF3         ; normalize mantissa
                ld    hl, rnd_mant23   ; load address of last random
                jp    fpaccu_to_mem    ; copy current random number

; process COS()
math_cos:       ld    hl, const_pi_div_2 ; load constant PI/2
                call  load_and_add_fpaccu ; addto argument

; process SIN(X)
math_sin:       call  push_fpaccu      ; push fpaccu (X)
                FPREG_CONST 8349h, 0FDAh, 0A221h ; constant 2*PI
                call  store_fpaccu     ; store in fpaccu
                POP_FPREG              ; restore X
                call  div_fpreg_fpaccu ; divide X / (2*PI)
                call  push_fpaccu      ; push X/2PI
                call  math_int         ; calculate INT part
                POP_FPREG              ; restore X/2PI
                call  subtr_fpreg_fpaccu ; calculate fractional part
                                       ; (X/2PI) - INT(X/2PI) = XREST
                ld    hl, const_0_25
                call  load_fpreg_and_subtr ; calculate 0.25 - XREST
                call  fpaccu_sgn       ; check sign
                scf
                jp    p, loc_2B88      ; is smaller than 0.25
                call  add_0_5          ; no, add 0.5
                call  fpaccu_sgn       ; check sign
                or    a                ; set sign flag
loc_2B88:       push  af               ; save it
                call  p, fpaccu_changesign ; was positive? change sign
                ld    hl, const_0_25   ; add constant 0.25
                call  load_and_add_fpaccu
                pop   af               ; restore flag
                call  nc, fpaccu_changesign ; correct sign again
                ld    hl, SIN_poly_tbl ; load SIN coefficient table
                jp    fpaccu_polyeval_sqr ; do polynomial eval

const_pi_div_2: db    21h, 0A2h, 0DAh, 0Fh, 49h, 81h ; constant PI/2
const_0_25:     db    0, 0, 0, 0, 0, 7Fh    ; constant 0.25
SIN_poly_tbl:   db    7
                db    90h, 0BAh, 34h, 76h, 6Ah, 82h    ; 3.66346472
                db    0E4h, 0E9h, 0E7h, 4Bh, 0F1h, 84h ; -15.08103172
                db    0B1h, 4Fh, 7Fh, 38h, 28h, 86h    ; 42.05517315
                db    31h, 86h, 64h, 69h, 99h, 87h     ; -76.70584506
                db    0E4h, 36h, 0E3h, 35h, 23h, 87h   ; 81.60524913
                db    24h, 31h, 0E7h, 5Dh, 0A5h, 86h   ; -41.34170224
                db    21h, 0A2h, 0DAh, 0Fh, 49h, 83h   ; 2*PI

; process TAN(X)
math_tan:       call  push_fpaccu      ; push fpaccu (X)
                call  math_sin         ; calculate SIN(X)
                POP_FPREG              ; restore argument again
                call  push_fpaccu_ex   ; push SIN(X)
                ex    de, hl           ; undo exchange
                call  store_fpaccu     ; store X
                call  math_cos         ; calculate COS(X)
                jp    pop_fpreg_and_div ; pop SIN(X) and calc SIN(X)/COS(X)

; process ATN()
math_atn:       call  fpaccu_sgn       ; get sign of argument
                call  m, push_changesign ; change sign on return
                call  m, fpaccu_changesign ; make now positive sign
                ld    a, (fpaccu_exp)  ; is value > 1?
                cp    81h
                jr    c, loc_2C0A      ; yes, skip
                ld    bc, 8100h        ; load constant 1.0 in fpreg
                ld    ix, 0
                ld    d, c
                ld    e, c
                call  div_fpreg_fpaccu ; divide by fpaccu (1/X)
                ld    hl, load_fpreg_and_subtr ; push routine to subtract
                                       ; fpaccu from constant at end
                push  hl
loc_2C0A:       ld    hl, ATN_poly_tbl ; load polynomial table for ATN
                call  fpaccu_polyeval_sqr
                ld    hl, const_pi_div_2 ; constant to subtract from
                ret

ATN_poly_tbl:   db    0Dh              ; count of polynomial parameters
                db    14h, 7, 0BAh, 0FEh, 62h, 75h     ; 0.00043296
                db    51h, 16h, 0CEh, 0D8h, 0D6h, 78h  ; -0.00327830
                db    4Ch, 0BDh, 7Dh, 0D1h, 3Eh, 7Ah   ; 0.01164663
                db    1, 0CBh, 23h, 0C4h, 0D7h, 7Bh    ; -0.02633864
                db    0DCh, 3Ah, 0Ah, 17h,    34h, 7Ch ; 0.04396729
                db    36h, 0C1h, 0A3h, 81h, 0F7h, 7Ch  ; -0.06042637
                db    0EBh, 16h, 61h, 0AEh, 19h, 7Dh   ; 0.07503963
                db    5Dh, 78h, 8Fh, 60h, 0B9h, 7Dh    ; -0.09051621
                db    0A2h, 44h, 12h, 72h, 63h, 7Dh    ; 0.11105742
                db    16h, 62h, 0FBh, 47h, 92h, 7Eh    ; -0.14285271
                db    0C0h, 0F0h, 0BFh, 0CCh, 4Ch, 7Eh ; 0.19999981
                db    7Eh, 8Eh, 0AAh, 0AAh, 0AAh, 7Fh  ; -0.33333333
                db    0F6h, 0FFh, 0FFh, 0FFh, 7Fh, 80h ; 1.0
				
				
				
token_tbl:      db    'E', 'N', 'D'+80h                ; token 0x80
                db    'F', 'O', 'R'+80h                ; token 0x81
                db    'N', 'E', 'X', 'T'+80h           ; token 0x82
                db    'D', 'A', 'T', 'A'+80h           ; token 0x83
                db    'I', 'N', 'P', 'U', 'T'+80h      ; token 0x84
                db    'D', 'I', 'M'+80h                ; token 0x85
                db    'R', 'E', 'A', 'D'+80h           ; token 0x86
                db    'L', 'E', 'T'+80h                ; token 0x87
                db    'G', 'O', ' ', 'T', 'O'+80h      ; token 0x88
                db    'F', 'N', 'E', 'N', 'D'+80h      ; token 0x89
                db    'I', 'F'+80h                     ; token 0x8a
                db    'R', 'E', 'S', 'T', 'O', 'R', 'E'+80h ; token 0x8b
                db    'G', 'O', ' ', 'S', 'U', 'B'+80h ; token 0x8c
                db    'R', 'E', 'T', 'U', 'R', 'N'+80h ; token 0x8d
                db    'R', 'E', 'M'+80h                ; token 0x8e
                db    'S', 'T', 'O', 'P'+80h           ; token 0x8f
                db    'O', 'U', 'T'+80h                ; token 0x90
                db    'O', 'N'+80h                     ; token 0x91
                db    'N', 'U', 'L', 'L'+80h           ; token 0x92
                db    'W', 'A', 'I', 'T'+80h           ; token 0x93
                db    'D', 'E', 'F'+80h                ; token 0x94
                db    'P', 'O', 'K', 'E'+80h           ; token 0x95
                db    'P', 'R', 'I', 'N', 'T'+80h      ; token 0x96
                db    '?'+80h                          ; token 0x97
                db    'L', 'I', 'S', 'T', 'E', 'N'+80h ; token 0x98
                db    'C', 'L', 'E', 'A', 'R'+80h      ; token 0x99
                db    'F', 'N', 'R', 'E', 'T', 'U', 'R', 'N'+80h ; token 0x9a
                db    'S', 'A', 'V', 'E'+80h           ; token 0x9b
                db    '!'+80h                          ; token 0x9c
                db    'U', 'S', 'I', 'N', 'G'+80h      ; token 0x9d
                db    'T', 'A', 'B', '('+80h           ; token 0x0e
                db    'T', 'O'+80h                     ; token 0x9f
                db    'F', 'N'+80h                     ; token 0xa0
                db    'S', 'P', 'C', '('+80h           ; token 0xa1
                db    'T', 'H', 'E', 'N'+80h           ; token 0xa2
                db    'N', 'O', 'T'+80h                ; token 0xa3
                db    'S', 'T', 'E', 'P'+80h           ; token 0xa4
                db    '+'+80h                          ; token 0xa5
                db    '-'+80h                          ; token 0xa6
                db    '*'+80h                          ; token 0xa7
                db    '/'+80h                          ; token 0xa8
                db    '^'+80h                          ; token 0xa9
                db    'A', 'N', 'D'+80h                ; token 0xaa
                db    'O', 'R'+80h                     ; token 0xab
                db    '>'+80h                          ; token 0xac
                db    '='+80h                          ; token 0xad
                db    '<'+80h                          ; token 0xae
                db    'S', 'G', 'N'+80h                ; token 0xaf
                db    'I', 'N', 'P'+80h                ; token 0xb0
                db    'A', 'B', 'S'+80h                ; token 0xb1
                db    'U', 'S', 'R'+80h                ; token 0xb2
                db    'F', 'R', 'E'+80h                ; token 0xb3
                db    'I', 'N', 'P'+80h                ; token 0xb4
                db    'P', 'O', 'S'+80h                ; token 0xb5
                db    'S', 'Q', 'R'+80h                ; token 0xb6
                db    'R', 'N', 'D'+80h                ; token 0xb7
                db    'L', 'O', 'G'+80h                ; token 0xb8
                db    'E', 'X', 'P'+80h                ; token 0xb9
                db    'C', 'O', 'S'+80h                ; token 0xba
                db    'S', 'I', 'N'+80h                ; token 0xbb
                db    'T', 'A', 'N'+80h                ; token 0xbc
                db    'A', 'T', 'N'+80h                ; token 0xbd
                db    'P', 'E', 'E', 'K'+80h           ; token 0xbe
                db    'L', 'E', 'N'+80h                ; token 0xbf
                db    'S', 'T', 'R', '$'+80h           ; token 0xc0
                db    'V', 'A', 'L'+80h                ; token 0xc1
                db    'A', 'S', 'C'+80h                ; token 0xc2
                db    'C', 'H', 'R', '$'+80h           ; token 0xc3
                db    'L', 'E', 'F', 'T', '$'+80h      ; token 0xc4
                db    'R', 'I', 'G', 'H', 'T', '$'+80h ; token 0xc5
                db    'M', 'I', 'D', '$'+80h           ; token 0xc6
                db    'L', 'P', 'O', 'S'+80h           ; token 0xc7
                db    'I', 'N', 'S', 'T', 'R'+80h      ; token 0xc8
                db    'E', 'L', 'S', 'E'+80h           ; token 0xc9
                db    'L', 'P', 'R', 'I', 'N', 'T'+80h ; token 0xca
                db    'T', 'R', 'A', 'C', 'E'+80h      ; token 0xcb
                db    'L', 'T', 'R', 'A', 'C', 'E'+80h ; token 0xcc
                db    'R', 'A', 'N', 'D', 'O', 'M', 'I', 'Z', 'E'+80h ; token 0xcd
                db    'S', 'W', 'I', 'T', 'C', 'H'+80h ; token 0xce
                db    'L', 'W', 'I', 'D', 'T', 'H'+80h ; token 0xcf
                db    'L', 'N', 'U', 'L', 'L'+80h      ; token 0xd0
                db    'W', 'I', 'D', 'T', 'H'+80h      ; token 0xd1
                db    'L', 'V', 'A', 'R'+80h           ; token 0xd2
                db    'L', 'L', 'V', 'A', 'R'+80h      ; token 0xd3
                db    'S', 'P', 'E', 'A', 'K'+80h      ; token 0xd4
                db    27h+80h                          ; "tic" token 0xd5
                db    'P', 'R', 'E', 'C', 'I', 'S', 'I', 'O', 'N'+80h ; token 0xd6
                db    'C', 'A', 'L', 'L'+80h           ; token 0xd7
                db    'K', 'I', 'L', 'L'+80h           ; token 0xd8
                db    'E', 'X', 'C', 'H', 'A', 'N', 'G', 'E'+80h ; token 0xd9
                db    'L', 'I', 'N', 'E'+80h           ; token 0xda
                db    'L', 'O', 'A', 'D', 'G', 'O'+80h ; token 0xdb
                db    'R', 'U', 'N'+80h                ; token 0xdc
                db    'L', 'O', 'A', 'D'+80h           ; token 0xdd
                db    'N', 'E', 'W'+80h                ; token 0xde
                db    'A', 'U', 'T', 'O'+80h           ; token 0xdf
                db    'C', 'O', 'P', 'Y'+80h           ; token 0xe0
                db    'A', 'L', 'O', 'A', 'D', 'C'+80h ; token 0xe1
                db    'A', 'M', 'E', 'R', 'G', 'E', 'C'+80h ; token 0xe2
                db    'A', 'L', 'O', 'A', 'D'+80h      ; token 0xe3
                db    'A', 'M', 'E', 'R', 'G', 'E'+80h ; token 0xe4
                db    'A', 'S', 'A', 'V', 'E'+80h      ; token 0xe5
                db    'L', 'I', 'S', 'T'+80h           ; token 0xe6
                db    'L', 'L', 'I', 'S', 'T'+80h      ; token 0xe7
                db    'R', 'E', 'N', 'U', 'M', 'B', 'E', 'R'+80h ; token 0xe8
                db    'D', 'E', 'L', 'E', 'T', 'E'+80h ; token 0xe9
                db    'E', 'D', 'I', 'T'+80h           ; token 0xea
                db    'C', 'O', 'N', 'T'+80h           ; token 0xeb
                db    0
serial:         dw    1234h            ; serial number
e_next_wo_for:  db    'N', 'E', 'X', 'T', ' ', 'W', '/', 'O', ' ', 'F', 'O', 'R'+80h
e_syntax_error: db    'S', 'Y', 'N', 'T', 'A', 'X', ' ', 'E', 'R', 'R', 'O', 'R'+80h
ret_wo_gosub:   db    'R', 'E', 'T', 'U', 'R', 'N', ' ', 'W', '/', 'O', ' '
                db    'G', 'O', 'S', 'U', 'B'+80h
e_out_of_data:  db    'O', 'U', 'T', ' ', 'O', 'F', ' ', 'D', 'A', 'T', 'A'+80h
e_ill_func:     db    'I', 'L', 'L', 'E', 'G', 'A', 'L', ' ', 'F', 'U', 'N'
                db    'C', 'T', 'I', 'O', 'N'+80h
e_arith_ov:     db    'A', 'R', 'I', 'T', 'H', 'M', 'E', 'T', 'I', 'C', ' '
                db    'O', 'V', 'E', 'R', 'F', 'L', 'O', 'W'+80h
e_out_of_mem:   db    'O', 'U', 'T', ' ', 'O', 'F', ' ', 'M', 'E', 'M', 'O', 'R', 'Y'+80h
e_undef_stmt:   db    'U', 'N', 'D', 'E', 'F', 'I', 'N', 'E', 'D', ' ', 'S'
                db    'T', 'A', 'T', 'E', 'M', 'E', 'N', 'T', ' '+80h
e_subscr_range: db    'S', 'U', 'B', 'S', 'C', 'R', 'I', 'P', 'T', ' ', 'O'
                db    'U', 'T', ' ', 'O', 'F', ' ', 'R', 'A', 'N', 'G', 'E'+80h
e_redim_array:  db    'R', 'E', '-', 'D', 'I', 'M', 'E', 'N', 'S', 'I', 'O'
                db    'N', 'E', 'D', ' ', 'A', 'R', 'R', 'A', 'Y'+80h
e_div0:         db    'C', 'A', 'N', 27h, 'T', ' ', '/', '0'+80h
e_ill_direct:   db    'I', 'L', 'L', 'E', 'G', 'A', 'L', ' ', 'D', 'I', 'R'
                db    'E', 'C', 'T'+80h
e_type_mis:     db    'T', 'Y', 'P', 'E', ' ', 'M', 'I', 'S', '-', 'M', 'A'
                db    'T', 'C', 'H'+80h
e_no_string:    db    'N', 'O', ' ', 'S', 'T', 'R', 'I', 'N', 'G', ' ', 'S'
                db    'P', 'A', 'C', 'E'+80h
e_stringlong:   db    'S', 'T', 'R', 'I', 'N', 'G', ' ', 'T', 'O', 'O', ' '
                db    'L', 'O', 'N', 'G'+80h
e_complex:      db    'T', 'O', 'O', ' ', 'C', 'O', 'M', 'P', 'L', 'E', 'X'+80h
e_cant_cont:    db    'C', 'A', 'N', 27h, 'T', ' ', 'C', 'O', 'N', 'T', 'I'
                db    'N', 'U', 'E'+80h
e_usercall:     db    'U', 'N', 'D', 'E', 'F', 'I', 'N', 'E', 'D', ' ', 'U'
                db    'S', 'E', 'R', ' ', 'C', 'A', 'L', 'L'+80h
e_file_n_found: db    'F', 'I', 'L', 'E', ' ', 'N', 'O', 'T', ' ', 'F', 'O'
                db    'U', 'N', 'D'+80h
e_ill_eof:      db    'I', 'L', 'L', 'E', 'G', 'A', 'L', ' ', 'E', 'O', 'F'+80h
e_files_differ: db    'F', 'I', 'L', 'E', 'S', ' ', 'D', 'I', 'F', 'F', 'E'
                db    'R', 'E', 'N', 'T'+80h
e_recover:      db    'R', 'E', 'C', 'O', 'V', 'E', 'R', 'E', 'D'+80h
e_fnreturn:     db    'F', 'N', 'R', 'E', 'T', 'U', 'R', 'N', ' ', 'W', '/'
                db    'O', ' ', 'F', 'U', 'N', 'C', 'T', 'I', 'O', 'N', ' '
                db    'C', 'A', 'L', 'L'+80h
e_miss_stmt:    db    'M', 'I', 'S', 'S', 'I', 'N', 'G', ' ', 'S', 'T', 'A'
                db    'T', 'E', 'M', 'E', 'N', 'T', ' ', 'N', 'U', 'M', 'B', 'E', 'R'+80h
a_invalid_input:db    '*', 'I', 'N', 'V', 'A', 'L', 'I', 'D', ' ', 'I', 'N'
                db    'P', 'U', 'T', '!+80h'
a_at_line:      db    ' ', '@', ' ', 'L', 'I', 'N', 'E', ' '+80h
a_ready:        db    CHAR_LF, 'R', 'E', 'A', 'D', 'Y', ':', '*'+80h
a_extralost:    db    '*', 'E', 'X', 'T', 'R', 'A', ' ', 'L', 'O', 'S', 'T', '*'+80h
a_break:        db    CHAR_LF, '*', 'B', 'R', 'E', 'A', 'K'+80h
                db    0
;
; Start of disposable part of BASIC
;
; undocumented internal diagnostic:
; print a hardcoded serial number

print_serial:   call  print_crlf       ; print a CRLF
                ld    hl, (serial)     ; print serial number?
                call  print_HL
                call  print_crlf       ; print a CRLF
loc_2FC3:       ld    hl, TDL_init_msg ; print out "TDL" init message
                call  print_string
;
; COLD START ENTRY POINT, initialize everything
coldstart:      xor    a               ; clear A, and CY
                ld    hl, iosuppress   ; start of program variables
loc_2FCD:       ccf                    ; set CY
loc_2FCE:       ld    (hl), a          ; clear cell
                inc   l                ; next cell
                jr    nz, loc_2FCE     ; no CY?, loop
                inc   h                ; increment H
                jr    c, loc_2FCD      ; was CY set, yes clear, and loop again
                                       ; effectively: clear memory range from 0100-02ff
                dec   hl               ; HL is 0300, decrement
                ld    sp, hl           ; initialize stack
                ld    (string_base), hl ; save stacktop
                ld    hl, 0FFFFh       ; set lineno to invalid
                ld    (lineno), hl
                ld    a, CHAR_COMMA    ; comma
                ld    (inputbuf-1), a  ; store
                ld    a, 0C3h          ; JP instruction
                ld    (resetvector), a ; store in reset vector
                ld    (outputvector), a ; store in output vector
                ld    (coldvector), a
                ld    hl, coldstart    ; address of coldstart
                ld    (cold_addr), hl  ; store it
                ld    iy, conparam     ; point to console parameter structure
                ld    hl, CONSOLEOUT
                ld    (output_addr), hl ; set output vector to console
                ld    a, 72            ; set line length to 72
                ld    (conparam.linelength), a ; store in console parameter set
                ld    (prtparam.linelength), a ; store in printer parameter set
                ld    a, 56            ; position of last complete print field
                                       ; print length is 14
                                       ; i.e. positions are 0,14,28,42,56
                ld    (conparam.last_field), a ; store in console parameter set
                ld    (prtparam.last_field), a ; store in printer parameter set
                ld    hl, WARMSTART    ; warm start address
                ld    (reset_addr), hl ; store in RESET vector
                ld    hl, stringstk    ; HL is addr of exprstack
                ld    (stringstkptr), hl ; store ptr
                ld    hl, 0            ; clear HL
                ld    (rnd_mant23), hl
                ld    (rnd_mant45), hl
                ld    (rndmant6_exp), hl
                ld    hl, highmem_msg  ; print "highest memory" message
                call  print_string
                call  get_input        ; get an input line
                call  nextchar         ; advance to find a number
                cp    'A'              ; was an A entered?
                jr    z, loc_2FC3      ; goto abort
                cpl                    ; complement input (obfuscate serial check)
                cp    0ACh             ; is it now AC, i.e. was 53h before, i.e. 'S' ?
                jp    z, print_serial  ; go print serial number
                inc   a                ; was FF?
                jr    nz, loc_3048     ; no, continue processing
; use memsize function get get max memory
                call  MEMSIZE          ; get the available memory size in B,A (high,low)
                ld    h, b             ; copy to HL
                ld    l, a
                jr    has_memsize      ; continue initializing
loc_3048:       ld    hl, inputbuf     ; point to inputbuf
                call  skipspace        ; skip space
                call  parse_number_fpaccu ; pack number in fpaccu
                ld    a, (hl)          ; get next char
                or    a                ; not end of buf?
                jp    nz, syntax_error ; oops, don't accept this
                call  fpaccu_to_u16    ; convert to u16 number in DE
                ex    de, hl           ; move to HL
                dec   hl               ; subtract 2 (end of memory)
                dec   hl
has_memsize:    ld    (memory_top), hl ; memory size in HL
                ld    (string_top), hl
                push  hl               ; save size
                ld    de, 300h         ; load base of memory
                or    a                ; clear CY
                sbc   hl, de           ; less than 0x300?
                pop   hl
loc_306A:       jp    c, out_of_memory_error ; too few memory
                ld    de, -100         ; subtract 100
                add   hl, de
                ld    de, 300h         ; subtract 0x300
                CPHL_DE   
                ld    de, print_serial ; start of disposable coldstart area
                jr    nc, loc_3082     ; larger than 0x300?
                ld    de, 300h         ; reserve space for stack
loc_3082:       CPHL_DE                ; at least enough memory for BASIC itself?
                jr    c, loc_306A      ; out of memory
                ld    sp, hl           ; put stack below top of memory
                ld    (string_base), hl
                ex    de, hl           ; top - 0x300
                ld    (start_memory), hl ; lowest memory usable
                call  check_memfree    ; verify still enough stack space
                or    a
                ex    de, hl
                sbc   hl, de           ; calculate difference
                ld    bc, -16          ; reserve 16 more bytes
                add   hl, bc
                call  print_crlf       ; do CRLF
                call  print_HL         ; print number in HL
                ld    hl, bytes_free_msg ; print bytes free message
                call  print_string
                ld    hl, print_string
                ld    (cold_addr), hl  ; put into cold addr (coldstart is now disposed)
                call  new_memory       ; enter interpreter loop
                jp    print_prompt     ; main loop
				
TDL_init_msg:   db    'T', '.', 'D', '.', 'L', '.', ' ', 'Z', '-', '8', '0', ' '
                db    'B', 'A', 'S', 'I', 'C', ' ', 'b', 'y', ' ', 'N', 'e', 'i'
                db    'l', ' ', 'C', 'o', 'l', 'v', 'i', 'n', ' ', '&>', ' ', 'R'
                db    'o', 'g', 'e', 'r', ' ', 'A', 'm', 'i', 'd', 'o', 'n', CHAR_LF
                db    'M', 'a', 'y', ' ', ' ', '1', '9', '7', '7', CHAR_LF+80h
highmem_msg:    db    CHAR_LF, 'H', 'i', 'g', 'h', 'e', 's', 't', ' ', 'M', 'e', 'm'
                db    'o', 'r', 'y'+80h
bytes_free_msg: db    ' ', 'B', 'y', 't', 'e', 's', ' ', 'F', 'r', 'e', 'e', CHAR_LF
welcome_msg:    db    CHAR_LF, 'W', 'e', 'l', 'c', 'o', 'm', 'e', ' ', 't', 'o', ' '
                db    'B', 'A', 'S', 'I', 'C', ',', ' ', 'V', 'e', 'r', '.', ' '
                db    '2', '.', '1', CHAR_LF, '<', 'T', 'D', 'L', ' ', 'Z', '-', '8'
                db    '0', ' ', 'H', 'i', 'g', 'h', ' ', 'P', 'r', 'e', 'c', 'i'
                db    's', 'i', 'o', 'n', ' ', 'E', 'x', 't', 'e', 'n', 'd', 'e'
                db    'd', ' ', 'V', 'e', 'r', 's', 'i', 'o', 'n', '>', CHAR_LF+80h
                end