0000                          ; Will Stevens
0000                          ; 25th Feb 2023
0000                          ; 1K 8080 BASIC
0000                          ; GPL v3
0000                          ; 
0000                          ; Terminal settings:
0000                          ; 
0000                          ; Assumes that outputting a newline requires
0000                          ; CR and LF, and that pressing return on the
0000                          ; terminal sends CR alone. 1K BASIC echoes all
0000                          ; characters it receives back to the terminal.
0000                          ; I believe that these settings are compatible
0000                          ; with using a Teletype Model 33 in full duplex
0000                          ; mode. If using a VT100 terminal emulator, LNM
0000                          ; must be reset so that pressing Return sends
0000                          ; CR alone.
0000                          ; 
0000                          ; Post-assembly checklist
0000                          ; 
0000                          ; 1. LineNumSub is at address 223h
0000                          ; 2. DivSub is atvaddress 1ffh
0000                          ; 3. LO(AbsSub)>LO(NextSub)
0000                          ; 4. In LineStartsWithInt, the jump to
0000                          ;    DeleteProgramLine is on the same
0000                          ;    page as DeleteProgramLine
0000                          ; 5. Program does not exceed 1k
0000                          ; 6. In ClassLookup, check that QuoteClass
0000                          ;    has LSBit different from othet class
0000                          ;    routines.
0000                          ; 7. Ready is at address 00BB
0000                          ; 8. Code before 'Ready:' does not overlap with
0000                          ;    'Ready:', Can be seen from the HEX file.
0000                          ; 9. AbsSub is at address 01BA
0000                          ; 
0000                          ; Development log:
0000                          ; 2023-03-03 About 450 bytes long
0000                          ; 2023-03-08 About 750 bytes long
0000                          ; 2023-03-11 About 840 bytes long
0000                          ; 2023-03-12 About 930 bytes long.
0000                          ;   String tokens added.
0000                          ;   * and / yet to be added.
0000                          ;   Some scope for size optimization.
0000                          ; 2023-03-12 About 940 bytes long
0000                          ;		* added
0000                          ;		some reduction in code size done
0000                          ; 2023-03-16 About 970 bytes long
0000                          ;   unsigned / and integer output added
0000                          ;		about 30 bytes could be saved
0000                          ;		by using RST in place of call
0000                          ;   in some places
0000                          ; 2023-03-17 About 940 bytes long
0000                          ; 2023-03-17 About 970 bytes long
0000                          ;		INPUT added
0000                          ; 2023-03-19 About 960 bytes long
0000                          ;    some bug fixes
0000                          ;		 capable of playing lunar lander
0000                          ; 2023-03-22 About 970 bytes long
0000                          ;		 signed / added
0000                          ; 2023-03-24 About 950 bytes long
0000                          ;		 more code size reductions
0000                          ;		 signed integer parsing supported
0000                          ; 2023-03-24 About 940 bytes long
0000                          ;    more code size reductions
0000                          ; 2023-03-27 About 950 bytes long
0000                          ;		 simplified operator calling and
0000                          ;		 simplified a few operators
0000                          ;		 working on memory rotate function needed
0000                          ;		 for line deletion and insertion
0000                          ; 2023-04-09 About 970 bytes long.
0000                          ;		 more code size reductions
0000                          ;		 first draft of memory rotate function added
0000                          ; 2023-04-12 About 995 bytes long
0000                          ;		 line deletion function more complete
0000                          ;		 looking for better way of decreasing
0000                          ;		 PROG_PTR after line deletion
0000                          ; 2023-04-16 About 986 bytes long
0000                          ;    line deletion apparently working
0000                          ;    some code size reductions
0000                          ; 2023-04-16 About 963 bytes long
0000                          ;			further code size reductions
0000                          ; 2023-04-17 About 930 bytes long
0000                          ;			looked for subroutine code sharing and
0000                          ;			LXI trick optimisations.
0000                          ;			Likely that some bugs will have been
0000                          ;			introduced when doing this
0000                          ; 2023-04-18 About 900 bytes long
0000                          ;			greatly reduced CharClass size
0000                          ; 2023-04-20 About 880 bytes long
0000                          ;			more code size reduction
0000                          ; 2023-04-23 About 970 bytes long
0000                          ;			first draft of code for LIST added
0000                          ; 2023-04-25 About 970 bytes long
0000                          ;			LIST command working
0000                          ; 2023-04-27 About 950 bytes long
0000                          ;			More code size reduction
0000                          ; 2023-04-28 About 950 bytes long
0000                          ;			used RST_CompareJump to save
0000                          ;			2 bytes for every CPI JZ where
0000                          ;			the jump is to same page
0000                          ; 2023-04-28 Free space: 78 bytes
0000                          ; 2023-04-29 Free space: 84 bytes
0000                          ;			Initialise PROG_PTR at start
0000                          ;			Added NEW and END
0000                          ;			Added direct statement handling
0000                          ; 2023-04-30 Free space: 86 bytes
0000                          ;			Fixed bugs with deleting first and
0000                          ;			last program lines
0000                          ; 2023-05-02 Free space: about 60 bytes
0000                          ;			added code to allow out-of-order
0000                          ;			line number entry (first draft)
0000                          ; 2023-05-02 Free space: about 54 bytes
0000                          ;			all basic functionality now implemented
0000                          ;			items to improve:
0000                          ;			division
0000                          ;			syntax checking
0000                          ; 2023-05-04 Free space: about 79 bytes
0000                          ;			more code size reduction
0000                          ;			partly through handling EndProgram
0000                          ;			and LineNum better in threaded code
0000                          ;			likely to have introduced bugs
0000                          ; 2023-05-07 Free space: about 69 bytes
0000                          ;			Improved expression evaluation by
0000                          ;			making it recursively callable
0000                          ;			and no longer requiring operator stack
0000                          ;			and about 20 bytes shorter.
0000                          ;			Used freed space for more syntax checks
0000                          ; 2023-05-08 Free space: about 44 bytes
0000                          ;			First draft of support for array var @
0000                          ; 2023-05-17 Free space: About 100 bytes
0000                          ;			First draft of new parser from
0000                          ;			experiments/parsing3.asm.
0000                          ;			Still need to modify string representation
0000                          ;			and change how INPUT parses integer,
0000                          ;			and check string token doesn't interfere
0000                          ;			after TokenList, and check order in
0000                          ;			TokenList.
0000                          ;			Seems likely that enough space has been
0000                          ;			freed to be able to implement FOR...NEXT
0000                          ; 2023-05-19 Free space: About 101 bytes
0000                          ;			Issues listed above have been addressed now
0000                          ;			Testing needed to iron out problems
0000                          ; 2023-05-26 Free space: About 84 bytes
0000                          ;			various bug fixes
0000                          ;			PRINT allows comma at end to suppress
0000                          ;			newline.
0000                          ;			Show > prompt symbol when ready.
0000                          ; 2023-05-27 Free space: About 17 bytes
0000                          ;			Added FOR NEXT (no STEP yet)
0000                          ;			Need more space
0000                          ; 2023-05-27 Free space: About 36 bytes
0000                          ;			Made a few small byte savings, and put
0000                          ;			token subs onto page 2 so that last one
0000                          ;			can flow onto page 3, freeing some space
0000                          ;			in page 2 to avoid having to jump out.
0000                          ;			One TODO to action
0000                          ; 2023-05-28 Free space: About 42 bytes
0000                          ; 2023-05-29 Free space: About 53 bytes
0000                          ;			Made some changes to * and / which I hope
0000                          ;			are improvements (efficienxy + code size)
0000                          ;			but testing needed to confirm this.
0000                          ; 2023-06-02 Free space: About 12 bytes
0000                          ;			Added support for STEP to FOR loops
0000                          ;			Noted where Z flag is in known state
0000                          ;			in JMP instructions, because there is
0000                          ;			potential space saving by having
0000                          ;			2-byte in-page JMP, JNZ or JZ,
0000                          ;			code shared with RST_CompareJump
0000                          ; 2023-06-03 Free space: About 10 bytes
0000                          ;			STEP works in +ve direction only
0000                          ;			Fixing will require more space
0000                          ;			Would also like to add ABS, RND, USR
0000                          ;			But probably need about 60 bytes for that
0000                          ; 2023-06-03 Free space: About 19 bytes
0000                          ;			Added in-page JZ to free up space
0000                          ;			Likely to have introduced errors
0000                          ; 2023-06-04 Free space: About 25 bytes
0000                          ;			Shortened PrintSub
0000                          ; 2023-06-04 Free space: about -21 bytes
0000                          ;			Implementing ABS and USR and skeleton
0000                          ;		  of RND makes it 21 bytes over budget.
0000                          ;			So it seems reasonable to think that
0000                          ;			space can be made for these.
0000                          ; 2023-06-05 Free space: about -15 bytes
0000                          ; 2023-06-19 Free space: about 6 bytes
0000                          ;			Replaced memory rotate with triple reversal
0000                          ;			algorithm. Back below size limit, but need
0000                          ;		  to rearrange things to realize this.
0000                          ; 2023-06-22 Free space: about 10 bytes
0000                          ;			All free space is in the RST area, which I
0000                          ;     am reluctant to use because I expect that
0000                          ;			when I try to target actual hardware I will
0000                          ;			need to extend PutChar, and maybe have
0000                          ;			some initialization code for e.g. UART.
0000                          ;			So discounting this I am 2 bytes over
0000                          ;			budget, and haven't implemented RND
0000                          ;			function yet
0000                          ; 2023-06-23 Free space : 18 bytes
0000                          ;			Saved space with more sharing between
0000                          ; 		LET and INPUT
0000                          ;			Ready to do a lot of testing
0000                          ; 2023-06-28 Free space : 20 bytes
0000                          ; 2023-06-28 Free space : 19 bytes
0000                          ;			Fixed enough bugs that lunar lander works
0000                          ;			Function calls don't work yet
0000                          ; 2023-07-01 Free space : 24 bytes
0000                          ;			ABS function works
0000                          ;			RND function currently does nothing
0000                          ;			need to make implementation of RND
0000                          ;			that fits in 17 bytes
0000                          ; 2023-07-04 Free space : 20 bytes
0000                          ;			Implemented simple lookup-based RND
0000                          ;			replaced newline RST with LDAX B, INX B
0000                          ;			saved a few bytes in LIST
0000                          ; 2023-07-05 Free space : 11 bytes
0000                          ;			Implemented XORSHIFT RND function
0000                          ; 2023-07-08 Free space: 10 bytes
0000                          ; 2023-07-12 Free space: 15 bytes
0000                          ;			Fixed forgotten issue where STEP in FOR
0000                          ;			loop didn't work if negative
0000                          ; 2023-07-13 Free space: 13 bytes
0000                          ;			Extended variable range up to 32
0000                          ;			So that user has 31 variables and array
0000                          ;			var 30 can be used to work out
0000                          ;			remaining memory
0000                          ;			var 31 is RNG seed
0000                          ; 2023-07-15 Noticed bug where -32768 isn't
0000                          ;     displayed
0000                          ; 2023-07-15 When playing REVERSE, saw corrupted
0000                          ;			array, which implies that bug where stack
0000                          ;			continually growing
0000                          ; 2023-07-16 Above two issues fixed. Former
0000                          ;     required change to PrintInteger. Latter
0000                          ;			was due to a GOTO from within FOR loop,
0000                          ;			in REVERSE and not necessarily a problem
0000                          ;			with this interpreter
0000                          ; 2024-01-01 Fixed bug where parse error wasn't
0000                          ;     displayed as ? during LIST
0000                          ; 2024-01-28 Fixed bug where @ was displayed as M
0000                          ;     during LIST
0000                          ; 2024-02-07 Working on corrections to comparison
0000                          ;     operators. Not in working state. Made I/O
0000                          ;     compatible with Dick Whipple's Front Panel
0000                          ;     8080 simulator
0000                          ; 2024-02-08 May have fixed comparison operator
0000                          ;     problem. Need to save 2 bytes to be able to
0000                          ;     test it
0000                          ; 2024-02-08 Reclaimed some space so that 3FEh is
0000                          ;     the last byte uses. Free space 5 bytes.
0000                          ; 2024-02-18 Worked towards reclaiming 4 bytes in
0000                          ;     the tokenizer. Good chance of being
0000                          ;     incorrect, will require debugging.
0000                          ; 2024-02-20 Debugged above changes and
0000                          ;     they seem okau. Free space 9 bytes
0000                          ; 2024-02-22 Rearranged RSTs and added CPI to end
0000                          ;     of RST_LDAXB_INXB_CPI to save memory.
0000                          ;     Free space still 9 bytes but now
0000                          ;     7 of those are at the end of 1K, so are
0000                          ;     easy to make use of.
0000                          ;     Need to check movement and alignment
0000                          ;     of subroutines.
0000                          ;     It would be useful to have a checklist of
0000                          ;     all dependencies that need to be checked
0000                          ;     when there are large movements in memory.
0000                          ; 
0000                          ;     Next things to do:
0000                          ;     - unterminated string check
0000                          ;     - forbidding excess chars in tokens
0000                          ;     - correct operator precedence for * /
0000                          ;     - error on divide by zero
0000                          ;     not sure whether all 4 can be done in
0000                          ;     only 7 bytes
0000                          ; 2024-02-25 Added unterminated string check and
0000                          ;     didvide by zero error. 2 bytes over budget.
0000                          ; 2024-02-25 Realised that removing reatriction
0000                          ;     that RUN, LIST and NEW only allowed in
0000                          ;     direct mode would will probably save a
0000                          ;     sufficient number of bytes to finish all
0000                          ;     outstanding work
0000                          ; 2024-02-28 Sveral changes related to issues
0000                          ;     listed above, Divide by zero and
0000                          ;     unterminated string now generate error
0000                          ;     messages. 2 bytes free which should be
0000                          ;     enough to make * and / equal precedence,
0000                          ;     but will test everything else first. Issue
0000                          ;     about tokens with excess chars not being
0000                          ;     detected as errors will remain unfixed in
0000                          ;     first release.
0000                          ; 2024-03-01 Found bug where recent changes
0000                          ;     caused DeleteProgramLine to move page.
0000                          ;     In the course of fixing it, may have saved
0000                          ;     5 bytes. Need to test that fix is correct.
0000                          ; 2024-03-01 Fixed a bug introduced on 28 Feb
0000                          ;     where ExecuteDirect was called without
0000                          ;     setting B. Wrote 'game of life' example
0000                          ;     program. When printing newline, added CR
0000                          ;     before after discovering that some
0000                          ;     terminals need this. Need to free up
0000                          ;     1 byte to fix operator precedence issue
0000                          ; 2024-03-02 This version correcly runs
0000                          ;     lander.bas, reverse.bas, life.bas,
0000                          ;     operatortests.bas, operatortests2.bas,
0000                          ;     looptests.bas
0000                          ; 2024-03-02 Freed up 1 byte by removing
0000                          ;     redundant STC
0000                          ; 2024-03-03 Added code to make * same
0000                          ;     precedence as / (needs testing).
0000                          ;     Changed RNG from XORSHIFT to LCG.
0000                          ;     This saved 3 bytes.
0000                          ;     Need to experiment with LCG constant
0000                          ;     for best RNG performance.
0000                          ;     Behaviour of RNG function changed so
0000                          ;     that max valid input parameter is 256,
0000                          ;     because low order bits of RNG have
0000                          ;     low period. Only high ordet bits of
0000                          ;     RNG are used for return value.
0000                          ; 2024-03-04 Altered EndProgram address.
0000                          ;     Temporarily tried making RAM start at 1000h
0000                          ;     to check that this doesn't cause problems
0000                          ; 2024-03-06 Changed IO to support Stefan Tramms
0000                          ;     8080 emulator.
0000                          ; 2024-03-11 Moved start of RAM back to 0400h
0000                          ; 2024-03-12 Changed initialisation so that
0000                          ;     spurious char is no longer output on
0000                          ;     reset or NEW.
0000                          ; 2024-03-15 Realised during testing that
0000                          ;     ExpEvaluate can sometimes try to return
0000                          ;     when stack isn't a return address.
0000                          ;     Realised that ExpEvaluate must either
0000                          ;     succeed or fail, with no backtrack.
0000                          ;     This required substantial changes to
0000                          ;     PrintSub, especially a change to how it
0000                          ;     knows if it has just had a comma. This
0000                          ;     is now done based on parity of H.
0000                          ;     To be retested.
0000                          ; 
0000                          ;     Had an idea that operators and statements
0000                          ;     could reside on different pages, creating
0000                          ;     more space for both, and perhaps removing
0000                          ;     the need for some of the Jumps out of
0000                          ;     page 2 to statement implementation.
0000                          ;2024-03-23
0000                          ;     Changed INPUT so that it doesn't display
0000                          ;     a prompt. It was confusing to have the
0000                          ;     > prompt as is used in direct mode. Instead
0000                          ;     programs that need a prompt before input
0000                          ;     can use the multistatement line
0000                          ;     PRINT "?", INPUT A
0000                          ; 2024-03-25 Found a fix for problem where
0000                          ;     -32768/2 has wrong sign. It costs 3 bytes
0000                          ;     so need to find 2 byte saving before Ready
0000                          ;     and 1 byte saving after Ready
0000                          ; 2024-03-26 In the process of making major
0000                          ;     rearrangements to save several bytes and
0000                          ;     fix the bug mentioned above.
0000                          ; 2024-03-27 Major rearrangements have been done.
0000                          ;      Net reault is to save 5 bytes, but need
0000                          ;      to carefully check whether any same-page
0000                          ;      assumptions are violated
0000                          ; 2024-03-28 Found and fixed several bugs related
0000                          ;			 to above changes. Execution of ? token
0000                          ;			 seems to take too long, implying a
0000                          ;			 remaining bug. 9 bytes free now, 5 of
0000                          ;			 which are contiguous at the end of the
0000                          ;			 program.
0000                          ; 2024-03-29 Two bugs to fix : prompt appears
0000                          ; 		 twice after entering first line.
0000                          ;			 detection of syntax errors is slow
0000                          ; 2024-04-01 Fixed several bugs introduced above.
0000                          ;      Need to run all tests again.
0000                          ; 2024-04-03 Changed newline behaviour so that
0000                          ;      VT100 terminals require LNM reset rather
0000                          ;      than set.
0000                          ; 2024-04-04 Reclaimed 2 bytes in
0000                          ;      DigitClassNotEnd. Used those two bytes to
0000                          ;      add a colon token. It can be used as a
0000                          ;      statement separator in multi-statement
0000                          ;      lines.
0000                          ; 2024-04-10 Modified PrintSub so that it no
0000                          ;      longer uses parity bit and should work
0000                          ;      on Z80
0000                          ; For development purposes assume we have
0000                          ; 1K ROM from 0000h-03FFh containing BASIC
0000                          ; 1K RAM from 0400h-0800h
0000                RAM_BASE:   EQU   0400h   
0000                RAM_TOP:   EQU   0800h   
0000                          ; Token values
0000                          ; 0-31 are variables (0 = @)
0000                          ; IntegerToken must be one more than last var
0000                INTEGERTOKEN:   EQU   32   
0000                QUESTIONMARKTOKEN:   EQU   33   
0000                STRINGTOKEN:   EQU   34   
0000                          ; Callable tokens are low byte of subroutine to call
0000                          ; Errors are displayed as Ex where x is an error
0000                          ; code which is tbe address on the stack when
0000                          ; Error subroutine is called.
0000                          ; Input buffer is just 8 bytes long
0000                          ; used by input statement to get an integer.
0000                          ; If there is a buffer overflow because user
0000                          ; enters too much, the behaviour is system
0000                          ; dependent - e.g. if writes above RAM
0000                          ; space do nothing then its not a problem.
0000                          ; If memory space repeats and lower 1K
0000                          ; is ROM then also not much of a problem.
0000                INPUT_BUFFER:   EQU   RAM_TOP-8   
0000                STACK_INIT:   EQU   RAM_TOP-8   
0000                          ; this must be on a 256 byte boundary
0000                VAR_SPACE:   EQU   RAM_BASE   
0000                          ; 30 words, first of which is not
0000                          ; accessible to user, so can be
0000                          ; used for PROG_PTR
0000                PROG_PTR:   EQU   RAM_BASE   
0000                          ; 2 words accessible to user as variables
0000                          ; 30 and 31 (^ and _)
0000                PROG_PARSE_PTR:   EQU   RAM_BASE+60   
0000                RNG_SEED:   EQU   RAM_BASE+62   
0000                PROG_BASE:   EQU   RAM_BASE+64   
0000                          .ORG   00h   
0000                          ; I would like this to be:
0000                          ; LXI H,PROG_BASE
0000                          ; SHLD PROG_PTR
0000                          ; JMP Ready
0000                          ; 
0000                          ; But this doesn't fit in 8 bytes.
0000                          ; Instead we find a place in the program
0000                          ; that already has "LXI B,PROG_BASE" and
0000                          ; follow it with "dw Ready" and set SP to that
0000                          ; address, then POP H from
0000                          ; the stack and store it in PROG_PTR, then
0000                          ; RET will jump to Ready.
0000                          ; We must ensure that Ready is at an address
0000                          ; that corresponds to a harmless instruction.
0000                          ; 00B8 to 00BF is a good range to aim for
0000                          ; because B8-BF are CMP instructions which
0000                          ; affect flags and nothing else.
0000   31 85 02               LXI   SP,ExecuteProgram+1   
0003   E1                     POP   H   
0004   22 00 04               SHLD   PROG_PTR   
0007   C9                     RET   
0008                          .ORG   08h   
0008                          ; PutChar is called frequently
0008                          ; PutChar must return with Z set
0008                PUTCHAR:   
0008                          ; port 1 is for char I/O
0008   D3 01                  OUT   1   
000A                          ; 
000A                          ; Having the wait loop after the character
000A                          ; is output will slow down I/O when running
000A                          ; on hardware, but I can't think of a way
000A                          ; of fitting this into 8 bytes otherwise.
000A                          ; 
000A                PUTCHARWAITLOOP:   ; address 000ah
000A                          ; TODO change these few instructions
000A                          ; if targetting hardware
000A   AF                     XRA   A   
000B   C9                     RET   
000C                          ;IN 1
000C                          ;ANI 040h
000C                          ;RZ
000C                          ;db 0c3h ; opcode for JMP
000C                          ; the following two bytes are
000C                          ; 0ah and 00h, so this jumps to
000C                          ; PutCharWaitLoop
000C                          ; 
0010                          .ORG   10h   
0010   0A                     LDAX   B   ; opcode 0ah
0011   00                     NOP   ; opcode 00h
0012   03                     INX   B   
0013   E3                     XTHL   
0014   BE                     CMP   M   
0015   23                     INX   H   
0016   E3                     XTHL   
0017   C9                     RET   
0018                          ; 
0018                          .ORG   18h   
0018                          ; byte after RST is compared with A
0018                          ; if equal then jump to address on same page.
0018                          ; 
0018                          ; only use where performance is not
0018                          ; important (parsing, printing)
0018   E3                     XTHL   
0019   BE                     CMP   M   
001A   23                     INX   H   
001B   C3 21 00               JMP   CompareJump_Entry   
001E                          ; 
001E                          ; 2 bytes free
0020                          .ORG   20h   
0020   E3                     XTHL   
0021                COMPAREJUMP_ENTRY:   
0021   C2 25 00               JNZ   JZPage_Skip   
0024   6E                     MOV   L,M   
0025                JZPAGE_SKIP:   
0025   23                     INX   H   
0026                EXPAPPLYOP:   ; shared code
0026   E3                     XTHL   
0027   C9                     RET   
0028                          .ORG   28h   
0028                COMPAREHLDE:   
0028                          ; compare HL and DE, return
0028                          ; Z equal, NZ if not equal
0028                          ; C equal, NC if not equal
0028                          ; A will be zero if Z is set
0028   7D                     MOV   A,L   
0029   AB                     XRA   E   
002A   C0                     RNZ   
002B   7C                     MOV   A,H   
002C   AA                     XRA   D   
002D   C0                     RNZ   
002E   37                     STC   
002F   C9                     RET   
0030                          .ORG   30h   
0030                NEGATEDE:   
0030                          ;flags are not affected
0030                          ; 
0030                          ; decrement and invert so that we end
0030                          ; up with D in A - sometimes handy
0030   1B                     DCX   D   
0031   7B                     MOV   A,E   
0032   2F                     CMA   
0033   5F                     MOV   E,A   
0034   7A                     MOV   A,D   
0035   2F                     CMA   
0036   57                     MOV   D,A   
0037   C9                     RET   
0038                          .ORG   38h   
0038                          ; BC points to program
0038                          ; DE contains value
0038                          ; Stack is used for both operands and
0038                          ; operators
0038                EXPEVALUATE:   
0038                          ; ExpEvaluate must not be called
0038                          ; from page 1, The hi byte of the return address
0038                          ; is a marker to distinguish it from an operator.
0038                          ; Only operators have hi byte = 1
0038                EXPEVALUATENUM:   
0038                          ; Expecting ( var integer or - sign
0038                          ; or function call
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
0038   D7 RST   2   
0039   BB                     DB   LeftBraceToken&0ffh   
        **MACRO UNROLL - RST_JZPAGE
003A   E7 RST   4   
003B   9F                     DB   (ExpLeftBrace&0ffh)-1   
        **MACRO UNROLL - RST_COMPAREJUMP
003C   DF RST   3   
003D   E6 73                  DB   SubSub&0xff,(ExpNegate&0ffh)-1   
003F                          ; 
003F                          ; last function
003F   FE BF                  CPI   (RndSub+1)&0ffh   
0041   D4 B1 00               CNC   Error   
0044                          ; first function
0044   FE B8                  CPI   AbsSub&0ffh   
0046   D2 A1 00               JNC   FunctionCall   ; between RndSub and AbsSub
0049                          ; 
0049   FE 20                  CPI   IntegerToken   
004B   DA 55 00               JC   ExpVar   
004E                          ; 
004E                          ; Integer token is one more than last var
004E                          ; token so if carry is set then it is a var
004E                          ; 
004E   C4 B1 00               CNZ   Error   
0051                          ; Fall through to ExpInteger
0051                EXPINTEGER:   
0051   60                     MOV   H,B   
0052   69                     MOV   L,C   
0053   03                     INX   B   
0054   03                     INX   B   
0055                          ; 
0055                          ; fall through with carry clear
0055                EXPVAR:   
0055                          ; carry set if jumped to here
0055                          ; 
0055   DC EE 02               CC   GetVarLocation   
0058                EXPVARGETVALUE:   
0058   5E                     MOV   E,M   
0059   23                     INX   H   
005A   56                     MOV   D,M   
005B                EXPEVALUATEOP:   
005B                          ;Expecting operator or right bracket or
005B                          ;end of expression
005B                          ; 
005B                          ;Are there operators on the stack?
005B   E1                     POP   H   
005C                          ; 
005C                          ; H will be 0, 2 or 3 if no operators on
005C                          ; stack (i.e. high byte of return address)
005C                          ; 
005C   7C                     MOV   A,H   
005D   3D                     DCR   A   
005E   C2 6D 00               JNZ   SkipExpApplyOp   
0061                          ; 
0061                          ; if L is equal to MulSub then apply it.
0061                          ; this gives * same precedence as /
0061                          ;MOV A,L
0061                          ;RST_CompareJump
0061                          ;DB (MulSub&0ffh),(ExpApplyOp&0ffh)-1
0061                          ; 
0061   7D                     MOV   A,L   
0062   FE E7                  CPI   NegateSub&0ffh   
0064   D2 26 00               JNC   ExpApplyOp   
0067                          ; 
0067   0A                     LDAX   B   
0068                          ; 
0068                          ; No longer needed since case below
0068                          ; includes this
0068                          ;CPI Operators&0ffh
0068                          ; Is it the end of the expression?
0068                          ;JC ExpApplyOp
0068                          ; 
0068                          ; Does operator on stack have GTE precedence?
0068                          ; (or end of expression, when A < operators)
0068   3D                     DCR   A   
0069   BD                     CMP   L   
006A                          ; 
006A   DA 26 00               JC   ExpApplyOp   ; apply the operator
006D                          ; that was on the stack
006D                          ; 
006D                SKIPEXPAPPLYOP:   
006D   E5                     PUSH   H   ; put operator that was on stack
006E                          ; back onto stack
006E                          ; 
006E   0A                     LDAX   B   
006F                          ; 
006F   FE CD                  CPI   Operators&0ffh   
0071                          ; Is it the end of the expression?
0071   D8                     RC   
0072                          ; 
0072   03                     INX   B   
0073                          ; 
0073                          ; fall through
0073   21                     DB   21h   ; LXI H eats 2 bytes
0074                EXPNEGATE:   
0074   3C                     INR   A   
0075   11 00 00               LXI   D,0   
0078                          ; 
0078   21 5B 00               LXI   H,ExpEvaluateOp   ; address to return to
007B                          ; after operator is called
007B   E5                     PUSH   H   
007C                          ; 
007C                          ; Put 0 onto stack and operator onto
007C                          ; operator stack
007C                          ; 
007C   D5                     PUSH   D   ; operand
007D   6F                     MOV   L,A   
007E   24                     INR   H   ; Assumes H was 0 and needs to be 1
007F   E5                     PUSH   H   
0080                          ; 
0080   C3 38 00               JMP   ExpEvaluateNum   
0083                FORSUBIMPL:   
0083                          ; Stack contains return address:
0083                          ; ExecuteProgramLoop - EPL
0083                          ; Keep it there even though it isn't used by
0083                          ; ForSub, it will be used by NextSub
0083                          ; 
0083   E5                     PUSH   H   ; stack contains <SP> VL+1, EPL
0084                          ; 
0084                          ; check that we have a 'TO' token
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
0084   D7 RST   2   
0085   A9                     DB   ToToken&0ffh   
0086   C4 B1 00               CNZ   Error   
0089                          ; 
        **MACRO UNROLL - RST_EXPEVALUATE
0089   FF RST   7   
        **MACRO UNROLL - RST_NEGATEDE
008A   F7 RST   6   
008B                          ; 
008B   D5                     PUSH   D   ; stack contains <SP> -T,VL+1, EPL
008C                          ; T is target
008C                          ; 
008C                          ; step is going to be 1 unless we encounter
008C                          ; a STEP token
008C   11 01 00               LXI   D,1   
008F   0A                     LDAX   B   
0090                          ; 
0090                          ; check for optional STEP token
        **MACRO UNROLL - RST_COMPAREJUMP
0090   DF RST   3   
0091   AA 93                  DB   StepToken&0ffh,(ForWithStep&0ffh)-1   
0093   21                     DB   21h   ; LXI H opcode eats the next 2 bytes
0094                FORWITHSTEP:   
0094                          ; we have step token
0094   03                     INX   B   
        **MACRO UNROLL - RST_EXPEVALUATE
0095   FF RST   7   
0096                          ; 
0096   E1                     POP   H   
0097   E1                     POP   H   ; H contains VL+1
0098                          ; 
0098                          ; B contains the start address of the
0098                          ; loop (LS)
0098                          ; 
0098   C5                     PUSH   B   ; stack contains -T <SP> LS,EPL
0099   3B                     DCX   SP   
009A   3B                     DCX   SP   ; stack contains <SP> -T,LS,EPL
009B   D5                     PUSH   D   ; stack contains <SP>,S,-T,LS,EPL
009C   E5                     PUSH   H   ; stack contains <SP>,VL+1,S,-T,LS,EPL
009D                          ; 
009D   C3 89 02               JMP   ExecuteProgramLoop   
00A0                EXPLEFTBRACE:   
00A0   0B                     DCX   B   
00A1                FUNCTIONCALL:   
00A1                          ; push return address
00A1   21 5B 00               LXI   H,ExpEvaluateOp   
00A4   E5                     PUSH   H   
00A5                          ; A contains the address to call on page 1
00A5                          ; push function address
00A5   6F                     MOV   L,A   
00A6   24                     INR   H   ; Assumes H was 0 and is now 1
00A7   E5                     PUSH   H   
00A8                          ; 
00A8                          ; fall through
00A8                          ; This must be before Error so that it
00A8                          ; can fall through
00A8                EXPBRACKETEDB:   
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
00A8   D7 RST   2   
00A9   BB                     DB   LeftBraceToken&0ffh   
00AA   C4 B1 00               CNZ   Error   
        **MACRO UNROLL - RST_EXPEVALUATE
00AD   FF RST   7   
00AE                          ; 
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
00AE   D7 RST   2   
00AF   AB                     DB   RightBraceToken&0ffh   
00B0   C8                     RZ   
00B1                          ; 
00B1                          ; fall through
00B1                          ;Display error code and go back to line entry
00B1                ERROR:    
00B1   CD 41 02               CALL   CRLF   
00B4   3E 45                  MVI   A,'E'   
        **MACRO UNROLL - RST_PUTCHAR
00B6   CF RST   1   
00B7   D1                     POP   D   
00B8   CD 64 03               CALL   PrintInteger   
00BB                          ; 
00BB                          ; fall through
00BB                          ; 
00BB                          ; we need ready to be at an address
00BB                          ; corresponding to harmless opcodes when
00BB                          ; executed in ExecuteProgram
00BB                          .ORG   00bbh   
00BB                READY:    
00BB                          ; Set stack pointer
00BB                          ; Do this every time to guard against
00BB                          ; GOSUB with no RETURN errors
00BB                          ; 
00BB   31 F8 07               LXI   SP,STACK_INIT   
00BE                          ; 
00BE   CD 41 02               CALL   CRLF   
00C1                          ; 
00C1                          ; Use this if no CRLF is needed
00C1                          ; and sure that stack can't be wrong
00C1                READYNONEWLINE:   
00C1                          ; 
00C1   2A 00 04               LHLD   PROG_PTR   
00C4   E5                     PUSH   H   ; push it because we need it after
00C5                          ; GetLine
00C5   CD 32 01               CALL   GetLine   
00C8                          ; 
00C8   36 80                  MVI   M,EndProgram&0ffh   
00CA                          ; 
00CA   22 3C 04               SHLD   PROG_PARSE_PTR   
00CD   E1                     POP   H   
00CE                          ; 
00CE   E5                     PUSH   H   
00CF   C1                     POP   B   
00D0                          ; 
00D0   7E                     MOV   A,M   
00D1                          ; Regardless of which branch taken
00D1                          ; we need this marker here.
00D1                          ; This overwrites the token to execute,
00D1                          ; but we've already got that in A
00D1   36 80                  MVI   M,EndProgram&0ffh   
00D3                          ; 
00D3   FE 20                  CPI   IntegerToken   
00D5   C2 8A 02               JNZ   ExecuteDirect   
00D8                          ; 
00D8                LINESTARTSWITHINT:   
00D8                          ; Get the line number into DE
00D8   23                     INX   H   
00D9   5E                     MOV   E,M   
00DA   23                     INX   H   
00DB   56                     MOV   D,M   
00DC   23                     INX   H   
00DD                          ; 
00DD                          ; Is it an integer all by itself?
00DD                          ; If so then delete the line
00DD                          ; 
00DD                          ; call GetLineNum to find either the line, or
00DD                          ; pointer to next location in program after it
00DD                          ; 
00DD   66                     MOV   H,M   ; preserve M (GetLineNum doesn't touch H)
00DE   CD FD 02               CALL   GetLineNum   
00E1   7C                     MOV   A,H   
00E2   2A 00 04               LHLD   PROG_PTR   
00E5   F5                     PUSH   PSW   
00E6                          ; 
        **MACRO UNROLL - RST_COMPAREJUMP
00E6   DF RST   3   
00E7   80                     DB   EndProgram&0ffh   
00E8   F8                     DB   (DeleteProgramLine&0ffh)-1   
00E9                          ; 
00E9   F1                     POP   PSW   
00EA                          ; if GetLineNum returns a match then this is
00EA                          ; an error, user must delete line first
00EA   CC B1 00               CZ   Error   
00ED                          ; 
00ED                          ; do a memory rotate with
00ED                          ; first = GetLine/ATNLN address
00ED                          ; middle = PROG_PTR
00ED                          ; last = PROG_PARSE_PTR
00ED                          ; 
00ED   36 23                  MVI   M,LineNumSub&0ffh   ; undo what we did earlier
00EF   EB                     XCHG   
00F0   2A 3C 04               LHLD   PROG_PARSE_PTR   
00F3                          ; 
00F3   E5                     PUSH   H   ; last
00F4   C5                     PUSH   B   ; first
00F5                          ; 
00F5   D5                     PUSH   D   ; middle
00F6                          ; 
00F6                          ; carry is clear here from the call to
00F6                          ; GetLineNum
00F6                          ; 
00F6   C3 09 01               JMP   Entry   
00F9                DELETEPROGRAMLINE:   
00F9                          ; 25 bytes
00F9   F1                     POP   PSW   
00FA                          ; 
00FA   C2 C1 00               JNZ   ReadyNoNewLine   ; line not found, do nothing
00FD   E5                     PUSH   H   
00FE   C5                     PUSH   B   ; first
00FF   E5                     PUSH   H   ; last
0100                          ; 
0100   09                     DAD   B   ; HL=PROG_PTR+first
0101                          ; 
0101   03                     INX   B   
0102   CD 18 03               CALL   ATNLN_Int   ; Z is set when this is called
0105                          ; 
0105                          ;set HL to what we want PROG_PTR to be
0105   50                     MOV   D,B   
0106   59                     MOV   E,C   
        **MACRO UNROLL - RST_NEGATEDE
0107   F7 RST   6   
0108                          ; 
0108   19                     DAD   D   ; HL=PROG_PTR+first-middle
0109                          ; 
0109                          ; because DAD D above always causes HL
0109                          ; to decrease, it must set carry
0109                          ; so STC below is not needed
0109                          ;STC ; skip first reverse in memory rotate
0109                          ; because we don't care about the
0109                          ; line being deleted
0109                          ; 
0109                ENTRY:    
0109                          ; carry is clear if coming from insert
0109                          ; 
0109   C5                     PUSH   B   ; middle (or first)
010A   22 00 04               SHLD   PROG_PTR   
010D                          ; 
010D                MEMORYROTATE:   
010D                          ; 27 bytes
010D                          ; stack must contain (from top down)
010D                          ; first, middle, first, last
010D                          ; DE = middle
010D                          ; HL = Last
010D   D4 1A 01               CNC   Reverse   
0110   CD 17 01               CALL   ReverseDH   
0113   01 C1 00               LXI   B,ReadyNoNewLine   
0116   C5                     PUSH   B   
0117                REVERSEDH:   
0117   E1                     POP   H   
0118   D1                     POP   D   
0119   E3                     XTHL   
011A                REVERSE:   
011A                          ; HL = last (i.e 1 after the last byte to swap)
011A                          ; DE = first
011A                REVERSELOOP:   
        **MACRO UNROLL - RST_COMPAREHLDE
011A   EF RST   5   
011B   C8                     RZ   
011C   2B                     DCX   H   
        **MACRO UNROLL - RST_COMPAREHLDE
011D   EF RST   5   
011E   C8                     RZ   
011F                          ; 
011F   46                     MOV   B,M   
0120   1A                     LDAX   D   
0121   77                     MOV   M,A   
0122   78                     MOV   A,B   
0123   12                     STAX   D   
0124   13                     INX   D   
0125                          ; 
0125   C3 1A 01               JMP   ReverseLoop   
0128                          ; GetLine sits entirely in page 1
0128                          ; good - it uses RST_CompareJump in two
0128                          ; places, so be careful if moving it
0128                          ; Also it assumes ClassLookup on same page
0128                          ; as NoCharClass
0128                NLTESTTRUE:   
0128                          ; error if we are in the middle
0128                          ; of a string
0128   7D                     MOV   A,L   
0129   FE 7A                  CPI   QuoteClassExpEnd&0ffh   
012B   CC B1 00               CZ   Error   
012E                          ; 
012E   E1                     POP   H   
012F                          ; 
012F   C3 41 02               JMP   CRLF   
0132                GETLINE:   
0132                          ; HL points where we want the line to be
0132                          ; parsed to.
0132                          ; On return HL points to byte after what we've
0132                          ; got.
0132                          ; 
0132   3E 3E                  MVI   A,'>'   
        **MACRO UNROLL - RST_PUTCHAR
0134   CF RST   1   
0135                GETLINENOPROMPT:   
0135   E5                     PUSH   H   
0136                          ; is there a better way of setting B to a
0136                          ; non-newline? Any other regs known not
0136                          ; to have this value?
0136   0E 00                  MVI   C,0   
0138                FRESHSTART:   
0138   21 65 01               LXI   H,NoCharClass   
013B                          ; 
013B                NLTEST:   
013B                          ; check for newline
013B   79                     MOV   A,C   
        **MACRO UNROLL - RST_COMPAREJUMP
013C   DF RST   3   
013D   0D 27                  DB   13,(NLTestTrue&0ffh)-1   
013F                          ; 
013F                NEXTCHARLOOP:   
013F                          ; This code is compatable with Stefan Tramm's
013F                          ; 8080 emulator
013F   DB 00                  IN   0   
0141   A7                     ANA   A   
        **MACRO UNROLL - RST_JZPAGE
0142   E7 RST   4   
0143   3E                     DB   (NextCharLoop&0ffh)-1   
0144   DB 01                  IN   1   
0146   4F                     MOV   C,A   
0147   D3 01                  OUT   1   ; echo
0149                          ; 
0149                          ; Do we have the same class as before?
0149   E5                     PUSH   H   
014A   21 C7 02               LXI   H,ClassLookup-1   
014D                          ; Test for quote first
014D                          ; This doesn't save spave, but takes 3 bytes
014D                          ; away from class lookup and puts them here
014D                          ; so can be used to change odd/even of
014D                          ; ...Class subroutines
014D                          ;RST_CompareJump
014D                          ;DB 34,(LC_QuoteTestTrue-1)&0ffh
014D                LOOKUPCLASSLOOP:   
014D   2C                     INR   L   
014E   BE                     CMP   M   
014F   2C                     INR   L   
0150   DA 4D 01               JC   LookupClassLoop   
0153                LC_QUOTETESTTRUE:   
0153   46                     MOV   B,M   
0154   E1                     POP   H   
0155                          ; 
0155                          ; are L and B equal?
0155   7D                     MOV   A,L   
0156   A8                     XRA   B   
0157                          ; Z if they are equal, NZ if not
0157   E9                     PCHL   ; Jump based on previous CharClass pointer
0158                DIGITCLASS:   
        **MACRO UNROLL - RST_JZPAGE
0158   E7 RST   4   
0159   69                     DB   (DigitClassNotEnd&0ffh)-1   
015A                DIGITCLASSEND:   
015A                          ; Write token into program
015A                          ; need to preserve DE, don't care about HL
015A   E3                     XTHL   
015B   36 20                  MVI   M,IntegerToken   
015D   23                     INX   H   
015E   73                     MOV   M,E   
015F   23                     INX   H   
0160   36                     DB   36h   ; opcode for MVI M eats next byte
0161                WRITE_SHARED_ATSP:   
0161   D1                     POP   D   
0162                WRITE_SHARED:   
0162   72                     MOV   M,D   
0163                WRITE_SHARED_WRITTEN:   
0163   23                     INX   H   
0164   E3                     XTHL   
0165                NOCHARCLASS:   
0165   68                     MOV   L,B   
0166   AF                     XRA   A   ; set Z
0167   57                     MOV   D,A   ; reset state information
0168   5F                     MOV   E,A   
0169   E9                     PCHL   
016A                DIGITCLASSNOTEND:   
016A                          ; 
016A   D5                     PUSH   D   
016B   E3                     XTHL   
016C                          ; 
016C                          ; A is zero at this point
016C                          ; Accumulate the value into D
016C                          ; Muliply by 10
016C                          ; 
016C                          ; 
016C   29                     DAD   H   
016D   29                     DAD   H   
016E   19                     DAD   D   
016F   29                     DAD   H   
0170                          ; 
0170                          ; Add in the new digit
0170                          ; 
0170   09                     DAD   B   
0171                          ; Because B has a value and C has the digit
0171                          ; value+48, we need to subtract those things
0171                          ; from H
0171   11 D0 A7               LXI   D,-((DigitClass&0ffh)*256+48)   
0174   19                     DAD   D   
0175                          ; 
0175   EB                     XCHG   
0176                          ; 
0176   E1                     POP   H   
0177                          ; 
0177   C3 3F 01               JMP   NextCharLoop   
017A                QUOTECLASSEXPEND:   
017A                          ; A is equal to:
017A                          ; char class (B) XOR QuoteCharClassExpEnd
017A                          ; 
017A                          ; so long as QuoteCharClass is the only class
017A                          ; with an odd address or the only one
017A                          ; with an even address then A will only
017A                          ; have LSB=1 if current char class
017A                          ; is QuoteCharClass - i.e. end of string
017A                          ; 
017A   E6                     DB   0e6h   ; opcode for ANI eats next byte
017B                          ; (which is 2dh lsbits are 01)
017B                          ; 
017B                QUOTECLASS:   
017B   2D                     DCR   L   ; set to QuoteClassExpEnd
017C                          ; first time through A is zero
017C                          ; on fall A is even unless B is QuoteClass
017C                          ; 
017C   A4                     ANA   H   ; H is 1
017D                          ; 
017D                          ; Now Z is set if this was first Quote, or if
017D                          ; we are in a string and haven't reached
017D                          ; last quote
017D                          ; 
017D                          ; carry is clear here
017D   DA                     DB   0dah   ; opcode for JC eats next 2 bytes
017E                LT0CLASS:   
017E   23                     INX   H   ; next char should always count as
017F                          ; different class
017F   00                     NOP   
0180                COMPCLASS:   
0180   00                     NOP   
0181   00                     NOP   
0182                ALPHACLASS:   
0182                          ; 
0182   E3                     XTHL   
0183   71                     MOV   M,C   
0184   23                     INX   H   
0185   E3                     XTHL   
0186                          ; 
0186   1B                     DCX   D   ; increase char count
0187                          ; 
0187                          ; if NZ then we will just
0187                          ; have written a different class char:
0187                          ; good, this ensures no spurious
0187                          ; strcmp matches from leftover
0187                          ; buffer contents
0187                          ; 
0187                          ; now we need to decide whether to jump to:
0187                          ; FreshStart - if its the last quote in
0187                          ;							 a string
0187                          ; NLTest		 - if part way through string or
0187                          ;								token
0187                          ; TokenClassEnd - if end of token
0187                          ; 
        **MACRO UNROLL - RST_JZPAGE
0187   E7 RST   4   
0188   3A                     DB   (NLTest&0ffh)-1   
0189                          ; 
0189   7D                     MOV   A,L   
        **MACRO UNROLL - RST_COMPAREJUMP
018A   DF RST   3   
018B   7A 37                  DB   QuoteClassExpEnd&0ffh,(FreshStart&0ffh)-1   
018D                          ; 
018D                TOKENCLASSEND:   
018D                          ; Make H point to the start of the token
018D                          ; to be looked up
018D   E3                     XTHL   
018E   19                     DAD   D   
018F                          ; 
018F                          ; it's a var if bits 7,6,5 are 010 and
018F                          ; E=-2
018F                          ; These aren't the only conditions that
018F                          ; could lead to the test below passing -
018F                          ; e.g. if 7,6,5=001 and E=10011110. But E
018F                          ; has to be large for this to happen, so
018F                          ; quite unlikely in practice.
018F   7E                     MOV   A,M   
0190   EE 40                  XRI   040h   
0192   57                     MOV   D,A   
0193   E6 E0                  ANI   0e0h   
0195   AB                     XRA   E   
0196                          ; 
        **MACRO UNROLL - RST_COMPAREJUMP
0196   DF RST   3   
0197   FE 61                  DB   0feh,(Write_Shared&0ffh)-1   
0199                          ; 
0199   11 8C 03               LXI   D,TokenList   
019C                LOOKUPTOKEN_LOOP:   
019C   1A                     LDAX   D   
019D   F5                     PUSH   PSW   
019E   E5                     PUSH   H   
019F                STRCMP:   
019F   13                     INX   D   
01A0   1A                     LDAX   D   
01A1   AE                     XRA   M   
01A2                          ; iff match then A is either 00h or 80h
01A2                          ; (80h if last char)
01A2   23                     INX   H   
        **MACRO UNROLL - RST_JZPAGE
01A3   E7 RST   4   
01A4   9E                     DB   (Strcmp&0ffh)-1   ; match and not last char
01A5                          ; 
01A5                          ; equal to 080h iff match and last char
01A5   EE 80                  XRI   080h   
01A7                          ; equal to Z iff match and last char
01A7   E1                     POP   H   
01A8                          ; 
        **MACRO UNROLL - RST_JZPAGE
01A8   E7 RST   4   
01A9   60                     DB   (Write_Shared_AtSP&0ffh)-1   
01AA                          ; 
01AA   F1                     POP   PSW   
01AB                LOOKUPTOKEN:   
01AB   1A                     LDAX   D   
01AC   17                     RAL   
01AD   1C                     INR   E   ; Z set if end of TokenList
01AE   D2 AB 01               JNC   LookupToken   
01B1   C2 9C 01               JNZ   LookupToken_Loop   
01B4                          ; 
01B4                          ; didn't find it
01B4                          ; if (HL)>=64 and (HL+1)<64 then its a var
01B4                          ; could do the var test here
01B4                          ; if it can be done in few bytes
01B4                          ; 
01B4   36 21                  MVI   M,QuestionMarkToken&0ffh   
        **MACRO UNROLL - RST_JZPAGE
01B6   E7 RST   4   
01B7   62                     DB   (Write_Shared_Written&0ffh)-1   
01B8                          .ORG   01b8h   
01B8                ABSSUB:   
01B8                          ; A = right brace token, which has high bit
01B8                          ; set, so no need to negate DE if XRA with D
01B8                          ; still leaves high bit set
01B8   AA                     XRA   D   
01B9   F8                     RM   
01BA                          ; 
        **MACRO UNROLL - RST_NEGATEDE
01BA   F7 RST   6   
01BB                          ; 
01BB                          ; shared code. okay for this to go here
01BB                          ; because in ExpEvaluateNum, test for
01BB                          ; left brace is before test for token
01BB                          ; between first and last function
01BB                LEFTBRACETOKEN:   
01BB   C9                     RET   
01BC                USRSUB:   
01BC   EB                     XCHG   
01BD   E9                     PCHL   
01BE                RNDSUB:   
01BE                          ; LCG
01BE                          ; don't use low byte in return value.
01BE                          ; Multiplier 47989 is mentioned here:
01BE                          ; https://groups.google.com/g/prng/c/evszGs76o1w?pli=1
01BE   D5                     PUSH   D   
01BF   2A 3E 04               LHLD   RNG_SEED   
01C2   11 75 BB               LXI   D,47989   
01C5   CD EB 01               CALL   MulSub   ; A is zero after this
01C8   EB                     XCHG   
01C9   23                     INX   H   
01CA   C3 D6 02               JMP   RndSubImpl   
01CD                          ; 
01CD                          ; Token values >= this are all operators
01CD                OPERATORS:   
01CD                          ; 
01CD                LTESUB:   
01CD                          ; Swap operands and fall through
01CD   EB                     XCHG   
01CE                GTESUB:   
        **MACRO UNROLL - RST_COMPAREHLDE
01CE   EF RST   5   
        **MACRO UNROLL - RST_JZPAGE
01CF   E7 RST   4   
01D0   DB                     DB   (BinReturn&0ffh)-1   
01D1                GTSUB:    
01D1                          ; Swap operands and fall through
01D1   EB                     XCHG   
01D2                LTSUB:    
01D2   7D                     MOV   A,L   
01D3   93                     SUB   E   
01D4   7C                     MOV   A,H   
01D5   9A                     SBB   D   
01D6   1F                     RAR   
01D7   AC                     XRA   H   
01D8   AA                     XRA   D   
01D9   17                     RAL   
01DA   3E                     DB   3eh   ; MVI A opcode to eat next byte
01DB                EQUALSUB:   
        **MACRO UNROLL - RST_COMPAREHLDE
01DB   EF RST   5   ; returns Z iff HL=DE
01DC                BINRETURN:   
01DC   3F                     CMC   
01DD   3E                     DB   3eh   ; MVI A opcode to eat next byte
01DE                          ; 
01DE                NOTEQUALSUB:   
        **MACRO UNROLL - RST_COMPAREHLDE
01DE   EF RST   5   ; returns Z iff HL=DE
01DF   11 01 00               LXI   D,1   
01E2   D0                     RNC   
01E3   1B                     DCX   D   
01E4   C9                     RET   
01E5                ADDSUB:   
01E5   D2                     DB   0d2h   ; opcode for JNC to eat 2 bytes
01E6                SUBSUB:   
01E6   00                     NOP   
01E7                NEGATESUB:   
        **MACRO UNROLL - RST_NEGATEDE
01E7   F7 RST   6   
01E8                          ;Add DE to HL and keep in DE
01E8   19                     DAD   D   
01E9   EB                     XCHG   
01EA                          ; 
01EA   C9                     RET   
01EB                MULSUB:   
01EB                          ; 20 bytes
01EB                          ; multiply HL and DE into DE, preserving B
01EB   C5                     PUSH   B   
01EC   44                     MOV   B,H   
01ED   4D                     MOV   C,L   
01EE                          ; TODO can we switch the role of HL and DE
01EE                          ; to avoid the extra XCHG before RET
01EE                MULTIPLY:   
01EE                          ;multiply BC and DE into DE
01EE   3E 10                  MVI   A,16   
01F0                MULLOOP:   
01F0   29                     DAD   H   
01F1   EB                     XCHG   
01F2   29                     DAD   H   
01F3   EB                     XCHG   
01F4   D2 F8 01               JNC   DontAdd   
01F7   09                     DAD   B   
01F8                DONTADD:   
01F8   3D                     DCR   A   
01F9   C2 F0 01               JNZ   MulLoop   
01FC                          ; 
01FC   EB                     XCHG   
01FD   C1                     POP   B   
01FE   C9                     RET   
01FF                          ; 
01FF                DIVSUB:   
01FF                          ; 31 bytes
01FF                          ;Divide HL by DE
01FF                          ;Remainder in HL
01FF                          ;Result in DE
01FF                DIVIDEHL:   
01FF                          ;Divide HL by DE
01FF                          ; Make HL and DE different signs
01FF   7C                     MOV   A,H   
0200   CD B8 01               CALL   AbsSub   
0203   F5                     PUSH   PSW   
0204                          ; 
0204                          ;Divide HL by DE
0204                          ;Assuming that HL and DE are different signs
0204   C5                     PUSH   B   
0205   01 FF FF               LXI   B,0ffffh   
0208                          ; 
0208                          ; Do the test for zero here because we want the
0208                          ; CZ to be on page 3
0208                          ; This means that divide by zero and unterminated
0208                          ; string both have tbe same error code, but kt
0208                          ; will be obvious to the programmer which is
0208                          ; intended
0208   7A                     MOV   A,D   
0209   B3                     ORA   E   
020A                DIVJZERROR:   
020A   CC B1 00               CZ   Error   
020D                          ; 
020D                DIVLOOP:   
020D   03                     INX   B   
020E   19                     DAD   D   
020F   1F                     RAR   ; look for mismatch between carry and
0210                          ; bit 7 of D to detect overflow/underflow
0210   AA                     XRA   D   
0211   F2 0D 02               JP   DivLoop   
0214                          ; if HL is zero then it must have been a negative number originally, and the remainder is zero, so don't make any change to HL, but increment quotient by 1
0214                          ; 
0214   7C                     MOV   A,H   
0215   B5                     ORA   L   
        **MACRO UNROLL - RST_JZPAGE
0216   E7 RST   4   ; assume it is on same page
0217                          ; because DivSub will
0217                          ; be right at end of page 2
0217   1A                     DB   (DivNoRestore&0ffh)-1   
0218                          ; 
        **MACRO UNROLL - RST_NEGATEDE
0218   F7 RST   6   
0219   19                     DAD   D   
021A   0B                     DCX   B   
021B                          ; 
021B                DIVNORESTORE:   
021B   03                     INX   B   
021C   50                     MOV   D,B   
021D   59                     MOV   E,C   
021E                          ; 
021E   C1                     POP   B   
021F                          ; 
021F   F1                     POP   PSW   
0220   F0                     RP   
        **MACRO UNROLL - RST_NEGATEDE
0221   F7 RST   6   
0222                          ; 
0222   C9                     RET   
0223                LINENUMSUB:   
0223   03                     INX   B   
0224   03                     INX   B   
0225                STATEMENTSEPSUB:   
0225   C9                     RET   
0226                          ; 
0226                PRINTSUB:   
0226                PRINTSUBLOOP:   
0226                          ; on call HL is address of PrintSub
0226                          ; so H=1
0226                          ; on subsequent passes H = 0 or QuoteChar
0226   0A                     LDAX   B   
0227                          ; 
0227   D6 22                  SUI   StringToken   
        **MACRO UNROLL - RST_JZPAGE
0229   E7 RST   4   
022A   35                     DB   (PrintSubString&0ffh)-1   
022B                          ; 
022B                          ; This assumes that LinenumSub is the
022B                          ; next token after StringToken
022B   FE 87                  CPI   (LastStatement-StringToken+1)&0ffh   
022D                          ; 
022D                          ; Set Z if we want a newline
022D   25                     DCR   H   
022E   DA 40 02               JC   PrintSubEnd   
0231                          ; 
0231                PRINTSUBEXPRESSION:   
        **MACRO UNROLL - RST_EXPEVALUATE
0231   FF RST   7   
0232   CD 64 03               CALL   PrintInteger   
0235                          ; 
0235   37                     STC   
0236                PRINTSUBSTRING:   
0236   D4 E1 02               CNC   OutputString   ; carry is clear on return
0239   67                     MOV   H,A   ; A is 0 or QuoteChar
023A                          ; 
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
023A   D7 RST   2   
023B   AC                     DB   CommaToken   
        **MACRO UNROLL - RST_JZPAGE
023C   E7 RST   4   
023D   25                     DB   (PrintSubLoop&0ffh)-1   
023E                          ; 
023E   0B                     DCX   B   
023F                          ; 
023F                          ; Got to end of print statement with no comma
023F                          ; so we want to print a newline.
023F                          ; 
023F   AF                     XRA   A   
0240                          ; 
0240                PRINTSUBEND:   
0240   C0                     RNZ   ; don't print newline if we've just had
0241                          ; comma
0241                CRLF:     
0241   3E 0D                  MVI   A,13   
        **MACRO UNROLL - RST_PUTCHAR
0243   CF RST   1   
0244   3E 0A                  MVI   A,10   
        **MACRO UNROLL - RST_PUTCHAR
0246   CF RST   1   
0247   C9                     RET   
0248                          ; 
0248                GOSUBSUB:   
        **MACRO UNROLL - RST_EXPEVALUATE
0248   FF RST   7   
0249   E1                     POP   H   
024A                          ; 
024A   C5                     PUSH   B   
024B   E5                     PUSH   H   
024C                          ; 
024C   3E                     DB   03eh   ; opcode for MVI A to eat next byte
024D                GOTOSUB:   
        **MACRO UNROLL - RST_EXPEVALUATE
024D   FF RST   7   
024E   CD FD 02               CALL   GetLineNum   
0251   C8                     RZ   
0252   CD B1 00               CALL   Error   
0255                INPUTSUB:   
0255   CD E9 02               CALL   GetVarLocationBVar   
0258   E5                     PUSH   H   
0259   21 F8 07               LXI   H,INPUT_BUFFER   
025C   C5                     PUSH   B   
025D   E5                     PUSH   H   
025E                          ; 
025E   CD 35 01               CALL   GetLineNoPrompt   
0261   C1                     POP   B   
        **MACRO UNROLL - RST_EXPEVALUATE
0262   FF RST   7   
0263   C1                     POP   B   
0264                          ; fall through
0264                POPHASSIGNTOVAR:   
0264   E1                     POP   H   
0265                          ; 
0265                          ; Put DE into var (HL)
0265                          ; 
0265   73                     MOV   M,E   
0266   23                     INX   H   
0267   72                     MOV   M,D   
0268                          ; 
0268   C9                     RET   
0269                FORSUB:   
0269   21 83 00               LXI   H,ForSubImpl   
026C   E5                     PUSH   H   
026D                          ; 
026D                          ; fall through
026D                          ; 
026D                LETSUB:   
026D   CD E9 02               CALL   GetVarLocationBVar   
0270   E5                     PUSH   H   
0271                          ; 
0271                          ; Test that we have an equals sign
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
0271   D7 RST   2   
0272                          ; 
0272   DB                     DB   EqualSub&0ffh   
0273   C4 B1 00               CNZ   Error   
0276                          ; 
        **MACRO UNROLL - RST_EXPEVALUATE
0276   FF RST   7   
0277                          ; 
0277   C3 64 02               JMP   POPHAssignToVar   
027A                          ; 
027A                IFSUB:    
        **MACRO UNROLL - RST_EXPEVALUATE
027A   FF RST   7   
027B   7A                     MOV   A,D   
027C   B3                     ORA   E   
027D   C0                     RNZ   
027E                          ; If DE zero then fall through to next line
027E   C3 1A 03               JMP   AdvanceToNextLineNum   
0281                          ; 
0281                ENDSUB:   
0281   C3 BB 00               JMP   Ready   
0284                          ; Hi byte of AdvanceToNextLineNum is 3
0284                          ; which is opcode for INR B : harmless
0284                ENDPROGRAM:   EQU   EndSub-1   
0284                          ; 
0284                EXECUTEPROGRAM:   
0284                          ; Point BC to first line
0284                          ; Don't skip over the line number
0284                          ; because we need the constant PROG_BASE
0284                          ; at this location in memory
0284   01 40 04               LXI   B,PROG_BASE   
0287   BB 00                  DW   Ready   ; Ready must correspond to
0289                          ; a harmless instruction sequence
0289                EXECUTEPROGRAMLOOP:   
0289   0A                     LDAX   B   
028A                          ; 
028A                EXECUTEDIRECT:   
028A                          ; 
028A   D6 23                  SUI   LineNumSub&0ffh   
028C                          ; 
028C                          ; Check that it is a token between
028C                          ; LinenumSub and LastStatement
028C   FE 86                  CPI   (LastStatement-LineNumSub+1)&0ffh   
028E   D4 B1 00               CNC   Error   
0291                          ; 
0291   03                     INX   B   
0292   C6 23                  ADI   LineNumSub&0ffh   
0294                          ; 
0294                          ; Carry is clear now
0294                          ; Sign is set/reset according to the
0294                          ; address of the statement Sub
0294                          ; e.g. for LineNumSub Sign is clear
0294                          ; 
0294                          ; Put return address onto stack
0294   21 89 02               LXI   H,ExecuteProgramLoop   
0297   E5                     PUSH   H   
0298                          ; 
0298                          ; Put pointer to call address into HL
0298   6F                     MOV   L,A   
0299                          ; ExecuteProgramLoop must be on the same page
0299                          ; page as PrintSub so that we don't have to
0299                          ; update H
0299                          ; Jump to it
0299                          ; Carry is clear when we do this
0299   E9                     PCHL   
029A                NEWSUB:   
029A   C7                     RST   0   
029B                LISTSUB:   
029B   C3 2B 03               JMP   ListSubImpl   
029E                RETURNSUB:   
029E                          ; Expect stack size to be 6 or more
029E                          ; any less and we have return without gosub
029E   21 0D F8               LXI   H,-(STACK_INIT-6)-1   
02A1   39                     DAD   SP   
02A2   DC B1 00               CC   Error   
02A5                          ; 
02A5   E1                     POP   H   ; Get return address first
02A6   C1                     POP   B   ; Get pointer to program loc to return to
02A7   E9                     PCHL   ; instead of RET
02A8                LASTSTATEMENT:   
02A8                NEXTSUB:   
02A8   E1                     POP   H   ; discard return address
02A9                          ; stack contains <SP> VL+1,S,-T,LS,EPL
02A9   E1                     POP   H   ; get VL+1
02AA                          ; stack contains VL+1 <SP> S,-T,LS,EPL
02AA   56                     MOV   D,M   
02AB   2B                     DCX   H   
02AC   5E                     MOV   E,M   
02AD                          ; 
02AD   E3                     XTHL   ; step is in HL, VL is in (SP)
02AE                          ; stack contains VL+1 <SP> VL, -T,LS,EPL
02AE   EB                     XCHG   ; step is in DE, var value in HL
02AF   19                     DAD   D   ; add step onto var
02B0   EB                     XCHG   ; result is in DE, step is in HL
02B1   E3                     XTHL   ; step is in (SP), VL is in HL
02B2                          ; stack contains VL+1 <SP> S, -T,LS,EPL
02B2                          ; 
02B2   73                     MOV   M,E   ; put back into VL
02B3   23                     INX   H   ; H = VL+1
02B4   72                     MOV   M,D   ; DE now has loop var value (LV)
02B5                          ; 
02B5   F1                     POP   PSW   ; get step so that hi bit of A has
02B6                          ; sign of step
02B6   E1                     POP   H   ; get -T
02B7                          ; stack contains VL+1,S,-T <SP> LS,EPL
02B7                          ; 
02B7   19                     DAD   D   ; HL now has LV-T
02B8                          ; 
02B8   AC                     XRA   H   ; xor sign of step with
02B9                          ; sign of result
02B9                          ; 
02B9                          ; if result of xor above is 1
02B9                          ; then keep looping, or if HL
02B9                          ; is zero then keep looping
02B9                          ; 
02B9   D1                     POP   D   ; this is LoopStart
02BA                          ; stack contains VL+1,S,-T,LS <SP> EPL
02BA                          ; 
02BA   FA C0 02               JM   NextSubLoop   
02BD                          ; 
02BD   7C                     MOV   A,H   
02BE   B5                     ORA   L   
02BF   C0                     RNZ   
02C0                          ; 
02C0                NEXTSUBLOOP:   
02C0                          ; 
02C0   42                     MOV   B,D   
02C1   4B                     MOV   C,E   
02C2   21 F6 FF               LXI   H,-10   
02C5   39                     DAD   SP   
02C6   F9                     SPHL   
02C7                          ; 
02C7   C9                     RET   
02C8                          ; 
02C8                          ; ( ) , TO STEP tokens must have values between
02C8                          ; statements and functions
02C8                TOTOKEN:   EQU   LastStatement+1   
02C8                STEPTOKEN:   EQU   LastStatement+2   
02C8                RIGHTBRACETOKEN:   EQU   LastStatement+3   
02C8                COMMATOKEN:   EQU   LastStatement+4   
02C8                CLASSLOOKUP:   
02C8   40 82                  DB   64,AlphaClass&0ffh   
02CA   3A 80                  DB   58,CompClass&0ffh   
02CC   30 58                  DB   48,DigitClass&0ffh   
02CE   23 7E                  DB   35,LT0Class&0ffh   
02D0   22 7B                  DB   34,QuoteClass&0ffh   
02D2   21 7E                  DB   33,LT0Class&0ffh   
02D4   00 38                  DB   0,FreshStart&0ffh   
02D6                RNDSUBIMPL:   
02D6   22 3E 04               SHLD   RNG_SEED   
02D9                          ; Use only the high byte to get a value
02D9                          ; between 0 and 255
02D9   6C                     MOV   L,H   
02DA   67                     MOV   H,A   
02DB   D1                     POP   D   
02DC                          ; 
02DC   CD FF 01               CALL   DivideHL   
02DF   EB                     XCHG   
02E0   C9                     RET   
02E1                          ; This 8 byte routine can be moved anywhere to
02E1                          ; fill holes. It needs a RET on the same
02E1                          ; page to jump to
02E1                OUTPUTSTRING:   
02E1                          ;Pointer in B points to string token marker
02E1   03                     INX   B   
02E2                OUTPUTSTRINGLOOP:   
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
02E2   D7 RST   2   
02E3   22                     DB   StringToken   
        **MACRO UNROLL - RST_JZPAGE
02E4   E7 RST   4   
02E5   FB                     DB   (OutputStringRet&0ffh)-1   
02E6                OUTPUTSTRING_WITHQUOTE:   
        **MACRO UNROLL - RST_PUTCHAR
02E6   CF RST   1   
        **MACRO UNROLL - RST_JZPAGE
02E7   E7 RST   4   
02E8   E1                     DB   (OutputStringLoop&0ffh)-1   
02E9                          ; This 20 byte routine can be moved as needed
02E9                GETVARLOCATIONBVAR:   
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
02E9   D7 RST   2   
02EA                          ; Test that we have a var
02EA   20                     DB   32   
02EB   D4 B1 00               CNC   Error   
02EE                GETVARLOCATION:   
02EE                          ; A should contain a var token
02EE                          ; and B points to tbe location after
02EE                          ; the var token (or array insex expression)
02EE                          ; return with var address in HL
02EE                          ; and B pointing to next char
02EE                          ; A will never be 255 on return
02EE   26 04                  MVI   H,VAR_SPACE/256   
02F0   87                     ADD   A   
02F1   6F                     MOV   L,A   
02F2                          ; 
02F2   C0                     RNZ   
02F3                          ; 
02F3                          ; fall through if it is array var
02F3                          ; 
02F3   CD A8 00               CALL   ExpBracketedB   
02F6                          ; 
02F6                          ; Now DE contains the array index
02F6                          ; Add it twice to get the offset
02F6                          ; 
02F6   2A 3C 04               LHLD   PROG_PARSE_PTR   
02F9   23                     INX   H   ; up 1 byte to avoid EndProgram marker
02FA   19                     DAD   D   
02FB   19                     DAD   D   
02FC                OUTPUTSTRINGRET:   
02FC   C9                     RET   
02FD                GETLINENUM:   
02FD                          ; Line number is in DE, look it up in the
02FD                          ; program and set BC to point to the LinenumSub
02FD                          ; token.
02FD                          ; 
02FD                          ; DE is preserved
02FD                          ; H is preserved
02FD                          ; L is not preserved
02FD                          ; 
02FD                          ; return with Z set if successful
02FD                          ; 
02FD                          ; Z clear if not successful, and BC points
02FD                          ; to the first byte of the line with number
02FD                          ; greater than the request
02FD                          ; 
02FD                          ; Carry is always clear on return
02FD                          ; 
02FD   01 3F 04               LXI   B,PROG_BASE-1   
0300                GETLINENUMLOOP:   
0300   CD 19 03               CALL   ATNLN_INXB   ; has one INX B preceeding
0303   C0                     RNZ   
0304                          ; 
0304   03                     INX   B   
0305                          ; 
0305                          ; Test for DE <= (BC), and return if true
0305   0A                     LDAX   B   
0306   03                     INX   B   
0307   93                     SUB   E   
0308   6F                     MOV   L,A   
0309   0A                     LDAX   B   
030A   9A                     SBB   D   ; C set if DE > (BC), and Z not set
030B                          ; C clear if DE <= (BC)
030B   DA 00 03               JC   GetLineNumLoop   
030E                          ; 
030E   0B                     DCX   B   
030F   0B                     DCX   B   
0310                          ; Now we want Z set if DE=(BC), clear
0310                          ; otherwise
0310                          ; 
0310                ATNLN_RETNZ:   ; shared code. Returns NZ if we know
0310                          ; that A is non-zero
0310                          ; 
0310   B5                     ORA   L   ; Carry will be cleared
0311   C9                     RET   
0312                ATNLN_STRING:   
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
0312   D7 RST   2   
0313   22                     DB   StringToken   
0314   C2 12 03               JNZ   ATNLN_String   
0317                          ; 
0317   C2                     DB   0c2h   ; opcode for JNZ eats 2 bytes
0318                ATNLN_INT:   ; Z is always set when we reach here
0318   03                     INX   B   
0319                ATNLN_INXB:   
0319   03                     INX   B   
031A                          ; 
031A                ADVANCETONEXTLINENUM:   
031A                          ; BC is a pointer to somewhere in the program.
031A                          ; Move onto the next line number.
031A                          ; Return with Z set if successful,
031A                          ; Z clear if fell off end of program
031A   0A                     LDAX   B   
        **MACRO UNROLL - RST_COMPAREJUMP
031B   DF RST   3   
031C   80 0F                  DB   EndProgram&0ffh,(ATNLN_RetNZ&0ffh)-1   
031E                          ; fell off end of program
031E                          ; 
031E   FE 23                  CPI   LinenumSub&0ffh   
0320   C8                     RZ   ; carry will be clear if we return here
0321                          ; 
0321   03                     INX   B   
0322                          ; 
        **MACRO UNROLL - RST_COMPAREJUMP
0322   DF RST   3   
0323   20 17                  DB   IntegerToken,(ATNLN_Int&0ffh)-1   
        **MACRO UNROLL - RST_COMPAREJUMP
0325   DF RST   3   
0326   22 11                  DB   StringToken,(ATNLN_String&0ffh)-1   
0328   C3 1A 03               JMP   AdvanceToNextLineNum   
032B                LISTSUBIMPL:   
032B   01 40 04               LXI   B,PROG_BASE   
032E                LISTLOOP:   
032E   3E 20                  MVI   A,' '   
        **MACRO UNROLL - RST_PUTCHAR
0330   CF RST   1   
0331                          ; 
        **MACRO UNROLL - RST_LDAXB_INXB_CPI
0331   D7 RST   2   
0332   80                     DB   EndProgram&0ffh   
0333   C8                     RZ   
0334                          ; 
0334   21 2E 03               LXI   H,ListLoop   ; so that we can loop using RET
0337   E5                     PUSH   H   
0338                          ; H is already set to the correct page
0338   2E 8B                  MVI   L,(TokenList-1)&0ffh   
033A                          ; These need to be on same page
        **MACRO UNROLL - RST_COMPAREJUMP
033A   DF RST   3   
033B   22 83                  DB   StringToken,(List_String&0ffh)-1   
        **MACRO UNROLL - RST_COMPAREJUMP
033D   DF RST   3   
033E   23 5A                  DB   LinenumSub&0ffh,(List_Linenum&0ffh)-1   
        **MACRO UNROLL - RST_COMPAREJUMP
0340   DF RST   3   
0341   20 5D                  DB   IntegerToken,(List_Integer&0ffh)-1   
0343   DA 88 03               JC   List_Var   
0346                          ; No need to check for end of TokenList
0346                          ; impossible not to be a token value in A
0346                LIST_TOKEN_LOOP:   
0346   56                     MOV   D,M   
0347   14                     INR   D   
0348   23                     INX   H   
0349   F2 46 03               JP   List_Token_Loop   
034C                LIST_TOKEN:   
034C                          ; on entry, A contains the token
034C                          ; so must not use A during this loop
034C   BE                     CMP   M   
034D   23                     INX   H   
034E   C2 46 03               JNZ   List_Token_Loop   
0351                          ; 
0351                LIST_TOKEN_STRING_LOOP:   
0351   7E                     MOV   A,M   
0352   E6 7F                  ANI   07fh   
        **MACRO UNROLL - RST_PUTCHAR
0354   CF RST   1   
0355   B6                     ORA   M   
0356   23                     INX   H   
0357   F2 51 03               JP   List_Token_String_Loop   
035A   C9                     RET   
035B                          ; 
035B                LIST_LINENUM:   
035B   CD 41 02               CALL   CRLF   
035E                LIST_INTEGER:   
035E   0A                     LDAX   B   
035F   03                     INX   B   
0360   5F                     MOV   E,A   
0361   0A                     LDAX   B   
0362   03                     INX   B   
0363   57                     MOV   D,A   
0364                          ; fall through to PrintInteger
0364                          ; 
0364                          ;Output the value in DE
0364                PRINTINTEGER:   
0364   AF                     XRA   A   
0365   F5                     PUSH   PSW   ; end marker is Z flag
0366                          ; 
0366   B2                     ORA   D   ; S is set if -ve
        **MACRO UNROLL - RST_NEGATEDE
0367   F7 RST   6   
0368                          ; 
0368   F2 6F 03               JP   PrintIntegerLoop   
036B   3E 2D                  MVI   A,'-'   
        **MACRO UNROLL - RST_PUTCHAR
036D   CF RST   1   
        **MACRO UNROLL - RST_NEGATEDE
036E   F7 RST   6   
036F                          ; 
036F                PRINTINTEGERLOOP:   
036F                          ; DE is -ve here, so that we can
036F                          ; handle -32768
036F                          ; 
036F   EB                     XCHG   
0370   11 0A 00               LXI   D,10   
0373                          ; 
0373   CD FF 01               CALL   DivideHL   
0376                          ; HL contains remainder after / 10
0376                          ; DE contains the quotient
0376   3E 30                  MVI   A,'0'   
0378   95                     SUB   L   ; L is -ve, so this adds upto 9 to '0'
0379   F5                     PUSH   PSW   ; push digit onto stack
037A                          ; 
037A                          ; if DE is zero we are done
037A   7A                     MOV   A,D   
037B   B3                     ORA   E   
037C   C2 6F 03               JNZ   PrintIntegerLoop   
037F                          ; 
037F                PRINTINTEGERLOOP2:   
037F   F1                     POP   PSW   
0380   C8                     RZ   ; Z is set on return, HL<=0
        **MACRO UNROLL - RST_PUTCHAR
0381   CF RST   1   
        **MACRO UNROLL - RST_JZPAGE
0382   E7 RST   4   
0383   7E                     DB   (PrintIntegerLoop2&0ffh)-1   
0384                LIST_STRING:   
0384   CD E6 02               CALL   OutputString_WithQuote   
0387   11                     DB   011h   ; LXI D eats 2 bytes
0388                LIST_VAR:   
0388   C6 40                  ADI   '@'   
        **MACRO UNROLL - RST_PUTCHAR
038A   CF RST   1   
038B   C9                     RET   
038C                          ; 
038C                          ; byte before TokenList must have high bit set
038C                          ; e.g. RET
038C                          ; order in this list must make sure that a
038C                          ; token A that is a left substring of another
038C                          ; token B appears later in the list than B
038C                          ; e.g. < is after <=
038C                TOKENLIST:   
038C   21                     DB   QuestionMarkToken&0ffh   
038D   BF                     DB   '?'+128   
038E   25                     DB   StatementSepSub&0ffh   
038F   BA                     DB   ':'+128   
0390   26                     DB   PrintSub&0ffh   
0391   50 52 49 4E D4         DB   "PRIN",'T'+128   
0396   6D                     DB   LetSub&0ffh   
0397   4C 45 D4               DB   "LE",'T'+128   
039A   4D                     DB   GotoSub&0ffh   
039B   47 4F 54 CF            DB   "GOT",'O'+128   
039F   48                     DB   GosubSub&0ffh   
03A0   47 4F 53 55 C2         DB   "GOSU",'B'+128   
03A5   9E                     DB   ReturnSub&0ffh   
03A6   52 45 54 55 52 CE      DB   "RETUR",'N'+128   
03AC   55                     DB   InputSub&0ffh   
03AD   49 4E 50 55 D4         DB   "INPU",'T'+128   
03B2   69                     DB   ForSub&0ffh   
03B3   46 4F D2               DB   "FO",'R'+128   
03B6   A8                     DB   NextSub&0ffh   
03B7   4E 45 58 D4            DB   "NEX",'T'+128   
03BB   7A                     DB   IfSub&0ffh   
03BC   49 C6                  DB   "I",'F'+128   
03BE   81                     DB   EndSub&0ffh   
03BF   45 4E C4               DB   "EN",'D'+128   
03C2   84                     DB   ExecuteProgram&0ffh   
03C3   52 55 CE               DB   "RU",'N'+128   
03C6   9B                     DB   ListSub&0ffh   
03C7   4C 49 53 D4            DB   "LIS",'T'+128   
03CB   9A                     DB   NewSub&0ffh   
03CC   4E 45 D7               DB   "NE",'W'+128   
03CF   B8                     DB   AbsSub&0ffh   
03D0   41 42 D3               DB   "AB",'S'+128   
03D3   BC                     DB   UsrSub&0ffh   
03D4   55 53 D2               DB   "US",'R'+128   
03D7   BE                     DB   RndSub&0ffh   
03D8   52 4E C4               DB   "RN",'D'+128   
03DB   A9                     DB   ToToken&0ffh   
03DC   54 CF                  DB   "T",'O'+128   
03DE   AA                     DB   StepToken&0ffh   
03DF   53 54 45 D0            DB   "STE",'P'+128   
03E3   AC                     DB   CommaToken   
03E4   AC                     DB   ","+128   
03E5   BB                     DB   LeftBraceToken&0ffh   
03E6   A8                     DB   '('+128   
03E7   AB                     DB   RightBraceToken&0ffh   
03E8   A9                     DB   ')'+128   
03E9   DB                     DB   EqualSub&0ffh   
03EA   BD                     DB   '='+128   
03EB   DE                     DB   NotEqualSub&0ffh   
03EC   3C BE                  DB   "<",'>'+128   
03EE   CE                     DB   GTESub&0ffh   
03EF   3E BD                  DB   ">",'='+128   
03F1   CD                     DB   LTESub&0ffh   
03F2   3C BD                  DB   "<",'='+128   
03F4   D2                     DB   LTSub&0ffh   
03F5   BC                     DB   '<'+128   
03F6   D1                     DB   GTSub&0ffh   
03F7   BE                     DB   '>'+128   
03F8   E5                     DB   AddSub&0ffh   
03F9   AB                     DB   '+'+128   
03FA   E6                     DB   SubSub&0ffh   
03FB   AD                     DB   '-'+128   
03FC   EB                     DB   MulSub&0ffh   
03FD   AA                     DB   '*'+128   
03FE   FF                     DB   DivSub&0ffh   
03FF   AF                     DB   '/'+128   


RAM_BASE:           0400 DEFINED AT LINE 385
                    > USED AT LINE 415
                    > USED AT LINE 419
                    > USED AT LINE 422
                    > USED AT LINE 423
                    > USED AT LINE 425
RAM_TOP:            0800 DEFINED AT LINE 386
                    > USED AT LINE 411
                    > USED AT LINE 412
INTEGERTOKEN:       0020 DEFINED AT LINE 392
                    > USED AT LINE 599
                    > USED AT LINE 822
                    > USED AT LINE 1039
                    > USED AT LINE 1813
                    > USED AT LINE 1840
QUESTIONMARKTOKEN:  0021 DEFINED AT LINE 393
                    > USED AT LINE 1222
                    > USED AT LINE 1940
STRINGTOKEN:        0022 DEFINED AT LINE 394
                    > USED AT LINE 1417
                    > USED AT LINE 1423
                    > USED AT LINE 1694
                    > USED AT LINE 1787
                    > USED AT LINE 1815
                    > USED AT LINE 1836
INPUT_BUFFER:       07F8 DEFINED AT LINE 411
                    > USED AT LINE 1481
STACK_INIT:         07F8 DEFINED AT LINE 412
                    > USED AT LINE 793
                    > USED AT LINE 1594
VAR_SPACE:          0400 DEFINED AT LINE 415
                    > USED AT LINE 1718
PROG_PTR:           0400 DEFINED AT LINE 419
                    > USED AT LINE 448
                    > USED AT LINE 801
                    > USED AT LINE 842
                    > USED AT LINE 908
PROG_PARSE_PTR:     043C DEFINED AT LINE 422
                    > USED AT LINE 809
                    > USED AT LINE 861
                    > USED AT LINE 1731
RNG_SEED:           043E DEFINED AT LINE 423
                    > USED AT LINE 1256
                    > USED AT LINE 1675
PROG_BASE:          0440 DEFINED AT LINE 425
                    > USED AT LINE 1546
                    > USED AT LINE 1755
                    > USED AT LINE 1819
PUTCHAR:            0008 DEFINED AT LINE 459
PUTCHARWAITLOOP:    000A DEFINED AT LINE 468
COMPAREJUMP_ENTRY:  0021 DEFINED AT LINE 518
                    > USED AT LINE 509
JZPAGE_SKIP:        0025 DEFINED AT LINE 521
                    > USED AT LINE 519
EXPAPPLYOP:         0026 DEFINED AT LINE 523
                    > USED AT LINE 646
                    > USED AT LINE 661
COMPAREHLDE:        0028 DEFINED AT LINE 532
NEGATEDE:           0030 DEFINED AT LINE 551
EXPEVALUATE:        0038 DEFINED AT LINE 575
EXPEVALUATENUM:     0038 DEFINED AT LINE 582
                    > USED AT LINE 695
EXPINTEGER:         0051 DEFINED AT LINE 608
EXPVAR:             0055 DEFINED AT LINE 615
                    > USED AT LINE 600
EXPVARGETVALUE:     0058 DEFINED AT LINE 619
EXPEVALUATEOP:      005B DEFINED AT LINE 624
                    > USED AT LINE 682
                    > USED AT LINE 749
SKIPEXPAPPLYOP:     006D DEFINED AT LINE 664
                    > USED AT LINE 636
EXPNEGATE:          0074 DEFINED AT LINE 678
                    > USED AT LINE 590
FORSUBIMPL:         0083 DEFINED AT LINE 697
                    > USED AT LINE 1506
FORWITHSTEP:        0094 DEFINED AT LINE 726
                    > USED AT LINE 723
EXPLEFTBRACE:       00A0 DEFINED AT LINE 745
                    > USED AT LINE 588
FUNCTIONCALL:       00A1 DEFINED AT LINE 747
                    > USED AT LINE 597
EXPBRACKETEDB:      00A8 DEFINED AT LINE 761
                    > USED AT LINE 1726
ERROR:              00B1 DEFINED AT LINE 775
                    > USED AT LINE 594
                    > USED AT LINE 605
                    > USED AT LINE 708
                    > USED AT LINE 764
                    > USED AT LINE 852
                    > USED AT LINE 960
                    > USED AT LINE 1368
                    > USED AT LINE 1473
                    > USED AT LINE 1519
                    > USED AT LINE 1560
                    > USED AT LINE 1596
                    > USED AT LINE 1708
READY:              00BB DEFINED AT LINE 788
                    > USED AT LINE 1536
                    > USED AT LINE 1547
READYNONEWLINE:     00C1 DEFINED AT LINE 799
                    > USED AT LINE 877
                    > USED AT LINE 920
LINESTARTSWITHINT:  00D8 DEFINED AT LINE 825
DELETEPROGRAMLINE:  00F9 DEFINED AT LINE 873
                    > USED AT LINE 847
ENTRY:              0109 DEFINED AT LINE 903
                    > USED AT LINE 871
MEMORYROTATE:       010D DEFINED AT LINE 910
REVERSEDH:          0117 DEFINED AT LINE 923
                    > USED AT LINE 918
REVERSE:            011A DEFINED AT LINE 928
                    > USED AT LINE 917
REVERSELOOP:        011A DEFINED AT LINE 932
                    > USED AT LINE 946
NLTESTTRUE:         0128 DEFINED AT LINE 955
                    > USED AT LINE 991
GETLINE:            0132 DEFINED AT LINE 966
                    > USED AT LINE 805
GETLINENOPROMPT:    0135 DEFINED AT LINE 975
                    > USED AT LINE 1486
FRESHSTART:         0138 DEFINED AT LINE 983
                    > USED AT LINE 1156
                    > USED AT LINE 1672
NLTEST:             013B DEFINED AT LINE 987
                    > USED AT LINE 1152
NEXTCHARLOOP:       013F DEFINED AT LINE 993
                    > USED AT LINE 999
                    > USED AT LINE 1090
LOOKUPCLASSLOOP:    014D DEFINED AT LINE 1014
                    > USED AT LINE 1018
LC_QUOTETESTTRUE:   0153 DEFINED AT LINE 1019
DIGITCLASS:         0158 DEFINED AT LINE 1030
                    > USED AT LINE 1083
                    > USED AT LINE 1668
DIGITCLASSEND:      015A DEFINED AT LINE 1034
WRITE_SHARED_ATSP:  0161 DEFINED AT LINE 1044
                    > USED AT LINE 1205
WRITE_SHARED:       0162 DEFINED AT LINE 1046
                    > USED AT LINE 1180
WRITE_SHARED_WRITTEN: 0163 DEFINED AT LINE 1048
                    > USED AT LINE 1224
NOCHARCLASS:        0165 DEFINED AT LINE 1052
                    > USED AT LINE 985
DIGITCLASSNOTEND:   016A DEFINED AT LINE 1060
                    > USED AT LINE 1032
QUOTECLASSEXPEND:   017A DEFINED AT LINE 1092
                    > USED AT LINE 959
                    > USED AT LINE 1156
QUOTECLASS:         017B DEFINED AT LINE 1106
                    > USED AT LINE 1670
LT0CLASS:           017E DEFINED AT LINE 1121
                    > USED AT LINE 1669
                    > USED AT LINE 1671
COMPCLASS:          0180 DEFINED AT LINE 1126
                    > USED AT LINE 1667
ALPHACLASS:         0182 DEFINED AT LINE 1129
                    > USED AT LINE 1666
TOKENCLASSEND:      018D DEFINED AT LINE 1158
LOOKUPTOKEN_LOOP:   019C DEFINED AT LINE 1184
                    > USED AT LINE 1214
STRCMP:             019F DEFINED AT LINE 1188
                    > USED AT LINE 1196
LOOKUPTOKEN:        01AB DEFINED AT LINE 1209
                    > USED AT LINE 1213
ABSSUB:             01B8 DEFINED AT LINE 1228
                    > USED AT LINE 596
                    > USED AT LINE 1350
                    > USED AT LINE 1970
LEFTBRACETOKEN:     01BB DEFINED AT LINE 1241
                    > USED AT LINE 586
                    > USED AT LINE 763
                    > USED AT LINE 1982
USRSUB:             01BC DEFINED AT LINE 1244
                    > USED AT LINE 1972
RNDSUB:             01BE DEFINED AT LINE 1249
                    > USED AT LINE 593
                    > USED AT LINE 1974
OPERATORS:          01CD DEFINED AT LINE 1264
                    > USED AT LINE 670
LTESUB:             01CD DEFINED AT LINE 1266
                    > USED AT LINE 1992
GTESUB:             01CE DEFINED AT LINE 1269
                    > USED AT LINE 1990
GTSUB:              01D1 DEFINED AT LINE 1273
                    > USED AT LINE 1996
LTSUB:              01D2 DEFINED AT LINE 1276
                    > USED AT LINE 1994
EQUALSUB:           01DB DEFINED AT LINE 1287
                    > USED AT LINE 1518
                    > USED AT LINE 1986
BINRETURN:          01DC DEFINED AT LINE 1289
                    > USED AT LINE 1272
NOTEQUALSUB:        01DE DEFINED AT LINE 1293
                    > USED AT LINE 1988
ADDSUB:             01E5 DEFINED AT LINE 1300
                    > USED AT LINE 1998
SUBSUB:             01E6 DEFINED AT LINE 1302
                    > USED AT LINE 590
                    > USED AT LINE 2000
NEGATESUB:          01E7 DEFINED AT LINE 1304
                    > USED AT LINE 645
MULSUB:             01EB DEFINED AT LINE 1312
                    > USED AT LINE 1258
                    > USED AT LINE 2002
MULTIPLY:           01EE DEFINED AT LINE 1321
MULLOOP:            01F0 DEFINED AT LINE 1324
                    > USED AT LINE 1334
DONTADD:            01F8 DEFINED AT LINE 1331
                    > USED AT LINE 1329
DIVSUB:             01FF DEFINED AT LINE 1340
                    > USED AT LINE 2004
DIVIDEHL:           01FF DEFINED AT LINE 1346
                    > USED AT LINE 1682
                    > USED AT LINE 1902
DIVJZERROR:         020A DEFINED AT LINE 1367
DIVLOOP:            020D DEFINED AT LINE 1370
                    > USED AT LINE 1376
DIVNORESTORE:       021B DEFINED AT LINE 1391
                    > USED AT LINE 1385
LINENUMSUB:         0223 DEFINED AT LINE 1404
                    > USED AT LINE 859
                    > USED AT LINE 1555
                    > USED AT LINE 1559
                    > USED AT LINE 1564
                    > USED AT LINE 1807
                    > USED AT LINE 1838
STATEMENTSEPSUB:    0225 DEFINED AT LINE 1407
                    > USED AT LINE 1942
PRINTSUB:           0226 DEFINED AT LINE 1410
                    > USED AT LINE 1944
PRINTSUBLOOP:       0226 DEFINED AT LINE 1411
                    > USED AT LINE 1442
PRINTSUBEXPRESSION: 0231 DEFINED AT LINE 1429
PRINTSUBSTRING:     0236 DEFINED AT LINE 1434
                    > USED AT LINE 1419
PRINTSUBEND:        0240 DEFINED AT LINE 1451
                    > USED AT LINE 1427
CRLF:               0241 DEFINED AT LINE 1454
                    > USED AT LINE 776
                    > USED AT LINE 795
                    > USED AT LINE 964
                    > USED AT LINE 1871
GOSUBSUB:           0248 DEFINED AT LINE 1461
                    > USED AT LINE 1950
GOTOSUB:            024D DEFINED AT LINE 1469
                    > USED AT LINE 1948
INPUTSUB:           0255 DEFINED AT LINE 1476
                    > USED AT LINE 1954
POPHASSIGNTOVAR:    0264 DEFINED AT LINE 1493
                    > USED AT LINE 1523
FORSUB:             0269 DEFINED AT LINE 1505
                    > USED AT LINE 1956
LETSUB:             026D DEFINED AT LINE 1511
                    > USED AT LINE 1946
IFSUB:              027A DEFINED AT LINE 1526
                    > USED AT LINE 1960
ENDSUB:             0281 DEFINED AT LINE 1535
                    > USED AT LINE 1539
                    > USED AT LINE 1962
ENDPROGRAM:         0280 DEFINED AT LINE 1539
                    > USED AT LINE 807
                    > USED AT LINE 820
                    > USED AT LINE 846
                    > USED AT LINE 1804
                    > USED AT LINE 1825
EXECUTEPROGRAM:     0284 DEFINED AT LINE 1541
                    > USED AT LINE 446
                    > USED AT LINE 1964
EXECUTEPROGRAMLOOP: 0289 DEFINED AT LINE 1550
                    > USED AT LINE 743
                    > USED AT LINE 1572
EXECUTEDIRECT:      028A DEFINED AT LINE 1553
                    > USED AT LINE 823
NEWSUB:             029A DEFINED AT LINE 1585
                    > USED AT LINE 1968
LISTSUB:            029B DEFINED AT LINE 1588
                    > USED AT LINE 1966
RETURNSUB:          029E DEFINED AT LINE 1591
                    > USED AT LINE 1952
LASTSTATEMENT:      02A8 DEFINED AT LINE 1602
                    > USED AT LINE 1423
                    > USED AT LINE 1559
                    > USED AT LINE 1660
                    > USED AT LINE 1661
                    > USED AT LINE 1662
                    > USED AT LINE 1663
NEXTSUB:            02A8 DEFINED AT LINE 1603
                    > USED AT LINE 1958
NEXTSUBLOOP:        02C0 DEFINED AT LINE 1647
                    > USED AT LINE 1641
TOTOKEN:            02A9 DEFINED AT LINE 1660
                    > USED AT LINE 707
                    > USED AT LINE 1976
STEPTOKEN:          02AA DEFINED AT LINE 1661
                    > USED AT LINE 723
                    > USED AT LINE 1978
RIGHTBRACETOKEN:    02AB DEFINED AT LINE 1662
                    > USED AT LINE 769
                    > USED AT LINE 1984
COMMATOKEN:         02AC DEFINED AT LINE 1663
                    > USED AT LINE 1440
                    > USED AT LINE 1980
CLASSLOOKUP:        02C8 DEFINED AT LINE 1665
                    > USED AT LINE 1006
RNDSUBIMPL:         02D6 DEFINED AT LINE 1674
                    > USED AT LINE 1261
OUTPUTSTRING:       02E1 DEFINED AT LINE 1689
                    > USED AT LINE 1435
OUTPUTSTRINGLOOP:   02E2 DEFINED AT LINE 1692
                    > USED AT LINE 1700
OUTPUTSTRING_WITHQUOTE: 02E6 DEFINED AT LINE 1697
                    > USED AT LINE 1923
GETVARLOCATIONBVAR: 02E9 DEFINED AT LINE 1703
                    > USED AT LINE 1478
                    > USED AT LINE 1512
GETVARLOCATION:     02EE DEFINED AT LINE 1710
                    > USED AT LINE 618
OUTPUTSTRINGRET:    02FC DEFINED AT LINE 1735
                    > USED AT LINE 1696
GETLINENUM:         02FD DEFINED AT LINE 1738
                    > USED AT LINE 840
                    > USED AT LINE 1471
GETLINENUMLOOP:     0300 DEFINED AT LINE 1757
                    > USED AT LINE 1771
ATNLN_RETNZ:        0310 DEFINED AT LINE 1778
                    > USED AT LINE 1804
ATNLN_STRING:       0312 DEFINED AT LINE 1785
                    > USED AT LINE 1788
                    > USED AT LINE 1815
ATNLN_INT:          0318 DEFINED AT LINE 1791
                    > USED AT LINE 886
                    > USED AT LINE 1813
ATNLN_INXB:         0319 DEFINED AT LINE 1793
                    > USED AT LINE 1758
ADVANCETONEXTLINENUM: 031A DEFINED AT LINE 1796
                    > USED AT LINE 1533
                    > USED AT LINE 1816
LISTSUBIMPL:        032B DEFINED AT LINE 1818
                    > USED AT LINE 1589
LISTLOOP:           032E DEFINED AT LINE 1820
                    > USED AT LINE 1828
LIST_TOKEN_LOOP:    0346 DEFINED AT LINE 1847
                    > USED AT LINE 1851
                    > USED AT LINE 1858
LIST_TOKEN:         034C DEFINED AT LINE 1853
LIST_TOKEN_STRING_LOOP: 0351 DEFINED AT LINE 1860
                    > USED AT LINE 1866
LIST_LINENUM:       035B DEFINED AT LINE 1870
                    > USED AT LINE 1838
LIST_INTEGER:       035E DEFINED AT LINE 1873
                    > USED AT LINE 1840
PRINTINTEGER:       0364 DEFINED AT LINE 1883
                    > USED AT LINE 780
                    > USED AT LINE 1431
PRINTINTEGERLOOP:   036F DEFINED AT LINE 1895
                    > USED AT LINE 1890
                    > USED AT LINE 1913
PRINTINTEGERLOOP2:  037F DEFINED AT LINE 1915
                    > USED AT LINE 1920
LIST_STRING:        0384 DEFINED AT LINE 1922
                    > USED AT LINE 1836
LIST_VAR:           0388 DEFINED AT LINE 1926
                    > USED AT LINE 1842
TOKENLIST:          038C DEFINED AT LINE 1939
                    > USED AT LINE 1182
                    > USED AT LINE 1832