*
* DATUM Integer BASIC by Scott Gogler
*
* Original code contained in "Working with DATUM, Book 3", edited by
* M.R. Haskard, (c) 1988 by Techsearch, Inc., Adelade, AUS.
* (ISBN: 0 909386 34 X)
*
* Modified (fixed?) HEX file obtained from "Old Micros", 25.Feb.26
* (https://sites.google.com/view/oldmicros/6802-max-board/datum-basic)
*
* Initial disassembly of modified HEX made with f9dasm:
* M6800/1/2/3/8/9/H6309 Binary/OS9/FLEX9 Disassembler V1.83
*
* Generated listing proofread against PDF of original code, errors
* corrected, labels, and comments added by Dave Hassler, March 2026.
* (l/c comments mine; any errors are most certainly mine, too. -dhh)
*

*****************************************************
*
*
*        B A S I C    I N T E R P R E T E R
*        ==================================
*
*             WRITTEN BY SCOTT GOGLER
*
*
* PROGRAM FUNCTION :
*
*    THIS PROGRAM IMPLEMENTS THE MAJOR FUNCTIONS
* OF AN INTEGER BASIC LANGUAGE INTERPRETER
* SPECIFICALLY FOR THE "DATUM" MICROCOMPUTER KIT.
*
*****************************************************

BACKSP	EQU	$08		BS CHARACTER
CR	EQU	$0D		CARRIAGE RETURN
ENDADD	EQU	$0010		END ADDR (USED BY MONITOR)
EOT	EQU	$04		END-OF-TEXT CHARACTER
FILMEM	EQU	$722F		UTIL/MON ADDR FOR FILLING MEM
IN	EQU	$70DA		UTIL/MON ADDR FOR INPUT A CHAR
LF	EQU	$0A		LINE FEED
LSMASK	EQU	$0F		MASK TO RETAIN LS PART OF BYTE
MEMLIM	EQU	$2000		ADDR OF MAX LIMIT USER PROGRAM
MOVMEM	EQU	$7252		UTIL/MON ADDR FOR MOVING MEM
MSMASK	EQU	$F0		MASK TO RETAIN MS PART OF BYTE
NEGMSK	EQU	$80		MASK TO DETERMINE IF NEG NO.
NMIV	EQU	$0000		ADDR OF NMI INTERRUPT VECTOR
NXTSPC	EQU	$73CB		UTIL/MON ADDR FOR OUTPUT SPACES
OUT	EQU	$70E7		UTIL/MON ADDR FOR OUTPUT CHAR
OUTS	EQU	$70C5		UTIL/MON ADDR FOR PRINT SPACES
PCRLF	EQU	$7402		UTIL/MON ADDR FOR PRINT CR, LF
PROGST	EQU	$1001		START ADDR OF USERS PROGRAM
PSTRNG	EQU	$7037		UTIL/MON ADDR FOR PRINT STRING
RESET	EQU	$7008		UTIL/MON ADDR FOR RESET MONITOR
STARAD	EQU	$000E		START ADDR (USED BY MONITOR)
STKLIM	EQU	$2700		MAX LIMIT OF USERS STACK TOP
TABSIZ	EQU	$08		SIZE OF TAB PRINT ZONE
USRSTK	EQU	$27FF		ADDR OF BOTTOM OF USERS STACK
VARBEG	EQU	$2000		BEGIN ADDR OF USER VAR AREA
VAREND	EQU	$2033		END ADDR OF USER VAR AREA
XTEMP	EQU	$0006		DESTIN ADDR (USED BY MONITOR)

*
*	ERROR MESSAGE CODES
*	-------------------
*

SYNTAX	EQU	$534E		(SN) SYNTAX ERROR
NOLINE	EQU	$4E4C		(NL) NONEXISTENT LINE NUMBER
DIVZER	EQU	$2F30		(/0) DIVISION BY ZERO
ARITOV	EQU	$4F56		(OV) ARITHMETIC OVERFLOW
FORNEX	EQU	$464E		(FN) FOR WITHOUT NEXT
NEXFOR	EQU	$4E46		(NF) NEXT WITHOUT FOR
GOSRET	EQU	$4752		(GR) GOSUB WITHOUT RETURN
RETGOS	EQU	$5247		(RG) RETURN WITHOUT GOSUB
OUTDAT	EQU	$4F44		(OD) OUT OF DATA
OUTMEM	EQU	$4F4D		(OM) OUT OF MEMORY
EXPERR	EQU	$4545		(EE) ERROR IN EXPRESSION
STAKOV	EQU	$534F		(SO) STACK OVERFLOW
NOCONT	EQU	$4343		(CC) CAN'T CONTINUE

*
*		INTERPRETER WORK AREA
*		--------------------
*
	ORG	$2034
BUFFER	RMB	72		INPUT BUFFER
*
	ORG	$207C
BRKFLG	RMB	1		<BREAK> FLAG
BUFPTR	RMB	2		POINTER TO INPUT BUFFER
COUNT	RMB	1		GENERAL PURPOSE COUNTING BYTE
DATPTR	RMB	2		PTR TO DATA ITEM LAST READ
ENDVAL	RMB	2		END VALUE FOR LOOPS
ERRCOD	RMB	3		ERROR CODE + EOT CHARACTER
ERRLIN	RMB	5		ASCII ERROR LINE NO. + EOT
FLAG	RMB	1		GENERAL PURPOSE FLAG
FNDPTR	RMB	2		PTR TO A LINE FOUND IN PROG
LASTCH	RMB	1		LAST CHAR PROCESSED IN PRINT
LENGTH	RMB	1		STORAGE FOR LENGTH OF A LINE
LINENO	RMB	2		STORAGE FOR BCD LINE NO.
LRGLIN	RMB	2		LARGEST LINE NO. IN PROG
LSPART	RMB	1		LS PART OF BCD LINE NO.
MSPART	RMB	1		MS PART OF BCD LINE NO.
NUMBER	RMB	5		ASCII REPRESENTATION OF A NO.
OPRND1	RMB	2		OPERAND USED IN ARITHMETIC
PRGCNT	RMB	2		BASIC LINE NO. PROG COUNTER
PROGEN	RMB	2		END ADDR OF USER PROG
RESULT	RMB	2		RESULT OF EVALUATED EXPRSN
RUNPTR	RMB	2		ADDR NEXT BASIC LINE TO RUN
SIGN	RMB	1		SIGN OF AN ASCII NUMBER
SP	RMB	2		SYSTEM STACK PTR TEMP STORAGE
TABPOS	RMB	1		TAB POSITION FOR PRINTING
TBLPTR	RMB	2		POINTER TO LOOK UP TABLES
TEMP	RMB	2		TEMPORARY INTEGER  STORAGE
UNOPTR	RMB	1		UNARY OPERATOR FLAG
USRSP	RMB	2		USER'S STACK POINTER
VAR	RMB	1		STORAGE FOR A VARIABLE NAME
VARNAM	RMB	1		STORAGE FOR A VARIABLE NAME
XTEMP0	RMB	2		INDEX REGISTER TEMP STORAGE
XTEMP1	RMB	2		INDEX REGISTER TEMP STORAGE
XTEMP2	RMB	2		INDEX REGISTER TEMP STORAGE
XTEMP3	RMB	2		INDEX REGISTER TEMP STORAGE
XTEMP4	RMB	2		INDEX REGISTER TEMP STORAGE
XTEMP5	RMB	2		INDEX REGISTER TEMP STORAGE

*
* 	BASIC INTERPRETER MAINLINE
*	--------------------------
*
*	THIS ROUTINE PERFORMS EITHER A WARM OR COLD
*	START, DEPENDING ON WHICH ENTRY POINT EXECUTION
*	BEGINS AT, THEN BEGINS THE INTERPRETER PROCESS.
*

        ORG     $2800

START   JSR     INTLZE		PERFORM INITIALIZATION
RESTRT  LDX     #STRTUP		DISPLAY START
        JSR     PSTRNG		UP MESSAGE
        STS     SP		SAVE STACK POINTER
        JMP     INTPRT		BEGIN INTERPRETER PROCESS

*
*	INITIALIZATION
*	--------------
*
*	THIS ROUTINE PERFORMS ALL THE NECESSARY
*	INITIALIZATION FOR A COLD START. IT ALSO DOUBLES
*	AS THE PROCESS FOR THE "NEW" COMMAND.
*

INTLZE  SEI			DISABLE <BREAK> KEY
        LDX     #BRKISR		SET UP INTERRUPT
        STX     NMIV		VECTOR
        LDAA    #EOT		SET UP END OF TEXT CHAR
        STAA    ERRCOD+2	  AT END OF ERROR CODE AND
        STAA    ERRLIN+4	  AT END OF ERROR LINE NO.
        BRA     NEW1		SKIP KEYWORD CHECK FOR "NEW"
NEW     LDX     XTEMP1		RETRIEVE SAVED BUFFER PTR
        JSR     CHKCR1		CHECK FOR <CR> AFTER KEYWORD
NEW1    LDX     #USRSTK		SET UP USER'S STACK POINTER
        STX     USRSP
        LDX     #PROGST		CLEAR USER PROGRAM AREA
        STX     PROGEN
        LDX     #VARBEG		SET ALL USER VARIBS TO ZERO
        STX     STARAD		(** REPLACE THIS FOR STANDALONE!!!)
        LDX     #VAREND
        STX     ENDADD
        CLRA
        JSR     FILMEM
        CLR     BRKFLG		NO <BREAK> OCCURRED
        CLR     LRGLIN		SET LARGEST LINE NO. = 0000
        CLR     LRGLIN+1
        LDAA    #CR		SET UP BYTE IMMEDIATELY
        STAA    PROGST-1	  BEFORE USER PROG TO BE <CR>
        RTS

*
*	INTERPRETER PROCESS
*	-------------------
*
*    THIS ROUTINE IS THE CENTRAL POINT OF THE ENTIRE
* INTERPRETER PROCESS. IT DISPLAYS THE PROMPT,
* ACCEPTS A LINE OF INPUT FROM THE USER AND BRANCHES
* TO EITHER EDITOR OR OPERATING SYSTEM MODE
* DEPENDING ON THE USER INPUT LINE.
*

INTPRT  CLR     LINENO		SET LINE NUMBER = 0000
        CLR     LINENO+1
        LDAA    #$01		SET TAB POSITION TO 1
        STAA    TABPOS
        LDX     #MESG1		DISPLAY MAIN PROMPT
        JSR     PSTRNG
        BSR     FILBUF		LOAD BUFFER FROM KEYBOARD
        LDX     #BUFFER
        JSR     SKPSPC		SKIP ANY SPACES
        JSR     CLASS		CLASSIFY FIRST NONSPACE CHAR
        CMPB    #$01		IF CHAR IS NON NUMERIC
        BEQ     EDMODE
        JSR     PCRLF		ADVANCE ONE LINE
        BSR     OPSYS		THEN BEGIN OPERATING SYS MODE
        BRA     INTPRT
EDMODE  BSR     EDITOR
        BRA     INTPRT
FILBUF  CLI
        LDX     #BUFFER		SET POINTER TO START OF BUFFER
FILBF1  JSR     IN		READ ONE CHARACTER
        CMPA    #BACKSP		  IF CHARACTER IS BACKSPACE AND
        BNE     FILBF2
        CPX     #BUFFER		  NOT AT START OF BUFFER
        BEQ     FILBF1
        DEX			THEN DECREMENT BUFFER POINTER
        BRA     FILBF1		  AND GET NEXT CHARACTER
FILBF2  TST     BRKFLG		IF <BREAK> PRESSED THEN
        BEQ     FILBF3		  JUMP TO BREAK ROUTINE
        JMP     BREAK
FILBF3  STAA    0,X		STORE CHAR IN BUFFER AND
        INX			  GET NEXT BUFFER POSITION
        CMPA    #CR		IF CHAR IS A <CR>
        BEQ     FILBF4		THEN BUFFER FILLED
        CPX     #BUFFER+72	IF BUFFER SIZE NOT EXCEEDED*
        BNE     FILBF1		  THEN READ NEXT CHAR
        DEX			OTHERWISE CHANGE LAST
        LDAA    #$0D		CHARACTER TO A <CR>
        STAA    0,X
FILBF4  SEI			DISABLE <BREAK> KEY
        RTS

*
*	OPERATING SYSTEM MODE
*	---------------------
*
*    THIS ROUTINE LOOKS TO SEE IF THE USER INPUT IS
* A VALID OPERATING SYSTEM COMMAND AND EXECUTES IT
* IF IT IS, OTHERWISE CONTROL IS TRANSFERRED TO
* IMMEDIATE MODE.
*
* I/P :
* IX = POINTER TO CURRENT BUFFER POSITION
*

OPSYS   STX     BUFPTR		STORE BUFFER POINTER
        LDX     #COMTBL		SET UP TABLE POINTER AT
        STX     TBLPTR		  START COMMAND KEYWORD TABLE
        LDX     BUFPTR		RETRIEVE BUFFER POINTER
        JSR     FINDKE		ATTEMPT TO FIND COMMAND
        TSTB			IF COMMAND NOT FOUND THEN
        BNE     OPSYS1
        BSR     IMMEDI
        RTS
OPSYS1  JSR     0,X
        RTS

*
*	IMMEDIATE MODE
*	--------------
*
*    THIS ROUTINE LOOKS TO SEE IF THE USER INPUT IS
* A VALID IMMEDIATE MODE KEYWORD AND EXECUTES IT IF
* IT IS, OTHERWISE THE INPUT IS ASSUMED TO BE AN
* EXPRESSION AND SO CONTROL IS TRANSFERRED TO THE
* EXPRESSION HANDLER.
*
* I/P :
* BUFPTR = POINTER TO CURRENT BUFFER POSITION
*

IMMEDI  LDX     #IMMTBL		SET UP TABLE POINTER AT
        STX     TBLPTR		  START IMMEDIATE KEYWORD TABLE
        LDX     BUFPTR		RETRIEVE BUFFER POINTER
        JSR     FINDKE		ATTEMPT TO FIND KEYWORD
        TSTB			IF KEYWORD NOT FOUND THEN
        BNE     IMMED1
        JSR     EXPRSN		PROCESS EXPRESSION
        RTS
IMMED1  JSR     0,X		OTHERWISE EXECUTE KEYWORD
        RTS

*
*	EDITOR
*	------
*
*    THIS ROUTINE USES THE USER INPUT TO ALTER THE
* CURRENT BASIC PROGRAM IN MEMORY ACCORDINGLY. IT
* EITHER AMENDS AN OLD LINE, INSERTS A NEW LINE,
* DELETES AN OLD LINE OR APPENDS A NEW LINE TO THE
* END OF THE CURRENT USER PROGRAM.
*
* I/P :
*   IX = POINI:ER TO FIRST NONSPACE CHAR IN BUFFER
*

EDITOR  JSR     NUMBCD		READ LINE NO., CONVERT TO BCD
        TST     MSPART		IF LINE NUMBER IS
        BNE     LINEOK
        TST     LSPART		0000 THEN DISPLAY
        BNE     LINEOK
        JMP     WHAT		"WHAT?" ERROR MESSAGE
LINEOK  JSR     SKPSPC		SKIP TO FIRST NONSPACE CHAR
        STX     BUFPTR		STORE BUFFER POINTER
        LDAA    #CR		IF FIRST CHAR IS A <CR>
        CMPA    0,X
        BEQ     EDITR5		THEN JUMP TO DELETE LINE
        LDAA    MSPART		IF LINE NO. IS DIFFERENT
        CMPA    LRGLIN		  THAN LARGEST LINE NO.
        BHI     EDITR4
        BNE     EDITR1		THEN JUMP TO INSERT/AMEND LINE
        LDAA    LSPART
        CMPA    LRGLIN+1
        BHI     EDITR4		OTHERWISE JUMP TO APPEND LINE
EDITR1  JSR     FINDLN		ATTEMPT TO FIND LINE IN PROG
        TSTB			IF LINE ALREADY EXISTS
        BNE     EDITR2
        BSR     DELET1		DELETE OLD LINE
EDITR2  LDX     BUFPTR
        LDAA    MSPART		TEST TO SEE IF THE
        CMPA    LRGLIN		  LINE DELETED WAS THE
        BCS     EDITR3		  AND IF SO MUST NOW
        LDAA    LSPART		  APPEND NEW LINE
        CMPA    LRGLIN+1
        BHI     EDITR4		OTHERWISE
        BEQ     EDITR4
EDITR3  BSR     INSERT		INSERT NEW LINE AND EXIT
        RTS
EDITR4  BSR     APPEND		APPEND LINE AND EXIT
        RTS
EDITR5  BSR     DELETE		DELETE LINE AND EXIT
        RTS

*
*	INSERT LINE
*	-----------
*
*    THIS ROUTINE INSERTS A NEW LINE INTO THE
* CORRECT POSITION WITHIN THE USER'S CURRENT PROGRAM
* AND UPDATES PROGRAM PARAMETERS ACCORDINGLY.
*
* I/P :
*   IX = POINTER TO START BASIC STATEMENT IN BUFFER
*   BUFPTR = SAME AS IX EXCEPT STORED
*   FNDPTR = PTR TO POSITION FOR INSERTION OF LINE
*   MSPART = MS BYTE OF BCD LINE NUMBER
*   LSPART = LS BYTE OF BCD LINE NUMBER
*

INSERT  STX     XTEMP0		STORE POINTER
        LDX     PROGEN		SET UP END ADDR OF PROG
        STX     ENDADD		BLOCK TO BE MOVED
        LDX     XTEMP0		RETRIEVE POINTER
        JSR     UPDEND		UPDATE PROGRAM END POINTER
        LDX     FNDPTR		SET UP START ADDR OF PROG
        STX     STARAD		BLOCK TO BE MOVED
        LDAB    LENGTH		CALCULATE DESTINATION ADDR
        JSR     IXADD		  OF BLOCK TO BE MOVED
        STX     XTEMP
        JSR     MOVMEM		MOVE PROG BLOCK TO CREATE GAP
        LDX     FNDPTR		GET PTR TO START OF NEW LINE
        JSR     ADDLN		ADD LINE TO GAP IN USER PROG
        RTS

*
*	APPEND LINE
*	-----------
*
*    THIS ROUTINE APPENDS A NEW LINE TO THE END OF
* THE USER'S CURRENT PROGRAM, AND UPDATES PROGRAM
* PARAMETERS ACCORDINGLY.
*
* I/P :
*   IX = POINTER TO START BASIC STATEMENT IN BUFFER
*   BUFPTR = SAME AS IX EXCEPT STORED
*   MSPART = MS BYTE OF BCD LINE NUMBER
*   LSPART = LS BYTE OF BCD LINE NUMBER
*

APPEND  BSR     UPDEND		UPDATE PROG END POINTER
        LDAA    MSPART		UPDATE LARGEST LINE NUMBER
        STAA    LRGLIN
        LDAA    LSPART		TO CURRENT LINE NUMBER
        STAA    LRGLIN+1
        LDX     XTEMP0		GET PTR TO START OF NEW LINE
        BSR     ADDLN		ADD NEW LINE TO USER PROGRAM
        RTS

*
*	DELETE LINE
*	-----------
*
*    THIS ROUTINE DELETES AN OLD LINE FROM THE USER
* PROGRAM GIVEN THE LINE NUMBER, AND UPDATES PROGRAM
* PARAMETERS (SUCH AS PROG END AND LARGEST LINE NO.)
* ACCORDINGLY.
*
* I/P :
*   MSPART = MS BYTE OF BCD LINE NUMBER
*   LSPART = LS BYTE OF BCD LINE NUMBER
*

DELETE  JSR     FINDLN		ATTEMPT TO FIND LINE IN PROG
        TSTB			IF LINE NOT FOUND THEN
        BEQ     DELET1		
        JMP     WHAT		DISPLAY "WHAT?" ERROR MESSAGE
DELET1  STX     XTEMP		STORE DESTINATION ADDRESS
        LDAA    LRGLIN		TEST IF LINE TO BE
        CMPA    0,X		  DELETED IS THE
        BNE     DELET4		  LARGEST LINE
        LDAA    LRGLIN+1	IF NOT THEN
        CMPA    1,X		  CONTINUE AS NORMAL
        BNE     DELET4		  OTHERWISE:
        DEX
        LDAA    #CR
DELET2  DEX			DETERMINE NEXT
        CMPA    0,X
        BNE     DELET2		LARGEST LINE NO.
        DEX
        DEX			AND UPDATE
        DEX
        CMPA    0,X		THE LARGEST
        BEQ     DELET3
        INX			LINE NUMBER
        INX
        INX			TO BE THIS
DELET3  INX
        LDX     0,X
        STX     LRGLIN
DELET4  LDX     XTEMP		RETRIEVE DESTINATION PTR
        LDAB    2,X		FIND START ADDRESS
        STAB    LENGTH		  OF BLOCK TO
        JSR     IXADD		  BE MOVED
        STX     STARAD		  AND STORE
        LDX     PROGEN		FIND END ADDRESS
        STX     ENDADD		  AND STORE
        LDAB    LENGTH		UPDATE END ADDRESS
        JSR     IXSUB
        STX     PROGEN		OF USER'S PROGRAM
        JSR     MOVMEM		MOVE REST OF PROG OVER LINE
        RTS

*
*	UPDATE END OF PROGRAM PARAMETER
*	-------------------------------
*
*    THIS ROUTINE CALCULATES AND STORES THE LENGTH
* OF THE PROGRAM LINE AND USES THIS TO UPDATE THE
* END OF PROGRAM POINTER.
*
* I/P :
*   IX = POINTER TO START BASIC STATEMENT IN BUFFER
*
* O/P :
*   XTEMP0 = OLD END OF PROGRAM POINTER
*   LENGTH = LENGTH OF BASIC LINE
*

UPDEND  LDAB    #$04		CALCULATE LENGTH
        LDAA    #CR
UPDEN1  INCB
        INX			OF BASIC LINE
        CMPA    0,X
        BNE     UPDEN1
        STAB    LENGTH		AND STORE LENGTH
        LDX     PROGEN
        STX     XTEMP0		SAVE OLD PROG END POINTER
UPDEN2  INX			INCREMENT FROG END POINTER
        CPX     #MEMLIM+1	IF PTR EXCEEDS LIMIT THEN
        BNE     UPDEN3
        LDX     #OUTMEM		SET UP ERROR CODE
        JMP     ERROR		  AND JUMP TO ERROR ROUTINE
UPDEN3  DECB			IF NOT FINISHED THEN
        BNE     UPDEN2		GO AND INCREMENT PTR AGAIN
        STX     PROGEN		OTHERWISE STORE NEW PROG END
        RTS			  AND EXIT

*
*	ADD LINE TO PROGRAM
*	-------------------
*
*    THIS ROUTINE WRITES THE NEW PROGRAM LINE INTO
* THE SPECIFIED POSITION IN THE CURRENT USER
* PROGRAM.
*
* I/P :
*   IX = PTR TO POSITION OF INSERTION OF NEW LINE
*   BUFPTR = POINTER TO BUFFER POSITION
*   MSPART = MS PART OF BCD LINE NUMBER
*   LSPART = LS PART OF BCD LINE NUMBER
*   LENGTH = LENGTH OF BASIC LINE
*

ADDLN   LDAA    MSPART		WRITE MSBYTE OF LINE
        STAA    0,X		  NUMBER TO PROGRAM
        INX			INCREMENT PROG POINTER
        LDAA    LSPART		WRITE LSBYTE OF LINE
        STAA    0,X		  NUMBER TO PROGRAM
        INX			INCREMENT PROG POINTER
        LDAA    LENGTH		WRITE LENGTH OF NEW LINE
        STAA    0,X		  TO PROGRAM
        INX			INCREMENT PROG POINTER
ADDLN1  STX     XTEMP0		STORE PROG POINTER
        LDX     BUFPTR		RETRIEVE BUFFER POINTER
        LDAA    0,X		GET CHARACTER FROM BUFFER
        INX			MOVE BUFFER PTR TO NEXT CHAR
        STX     BUFPTR		STORE BUFFER POINTER
        LDX     XTEMP0		RETRIEVE PROG POINTER
        STAA    0,X		WRITE CHAR TO PROGRAM
        INX			MOVE PROG PTR TO NEXT POSN
        CMPA    #CR		IF NOT END LINE TO BE WRITTEN
        BNE     ADDLN1		  THEN GO AND WRITE NEXT CHAR
Z29FF   RTS			  OTHERWISE EXIT

*
*	FIND KEYWORD
*	------------
*
*    THIS ROUTINE ATTEMPTS TO FIND A REQUIRED
* KEYWORD IN THE LOOKUP TABLES, GIVEN THE TABLE IN
* WHICH TO SEARCH FOR THE KEYWORD.
*
* I/P :
*   IX = POINTER TO START OF KEYWORD
*   TBLPTR = START ADDRESS OF LOOKUP TABLE
*
* O/P :
*   IX = START ADDRESS OF KEYWORD ROUTINE (IF FOUND)
*   XTEMP1 = PTR TO CHAR FOLLOWING 3 CHAR KEYWORD
*            (IF FOUND)
*   ACCB = INDICATOR FOR KEYWORD FOUND
*        = 00   IF NOT FOUND
*	 = FF   IF FOUND
*

FINDKE  STX     XTEMP0		STORE START ADDR OF KEYWORD
FINDK1  LDAB    #$05		SET COUNTER
FINDK2  LDAA    0,X		GET CHAR AT KEYWORD POINTER
        INX			SET KEYWORD PTR AT NEXT CHAR
        STX     XTEMP1		STORE KEYWORD POINTER
        LDX     TBLPTR		RETRIEVE TABLE POINTER
        CMPA    0,X		COMPARE CHAR WITH TABLE
Z2A10   BEQ     FINDK4		IF CHAR IS DIFFERENT THEN
FINDK3  INX			MOVE POINTER
        DECB			  TO NEXT
        BNE     FINDK3		  KEYWORD IN
        STX     TBLPTR		  LOOK UP TABLE
        TST     0,X		AND IF END OF LOOK UP
        BEQ     FINDK6		  TABLE THEN EXIT OTHERWISE
        LDX     XTEMP0		GET START OF KEYWORD AGAIN
        BRA     FINDK1		AND ATTEMPT TO MATCH KEYWORD
FINDK4  INX			IF CHAR IS SAME THEN
        DECB			  DECREMENT COUNTER
        CMPB    #$02		CHECK IF ALL KEYWORD MATCHES
        BEQ     FINDK5		  AND IF NOT
        STX     TBLPTR		  STORE TABLE POINTER
        LDX     XTEMP1		AND RETRIEVE KEYWORD POINTER
        BRA     FINDK2		  AND CHECK NEXT CHAR
FINDK5  LDX     0,X		GET ADDR OF KEYWORD ROUTINE
        RTS
FINDK6  LDX     XTEMP0		SET LINE POINTER BACK
        STX     XTEMP1		  IN ORIGINAL POSITION
        RTS

*
*	KEYWORD LOOKUP TABLES
*	---------------------
*

COMTBL  FCC	'LIS'		START COMMAND KEYWORD TABLE
        FDB	LIST
	FCC	'MON'
	FDB	MONITR
	FCC	'NEW'
	FDB	NEW
	FCC	'RUN'
	FDB	RUN
	FCB	#$00		END COMMAND KEYWORD TABLE
RUNTBL	FCC	'DAT'		START RUN KEYWORD TABLE
	FDB	REM
	FCC	'FOR'
	FDB	FOR
	FCC	'GOS'
	FDB	GOSUB
	FCC	'INP'
	FDB	INPUT
	FCC	'NEX'
	FDB	NEXT
	FCC	'REA'
	FDB	READ
IMMTBL	FCC	'END'		START IMMEDIATE KEYWORD TABLE
	FDB	END
	FCC	'GOT'
	FDB	GOTO
	FCC	'IF '
	FDB	IF
	FCC	'LET'
	FDB	EXPRSN
	FCC	'POK'
	FDB	POKE
	FCC	'PRI'
	FDB	PRINT
	FCC	'REM'
	FDB	REM
	FCC	'RET'
	FDB	RETURN
	FCC	'STO'
	FDB	STOP
	FCB	#$00		END RUN AND IMMEDIATE TABLES
IFTBL	FCC	'DAT'		START "IF" KEYWORD TABLE
	FDB	REM
	FCC	'FOR'		( TABLE OF
	FDB	FOR
	FCC	'IF '		KEYWORDS NOT
	FDB	IF
	FCC	'INP'		ALLOWED
	FDB	INPUT
	FCC	'NEX'		WITHIN
	FDB	NEXT
	FCC	'REM'		IF..THEN..)
	FDB	REM
	FCB	#$00		END "IF" KEYWORD TABLE
FNTBL	FCC	'PEE'		START FUNCTION KEYWORD TABLE
	FDB	PEEK
	FCB	#$00		END FUNCTION KEYWORD TABLE

*
*	LIST
*	----
*
*    THIS ROUTINE LISTS EITHER THE ENTIRE USER'S
* PROGRAM OR A SUBSET OF IT, WHERE THE SUBSET MAY BE
* ONLY ONE LINE, DEPENDING ON THE PARAMETERS
* SUPPLIED IN THE INPUT BUFFER.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

LIST    JSR     PCRLF		ADVANCE ONE LINE
        LDX     XTEMP1		RETRIEVE SAVED BUFFER PTR
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
        CMPA    #CR		IF THIS CHAR IS A <CR>
        BNE     LIST1		  THEN SET LIST POINTER
        LDX     #PROGST		  AT START OF USER PROG,
        LDAA    LRGLIN		  SET HIGHEST LINE NO.
        LDAB    LRGLIN+1	  TO LARGEST CURRENT LINE NO.
        BRA     OUTLIS		  AND PRINT LISTING
LIST1   JSR     NUMBCD		OTHERWISE READ LINE NUMBER
        STX     BUFPTR		STORE BUFFER POINTER
        JSR     FINDLN		POSN LIST PTR AT LOWEST LINE
        LDX     BUFPTR		RETRIEVE BUFFER POINTER
        JSR     SKPSPC		SKIP ANY FOLLOWING SPACES
        CMPA    #CR		IF NEXT CHARALTtit IS NOT
        BEQ     LIST2		  A <CR> THEN
        JSR     NUMBCD		  READ HIGHEST LINE NUMBER
LIST2   JSR     CHKCR1		CHECK FOR <CR> AT END OF LINE
        LDX     FNDPTR		RETRIEVE LIST POINTER
LIST3   LDAA    MSPART		SET UP HIGHEST LINE NO.
        LDAB    LSPART		( = LOWEST IF NOT SPECIFIED
OUTLIS  CLI			ENABLE <BREAK> KEY
        CPX     PROGEN		IF LIST POINTER IS AT END OF
        BEQ     ENDLIS		  USER PROG, LISTING COMPLETE
        CMPA    0,X		IF LINE NUMBER AT
        BHI     OUTLS1		  LIST POINTER IS HIGHER
        BNE     ENDLIS		  THAN HIGHEST LINE
        CMPB    1,X		  NUMBER THEN LISTING
        BCS     ENDLIS		  IS COMPLETE OTHERWISE
OUTLS1  STX     FNDPTR		STORE LIST POINTER
        STAA    MSPART		STORE HIGHEST LINE NUMBER
        STAB    LSPART
        JSR     BCDNUM		PRINT OUT CURRENT
        LDX     #ERRLIN		  LINE'S NUMBER
        JSR     PSTRNG
        JSR     OUTS		PRINT A SPACE
        LDX     FNDPTR		RETRIEVE LIST POINTER
        INX			INCREMENT LIST POINTER
        INX			  PAST LENGTH OF LINE
OUTLS2  INX
        LDAA    0,X		READ CHAR AT LIST POINTER
        JSR     OUT		PRINT CHAR AT LIST POINTER
        CMPA    #CR		IF CHAR WAS NOT A <CR>
        BNE     OUTLS2		  THEN GET NEXT CHARACTER
        LDAA    #LF		OTHERWISE PRINT A <LF>
        JSR     OUT
        INX			AND REPEAT FOR NEXT LINE
        TST     BRKFLG		IF <BREAK> WAS
        BEQ     LIST3		  PRESSED THEN GO AND
        JMP     BREAK		  PROCESS <BREAK>
ENDLIS  SEI			DISABLE <BREAK> KEY
        RTS

*
*	MONITOR
*	-------
*
*    THIS ROUTINE RETURNS CONTROL TO THE DATERM
* MONITOR PROGRAM.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

MONITR  LDX     XTEMP1		RETRIEVE SAVED BUFFER PTR
        JSR     CHKCR1		CHECK FOR <CR> AFTER KEYWORD
        JMP     RESET		RETURN TO MONITOR

*
*	RUN
*	---
*
*    THIS ROUTINE RUNS AN ENTIRE USER PROGRAM
* STARTING AT THE FIRST LINE IN MEMORY UNLESS "STOP"
* OR "END" ARE ENCOUNTERED, OR THE <BREAK> KEY IS
* PRESSED.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

RUN     LDX     XTEMP1		RETRIEVE SAVED BUFFER PTR
        JSR     CHKCR1		CHECK FOR <CR> AFTER KEYWORD
        LDX     #PROGST		GET PROGRAM START ADDR
        CPX     PROGEN		IF NO PROGRAM IN MEMORY
        BEQ     RUN3		  THEN END RUN OTHERWISE
        LDX     #PROGST-1	SETUP DATA PTR AT <CR>
        STX     DATPTR		  IMMEDIATELY BEFORE USER PROG
        LDX     #VARBEG
        STX     STARAD		SET ALL USER
        LDX     #VAREND
        STX     ENDADD		VARIABLES
        CLRA
        JSR     FILMEM		TO ZERO
        LDX     #USRSTK		SET USER STACK PTR
        STX     USRSP		  TO TOP OF USER STACK
        LDX     #PROGST		INITIALISE RUN PTR AT FIRST
        STX     RUNPTR		  INSTRUCTION OF USER FROG
        LDX     PROGST		SET PROGRAM COUNTER = FIRST
        STX     PRGCNT		  LINE NO. OF USER PROGRAM
GORUN   CLI			ENABLE <BREAK> KEY
RUN1    BSR     EXECUT		EXECUTE A PROGRAM LINE
        TST     BRKFLG		IF <BREAK> WAS PRESSED
        BEQ     RUN2		  THEN GO AND
        JSR     BREAK		  PROCESS <BREAK>
RUN2    LDX     PRGCNT		IF NOT END OF
        CPX     #$FFFF		  USER PROG THEN
        BNE     RUN1		  EXECUTE NEXT PROGRAM LINE
        SEI			OTHERWISE DISABLE <BREAK> KEY
RUN3    RTS			AND END RUN

*
*	EXECUTE ONE PROGRAM LINE
*	------------------------
*
*    THIS ROUTINE INCREMENTS THE USER'S PROGRAM
* COUNTER AND RUN POINTER TO THE NEXT LINE OF THE
* USER'S PROGRAM THEN EXECUTES THE CURRENT PROGRAM
* LINE.
*

EXECUT  LDX     PRGCNT		STORE PROGRAM COUNTER
        STX     LINENO		  AS CURRENT LINE NO.
        LDX     RUNPTR		SET LINE PTR AT
        STX     XTEMP1		  RUN PTR POSITION
        LDAB    2,X		SET RUN PTR
        JSR     IXADD		  AT NEXT LINE
        STX     RUNPTR		  TO BE RUN
        CPX     PROGEN		IF NOT END OF USER
        BEQ     EXECU1		  PROG THEN INCREMENT PROGRAM
        LDX     0,X		  COUNTER TO NEXT LINE
        BRA     EXECU2		OTHERWISE SET PROGRAM
EXECU1  LDX     #$FFFF		  COUNTER = FFFF
EXECU2  STX     PRGCNT
EXECU3  LDX     #RUNTBL		SET UP TABLE POINTER AT
        STX     TBLPTR		  START OF RUN KEYWORD TABLE
        LDX     XTEMP1		RETRIEVE PTR TO PROG LINE
        INX			MOVE LINE POINTER
        INX			  PAST LINE NO.
        INX			  AND LENGTH BYTES
        STX     XTEMP1		SAVE LINE PTR
EXECU4  JSR     FINDKE		ATTEMPT TO FIND KEYWORD
        TSTB			IF KEYWORD NOT FOUND THEN
        BNE     EXECU5
        JSR     EXPRSN		PROCESS EXPRESSION
        RTS
EXECU5  JSR     0,X		OTHERWISE EXECUTE KEYWORD
        RTS			NEXT PROG LINE

*
*	END
*	---
*
*    THIS ROUTINE CLEARS THE USER STACK THEN RETURNS
* TO THE INTERPRETER PROCESS, ENDING THE RUN OF A
* USER PROGRAM.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

END     LDX     XTEMP1		RETRIEVE SAVED LINE PTR
        JSR     CHKCR2		CHECK FOR <CR> AFTER KEYWORD
END1    LDX     #USRSTK		CLEAR USER'S STACK
        STX     USRSP
END2    LDS     SP		CLEAR SYSTEM STACK
        JMP     INTPRT		EXECUTE INTERPRETER PROCESS

*
*	FOR...TO...(STEP)
*	-----------------
*
*    THIS ROUTINE INITIATES A BASIC PROGRAM LOOP BY
* ASSIGNING AN INITIAL AND A FINAL VALUE TO A
* VARIABLE AND BY ALSO DEFINING THE STEP SIZE BY
* WHICH THE VARIABLE SHALL BE INCREMENTED/
* DECREMENTED UNTIL IT REACHES ITS FINAL VALUE.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

FOR     LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     SKPSPC		MOVE PTR TO FIRST NONSPACE
        JSR     CLASS		CLASSIFY CHARACTER
        CMPB    #$02		IF CHAR IS NOT A
        BEQ     FOR2		  VARIABLE NAME THEN
FOR1    JMP     SYNERR		  SYNTAX ERROR OTHERWISE :
FOR2    LDAA    0,X		READ AND
        STAA    VARNAM		  STORE VARIABLE NAME
        INX			MOVE LINE PTR PAST VARIABLE
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        LDAA    #'='		IF CHAR IS NOT "="
        CMPA    0,X		  THEN
        BNE     FOR1		  SYNTAX ERROR OTHERWISE :
        STX     XTEMP1		SAVE LINE PTR
        LDX     USRSP		SET UP TEMP USER SP
        CLR     FLAG		INDICATE NO GOSUBS ON STACK
FOR3    CPX     #USRSTK		IF AT END OF STACK OR
        BEQ     FOR7
        LDAA    1,X		IF VARIABLE NAME IS ALREADY
        CMPA    VARNAM
        BEQ     FOR5		ON STACK THEN EXIT LOOP
        CMPA    #$00		IF GOSUB ADDR FOUND
        BNE     FOR4		THEN INDICATE GOSUB
        LDAA    #$FF		  ADDRESS EXISTS
        STAA    FLAG		  ON STACK
FOR4    INX
        INX			DECREMENT TEMP STACK PTR
        INX
        BRA     FOR3		REPEAT LOOP
FOR5    TST     FLAG		IF GOSUB ADDR FOUND
        BEQ     FOR6		  ON USER STACK THEN
        LDX     #GOSRET		  GOSUB WITHOUT RETURN ERROR
        JMP     ERROR
FOR6    INX
        INX			DECREMENT TEMP STACK PTR
        INX
        STX     USRSP		STORE TEMP STACK PTR
FOR7    LDX     USRSP		GET ORIGINAL STACK PTR
        JSR     CHKSTK		ENSURE NO STACK OVERFLOW
        LDAA    LINENO+1	PUSH CURRENT LINE NUMBER
        STAA    0,X
        DEX			  AND VARIABLE NAME
        LDAA    LINENO
        STAA    0,X		  ONTO USER STACK,
        DEX
        LDAA    VARNAM		  AND INCREMENT USER'S
        STAA    0,X
        DEX			  STACK POINTER
        STX     USRSP
        LDX     XTEMP1		RETRIEVE LINE PTR
        INX			MOVE LINE PTR PAST "="
        JSR     SKPSPC		MOVE POINTER TO NEXT NONSPACE
        JSR     EVAL		EVALUATE EXPRESSION
        JSR     EXPRS5		ASSIGN RESULT TO VARIABLE
        BSR     TO		PROCESS TO, STEP STMTS
        JSR     GETVAR		GET VARIABLE VALUE
        TST     OPRND1		IF STEP VALUE IS POSITIVE
        BMI     FOR10		  AND VARIABLE VALUE
        JSR     DUDCPX		  IS > END LOOP VALUE
        BGT     FOR11		OR
FOR9    RTS			  IF STEP VALUE IS NEGATIVE
FOR10   JSR     DUDCPX		  AND VARIABLE VALUE
        BGE     FOR9		  IS < END LOOP VALUE
FOR11   BSR     ENDFOR		  THEN END OF FOR LOOP
        RTS			OTHERWISE CONTINUE NEXT LINE

*
*	TO
*	--
*
*    THIS ROUTINE DETERMINES THE TERMINATING VALUE
* FOR A LOOP VARIABLE FROM THE FOR...TO...(STEP)
* STATEMENT.
*
* I/P :
*   XTEMP1 = LINE POINTER
*
* O/P :
*   XTEMP1 = LINE POINTER (UPDATED)
*   ENDVAL = TERMINATING VALUE FOR LOOP VARIABLE
*

TO      LDX     XTEMP1		RETRIEVE LINE PTR
        LDAA    0,X		CHECK THAT
        LDAB    1,X
        CMPA    #'T'		  NEXT TWO CHARS
        BEQ     TO2
TO1     JMP     SYNERR		  ARE "TO" - IF NOT
TO2     CMPB    #'O'
        BNE     TO1		  THEN SYNTAX ERROR
        INX			MOVE LINE PTR PAST
        INX			  KEYWORD "TO"
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        JSR     EVAL		EVALUATE EXPRESSION
        LDX     RESULT		ASSIGN RESULT TO
        STX     ENDVAL		  END LOOP VARIABLE

*
*	STEP
*	----
*
*    THIS ROUTINE DETERMINES THE STEPPING VALUE FOR
* A LOOP VARIABLE FROM THE FOR...TO...(STEP)
* STATEMENT.
*
* I/P :
*   XTEMP1 = LINE POINTER

*
* O/P :
*   OPRND1 = STEP VALUE FOR LOOP VARIABLE
*

STEP    LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        CMPA    #CR		IF NO STEP IS
        BNE     STEP1		  SPECIFIED THEN
        CLR     OPRND1
        LDAA    #$01		  SET STEP VALUE TO +1
        STAA    OPRND1+1
        RTS			OTHERWISE :
STEP1   STX     XTEMP1		STORE LINE POINTER
        LDX     0,X
        CPX     #$5354		CHECK THAT
        BEQ     STEP3
STEP2   JMP     SYNERR		  NEXT STATEMENT
STEP3   LDX     XTEMP1
        LDX     2,X		  IS "STEP"
        CPX     #$4550
        BNE     STEP2
        LDX     XTEMP1		RETRIEVE LINE PTR
        INX
        INX			MOVE LINE PTR PAST
        INX			  "STEP" STATEMENT
        INX
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        JSR     EVAL		EVALUATE EXPRESSION
        LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     CHKCR2		CHECK FOR <CR> AT END OF LINE
        STX     XTEMP1		STORE LINE POINTER
        LDX     RESULT		GET STEP VALUE AND
        STX     OPRND1		STORE IN OPRND1
        RTS

*
*	ENDFOR
*	------
*
*    THIS ROUTINE TERMINATES A FOR...NEXT LOOP BY
* SEARCHING FOR THE CORRESPONDING "NEXT' TO THE
* CURRENT "FOR" STATEMENT AND SETTING UP FOR
* EXECUTION TO CONTINUE AT THE FIRST LINE FOLLOWING
* THAT "NEXT" STATEMENT.
*
* I/P :
*   VARNAM = VARIABLE CORRESPONDING TO CURRENT "FOR"
*

ENDFOR  LDX     USRSP		REMOVE LOOP REFERENCE
        INX			  FROM USER STACK
        INX
        INX
        STX     USRSP
        LDX     RUNPTR		RETRIEVE TEMP RUN PTR
ENDFR1  CPX     PROGEN		COMPARE PTR TO PROG END
        BEQ     ENDFR3		IF PTR NOT AT PROG END THEN
        LDAA    3,X
        CMPA    #'N'		  COMPARE FIRST THREE
        BNE     ENDFR2
        LDAA    4,X		  CHARACTERS OF TEMP RUN PTR
        CMPA    #'E'
        BNE     ENDFR2		  LINE WITH "NEX". IF
        LDAA    5,X
        CMPA    #'X'		  CHARS = "NEX" THEN
        BNE     ENDFR2
        LDAB    #$05		  MOVE TEMP RUN PTR
        JSR     IXADD
        JSR     FNDSPC		  PAST "NEXT" STATEMENT AND
        LDAA    0,X		COMPARE VARIABLE FOUND
        CMPA    VARNAM		  WITH FOR LOOP VARIABLE. IF
        BEQ     ENDFR4		  CORRECT VAR THEN STOP SEARCH
ENDFR2  LDX     RUNPTR		OTHERWISE RETRIEVE RUN PTR,
        LDAB    2,X
        JSR     IXADD		  ADD LENGTH OF LINE TO IT,
        STX     RUNPTR		  AND REPLACE IT
        BRA     ENDFR1		  THEN CONTINUE SEARCH
ENDFR3  LDX     #FORNEX		IF RUN PTR AT END OF FROG
        JSR     ERROR		  THEN FOR WITHOUT NEXT ERROR
ENDFR4  LDX     RUNPTR		CORRECT "NEXT" FOUND :
        LDAB    2,X
        JSR     IXADD
        CPX     PROGEN		IF AT END OF PROGRAM
        BNE     ENDFR6		  THEN END, OTHERWISE
        JMP     END1		SET RUN PTR AT ADDR OF
ENDFR6  STX     RUNPTR		  LINE FOLLOWING NEXT STMT
        LDX     0,X		  AND SET PROG COUNTER TO
        STX     PRGCNT		  THE LINE NO. OF THAT LINE
        RTS

*
*	GOSUB
*	-----
*
*    THIS ROUTINE TRANSFERS CONTROL TEMPORARILY TO A
* SUBROUTINE STARTING AT A SPECIFIED LINE NUMBER.
* THE RETURN-TO LINE NUMBER (I.E. THE NEXT LINE NO.
* IN SEQUENCE) IS PLACED ON THE USER STACK AND THEN
* CONTROL WITHIN THE USER'S PROGRAM IS TRANSFERRED
* TO THE SUBROUTINE USING GOTO.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

GOSUB   JSR     CHKSTK		ENSURE NO STACK OVERFLOW
        LDX     USRSP		THEN PUSH THE
        LDAA    PRGCNT+1
        STAA    0,X		RETURN LINE NUMBER
        DEX
        LDAA    PRGCNT		ONTO THE USER'S STACK
        STAA    0,X
        DEX			AND INCREMENT THE
        CLR     0,X
        DEX			USER'S STACK POINTER
        STX     USRSP

*
*	GOTO
*	----
*
*    THIS ROUTINE TRANSFERS CONTROL TO ANOTHER LINE
* NUMBER BY READING THE LINE NUMBER THEN UPDATING
* THE PROGRAM COUNTER TO THIS LINE NUMBER AND ALSO
* UPDATING THE RUN POINTER TO POINT TO THE NEW LINE
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

GOTO    LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
        JSR     CLASS		CLASSIFY FIRST NONSPACE
        CMPB    #$01		IF THIS CHAR IS
        BEQ     GOTO1		  NOT NUMERIC THEN
        JMP     SYNERR		  DISPLAY SYNTAX ERROR MESSAGE
GOTO1   JSR     NUMBCD		OTHERWISE READ LINE NUMBER
        JSR     CHKCR2		CHECK FOR <CR> AT END OF LINE
GOTO2   JSR     FINDLN		FIND LINE IN USER PROG
        TSTB			IF LINE WANT TO GO TO
        BEQ     GOTO3		  IS NONEXISTENT THEN
        LDX     #NOLINE		  SET UP ERROR CODE
        JMP     ERROR		DISPLAY ERROR MESSAGE
GOTO3   LDAA    MSPART		OTHERWISE STORE LINE NO.
        STAA    PRGCNT
        LDAA    LSPART		IN PROGRAM COUNTER AND
        STAA    PRGCNT+1
        STX     RUNPTR		SET UP RUN PTR AT NEXT LINE
        TST     LINENO		IF GOTO USED
        BNE     GOTO4		  FROM IMMEDIATE MODE
        TST     LINENO+1	  THEN EXECUTE
        BNE     GOTO4		  PROGRAM FROM
        JSR     GORUN		  GOTO LINE NUMBER. OTHERWISE
GOTO4   RTS			RETURN

*
*	IF...THEN
*	---------
*
*    THIS ROUTINE PROCESSES THE BASIC STATEMENT
* FOLLOWING THE THEN KEYWORD ONLY ON FINDING THE
* TRUE RESULT OF EVALUATING AN EXPRESSION. IF THE
* EXPRESSION RESULT IS FALSE, NO FURTHER PROCESSING
* IS CARRIED OUT.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

IF      LDX     XTEMP1		RETRIEVE LINE POINTER
        JSR     SKPSPC		MOVE PTR TO FIRST NONSPACE
        JSR     EVAL		EVALUATE EXPRSN
        LDX     XTEMP1		RETRIEVE LINE POINTER
        LDX     0,X
        CPX     #$5448		CHECK THAT
        BNE     IF1
        LDX     XTEMP1		NEXT STATEMENT
        LDX     2,X
        CPX     #$454E		IS "THEN"
        BEQ     IF2
IF1     JMP     SYNERR		DISPLAY SYNTAX ERROR MESSAGE
IF2     LDX     XTEMP1		RETRIEVE LINE PTR
        INX
        INX			MOVE LINE PTR
        INX
        INX			PAST "THEN" STATEMENT
        STX     XTEMP1		STORE LINE PTR
        TST     RESULT		IF RESULT OF
        BNE     THEN		  EVALUATING EXPRESSION
        TST     RESULT+1	  IS ZERO THEN
        BNE     THEN
        RTS			  NO FURTHER PROCESSING

THEN    JSR     SKPSPC		OTHERWISE SKIP TO NONSPACE
        STX     XTEMP1		STORE LINE POINTER
        LDX     #IFTBL		IF THE STATEMENT
        STX     TBLPTR
        LDX     XTEMP1		FOLLOWING "THEN" IS AN
        JSR     FINDKE
        TSTB			ILLEGAL ONE FOR IF..THEN,
        BEQ     THEN1
        BRA     IF1		THEN SYNTAX ERROR OTHERWISE
THEN1   LDX     LINENO		SET TABLE PTR AT THE
        BEQ     THEN2
        LDX     #RUNTBL		  APPROPRIATE LOOKUP TABLE
        BRA     THEN3
THEN2   LDX     #IMMTBL		  AS DETERMINED BY THE
THEN3   STX     TBLPTR		  CURRENT MODE
        LDX     XTEMP1
        JMP     EXECU4		EXECUTE STATEMENT

*
*	INPUT
*	-----
*
*    THIS ROUTINE ASSIGNS A VALUE TO EACH VARIABLE
* IN THE VARIABLE LIST WHICH FOLLOWS THE KEYWORD,
* WHERE THE VALUES ARE ENTERED BY THE USER IN AN
* INPUT BUFFER.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

INPUT   LDX     XTEMP1		RETRIEVE LINE POINTER
        STX     XTEMP2		SAVE INITIAL LINE PTR
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
INPUT1  JSR     CLASS		IF CHAR IS NOT ALPHABETIC
        CMPB    #$02
        BEQ     INPUT3
INPUT2  JMP     SYNERR		DISPLAY SYNTAX ERROR MESSAGE
INPUT3  LDAA    0,X		OTHERWISE :
        STAA    VAR		STORE VARIABLE NAME
        STX     XTEMP1		STORE LINE POINTER
INPUT4  LDX     #MESG2
        JSR     PSTRNG		DISPLAY INPUT PROMPT
        LDX     PRGCNT		SET UP PROGRAM COUNTER
        STX     XTEMP0		  TO THE CURRENT LINE NO.
        LDX     LINENO		  IN CASE <BREAK> IS PRESSED
        STX     PRGCNT		  SO INPUT REPEATED IF RETURN
        JSR     FILBUF		GET USER INPUT
        LDX     XTEMP0		RESTORE PROGRAM COUNTER
        STX     PRGCNT		  TO FOLLOWING LINE NO. AGAIN
        LDX     #BUFFER		SET PTR AT START INPUT BUFFER
INPUT5  JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        CMPA    #CR		IF NONSPACE IS A <CR>
        BEQ     INPUT4		  THEN GO AND GET MORE INPUT
        CLR     FLAG		SET FLAG TO INDICATE THAT
        COM     FLAG		  ASCHEX CALLED FROM INPUT
        JSR     ASCHEX		READ AND STORE INPUT NO.
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        CMPA    #CR		IF THE NEXT NONSPACE IS NOT
        BEQ     INPUT7
        CMPA    #','		A <CR> OR "," THEN BAD INPUT
        BEQ     INPUT6
        JMP     BADINP
INPUT6  INX			IF NEXT NONSPACE WAS A
        JSR     SKPSPC		  COMMA THEN SKIP COMMA
INPUT7  STX     BUFPTR		STORE BUFFER PTR
        JSR     PUTVAL		ASSIGN INPUT NO. TO VARIABLE
        LDX     XTEMP1		RETRIEVE LINE PTR
        INX			MOVE LINE PTR PAST VAR
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        CMPA    #CR		IF NONSPACE CHAR IS <CR>
        BEQ     INPUT8		  THEN FINISHED
        CMPA    #','		OTHERWISE IF NOT A ","
        BNE     INPUT2		  THEN SYNTAX ERROR
        INX			OTHERWISE SKIP' COMMA
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        JSR     CLASS		CLASSIFY NEXT NONSPACE CHAR
        CMPB    #$02		IF CHAR NOT ALPHABETIC
        BNE     INPUT2		  THEN SYNTAX ERROR
        LDAA    0,X		OTHERWISE
        STAA    VAR		STORE VARIABLE NAME
        STX     XTEMP1		STORE LINE POINTER
        LDX     BUFPTR		RETRIEVE BUFFER POINTER
        BRA     INPUT5		REPEAT FOR NEXT VARIABLE
INPUT8  JSR     PCRLF		  IN INPUT LIST
        RTS

*
*	ASSIGN EXPRESSION (LET)
*	-----------------------
*
*    THIS ROUTINE ASSIGNS THE EVALUATED RESULT OF AN
* EXPRESSION TO A VARIABLE.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

EXPRSN  LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     SKPSPC		MOVE PTR TO FIRST NONSPACE
        JSR     CLASS		CLASSIFY CHARACTER
        CMPB    #$02		IF CHAR IS A VARIABLE THEN
        BNE     EXPRS1
        LDAA    0,X		STORE VARIABLE NAME
        STAA    VARNAM
        INX			MOVE PTR PAST VARIABLE
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        LDAA    #'='		IF CHAR IS NOT "="
        CMPA    0,X		  THEN
        BEQ     EXPRS3
EXPRS1  LDX     LINENO		IF CURRENTLY IN
        BEQ     EXPRS2		  RUN MODE THEN
        JMP     SYNERR		  DISPLAY SYNTAX ERROR MESSAGE
EXPRS2  JMP     WHAT		OTHERWISE DISPLAY "WHAT?"
EXPRS3  INX			  ELSE MOVE PTR PAST "="
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        JSR     EVAL		GO AND EVALUATE EXPRESSION
        LDX     XTEMP1		RETRIEVE LINE POINTER
        TST     LINENO
        BNE     EXPRS4		CHECK FOR <CR> AT END
        TST     LINENO+1
        BNE     EXPRS4		OF LINE DEPENDING
        JSR     CHKCR1
        BRA     EXPRS5		ON CURRENT MODE
EXPRS4  JSR     CHKCR2
EXPRS5  LDAA    VARNAM		GET VARIABLE NAME AND
        STAA    VAR		STORE IT IN VAR
PUTVAL  JSR     GETVA1		GET VARIABLE ADDRESS
        LDAA    RESULT		STORE MS BYTE OF RESULT
        STAA    0,X		  IN VARIABLE AREA
        LDAA    RESULT+1	STORE LS BYTE OF RESULT
        STAA    1,X		  IN VARIABLE AREA
        RTS

*
*	NEXT
*	----
*
*    THIS ROUTINE FIRSTLY ADDS THE STEP VALUE FOUND
* IN THE CORRESPONDING "FOR" STATEMENT TO THE
* VARIABLE VALUE, THEN DETERMINES WHETHER OR NOT THE
* ASSOCIATED LOOP SHOULD BE TERMINATED. IF THE LOOP
* IS TO CONTINUE THEN EXECUTION IS SET UP TO
* CONTINUE AT THE FIRST STATEMENT FOLLOWING THE
* "FOR" STATEMENT.
*
* I/P  :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

NEXT    LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
        JSR     CLASS		CLASSIFY CHARACTER
        CMPB    #$02		IF CHAR IS NOT A
        BEQ     NEXT2		  VARIABLE NAME THEN
        JMP     SYNERR		  SYNTAX ERROR OTHERWISE:
NEXT2   LDAA    0,X		READ AND STORE
        STAA    VARNAM		  VARIABLE NAME
        INX			MOVE LINE PTR PAST VARIABLE
        JSR     CHKCR2		CHECK FOR <CR> AT END LINE
        LDX     USRSP		SET UP TEMP USER SP
        CLR     FLAG		INDICATE NO GOSUBS ON STACK
NEXT3   CPX     #USRSTK		IF AT END OF STACK OR
        BEQ     NEXT5
        LDAA    1,X		IF CORRESPONDING "FOR" FOUND
        CMPA    VARNAM
        BEQ     NEXT6		THEN EXIT LOOP OTHERWISE:
        CMPA    #$00		IF GOSUB ADDR FOUND
        BNE     NEXT4		  THEN INDICATE GOSUB
        LDAA    #$FF		  ADDRESS EXISTS
        STAA    FLAG		  ON STACK
NEXT4   INX
        INX			DECREMENT TEMP STACK PTR
        INX
        BRA     NEXT3		REPEAT LOOP
NEXT5   LDX     #NEXFOR		IF END OF STACK FOUND
        JSR     ERROR		  THEN NEXT WITHOUT FOR ERROR
NEXT6   TST     FLAG		IF GOSUB ADDR
        BEQ     NEXT7		  FOUND ON USER
        LDX     #GOSRET		  STACK THEN
        JSR     ERROR		  GOSUB WITHOUT RETURN ERROR
NEXT7   STX     USRSP		STORE STACK PTR
        LDAA    2,X
        STAA    MSPART		RETRIEVE LINE NO.
        LDAA    3,X
        STAA    LSPART		  OF "FOR" STATEMENT
        JSR     FINDLN		FIND THAT LINE IN PROG
NEXT8   LDAA    #'T'
        CMPA    0,X		SEARCH FOR
        BNE     NEXT9
        LDAA    #'O'		"TO" STATEMENT
        CMPA    1,X
        BEQ     NEXT10		IN THAT LINE
NEXT9   INX
        BRA     NEXT8
NEXT10  STX     XTEMP1		STORE LINE PTR
        JSR     TO		GET END LOOP AND STEP VALUES
        JSR     GETVAR		GET VARIABLE VALUE
        STX     RESULT		STORE IN RESULT
        JSR     ADD		ADD STEP VALUE TO VAR VALUE
        JSR     EXPRS5		AND REPLACE IN VARIABLE
        LDX     RESULT		GET NEW VAR VALUE
        TST     OPRND1		IF STEP VALUE IS POSITIVE
        BMI     NEXT12		  AND VARIABLE VALUE
        BSR     DUDCPX		  IS <= END LOOP VALUE
        BLE     NEXT13		THEN CONT EXECUTION OF LOOP
NEXT11  LDX     USRSP		END OF LOOP:
        INX
        INX			DECREMENT STACK POINTER
        INX			(TO REMOVE LOOP VARIABLE)
        STX     USRSP
        RTS			IF STEP VALUE IS NEGATIVE
NEXT12  BSR     DUDCPX		  AND VARIABLE VALUE
        BLT     NEXT11		  IS >= END LOOP VALUE
NEXT13  LDX     XTEMP1		  THEN:
        INX			INCREMENT LINE PTR PAST <CR>
        JMP     ENDFR6		CONTINUE EXECUTION OF LOOP

*
*	CPX EMULATE
*	-----------
*
*    THIS ROUTINE PERFORMS THE ASSEMBLER INSTRUCTION
* "CPX ENDVAL". UNLIKE THE TRUE "CPX ENDVAL"
* INSTRUCTION THIS ROUTINE SETS (AS APPROPRIATE) THE
* Z, N AND V BITS IN THE CONDITION CODE REGISTER IN
* THE WAY THAT M6800 CHIP SPECIFICATIONS SAY IT
* SHOULD.
*
* I/P :
*   IX = INDEX REGISTER VALUE
*
* O/P :
*   Z, N AND V BITS SET APPROPRIATELY IN THE
*   CONDITION CODE REGISTER
*

DUDCPX  CPX     ENDVAL		SET THE Z BIT IF APPROPRIATE
        BEQ     DUDCP2		IF Z BIT SET THEN END
        STX     TEMP		OTHERWISE STORE INDEX REGISTER
        LDAA    TEMP+1		SUBTRACT ENDVAL
        SUBA    ENDVAL+1	  FROM INDEX
        LDAA    TEMP		  REGISTER WHILE SETTING
        SBCA    ENDVAL		  V AND N BITS AS
DUDCP1  TPA			  APPROPRIATE
        ANDA    #$FB		CLEAR Z BIT
        TAP
DUDCP2  RTS			END OF "CPX ENDVAL"

*
*	POKE
*	----
*
*    THIS ROUTINE STORES A SINGLE BYTE VALUE AT THE
* ADDRESS SPECIFIED IN THE "POKE" STATEMENT.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

POKE    LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
        JSR     EVAL		EVALUATE EXPRESSION
        LDX     RESULT		GET POKE ADDRESS
        STX     XTEMP5		STORE POKE ADDRESS
        LDX     XTEMP1		RETRIEVE LINE PTR
        LDAA    #','		IF NEXT CHAR
        CMPA    0,X		  IS NOT A COMMA
        BEQ     POKE1		  THEN
        JMP     SYNERR		  SYNTAX ERROR OTHERWISE:
POKE1   INX			MOVE PTR PAST COMMA
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        JSR     EVAL		EVALUATE EXPRESSION
        LDX     XTEMP1		RETRIEVE LINE PTR
        JSR     CHKCR2		CHECK FOR <CR> AT END LINE
        LDX     XTEMP5		RETRIEVE POKE ADDRESS
        LDAA    RESULT+1	GET LS BYTE OF RESULT
        STAA    0,X		STORE RESULT AT POKE ADDR
        RTS

*
*	PRINT
*	-----
*
*    THIS ROUTINE DISPLAYS ON THE SCREEN ALL ITEMS
* IN THE PRINT LIST FOLLOWING THE KEYWORD. THESE
* ITEMS MAY BE STRINGS, NUMERIC RESULTS OF
* EXPRESSIONS, AND/OR TAB POSITIONS.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER K.iXORD

PRINT   LDX     XTEMP1		RETRIEVE LINE POINTER
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
        CLR     LASTCH		SET LAST CHAR NOT = ; OR ,
PRINT1  CMPA    #CR		IF CURRENT CHAR IS A <CR>
        BNE     PRINT2
        JMP     PRINT5		  THEN END OF PRINT
PRINT2  CMPA    #'"'		ELSE IF CURRENT CHAR IS A "
        BEQ     STRING		  THEN GO AND PRINT STRING
        CMPA    #','		ELSE IF CURRENT CHAR IS A ,
        BEQ     TAB		  THEN GO TO NEXT TAB POSITION
        CMPA    #';'		ELSE IF CURRENT CHAR IS A ;
        BNE     NUMB		  THEN PROCESS DELIMITER
        JMP     NOSPC		ELSE :
NUMB    JSR     EVAL		EVALUATE EXPRESSION
        JSR     HEXASC		CONVERT RESULT TO ASCII
        TST     SIGN		IF RESULT IS NEGATIVE
        BEQ     NUMB1
        LDAA    #'-'
        JSR     OUT		THEN DISPLAY NEGATIVE SIGN
        BRA     NUMB2
NUMB1   JSR     OUTS		OTHERWISE DISPLAY A SPACE
NUMB2   JSR     UPDTAB		UPDATE TAB POSITION
        LDAA    #'0'
        LDX     #NUMBER		SET PTR AT START OF NO.
        LDAB    #$04
NUMB3   CMPA    0,X		SKIP ANY
        BNE     NUMB4
        INX			LEADING ZEROS
        DECB
        BNE     NUMB3

NUMB4   INCB
NUMB5   LDAA    0,X
        JSR     OUT		PRINT ALL REMAINING
        STAB    COUNT
        BSR     UPDTAB
        LDAB    COUNT
        INX			DIGITS WHILE UPDATING
        DECB
        BNE     NUMB5		THE TAB POSITION
        JSR     OUTS		PRINT TRAILING SPACE
        BSR     UPDTAB		UPDATE TAB POSITION
        LDX     XTEMP1		RETRIEVE LINE POINTER
PRINT3  JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        CLR     LASTCH		SET LAST CHAR NOT = ; OR ,
        LDAA    0,X		READ NEXT CHARACTER
        CMPA    #CR		IF NEXT CHARACTER
        BEQ     PRINT1
        CMPA    #';'		IS A <CR> OR A ";"
        BEQ     PRINT1
        CMPA    #','		OR A "," THEN NEXT PRINT ITEM
        BEQ     PRINT1
PRINT4  JMP     SYNERR		DISPLAY SYNTAX ERROR MESSAGE
STRING  INX			MOVE LINE PTR TO NEXT CHAR
        LDAA    0,X		IF A <CR> FOUND
        CMPA    #CR		  BEFORE CLOSING QUOTES
        BEQ     PRINT4		  THEN SYNTAX ERROR
        CMPA    #'"'		IF NEXT CHAR IS " THEN
        BNE     STRNG1		  END OF STRING SO
        INX			  MOVE LINE PTR PAST QUOTE
        BRA     PRINT3		  AND DO END STRING PROCESSING
STRNG1  JSR     OUT		OTHERWISE PRINT CURRENT CHAR
        BSR     UPDTAB		UPDATE TAB POSITION
        BRA     STRING		REPEAT FOR NEXT CHAR
TAB   	LDAB    #TABSIZ+1	CALCULATE NO. OF SPACES
        SUBB    TABPOS		  UNTIL NEXT PRINT ZONE
        JSR     NXTSPC		PRINT THAT MANY SPACES
        CLR     TABPOS		SET TAB POSITION
        INC     TABPOS		  TO 1 AGAIN
        LDAA    #','		READ CHARACTER AGAIN
NOSPC   STAA    LASTCH		STORE LAST CHARACTER
        INX			MOVE LINE PTR TO NEXT CHAR
        JSR     SKPSPC		MOVE LINE PTR TO NEXT NONSPACE
        JMP     PRINT1		GO PROCESS NEXT PRINT ITEM
PRINT5   LDAA    #';'		END OF PRINT :
        CMPA    LASTCH		IF LAST CHARACTER
        BEQ     PRINT6
        LDAA    #','		WAS NOT A ;
        CMPA    LASTCH
        BEQ     PRINT6		OR A , THEN
        JSR     PCRLF		PRINT A <CR> AND <LF>
        LDAA    #$01		RESET TAB POSITION
        STAA    TABPOS		TO 1 AGAIN
PRINT6  RTS			RETURN

*
*	UPDATE TAB POSITION
*	-------------------
*
*    THIS ROUTINE INCREMENTS THE TAB POSITION AND IF
* IT EXCEEDS THE TAB SIZE IT IS RESET TO 1 AGAIN.
*

UPDTAB  INC     TABPOS		INCREMENT TAB POSITION
        LDAB    #TABSIZ		IF TAB POSITION > TAB SIZE
        CMPB    TABPOS
        BGE     UPDTB1		THEN RESET TAB
        LDAB    #$01
        STAB    TABPOS		POSITION TO 1 AGAIN
UPDTB1  RTS

*
*	READ
*	----
*
*    THIS ROUTINE ASSIGNS A VALUE TO EACH VARIABLE
* IN THE VARIABLE LIST (WHICH FOLLOWS THE READ
* STATEMENT) FROM THE CURRENT POSITION OF THE DATA
* POINTER AND INCREMENTS THE DATA POINTER ONCE FOR
* EVERY VALUE ASSIGNED.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

READ    LDX     XTEMP1		RETRIEVE LINE POINTER
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
READ1   JSR     CLASS		IF CHAR IS NOT ALPHABETIC
        CMPB    #$02
        BEQ     READ3
READ2   JMP     SYNERR		DISPLAY SYNTAX ERROR MESSAGE
READ3   LDAA    0,X		OTHERWISE :
        STAA    VAR		STORE VARIABLE NAME
        INX			MOVE PTR PAST VARIABLE
        JSR     SKPSPC		SKIP TO NEXT NONSPACE
        CMPA    #CR		IF NEXT NONSPACE IS NOT
        BEQ     READ4		  A <CR> OR A ","
        CMPA    #','
        BNE     READ2		  THEN SYNTAX ERROR OTHERWISE
        INX			MOVE PTR PAST COMMA AND
        JSR     SKPSPC		  SKIP ANY SPACES (COMMA ONLY)
READ4   STX     XTEMP1		STORE LINE POINTER
        LDX     DATPTR		RETRIEVE DATA POINTER
        LDAA    0,X
        CMPA    #CR		IF DATA POINTER IS
        BNE     READ9		  POINTING TO A <CR> THEN
        INX			  MOVE DATA PTR TO NEXT LINE
READ6   CPX     PROGEN		IF DATA PTR AT
        BNE     READ7		  END OF PROGRAM THEN
        LDX     #OUTDAT		  OUT OF DATA SO
        JSR     ERROR		  DISPLAY ERROR MESSAGE
READ7   LDAA    3,X		IF THE CURRENT LINE
        CMPA    #'D'
        BNE     READ8
        LDAA    4,X		BEGINS WITH A
        CMPA    #'A'
        BNE     READ8
        LDAA    5,X		DATA STATEMENT THEN
        CMPA    #'T'
        BNE     READ8
        LDAB    #$06		MOVE DATA PTR TO
        JSR     IXADD		  FIRST CHAR AFTER KEYWORD
        JSR     FNDSPC		MOVE PTR PAST KEYWORD
        BRA     READ10
READ8   LDAB    2,X		OTHERWISE :
        JSR     IXADD		MOVE DATA PTR TO NEXT LINE
        BRA     READ6		  AND REPEAT
READ9   INX			IF DATA PTR WAS POINTING TO A
        JSR     SKPSPC		  COMMA THEN SKIP COMMA
READ10  CLR     FLAG		ASCHEX NOT CALLED FROM INPUT
        JSR     ASCHEX		READ AND STORE DATA
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        CMPA    #CR		IF NEXT NONSPACE IS NOT
        BEQ     READ11		  A <CR> OR A ",
        CMPA    #','
        BNE     READ2		  THEN SYNTAX ERROR
READ11  STX     DATPTR		STORE DATA POINTER
        JSR     PUTVAL		ASSIGN DATA TO VARIABLE
        LDX     XTEMP1		RETRIEVE LINE POINTER
        LDAA    #CR		IF LINE PTR CHAR IS NOT <CR>
        CMPA    0,X		  THEN
        BEQ     READ12		  REPEAT ENTIRE PROCESS FOR
        JMP     READ1		  NEXT VARIABLE IN READ LIST
READ12  RTS			OTHERWISE FINISHED

*
*	REM
*	---
*
*    THIS ROUTINE IGNORES THE REST OF THE PROGRAM
* LINE.
*

REM     RTS			DUMMY "DO NOTHING" ROUTINE

*
*	RETURN
*	------
*
*    THIS ROUTINE TRANSFERS CONTROL BACK TO THE LINE
* WHOSE LINE NUMBER IS THE FIRST FOUND ON THE STACK
* CORRESPONDING TO A GOSUB STACK ELEMENT. ANY LOOPS
* LEFT OPEN ARE DISCARDED BY REMOVING THEM FROM THE
* STACK WHILE SEARCHING FOR THE GOSUB STACK ELEMENT.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*

RETURN  LDX     XTEMP1		RETRIEVE LINE POINTER
        JSR     FNDSPC		FIND SPACE DELIMITER
        JSR     CHKCR2		CHECK FOR <CR> AT END OF LINE
        LDX     USRSP		RETRIEVE USER STACK PTR
RETUR1  CPX     #USRSTK		IF AT BOTTOM OF STACK
        BNE     RETUR4		  THEN :
        LDX     LINENO		  IF IN IMMEDIATE THEN
        BNE     RETUR2		    CAN'T CONTINUE ERROR
        LDX     #NOCONT		  IF IN RUN MODE
        BRA     RETUR3		    THEN SET UP FOR RETURN
RETUR2  LDX     #RETGOS		    WITHOUT GOSUB ERROR
RETUR3  JMP     ERROR		  DISPLAY ERROR MESSAGE
RETUR4  CLRA			OTHERWISE:
        CMPA    1,X		CHECK IF LAST STACK ELEMENT
        BEQ     RETUR5		  WAS A RETURN ADDRESS
        INX			IF NOT, THEN MOVE
        INX			  STACK POINTER TO
        INX			  NEXT STACK ELEMENT
        BRA     RETUR1		  AND REPEAT THE ABOVE
RETUR5  LDAA    3,X		OTHERWISE:
        STAA    LSPART		EXTRACT LINE NUMBER
        LDAA    2,X
        STAA    MSPART		  FROM LAST ELEMENT
        INX			MOVE THE STACK
        INX			  POINTER TO THE
        INX			  NEXT STACK ELEMENT
        CMPA    #$FF		IF LINE EXTRACTED
        BNE     RETUR6		  IS FFFF THEN
        JMP     END1		  END USER PROGRAM
RETUR6  STX     USRSP		SET USER STACK PTR
        JMP     GOTO2		GOTO EXTRACTED LINE NO.

*
*	BREAK/STOP PROCESS
*	------------------
*
*    THIS ROUTINE PERFORMS EITHER THE PROCESSES
* REQUIRED AFTER <BREAK> IS PRESSED OR THE PROCESSES
* REQUIRED AFTER "STOP" IS ENCOUNTERED IN THE USER'S
* PROGRAM, DEPENDING ON THE ENTRY POINT. CONTROL IS
* THEN RETURNED TO THE INTERPRETER PROCESS.
*

BREAK   CLR     BRKFLG		CLEAR <BREAK> FLAG
        BRA     STOP1		SKIP KEYWORD CHECK FOR "STOP"
STOP    LDX     XTEMP1		RETRIEVE SAVED BUFFER PTR
        JSR     FNDSPC		FIND SPACE DELIMITER
        JSR     CHKCR2		CHECK FOR <CR> AFTER KEYWORD
STOP1   LDX     #LINENO		SET UP LINE NUMBER
        JSR     BCDNUM		  IN STOPPED MESSAGE
        LDX     #MESG4
        JSR     PSTRNG		DISPLAY STOPPED
        LDX     #ERRLIN
        JSR     PSTRNG		MESSAGE
        JSR     PCRLF
        TST     LINENO		IF CURRENTLY IN
        BNE     STOP2
        TST     LINENO+1	  RUN MODE THEN
        BEQ     STOP3
STOP2   JSR     CHKSTK		ENSURE NO STACK OVERFLOW
        LDX     USRSP		  THEN PUSH THE
        LDAA    PRGCNT+1
        STAA    0,X		  NEXT LINE NUMBER
        DEX
        LDAA    PRGCNT		  ONTO THE USER'S STACK
        STAA    0,X
        DEX			  AND DECREMENT THE
        CLR     0,X
        DEX			  USER'S STACK POINTER
        STX     USRSP
STOP3   JMP     END2		GO BACK TO INTPRT PROCESS

*
*	SYNTAX ERROR
*	------------
*
*    THIS ROUTINE DISPLAYS THE SYNTAX ERROR MESSAGE
*
* THEN RETURNS TO THE INTERPRETER PROCESS (USING
* THE ERROR ROUTINE BELOW).
*

SYNERR	LDX	#SYNTAX		SET UP ERROR CODE

*
*	ERROR MESSAGE
*	-------------
*
*    THIS ROUTINE DISPLAYS AN APPROPRIATE ERROR
* MESSAGE GIVEN THE ERROR CODE THEN RETURNS TO THE
* INTERPRETER PROCESS.
*
* I/P :
*   IX = ERROR CODE
*

ERROR   STX     ERRCOD		SET UP ERROR CODE
        LDX     #LINENO		SET UP LINE NUMBER
        JSR     BCDNUM		  IN ERROR MESSAGE
        JSR     PCRLF		PRINT A <CR>,<LF>
        LDX     #ERRCOD
        JSR     PSTRNG		DISPLAY ERROR CODE
        LDX     #MESG3
        JSR     PSTRNG		DISPLAY " ERROR IN "
        LDX     #ERRLIN
        JSR     PSTRNG		DISPLAY LINE NUMBER
        JSR     PCRLF		PRINT A <CR> , <LF>
        JMP     END1		JUMP TO END ROUTINE

*
*	"WHAT?" MESSAGE
*	---------------
*
*    THIS ROUTINE DISPLAYS THE "WHAT?" MESSAGE IN
* RESPONSE TO AN OPERATING SYSTEM MODE OR IMMEDIATE
* MODE ERROR, THEN RETURNS TO THE INTERPRETER
* PROCESS.
*

WHAT    LDX     #MESG6		DISPLAY 'WHAT?" MESSAGE
        JSR     PSTRNG
        JSR     PCRLF
        JMP     END2		GO BACK TO INTPRT PROCESS

*
*	BAD INPUT MESSAGE
*	-----------------
*
*    THIS ROUTINE DISPLAYS THE MESSAGE FOR BAD INPUT
* THEN RETURNS TO THE BEGINNING OF THE INPUT ROUTINE
* AND STARTS INPUT AGAIN.
*

BADINP  LDX     #MESG5
        JSR     PSTRNG		DISPLAY BAD INPUT MESSAGE
        LDX     XTEMP2		RETRIEVE INITIAL LINE PTR
        STX     XTEMP1		  AND STORE BACK AS LINE PTR
        JMP     INPUT		RESTART INPUT ROUTINE

*
*	EVALUATE EXPRESSION
*	-------------------
*
*    THIS ROUTINE EVALUATES THE RESULT OF ANY
* RELATIONAL OR ARITHMETIC EXPRESSION STARTING FROM
* THE POSITION POINTED TO BY IX AND ENDING AT THE
* FIRST CHARACTER WHICH IS NOT PART OF THE
* EXPRESSION BUT IS THOUGHT TO BE LEGAL.
*
* I/P :
*   IX = POINTER TO START OF EXPRESSION
*
* O/P :
*   XTEMP1 = PTR TO FIRST CHAR AFTER EXPRESSION
*   RESULT = EVALUATED VALUE OF EXPRESSION
*

EVAL    STX     XTEMP1		STORE LINE POINTER
        JSR     CHKSTK		ENSURE NO STACK OVERFLOW
        LDX     USRSP		PUSH AN EXPRESSION MARKER
        DEX
        DEX			  ONTO THE USER'S STACK
        LDAA    #$01		  AND INCREMENT THE
        STAA    0,X
        DEX
        STX     USRSP		  USER'S STACK POINTER
        BSR     PRCEXP		PROCESS EXPRESSION
        LDX     USRSP		RETRIEVE USER'S STACK PTR
        LDAA    1,X		IF NEXT STACK ELEMENT
        CMPA    #$01		  IS NOT AN EXPRESSION MARKER
        BEQ     EVAL1		  THEN
        LDX     #EXPERR		    ERROR IN EXPRESSION
        JMP     ERROR		OTHERWISE
EVAL1   INX
        INX			POP EXPRESSION MARKER
        INX
        STX     USRSP		FROM USER STACK AND
        RTS			RETURN

*
*	PROCESS EXPRESSION
*	------------------
*
*    THIS ROUTINE PERFORMS THE ACTUAL EVALUATION OF
* AN EXPRESSION BY PROCESSING EACH OPERATOR ONE AT
* TIME UNTIL THE END OF THE EXPRESSION IS FOUND.
* NOTE THAT THE END OF AN EXPRESSION IS TRUE ON
* FINDING ANY ONE OF : <CR>, COMMA, SEMICOLON, "TO",
* "THEN", "STEP', OR CLOSING BRACKET.
*
* I/P :
*   XTEMP1 = POINTER TO START OF EXPRESSION
*
* O/P :
*   XTEMP1 = PTR TO FIRST CHAR AFTER EXPRESSION
*   RESULT = EVALUATED VALUE OF EXPRESSION
*

PRCEXP  JSR     CHKSTK		ENSURE NO STACK OVERFLOW
        LDX     USRSP		PUSH OPERAND = 0
        CLR     0,X
        DEX			AND OPERATOR = +
        CLR     0,X
        DEX			ONTO USER'S STACK
        LDAA    #'+'
        STAA    0,X		AND INCREMENT USER'S
        DEX
        STX     USRSP		STACK POINTER
        LDX     XTEMP1		RETRIEVE LINE POINTER
PRCEX1  JSR     PRUNOP		PROCESS UNARY OPERATOR
        STX     XTEMP1		STORE LINE POINTER
        LDX     USRSP		RETRIEVE STACK POINTER
        DEX			INCREMENT USER
        DEX			  STACK POINTER
        DEX			  AND
        LDAA    UNOPTR		  ADD UNARY OPERATOR
        STAA    1,X		  TO USER STACK
        STX     USRSP		STORE STACK POINTER
        JSR     PROPND		PROCESS OPERAND
        JSR     PFUNOP		PERFORM UNARY OPERATION
        JSR     PFBIOP		PERFORM BINARY OPERATION
        LDAA    0,X		IF NOT END OF EXPRSN I.E.:
        LDAB    1,X
        CMPA    #CR		  <CR> NOT FOUND
        BEQ     PRCEX4
        CMPA    #','		  AND COMMA NOT FOUND
        BEQ     PRCEX4
        CMPA    #';'		  AND SEMICOLON NOT FOUND
        BEQ     PRCEX4
        CMPA    #')'		  AND END BRACKET NOT FOUND
        BEQ     PRCEX4
        CMPA    #'T'		  AND "TO" NOT FOUND
        BNE     PRCEX2
        CMPB    #'O'
        BEQ     PRCEX4
        CMPB    #'H'		  AND "TH" (THEN) NOT FOUND
        BEQ     PRCEX4
PRCEX2  CMPA    #'S'		  AND "ST" (STEP) NOT FOUND
        BNE     PRCEX3
        CMPB    #'T'
        BEQ     PRCEX4		THEN :
PRCEX3  JSR     PRBIOP		PROCESS BINARY OPERATOR AND
        BRA     PRCEX1		  REPEAT OTHERWISE:
PRCEX4  STX     XTEMP1		STORE LINE POINTER AND
        RTS			  RETURN

*
*	PROCESS UNARY OPERATOR
*	----------------------
*
*    THIS ROUTINE DETERMINES WHAT UNARY OPERATOR
* EXISTS AT THE CURRENT LINE POINTER POSITION (IF
* ANY) AND SETS UP A UNARY OPERATOR FLAG
* ACCORDINGLY. THE LINE POINTER IS THEN MOVED TO
* THE OPERAND IF NECESSARY.
*
* I/P :
*   IX = LINE POINTER POSITION
*
* O/P :
*   IX = LINE PTR POSITION POINTING TO NEXT OPERAND
*   UNOPTR = UNARY OPERATOR FLAG
*          = 2B (+) FOR UNARY +
*          = 2D (-) FOR UNARY -
*          = 27 (') FOR UNARY NOT
*

PRUNOP  LDAA    #'+'		ASSUME UNARY OPERATOR
        STAA    UNOPTR		  IS UNARY +
        LDAA    0,X
        CMPA    #'+'		IF CHAR IS "+" THEN
        BEQ     PRUNO3		  PROCESS UNARY +
        CMPA    #'-'		IF CHAR IS "-" THEN
        BEQ     PRUNO3		  PROCESS UNARY -
        CMPA    #'N'		IF NEXT 3 CHARS
        BNE     PRUNO4
        LDAA    1,X
        CMPA    #$'O'		  ARE "NOT" THEN
        BNE     PRUNO4
        LDAA    2,X
        CMPA    #'T'
        BNE     PRUNO4
        INX			  INCREMENT LINE PTR TWICE
        INX			($27 IS ASCII FOR APOSTROPHE)
        LDAA    #$27		GET OPERATOR FLAG FOR 'NOT"
PRUNO2  INX			MOVE LINE PTR PAST OPERATOR
        STAA    UNOPTR		STORE UNARY OPERATOR FLAG
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        RTS
PRUNO3  STX     XTEMP1		STORE LINE POINTER
        BSR     PRUNO2		STORE UNARY OPERATOR FLAG
        JSR     CLASS		IF NEXT OPERAND IS
        CMPB    #$01		  NUMERIC THEN
        BNE     PRUNO4		
        LDX     XTEMP1		  NO UNARY OPERATOR
        LDAA    #'+'		  (WILL FIX WHEN READ NO.)
        STAA    UNOPTR		OTHERWISE
PRUNO4  RTS			LEAVE UNARY OPERATOR AS IS

*
*	PROCESS OPERAND
*	---------------
*
*    THIS ROUTINE OBTAINS THE VALUE FOR THE OPERAND
* AT THE LINE POINTER, WHERE THE OPERAND MAY BE THE
* VALUE OBTAINED FROM A FUNCTION, A VARIABLE, A
* CONSTANT, OR ANOTHER EXPRESSION ENCLOSED IN
* BRACKETS.
*
* I/P :
*   XTEMP1 = POINTER TO OPERAND
*
* O/P :
*   IX = LINE PTR POSITION POINTING TO THE FIRST
*        NONSPACE CHAR AFTER THE OPERAND
*   RESULT = VALUE OF OPERAND
*

PROPND  LDX     #FNTBL		SET UP TABLE POINTER AT
        STX     TBLPTR		  START OF FUNCTION TABLE
        LDX     XTEMP1		RETRIEVE LINE POINTER
        JSR     FINDKE		LOOK FOR FUNCTION IN
        TSTB			  FUNCTION KEYWORD TABLE
        BEQ     PRVAR		IF KEYWORD FOUND THEN :
        JSR     0,X		  PROCESS FUNCTION
        LDX     XTEMP1		  RETRIEVE LINE PTR
PRFN1   INX			  MOVE PTR PAST END BRACKET
PRFN2   JSR     SKPSPC		  MOVE PTR TO NEXT NONSPACE
        RTS			OTHERWISE :
PRVAR   LDX     XTEMP1
        JSR     CLASS		IF CHAR AT PTR IS
        CMPB    #$02		  ALPHABETIC THEN :
        BNE     PRBRKT
        LDAA    0,X		  READ VARIABLE NAME
        STAA    VAR
        JSR     GETVAL		  RETRIEVE VARIABLE VALUE
        STX     RESULT		  STORE IN RESULT
        LDX     XTEMP1		  RETRIEVE LINE POINTER
        INX			  MOVE PTR PAST VARIABLE NAME
        BRA     PRFN2		OTHERWISE :
PRBRKT  LDAA    0,X		IF CHAR AT PTR IS
        CMPA    #'('		  AN OPENING BRACKET THEN :
        BNE     PRCON
        INX			  MOVE LINE PTR PAST BRACKET
        JSR     SKPSPC		  MOVE PTR TO NEXT NONSPACE
        STX     XTEMP1		  STORE LINE PTR
        JSR     PRCEXP		  PROCESS EXPRSN (RECURSION!)
        LDX     XTEMP1		  RETRIEVE LINE POINTER
        LDAA    0,X
        CMPA    #')'		ENSURE NEXT CHAR IS A
        BEQ     PRFN1		  CLOSING BRACKET - IF NOT :
        LDX     #EXPERR		    ERROR IN EXPRESSION
        JMP     ERROR		OTHERWISE (NOT OPEN BRACKET):
PRCON   JSR     ASCHEX		  MUST BE A CONSTANT SO
        BRA     PRFN2		  PROCESS CONSTANT AND RETURN

*	PERFORM UNARY OPERATION
*	-----------------------
*
*    THIS ROUTINE PERFORMS THE UNARY OPERATION
* DEFINED IN UNOPTR ON THE OPERAND FOUND IN RESULT.
*
* I/P :
*   RESULT = OPERAND FOR UNARY OPERATION
*
* O/P :
*   OPRND1 = ANSWER AFTER UNARY OPERATION
*

PFUNOP  STX     XTEMP1		STORE LINE POINTER
        LDX     USRSP		GET STACK POINTER
        LDAA    1,X		GET UNARY OPERATOR
        INX			  FROM USER STACK
        INX			  AND DECREMENT USER
        INX			  STACK POINTER
        STX     USRSP		STORE STACK POINTER
        CMPA    #'+'		IF UNARY OPERATOR = + THEN
        BNE     PFNEG
PFUNO1  LDX     RESULT		  GET RESULT AND
        STX     OPRND1		  STORE IN OPRND1
        LDX     XTEMP1		  RETRIEVE LINE PTR AND
        RTS			  RETURN
PFNEG   CMPA    #'-'		IF UNARY OPERATOR = - THEN
        BNE     PFNOT
        LDX     #RESULT
        JSR     NEGATE		  NEGATE OPERAND AND
        BRA     PFUNO1		  RETURN
PFNOT   JSR     NOT		IF UNARY OP = NOT THEN
        BRA     PFUNO1		  PERFORM NOT AND RETURN

*
*	PERFORM BINARY OPERATION
*	------------------------
*
*    THIS ROUTINE PERFORMS THE BINARY OPERATION
* FOUND IN THE LAST ELEMENT OF THE USERS STACK ON
* TWO OPERANDS, ONE OF WHICH WAS ALSO IN THE LAST
* ELEMENT OF THE USERS STACK, AND THE OTHER IS
* CONTAINED IN RESULT.
*
* I/P :
*   OPRND1 = ONE OPERAND FOR BINARY OPERATOR
*
* O/P :
*   RESULT = ANSWER AFTER BINARY OPERATION
*

PFBIOP  STX     XTEMP1		STORE LINE POINTER
        LDX     USRSP		RETRIEVE STACK POINTER
        LDX     2,X		GET SECOND OPERAND AND
        STX     RESULT		  STORE IN RESULT
        LDX     USRSP
        LDAB    1,X		GET BINARY OPERATOR
        INX
        INX			DECREMENT STACK POINTER
        INX
        STX     USRSP		STORE STACK POINTER
        LDX     XTEMP1		RETRIEVE LINE POINTER
        CMPB    #'+'		IF BINARY OPERATOR = +
        BNE     PFSUBT		  THEN
        JSR     ADD		  PERFORM ADDITION
        RTS			OTHERWISE
PFSUBT  CMPB    #'-'		IF BINARY OPERATOR = -
        BNE     PFMULT		  THEN
        JSR     SUBT		  PERFORM SUBTRACTION
        RTS			OTHERWISE
PFMULT  CMPB    #'*'		IF BINARY OPERATOR = *
        BNE     PFDIV		  THEN
        JSR     MULT		  PERFORM MULTIPLICATION
        RTS			OTHERWISE
PFDIV   CMPB    #'/'		IF BINARY OPERATOR = /
        BNE     PFAND		  THEN
        JSR     DIVIDE		  PERFORM DIVISION
        RTS			OTHERWISE
PFAND   CMPB    #'&'		IF BINARY OPERATOR = AND
        BNE     PFOR		  THEN
        JSR     AND		  PERFORM LOGICAL AND
        RTS			OTHERWISE
PFOR    CMPB    #'#'		IF BINARY OPERATOR = OR
        BNE     PFEQL		  THEN
        JSR     OR		  PERFORM LOGICAL OR
        RTS			OTHERWISE
PFEQL   CMPB    #'='		IF BINARY OPERATOR = =
        BNE     PFLT		  THEN
        JSR     EQUALS		  PERFORM EQUALS RELATION
        RTS			OTHERWISE
PFLT    CMPB    #'<'		IF BINARY OPERATOR = <
        BNE     PFGT		  THEN
        JSR     LT		  PERFORM LESS THAN RELATION
        RTS			OTHERWISE
PFGT    JSR     GT		  PERFORM GREATER THAN RELN
        RTS

*
*	PROCESS BINARY OPERATOR
*	-----------------------
*
*    THIS ROUTINE DETERMINES WHAT BINARY OPERATOR
* EXISTS AT THE CURRENT LINE POINTER POSITION AND
* SETS UP THIS BINARY OPERATOR IN THE USERS STACK
* ALONG WITH AN OPERAND FOR IT: THE RESULT OF THE
* EXPRESSION UP TO THE CURRENT POSITION OF THE LINE
* POINTER. THE LINE POINTER IS MOVED PAST THE
* OPERATOR TO THE NEXT OPERAND.
*
* I/P :
*   IX = POINTER TO BINARY OPERATOR
*   RESULT = RESULT OF EXPRESSION UP TO CURRENT
*            LINE POINTER POSITION
*
* O/P :
*   IX = POINTER TO OPERAND FOLLOWING THE BINARY
*        OPERATOR

PRBIOP  STX     XTEMP1		STORE LINE PTR
        JSR     CHKSTK		ENSURE NO STACK OVERFLOW
        LDX     USRSP		RETRIEVE STACK POINTER
        LDAA    RESULT+1	GET LS BYTE OF RESULT
        STAA    0,X		  AND STORE IN USER STACK
        DEX
        LDAA    RESULT		GET MS BYTE OF RESULT
        STAA    0,X		  AND STORE IN USER STACK
        DEX
        DEX			INCREMENT STACK POINTER
        STX     USRSP		STORE STACK POINTER
        LDX     XTEMP1		RETRIEVE LINE POINTER
        LDAA    0,X		GET BINARY OPERATOR CHAR
        CMPA    #'+'		IF CHAR IS "+" THEN
        BEQ     PRBIO1		STORE BINARY OPERATOR
        CMPA    #'-'		IF CHAR IS "-" THEN
        BEQ     PRBIO1		STORE BINARY OPERATOR
        CMPA    #'*'		IF CHAR IS "*" THEN
        BEQ     PRBIO1		STORE BINARY OPERATOR
        CMPA    #'/'		IF CHAR IS "/" THEN
        BEQ     PRBIO1		STORE BINARY OPERATOR
        CMPA    #'A'		IF NEXT 3 CHARS
        BNE     PRBIO2
        LDAA    1,X
        CMPA    #'N'
        BNE     PRBIO4		ARE "AND" THEN :
        LDAA    2,X
        CMPA    #'D'
        BNE     PRBIO4
        INX			INCREMENT LINE PTR TWICE
        INX
        STX     XTEMP1		STORE LINE POINTER
        LDAA    #'&'		GET OPERATOR FLAG FOR "AND"
PRBIO1  LDX     USRSP		RETRIEVE USER STACK PTR
        STAA    1,X		STORE OPERATOR IN USER STACK
        LDX     XTEMP1		RETRIEVE LINE POINTER
        INX			MOVE LINE PTR PAST OPERATOR
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        RTS			  AND RETURN
PRBIO2  CMPA    #'O'		IF NEXT 2 CHARS
        BNE     PRBIO3
        LDAA    1,X		ARE "OR" THEN :
        CMPA    #'R'
        BNE     PRBIO4
        INX			INCREMENT LINE POINTER
        STX     XTEMP1		STORE LINE POINTER
        LDAA    #'#'		GET OPERATOR FLAG FOR "OR"
        BRA     PRBIO1		  AND STORE BINARY OPERATOR
PRBIO3  CMPA    #'='		IF CHAR IS "=" THEN
        BEQ     PRBIO1		  STORE BINARY OPERATOR
        CMPA    #'<'		IF CHAR IS "<" THEN
        BEQ     PRBIO1		  STORE BINARY OPERATOR
        CMPA    #'>'		IF CHAR IS ">" THEN
        BEQ     PRBIO1		  STORE BINARY OPERATOR
PRBIO4  JMP     SYNERR		OTHERWISE SYNTAX ERROR

*
*	NEGATE
*	------
*
*     THIS ROUTINE NEGATES A 2 BYTE, 2'S COMPLEMENT
* HEXADECIMAL NUMBER.
* I.E. NUMB := - NUMB
*
* I/P :
*   IX = POINTER TO NUMBER TO BE NEGATED
*

NEGATE  LDAA    #$80		TEST IF NUMBER
        CMPA    0,X
        BNE     NEGAT1		TRYING TO NEGATE IS
        TST     1,X
        BNE     NEGAT1		-32768 IF SO THEN
        LDX     #ARITOV		  SETUP FOR ARITH OVERFLOW AND
        JMP     ERROR		  DISPLAY ERROR MESSAGE ELSE
NEGAT1  COM     0,X		COMPLEMENT ENTIRE
        LDAA    1,X		  NUMBER THEN
        COMA
        ADDA    #$01		  ADD 1 TO LOWER ORDER BYTE
        STAA    $01,X
        BCC     NEGAT2		IF CARRY GENERATED THEN
        INC     0,X		  ADD 1 TO HIGHER ORDER BYTE
NEGAT2  RTS

*
*	ADD
*	---
*
*    THIS ROUTINE PERFORMS THE ADDITION OF TWO 2
* BYTE, 2'S COMPLEMENT HEXADECIMAL NUMBERS, NAMELY
* RESULT AND OPRND1, AND PUTS THE ANSWER IN RESULT.
* I.E. RESULT := RESULT + OPRND1
*
* I/P :
*   RESULT = NUMBER TO BE ADDED TO
*   OPRND1 = NUMBER TO ADD
*
* O/P :
*   RESULT = RESULT OF ADDITION
*

ADD     LDAA    RESULT+1	ADD LOWER ORDER
        ADDA    OPRND1+1	  BYTES TOGETHER
        STAA    RESULT+1	STORE BACK IN RESULT
        LDAA    RESULT		ADD HIGHER ORDER BYTES
        ADCA    OPRND1		INCLUDING ANY CARRY FROM
        BVC     ADD1		  PREVIOUS ADDITION
        LDX     #ARITOV		IF ARITHMETIC OVERFLOW THEN
        JMP     ERROR		  DISPLAY ERROR MESSAGE
ADD1    STAA    RESULT		ELSE STORE BACK IN RESULT
        RTS

*
*	SUBTRACT
*	--------
*
*    THIS ROUTINE PERFORMS THE SUBTRACTION OF TWO
* 2 BYTE, 2'S COMPLEMENT HEXADECIMAL NUMBERS, NAMELY
* RESULT AND OPRND1, AND PUTS THE ANSWER IN RESULT.
* I.E. RESULT := RESULT - OPRND1
*
* I/P :
*   RESULT = NUMBER TO BE SUBTRACTED FROM
*   OPRND1 = NUMBER TO SUBTRACT
*
* O/P :
*   RESULT = RESULT OF SUBTRACTION
*

SUBT    STX     XTEMP0		SAVE IX
        LDX     #OPRND1
        BSR     NEGATE		NEGATE OPERAND 1
        BSR     ADD		ADD OPERAND 1 TO RESULT
        LDX     #OPRND1
        BSR     NEGATE		NEGATE OPERAND 1 BACK AGAIN
        LDX     XTEMP0		RESTORE IX
        RTS

*
*	MULTIPLY
*	--------
*
*    THIS ROUTINE PERFORMS THE MULTIPLICATION OF TWO
* 2 BYTE, 2'S COMPLEMENT HEXADECIMAL NUMBERS, NAMELY
* RESULT AND OPRND1, AND PUTS THE ANSWER IN RESULT.
* I.E. RESULT := RESULT * OPRND1
*
* I/P :
*   RESULT = NUMBER TO BE MULTIPLIED
*   OPRND1 = NUMBER TO MULTIPLY BY
*
* O/P :
* RESULT = RESULT OF MULTIPLICATION
*

MULT    STX     XTEMP0		SAVE IX
        CLR     SIGN		ASSUME OPERAND 1 IS POSITIVE
        LDAA    OPRND1		IF OPERAND 1 IS NEGATIVE
        ANDA    #NEGMSK
        BEQ     MULT1		THEN CHANGE SIGN TO
        COM     SIGN
        LDX     #OPRND1		  INDICATE THIS AND
        BSR     NEGATE		  MAKE OPERAND 1 POSITIVE
MULT1   LDX     OPRND1		GET NO. OF REPEATED ADDS
        LDAA    RESULT		SET UP OPERAND 1
        STAA    OPRND1
        LDAA    RESULT+1	EQUAL TO RESULT
        STAA    OPRND1+1
        CLR     RESULT		INITIALISE RESULT
        CLR     RESULT+1	  TO ZERO
        CPX     #$0000		IF NO REPEATED ADDITIONS
        BEQ     MULT3		  THEN FINISHED
MULT2   BSR     ADD		OTHERWISE ADD ONCE
        DEX			DECREMENT NO OF REPEATED
        BNE     MULT2		  ADDS AND REPEAT
MULT3   TST     SIGN		IF OPERAND 1 WAS ORIGINALLY
        BEQ     MULT4		  NEGATIVE THEN
        LDX     #RESULT
        JSR     NEGATE		  NEGATE RESULT
MULT4   LDX     XTEMP0		RESTORE IX
        RTS

*	DIVIDE
*	------
*
*    THIS ROUTINE PERFORMS THE DIVISION OF TWO 2
* BYTE, 2'S COMPLEMENT HEXADECIMAL NUMBERS, NAMELY
* RESULT AND OPRND1, AND PUTS THE ANSWER IN RESULT.
* I.E. RESULT := RESULT DIV OPRND1
*
* I/P :
*   RESULT = DIVIDEND
*   OPRND1 = DIVISOR
*
* O/P
*   RESULT = RESULT OF DIVISION
*   OPRND1 = REMAINDER FROM DIVISION
*

DIVIDE  STX     XTEMP4		SAVE IX
        LDX     OPRND1		IF DIVISOR IS ZERO THEN
        BNE     DIVID1		  DIVIDE BY ERROR SO SET
        LDX     #DIVZER		  UP ERROR CODE AND
        JMP     ERROR		  DISPLAY ERROR MESSAGE
DIVID1  CLR     SIGN		ASSUME SIGN IS POSITIVE
        LDAA    RESULT		IF SIGN OF RESULT OPERAND
        ANDA    #NEGMSK		  IS NEGATIVE THEN
        BEQ     DIVID2
        COM     SIGN		  COMPLEMENT SIGN
        LDX     #RESULT
        JSR     NEGATE		  AND NEGATE RESULT OPERAND
DIVID2  LDAA    OPRND1		IF SIGN OF OPERAND1
        ANDA    #NEGMSK		  IS NEGATIVE THEN
        BEQ     DIVID3
        COM     SIGN		  COMPLEMENT SIGN
        LDX     #OPRND1
        JSR     NEGATE		(#$ffff is #-1 in original)
DIVID3  LDX     #$FFFF		INITIALISE ANSWER = -1
DIVID4  JSR     SUBT		SUBTRACT OPRND1 FROM RESULT
        INX			SET ANSWER UP BY 1
        LDAA    RESULT		IF RESULT OF SUBTRACTION IS
        ANDA    #NEGMSK		  STILL > ZERO THEN CONTINUE
        BEQ     DIVID4		  SUBRACTING OTHERWISE FINISH
        JSR     ADD		CALCULATE REMAINDER
        LDAA    RESULT		STORE REMAINDER
        STAA    OPRND1
        LDAA    RESULT+1	  INTO OPERAND 1
        STAA    OPRND1+1
        STX     RESULT		STORE ANSWER IN RESULT
        TST     SIGN		IF SIGN OF ANSWER
        BEQ     DIVID5		  IS NEGATIVE THEN
        LDX     #RESULT
        JSR     NEGATE		  NEGATE RESULT
        LDX     #OPRND1
        JSR     NEGATE		  AND NEGATE REMAINDER
DIVID5  LDX     XTEMP4		RESTORE IX
        RTS

*
*	AND
*	---
*
*    THIS ROUTINE PERFORMS THE BOOLEAN 'AND' ON TWO
* NUMBERS, NAMELY RESULT AND OPRND1 ACCORDING TO THE
* FOLLOWING TABLE :
*
*   RESULT    | OPRND1    | RESULT AND OPRND1
*   ----------+-----------+------------------
*   0000      | 0000      | 0000
*   0000      | OTHERWISE | 0000
*   OTHERWISE | 0000      | 0000
*   OTHERWISE | OTHERWISE | 0001
*
* I/P :
*   RESULT = FIRST NUMBER
*          = 0000 IF FALSE
*          = OTHERWISE IF TRUE
*   OPRND1 = SECOND NUMBER
*          = 0000 IF FALSE
*          = OTHERWISE IF TRUE
*
* O/P :
*   RESULT = BOOLEAN ANSWER
*          = 0000 IF FALSE
*          = 0001 IF TRUE
*

AND     BSR     COMPAR		GET RESULT
        CPX     #$0000		COMPARE WITH "FALSE"
        BEQ     EQUAL2		IF FALSE THEN LEAVE (this is original)
Z3501   LDX     OPRND1		GET OPRND1        (mod code has 27 00)
        BEQ     EQUAL2		IF FALSE THEN LEAVE ELSE
        BRA     EQUAL1		BOTH TRUE SO ANSWER = TRUE

*
*	OR
*	--
*
*    THIS ROUTINE PERFORMS THE BOOLEAN 'OR' ON TWO
* NUMBERS, NAMELY RESULT AND OPRND1 ACCORDING TO THE
* FOLLOWING TABLE :
*
*   RESULT    | OPRND1    | RESULT AND OPRND1
*   ----------+-----------+------------------
*   0000      | 0000      | 0000
*   0000      | OTHERWISE | 0001
*   OTHERWISE | 0000      | 0001
*   OTHERWISE | OTHERWISE | 0001
*
* I/P :
*   RESULT = FIRST NUMBER
*          = 0000 IF FALSE
*          = OTHERWISE IF TRUE
*   OPRND1 = SECOND NUMBER
*          = 0000 IF FALSE
*          = OTHERWISE IF TRUE
*
* O/P :
*   RESULT = BOOLEAN ANSWER
*          = 0000 IF FALSE
*          = 0001 IF TRUE
*

OR      BSR     COMPAR		GET RESULT
        CPX     #$0000		COMPARE WITH "FALSE"
        BNE     EQUAL1		IF TRUE THEN ANSWER = TRUE
        LDX     OPRND1		GET OPRND1
        BNE     EQUAL1		IF TRUE THEN ANSWER = TRUE
        BRA     EQUAL2		ELSE BOTH FALSE SO LEAVE

*
*	NOT
*	---
*
*    THIS ROUTINE PERFORMS THE BOOLEAN COMPLEMENT ON
* A SINGLE NUMBER, NAMELY RESULT, ACCORDING TO THE
* FOLLOWING TABLE :
*
*   RESULT    | NOT RESULT
*   ----------+-----------
*   0000      | 0001
*   OTHERWISE | 0000
*
* I/P :
*   RESULT = NUMBER TO BE COMPLEMENTED
*          = 0000 IF FALSE
*          = OTHERWISE IF TRUE
*
* O/P :
*   RESULT = COMPLEMENTED ANSWER
*          = 0000 IF FALSE
*          = 0001 IF TRUE
*

NOT     BSR     COMPAR		GET RESULT
        CPX     #$0000		COMPARE WITH "FALSE"
        BNE     EQUAL2		IF TRUE THEN MAKE FALSE
        BEQ     EQUAL1		IF FALSE THEN MAKE TRUE

*
*	EQUALS
*	------
*
*    THIS ROUTINE COMPARES TWO NUMBERS, NAMELY THE
* RESULT AND OPRND1 AND DEThRMINES WHETHER THEY ARE
* EQUAL OR NOT.
* I.E. COMPARE:  RESULT = OPRND1
*
* I/P :
*   RESULT = FIRST NUMBER
*   OPRND1 = SECOND NUMBER
*
* O/P :
*   RESULT = INDICATOR WHETHER NUMBERS ARE EQUAL OR
*            NOT
*            = 0000 IF FIRST NUMBER NOT = SECOND NUM
*            = 0001 IF FIRST NUMBER = SECOND NUMBER
*

EQUALS  BSR     COMPAR		COMPARE TWO NUMBERS
        BNE     EQUAL2		IF NUMBERS ARE SAME
EQUAL1  INC     RESULT+1		  SET RELATION TO BE TRUE
EQUAL2  LDX     XTEMP0		RESTORE IX
        RTS

*
*	LESS THAN
*	---------
*
*    THIS ROUTINE COMPARES TWO NUMBERS, NAMELY
* RESULT AND OPRND1 AND DETERMINES WHETHER RESULT
* IS LESS THAN OPRND1 OR NOT.
* I.E. COMPARE: RESULT < OPRND1
*
* I/P :
*   RESULT = FIRST NUMBER
*   OPRND1 = SECOND NUMBER
*
* O/P :
*   RESULT = INDICATOR WHETHER FIRST NUMBER IS LESS
*            THAN SECOND NUMBER OR NOT
*          = 0000 IF FIRST NUMBER NOT < SECOND NUM
*          = 0001 IF FIRST NUMBER < SECOND NUMBER
*

LT      BSR     COMPAR		COMPARE TWO NUMBERS
        BGE     EQUAL2		IF FIRST < SECOND THEN
        BRA     EQUAL1		SET RELATION TO BE TRUE

*
*	GREATER THAN
*	------------
*
*    THIS ROUTINE COMPARES TWO NUMBERS, NAMELY
* RESULT AND OPRND1 AND DETERMINES WHETHER RESULT
* IS GREATER THAN OPRND1 OR NOT.
* I.E. COMPARE: RESULT > OPRND1
*
* I/P :
*   RESULT = FIRST NUMBER
*   OPRND1 = SECOND NUMBER
*
* O/P :
*   RESULT = INDICATOR WHETHER FIRST NUMBER IS
*            GREATER THAN SECOND NUMBER OR NOT
*          = 0000 IF FIRST NUMBER NOT > SECOND NUM
*          = 0001 IF FIRST NUMBER > SECOND NUMBER
*

GT      BSR     COMPAR		COMPARE TWO NUMBERS
        BLE     EQUAL2		IF FIRST > SECOND THEN
        BRA     EQUAL1		SET RELATION TO BE TRUE

*	
*	COMPARE
*	-------
*
*    THIS ROUTINE COMPARES TWO NUMBERS IN
* PREPARATION FOR A RELATIONAL OPERATION.
*
* I/P :
*   RESULT = FIRST NUMBER TO BE COMPARED
*   OPRND1 = SECOND NUMBER TO BE COMPARED
*
* O/P :
*   RESULT = INDICATOR INITIALISED TO FALSE
*            RELATION EXPRESSION   I.E.:
*          = 0000
*

COMPAR  STX     XTEMP0		SAVE IX
        LDX     RESULT		READ RESULT INTO IX
        CLR     RESULT		SET RELATION TO BE
        CLR     RESULT+1	  FALSE INITIALLY
        CPX     OPRND1
        BNE     COMPA1		EMULATE "CPX OPRND1"
        RTS
COMPA1  STX     TEMP		TO MAKE COMPARISON
        LDAA    TEMP+1
        SUBA    OPRND1+1	(SEE DUDCPX ROUTINE FOR
        LDAB    TEMP
        SBCB    OPRND1		REASON AND DETAILS)
        JMP     DUDCP1

*
*	PEEK
*	----
*
*    THIS ROUTINE DETERMINES THE MEMORY BYTE STORED
* AT THE ADDRESS SPECIFIED AS THE ONLY PARAMETER OF
* THE PEEK FUNCTION, AND RETURNS THIS BYTE IN
* DECIMAL NOTATION.
*
* I/P :
*   XTEMP1 = POINTER TO FIRST CHAR AFTER KEYWORD
*
* O/P :
*   RESULT = VALUE OF BYTE AT SPECIFIED ADDRESS
*   XTEMP1 = POINTER TO CLOSING BRACKET OF FUNCTION
*

PEEK    LDX     XTEMP1		RETRIEVE LINE POINTER
        INX			MOVE LINE PTR PAST KEYWORD
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        LDAA    #'('		IF NEXT CHAR IS
        CMPA    0,X
        BEQ     PEEK1		  NOT AN OPEN BRACKET: "("
        JSR     SYNERR		  THEN SYNTAX ERROR OTHERWISE
PEEK1   INX			MOVE PTR PAST BRACKET
        JSR     SKPSPC		MOVE PTR TO NEXT NONSPACE
        STX     XTEMP1		STORE LINE PTR
        JSR     PRCEXP		PROCESS EXPRSN (RECURSION!)
        LDX     RESULT		GET ADDRESS OF BYTE
        LDAA    0,X		GET VALUE OF BYTE
        CLR     RESULT
        STAA    RESULT+1	  AND STORE IT IN "RESULT"
        RTS

*
*	FIND LINE IN USER PROGRAM
*	-------------------------
*
*    THIS ROUTINE ATTEMPTS TO FIND A LINE WITHIN THE
* USER'S PROGRAM SPECIFIED BY A LINE NUMBER. IF THE
* LINE DOES NOT EXIST THE SEARCH POINTER IS
* POSITIONED TO WHERE THE LINE SHOULD BE, AND A FLAG
* IS SET TO INDICATE THAT THE LINE WAS NOT FOUND.
*
* I/P :
*   MSPART = MS BYTE OF BCD LINE NO. LOOKING FOR
*   LSPART = LS BYTE OF BCD LINE NO. LOOKING FOR
*
* O/P :
*   IX = POINTER TO LINE LOOKING FOR (IF FOUND)
*      = POINTER TO WHERE LINE SHOULD BE (IF NOT)
*   ACCB = INDICATOR IF LINE FOUND
*        = 00   IF FOUND
*        = FF   IF NOT FOUND
*   FNDPTR = SAME AS IX EXCEPT STORED
*

FINDLN  CLRB
        TST     LINENO		ANTICIPATE LINE WILL BE FOUND
        BNE     FINDL1		IF IN EDITOR/IMMEDIATE MODE
        TST     LINENO		  THEN GO AND INITIALISE
        BEQ     FINDL2		FIND POINTER AT START
FINDL1  LDAA    MSPART		  OF USER PROGRAM
        CMPA    LINENO		IF IN RUN MODE THEN
        BHI     FINDL3		  GO AND INITIALIZE FIND
        BNE     FINDL2		  POINTER AT THE NEXT LINE ONLY
        LDAA    LSPART		  IF LINE LOOKING FOR IS
        CMPA    LINENO+1	  GREATER THAN CURRENT ONE
        BHI     FINDL3		OTHERWISE GO AND INITIALIZE
FINDL2  LDX     #PROGST		  FIND POINTER AT PROG START
        BRA     FINDL4
FINDL3  LDX     RUNPTR		SET FIND PTR AT NEXT LINE
FINDL4  CPX     PROGEN		IF END OF USERS PROGRAM
        BEQ     NOTFND		  THEN LINE NOT FOUND
        LDAA    MSPART		COMPARE LINE NO. LOOKING FOR
        CMPA    0,X		  WITH LINE NO. AT FIND PTR
        BHI     SEARCH		IF THEY ARE THE SAME
        BNE     NOTFND		  THEN LINE FOUND, IF
        LDAA    LSPART		  LINE NO. AT FIND PTR IS LESS
        CMPA    1,X		  THEN CONTINUE SEARCH, IF LINE
        BHI     SEARCH		  NO. AT FIND POINTER IS MORE
        BEQ     FOUND		  THEN LINE NOT FOUND
NOTFND  COMB			LINE NOT FOUND: SET FLAG
FOUND   STX     FNDPTR		LINE FOUND: STORE FIND PTR
        RTS			  AND EXIT
SEARCH  LDAB    2,X		CONTINUE SEARCHING:
        JSR     IXADD		MOVE FIND POINTER TO
        CLRB			  BEGINNING OF NEXT LINE
        BRA     FINDL4		COMPARE LINE NO.S AGAIN

*
*	GET VARIABLE
*	------------
*
*    THIS ROUTINE GETS THE VARIABLE SPECIFIED IN
* VARNAM AND PLACES IT IN VAR READY FOR THE GET
* VARIABLE VALUE ROUTINE.
*
* I/P :
*   VARNAM = VARIABLE NAME
*
* O/P :
*   VAR = SAME VARIABLE NAME
*

GETVAR  LDAB    VARNAM		GET VARIABLE NAME AND
        STAB    VAR		STORE IT IN VAR

*
*	GET VARIABLE VALUE
*	------------------
*
*    THIS ROUTINE RETURNS THE CURRENT VALUE FOR THE
* VARIABLE SPECIFIED IN VAR.
*
* I/P :
*   VAR =VARIABLE WHOSE VALUE IS REQUIRED
*
* O/P :
*   IX = VALUE OF VARIABLE: VAR
*

GETVAL  BSR     GETVA1		GET VARIABLE ADDRESS
        LDX     0,X		GET VARIABLE VALUE
        RTS
GETVA1  LDAB    VAR		CALCULATE OFFSET FOR
        SUBB    #'A'		  VARIABLE NAME FROM
        ASLB			  BASE ADDRESS OF
        LDX     #VARBEG		  VARIABLE AREA
        JSR     IXADD		ADD OFFSET TO BASE ADDR
        RTS

*
*	CONVERT NUMBER TO BCD
*	---------------------
*
*    THIS ROUTINE CONVERTS A LINE NUMBER OF MAXIMUM
* LENGTH = 4 BYTES TO A 2 BYTE PACKED BCD FORMAT.
* THE LINE NUMBER IS ASSUMED TO HAVE ENDED ON
* ENCOUNTERING A NON DIGIT OR AFTER 4 BYTES HAVE
* BEEN READ.
*
* I/P :
*   IX = PTR TO START OF LINE NO. TO BE CONVERTED
*
* O/P :
*   IX = POINTER TO FIRST CHAR AFTER LINE NUMBER
*   MSPART = MS BYTE OF BCD LINE NUMBER
*   LSPART = LS BYTE OF BCD LINE NUMBER
*

NUMBCD  CLR     MSPART		INITIALIZE LINE NUM = 0000
        CLR     LSPART
        LDAA    #4		SET UP COUNT OF CHARS TO READ
        STAA    COUNT
NUMBC1  JSR     CLASS		CLASSIFY CURRENT CHAR
        CMPB    #$01		IF CHAR IS NOT A DIGIT
        BNE     ENDNUM		  THEN END READING NO., SO EXIT
        LDAA    #4		OTHERWISE
NUMBC2  ASL     LSPART		  MULTIPLY LINE NUMBER
        ROL     MSPART
        DECA			  BY 10
        BNE     NUMBC2
        LDAA    0,X		GET CURRENT CHARACTER
        ANDA    #LSMASK		REMOVE UPPER HALF OF BYTE
        ORAA    LSPART		  AND ADD RESULT TO THE
        STAA    LSPART		  LINE NUMBER AT THIS STAGE
        INX			MOVE POINTER TO NEXT CHAR
        DEC     COUNT		DEC COUNT OF CHARS TO BE READ
        BNE     NUMBC1		IF MORE TO READ GO READ NEXT
ENDNUM  RTS			OTHERWISE EXIT

*
*	CONVERT BCD TO NUMBER
*	---------------------
*
*    THIS ROUTINE CONVERTS A 2 BYTE PACKED BCD LINE
* NUMBER BACK TO A 4 BYTE NUMERIC FORMAT.
*
* I/P :
*   IX = POINTER TO BCD LINE NUMBER
*
* O/P :
*   ERRLIN = 4 BYTE ASCII CONVERSION OF LINE NO.
*

BCDNUM  STX     XTEMP0		STORE ADDR OF BCD LINE. NO.
        LDX     #ERRLIN		SET UP ADDR OF CONVERTED
        STX     XTEMP1		  NUMBER
        CLR     FLAG		SET UP FLAG
BCDNU1  LDX     XTEMP0		RETRIEVE ADDR OF BCD LINE NO.
        LDAA    0,X		TAKE BYTE FROM
        ANDA    #MSMASK
        LSRA			  BCD LINE NUMBER AND
        LSRA
        LSRA			  CALCULATE MS DIGIT
        LSRA
        ORAA    #$30		  FROM IT
        LDAB    0,X		TAKE BYTE FROM BCD LINE
        ANDB    #LSMASK		  NUMBER AND CALCULATE
        ORAB    #$30		  LS DIGIT FROM IT
        INX			BUMP POINTER TO NEXT BYTE
        STX     XTEMP0		  AND STORE POINTER
        LDX     XTEMP1		RETRIEVE DESTINATION ADDR
        STAA    0,X		WRITE MS DIGIT TO DESTINATION
        STAB    1,X		WRITE LS DIGIT TO DESTINATION
        INX			BUMP POINTER TO NEXT
        INX			  LOCATIONS IN DESTINATION
        STX     XTEMP1		STORE DESTINATION POINTER
        COM     FLAG		INVERT FLAG AND
        BNE     BCDNU1		  REPEAT ONCE MORE,
        RTS			THEN EXIT

*
*	CONVERT HEX NUMBER TO ASCII
*	---------------------------
*
*    THIS ROUTINE CONVERTS A 2'S COMPLEMENT HEX
* NUMBER TO A 5 DIGIT (5 BYTE) ASCII EQUIVALENT,
* WITH THE SIGN INDICATED SEPARATELY IN A FLAG.
*
* I/P :
*   RESULT = HEX NUMBER TO BE CONVERTED
*
* O/P
*   NUMBER = 5 DIGIT ASCII CONVERSION
*   SIGN = SIGN OF ASCII CONVERSION
*	 = 00	IF POSITIVE
*	 = FF	IF NEGATIVE
*

HEXASC  CLR     SIGN		SET SIGN = POSITIVE NO.
        LDX     RESULT		IF NUMBER TO BE
        CPX     #$8000
        BNE     HEXAS1		  CONVERTED IS -32768
        COM     SIGN
        LDX     #$3332		  THEN SPECIAL CASE :
        STX     NUMBER
	LDX	#$3736		    MAKE SIGN NEGATIVE AND
        STX     NUMBER+2
        LDAA    #$38		    SET UP DIGITS IN NUMBER
        STAA    NUMBER+4
        RTS
HEXAS1  LDAA    RESULT		LOOK TO SEE IF
        ANDA    #NEGMSK		  NUMBER IS NEGATIVE
        BEQ     HEXAS2		IF SO THEN
        LDX     #RESULT
        JSR     NEGAT1		  NEGATE NUMBER
        COM     SIGN
HEXAS2  LDX     #NUMBER		SET PTR AT MS DIGIT
        STX     XTEMP3		  OF ASCII NUMBER
        LDX     #DECTBL		SET TBL PTR START DECTBL
HEXAS3  LDAA    0,X		READ DECIMAL NUMBER
        STAA    OPRND1		  AT DECIMAL TABLE
        LDAA    1,X		  POINTER AND SET NUMBER
        STAA    OPRND1+1	  UP IN OPRND1
        LDAB    SIGN		SAVE SIGN
        JSR     DIVIDE		DIVIDE RESULT BY OPRND1
        STAB    SIGN		RESTORE SIGN
        LDAA    RESULT+1	GET SINGLE DIGIT ANSWER
        ORAA    #$30		CONVERT TO ASCII CHAR
        STX     XTEMP0		SAVE DECIMAL TABLE PTR
        LDX     XTEMP3		RETRIEVE ASCII NO. PTR
        STAA    0,X		STORE ASCII DIGIT
        INX			MOVE PTR TO NEXT ASCII DIGIT
        STX     XTEMP3		STORE ASCII NO. PTR
        LDX     OPRND1		GET REMAINDER FROM DIVISION
        STX     RESULT		  AND SET UP IN RESULT
        LDX     XTEMP0		RETRIEVE DECIMAL TABLE PTR
        INX			MOVE DECIMAL TABLE PTR
        INX			  TO NEXT DECIMAL NUMBER
        CPX     #DECTBL+10	IF NOT FINISHED CONVERSION
        BNE     HEXAS3		  THEN REPEAT
        RTS

*
*	CONVERT ASCII NUMBER TO HEX
*	---------------------------
*
*    THIS ROUTINE READS AND CONVERTS AN ASCII SIGNED
* INTEGER TO ITS 2 BYTE, 2'S COMPLEMENT HEX
* EQUIVALENT. THE ASCII NUMBER MAY INCLUDE AN
* OPTIONAL SIGN (+ OR -).
*
* I/P :
*   IX = PTR TO START OF NUMBER TO BE CONVERTED
*   FLAG = INDICATOR WHERE THIS ROUTINE CALLED FROM
*        = FF 	IF CALLED FROM INPUT
*	 = 00 	OTHERWISE
*
* O/P :
*   IX = PTR TO FIRST CHAR AFTER NUMBER CONVERTED
*   RESULT = 2 BYTE HEX CONVERSION
*

ASCHEX  CLR     SIGN		SET SIGN = POSITIVE NO.
        LDAA    0,X		IF FIRST CHAR IS
        CMPA    #'-'		  A "-" THEN
        BNE     ASCHX1
        COM     SIGN		  SET SIGN = NEGATIVE NO.
        BRA     ASCHX2
ASCHX1  CMPA    #'+'		IF FIRST CHAR IS
        BNE     ASCHX3		  A SIGN CHAR THEN
ASCHX2  INX			  MOVE POINTER PAST SIGN
        JSR     SKPSPC		  SKIP TO NEXT NONSPACE
ASCHX3  JSR     CLASS		IF NEXT CHAR
        CMPB    #$01		  NOT NUMERIC THEN :
        BEQ     ASCHX5
        TST     FLAG
        BEQ     ASCHX4		BAD INPUT ERROR IF
        PULA			  ASCHEX CALLED FROM INPUT
        PULA			  SO UNSTACK LAST RETURN ADDR
        JMP     BADINP		  AND DISPLAY MESSAGE, ELSE
ASCHX4  JMP     SYNERR		DISPLAY SYNTAX ERROR MESSAGE
ASCHX5  CLR     RESULT		SET HEX NO. TO
        CLR     RESULT+1	  ZERO INITIALLY
ASCHX6  CLR     OPRND1
        LDAA    0,X		GET A DIGIT
        ANDA    #LSMASK		REMOVE MS PART OF BYTE
        STAA    OPRND1+1	SET UP OPERAND 1 FROM DIGIT
        BSR     ADDOP		  ADD OPERAND 1 TO RESULT
        INX			MOVE POINTER TO NEXT CHAR
        JSR     CLASS		IF NEXT CHAR IS
        CMPB    #$01		  ANOTHER NUMERIC THEN
        BNE     ASCHX8
        LDAA    RESULT
        STAA    OPRND1		  MULTIPLY RESULT
        LDAA    RESULT+1
        STAA    OPRND1+1	  BY 10 USING
        LDAB    #$09
ASCHX7  BSR     ADDOP		  REPEATED ADDITION
        DECB
        BNE     ASCHX7
        BRA     ASCHX6		REPEAT FOR NEXT DIGIT
ASCHX8  TST     SIGN		IF SIGN IS NEGATIVE
        BEQ     ASCHX9
        STX     XTEMP0		  THEN NEGATE RESULT
        LDX     #RESULT
        JSR     NEGAT1		  IN 2'S COMPLEMENT
        LDX     XTEMP0
ASCHX9  RTS			RETURN
ADDOP   LDAA    RESULT+1	ADD LOWER ORDER
        ADDA    OPRND1+1	  BYTES TOGETHER
        STAA    RESULT+1	STORE BACK IN RESULT
        LDAA    RESULT		ADD HIGHER ORDER BYTES
        ADCA    OPRND1		INCLUDING ANY CARRY FROM
        BVC     ADDOP2		  PREVIOUS ADDITION
        CMPA    #$80		IF ARITHMETIC OVERFLOW
        BNE     ADDOP1
        TST     RESULT+1	  THEN DISPLAY ERROR MESSAGE
        BNE     ADDOP1
        TST     SIGN		  BUT ONLY IF RESULT IS NOT
        BNE     ADDOP2
ADDOP1  LDX     #ARITOV		  $8000 WITH NEGATIVE SIGN
        JMP     ERROR		  (I.E. : —32768)
ADDOP2  STAA    RESULT		STORE BACK IN RESULT
        RTS

*
*	CLASSIFY A CHARACTER
*	--------------------
*
*    THIS ROUTINE DETERMINES THE CLASS OF A
* CHARACTER POINTED TO BY THE INDEX REGISTER. THE
* CLASS IS RETURNED IN ACCUMULATOR B.
*
* I/P :
*   IX = POINTER TO CHARACTER TO BE CLASSIFIED
*
* O/P :
*   ACCB = CLASS OF CHARACTER :
*        = 01 FOR CHARACTERS 0...9
*        = 02 FOR CHARACTERS A...Z
*        = 03 FOR OTHER CHARACTERS
*

CLASS   LDAA    0,X		GET CHARACTER
        LDAB    #$01		INITIALIZE CHAR TYPE = DIGIT
        SUBA    #'0'		IS CHAR BETWEEN "0"
        BLT     CLASS1
        SUBA    #10		AND "9" (was #$10 in modded source)
        BLT     CLASS3		IF SO THEN EXIT OTHERWISE
CLASS1  INCB			SET CHAR TYPE = LETTER
        SUBA    #7		IS CHAR TYPE
        BLT     CLASS2		  A LETTER ?
        SUBA    #26
        BLT     CLASS3		IF SO THEN EXIT OTHERWISE
CLASS2  INCB			SET CHAR TYPE = OTHER
CLASS3  RTS

*
*	ADD TO IX
*	---------
*
*    THIS ROUTINE ADDS A SPECIFIED QUANTITY TO THE
* INDEX REGISTER.
*
* I/P :
*   IX = ORIGINAL VALUE OF IX
*   ACCB = AMOUNT TO BE ADDED TO IX
*
* O/P :
*   IX = RESULTING VALUE OF IX
*

IXADD   TSTB			IF ACCB NOT = 00
        BEQ     IXADD1
        INX			  ADD 1 TO IX
        DECB
        BRA     IXADD		REPEAT UNTIL FINISHED
IXADD1  RTS

*
*	SUBTRACT FROM IX
*	----------------
*
*    THIS ROUTINE SUBTRACTS A SPECIFIED QUANTITY
* FROM THE INDEX REGISTER.
*
* I/P :
*   IX = ORIGINAL VALUE OF IX
*   ACCB = AMOUNT TO BE SUBTRACTED FROM IX
*
* O/P :
*   IX = RESULTING VALUE OF IX
*

IXSUB   TSTB			IF ACCB NOT = 00
        BEQ     IXSUB1
        DEX			  SUBTRACT 1 FROM IX
        DECB
        BRA     IXSUB		REPEAT UNTIL FINISHED
IXSUB1  RTS

*
*	FIND SPACE
*	----------
*
*    THIS ROUTINE SEARCHES FOR THE NEXT SPACE
* CHARACTER, STOPPING ITS SEARCH ON REACHING THE END
* OF A LINE  I.E. ON ENCOUNTERING A <CR>. ON ENDING
* THE SEARCH FOR A SPACE THE SKIP SPACE ROUTINE IS
* THEN EXECUTED TO MOVE THE POINTER TO THE NEXT
* NONSPACE CHARACTER.
*
* I/P :
*   IX = ORIGINAL VALUE FOR POINTER
*
* O/P :
*   IX = POINTER TO FIRST SPACE OR <CR> FOUND
*

FNDSPC  LDAA    0,X		READ CHARALaER AT POINTER
        CMPA    #$20		IF CHARALTER IS A SPACE
        BEQ     SKPSPC		  THEN EXIT OTHERWISE
        CMPA    #CR		IF END OF LINE
        BEQ     SKPSPC		  THEN EXIT OTHERWISE
        INX			INCREMENT POINTER TO NEXT
        BRA     FNDSPC		  CHARACTER AND REPEAT

*
*	SKIP SPACES
*	-----------
*
*    THIS ROUTINE SKIPS TO THE FIRST NONSPACE
* CHARACTER ENCOUNTERED IF NOT ALREADY AT A NONSPACE
* CHARACTER.
*
* I/P :
*   IX - ORIGINAL VALUE FOR POINTER
*
* O/P :
*   IX = POINTER TO FIRST NONSPACE FOUND
*   ACCA = FIRST NONSPACE CHARALTER FOUND
*

SKPSPC  LDAA    0,X
        CMPA    #$20		IS CHAR AT IX A SPACE ?
        BNE     SKPSP1
        INX			IF SO SKIP TO NEXT CHAR
        BRA     SKPSPC
SKPSP1  RTS

*
*	CHECK STACK
*	-----------
*
*    THIS ROUTINE CHECKS TO SEE IF ADDING ANOTHER
* ELEMENT (3 BYTES) TO THE USER'S STACK WILL CAUSE
* STACK OVERFLOW - IF SO A STACK OVERFLOW MESSAGE IS
* DISPLAYED.
*

CHKSTK  STX     XTEMP0		SAVE IX
        LDX     USRSP		CHECK THAT STACK POINTER
        CPX     #STKLIM		  IS GREATER THAN THE STACK
        BNE     STAKOK		  LIMIT. IF NOT THEN
        LDX     #STAKOV		    SET UP ERROR MESSAGE
        JMP     ERROR		    AND DISPLAY ERROR MESSAGE
STAKOK  LDX     XTEMP0		OTHERWISE RETRIEVE IX
        RTS			  AND EXIT

*
*	CHECK FOR <CR> #1
*	-----------------
*
*    THIS ROUTINE CHECKS TO SEE IF THE NEXT
* NONSPACE CHARACTER IS A <CR> FOR OPERATING SYSTEM
* COMMANDS - IF NOT CONTROL IS TRANSFERRED TO THE
* "WHAT?" ROUTINE.
*
* I/P :
*   IX = POINTER TO LINE TO BE CHECKED
*

CHKCR1  JSR     SKPSPC		SKIP TO FIRST NONSPACE
        CMPA    #CR		IF THIS CHARACTER IS
        BEQ     CHKCR3		  NOT A <CR> THEN
        JMP     WHAT		  DISPLAY WHAT MESSAGE

*
*	CHECK FOR <CR> #2
*	-----------------
*
*    THIS ROUTINE CHECKS TO SEE IF THE NEXT
* NONSPACE CHARACTER IS A <CR> FOR BASIC KEYWORDS
* - IF NOT CONTROL IS TRANSFERRED TO THE ERROR
* ROUTINE.
*
* I/P
*   IX = POINTER TO LINE TO BE CHECKED
*

CHKCR2  JSR     SKPSPC		SKIP TO FIRST NONSPACE
        CMPA    #CR		IF THIS CHARACTER IS
        BEQ     CHKCR3		  NOT A <CR> THEN
        JMP     SYNERR		  DISPLAY SYNTAX ERROR MESSAGE
CHKCR3  RTS			OTHERWISE EXIT

*
*	<BREAK> INTERRUPT SERVICE ROUTINE
*	---------------------------------
*
*    THIS ROUTINE SETS A BREAK FLAG TO INDICATE THAT
* THE <BREAK> KEY HAS PRESSED BY THE USER.

BRKISR  SEI			DISABLE ANY MORE INTERRUPTS
        COM     BRKFLG		SET <BREAK> FLAG
        CLI			ENABLE INTERRUPTS AGAIN
        RTI			RETURN FROM ISR

*
*	MESSAGES
*	--------
*

*	STARTUP MESSAGE
STRTUP	FCC	'<BASIC>'
	FCB	CR,LF,LF,EOT

*	OPERATING SYSTEM PROMPT
MESG1	FCB	CR,LF
	FCC	'! '
	FCB	EOT

* INPUT PROMPT "?"		(missing in the modded source)
MESG2	EQU	$773A		(points to $3F $04 in DATERM monitor)

* ERROR MESSAGE
MESG3	FCC	' ERROR IN '
	FCB	EOT

* <BREAK>/STOP MESSAGE
MESG4	FCB	CR,LF
	FCC	'STOPPED AT '
	FCB	EOT

* BAD INPUT MESSAGE
MESG5	FCB	CR,LF
	FCC	'BAD INPUT'
	FCB	CR,LF,EOT

* "WHAT?" ERROR MESSAGE		(missing in the modded source, points)
MESG6	EQU	$76CA		(to CR,LF,'WHAT?',4 in DATERM monitor)

*
*	TABLE OF DECIMAL NUMBERS
*	------------------------
*
*    THE NUMBERS IN THIS TABLE EACH FILL 2 BYTES AND
* ARE IN 2'S COMPLEMENT FORM. THEY CONSIST OF THE
* DECIMAL NUMBERS :
*   10000
*    1000
*     100
*      10
*       1
* I.E. EACH NUMBER IS A POWER OF 10. THIS TABLE IS
* USED IN THE ROUTINE "CONVERT HEX NUMBER TO ASCII".
*

DECTBL  FCB	$27,$10		DECIMAL 10000
	FCB	$03,$E8		DECIMAL 1000
	FCB	$00,$64		DECIMAL 100
	FCB	$00,$0A		DECIMAL 10
	FCB	$00,$01		DECIMAL 1
