; > Execute
; Program execute dispatch loop

; CHANGES
; =======
; 17-Jan-2009 JGH: Line continuation character within SkipSpaces
; 25-Oct-2009 JGH: Places zero word at top of stack so 2(sp) can be examined


; Error handler
; =============
; Generate inline error
.Error
mov  (sp)+,r0		; Pop return address
.ErrorHandler
mov  SV_LINE,SV_ERL	; Save current error line
clr  SV_LINE		; Clear current line number
mov  r0,SV_FAULT	; Current error
movb (r0),r0		; Get current error number
movb r0,SV_ERR		; Save current error number
jsr  pc,IO_AckEsc	; Acknowledge any pending Escape state
tstb SV_ERR
beq  ErrorFatal		; If ERR=0, ignore ON ERROR
mov  SV_HIMEM,sp	; Clear machine stack
mov  sp,SV_STACK	; Clear BASIC stack
mov  SV_ONERR,r5	; Get ON ERROR handler
; Should check for (r5)=tknLOCAL, clear stack if absent, step past if present
bne  Execute		; If set, jump to execute this code
.ErrorFatal
jsr  pc,cmdREPORT	; Display error message
mov  SV_ERL,r0		; Get error line
beq  ErrorNoErl		; Avoid printing 'at line 0'
jsr  pc,PrintInline
equb " at line ",0
align
mov  SV_ERL,r0
jsr  pc,PrintLineNum	; Print line number with no space padding
.ErrorNoErl
jsr  pc,IO_NEWL
jmp  Immediate		; Drop to immediate mode

; REPORT - Display current error message
; ======================================
.cmdREPORT
jsr  pc,IO_NEWL		; Print newline
mov  SV_FAULT,r1	; Get current error block
inc  r1			; Step past error number
jmp  PrintR1		; Print via token expansion

; RUN [str$]
; ==========
; Run program in memory or chain program from file
.cmdRUN
jsr  pc,CheckEndToken	; Any parameters?
beq  RunProgram		; No, RUN program

; CHAIN str$
; ==========
; Fetch CR-string
; Call LoadProgram
; Continue into RUN
.cmdCHAIN
jsr  pc,EvalStringCR	; Get cr-string parameter

; ChainStartup
; ------------
; Chain program, name already at R4
.ChainStartup
mov  SV_HIMEM,SP	; Put stack at top of memory
jsr  pc,LoadProgram	; Load file as a program

; RUN - Run program in memory
; ===========================
; LOMEM=TOP
; VAREND=TOP
; DATAPTR=PAGE
; STACK=HIMEM
; Clear dynamic variables
; LPTR=PAGE
; Enter Execution loop
.RunProgram
jsr  pc,VarsHeapInit	; LOMEM=TOP, VAREND=TOP, DATAPTR=PAGE, STACK=HIMEM
mov  SV_HIMEM,SP	; Put system stack at top of memory
mov  SV_PAGE,R5		; Point to start of program
inc  R5			; Step past <cr>
mov  #0,-(sp)		; Put an empty word at top of stack

; Step past line header after <cr> or at start of program
; -------------------------------------------------------
.ExecLineEnd
jsr  pc,ExecPastCR	; Step past line header
			; Continue executing

; Execute program code
; =====================
; R5=BASIC program pointer
; R4/R3=32-bit accumulator
; R2=value type/exponent
; R1/R0=working
;
.Execute
mov  r5,SV_LPTR		; Store program pointer
jsr  pc,IO_Escape	; Check Escape state
.ExecLineNext
movb (r5)+,r0		; Step past space
cmpb r0,#&20
beq  ExecLineNext	; Point to next char
cmpb r0,#&3A		; Is current char a colon?
beq  ExecLineNext	; Move past colons
cmpb r0,#tknTHEN	; Start of THEN clause?
beq  ExecLineNext	; Move past it
cmpb r0,#13		; End of line?
beq  ExecLineEnd	; Step past <cr>
jsr  pc,ExecByte	; Execute this byte
jmp  Execute		; Execute next statement

; Step past line header, checking for end of program
; --------------------------------------------------
; r0=13, r5=>after <cr>
.ExecPastCR
add  #3,r5		; Step past line header
movb &FFFD(r5),r0	; Get byte after <cr>
cmpb r0,#&FF		; Program terminator?
beq  cmdEND		; End of program
mov  SV_TRACE,r1	; Get TRACE status
beq  ExecNoTrace	; Return if TRACE OFF
mov  &FFFE(r5),r2	; Get line number
sub  r1,r2		; Compare line number with trace line
bcc  ExecNoTrace	; line<trace line
mov  #ASC"[",r0		; Print trace line number
jsr  pc,IO_WRCH
mov  SV_LINE,r0
jsr  pc,PrintLineNumber
mov  #ASC"]",r0
jsr  pc,IO_WRCH
mov  #ASC" ",r0
jsr  pc,IO_WRCH
.ExecNoTrace
rts  pc

; END
; ===
.cmdEND
; jsr pc,CheckEndStatement
jsr pc,FindTOP
; Should end-of-program look for TOP or go straight to immediate?
jmp  Immediate

; Execute command represented by the current byte
; -----------------------------------------------
.ExecByte
bic  #&FF00,r0		; Ensure &80-&FF
sub #&C0,r0		; Reduce range
bcs ExecNotCommand	; Not a command token
add  r0,r0		; Offset into command table
adr  CommandTable,r1	; Point to command address table
add  r0,r1		; Index into command table
add  (r1),r1		; Calculate routine address
jsr  pc,SkipSpaces	; r5=>current char, r0=current char
jmp  (r1)		; Jump to command routine

; Not a command token
; -------------------
.ExecNotCommand
cmpb r0,#tknELSE-&C0	; Current char 'ELSE'?
beq  cmdELSE
cmpb r0,#tknOFF-&C0	; Current char 'OFF'?
beq  cmdOFF_
cmpb r0,#ASC"="-&C0	; Current char '='?
beq  cmdEquals_
cmpb r0,#ASC"["-&C0	; Current char '['
beq  cmdAssem_
mov  r0,r1
jsr  pc,SkipSpaces	; r5=>next char, r0=next char
cmpb r1,#tknLINENUM	; Current char a line number marker after a THEN?
beq  cmdGOTO_
cmpb r1,#tknERROR-&C0	; Current char 'ERROR'?
beq  cmdERROR_
cmpb r1,#tknEXT-&C0	; Current char 'EXT'?
beq  cmdEXT_
cmpb r1,#ASC"*"-&C0	; Current char '*'?
bne  cmdAssign_		; Not '*', must be variable assignment
			; Fall through to '*' command
; nb, skipspaces causes 'A  A%=' to become ' A%=', '!   a=' to become ' a='
; not a problem if FindVar depended on to not skip spaces

; *command
; ========
mov  r5,r0		; Point to *command
jsr  pc,IO_CLI		; Pass to CLI

; Skip past a line, *command, REM, etc
; ------------------------------------
.SkipLine
.cmdELSE
.cmdREM
.cmdDEF
.cmdDATA
movb (r5)+,r0		; Get character
cmpb r0,#13
bne  SkipLine		; Loop until <cr>
dec  r5			; Point to <cr>
rts  pc

; Bounce off to routines
; ----------------------
.cmdEquals_	jmp  cmdEquals
.cmdAssem_	jmp  cmdAssem
.cmdAssign_	dec  r5		; Point to start of variable
		jmp  cmdAssign
.cmdERROR_	jmp  cmdERROR
.cmdGOTO_	jmp  cmdGOTO
.cmdOFF_	jmp  cmdOFF
.cmdEXT_	jmp  cmdEXT


; Various parsing routines
; ========================

; Check for end of statement, returns Z if end of statement
; ---------------------------------------------------------
.CheckEndStatement
movb (r5)+,r0
cmpb r0,#&20
beq  CheckEndStatement	; Skip any spaces
dec r5
.CheckEndToken
cmpb r0,#tknELSE
bcc  CheckEndStRet
.CheckColon
cmp  r0,#&3A
bcc  CheckEndStRet
cmp  r0,#&0D
.CheckEndStRet
rts pc

; Fetch next non-space character
; ------------------------------
.FetchNextChar
inc r5			; Step past current character
;
; Skip past any spaces, and return current character
; --------------------------------------------------
.SkipSpaces
movb (r5)+,r0
cmpb r0,#&20
beq  SkipSpaces		; Loop until non-space
cmp  r0,#ASC"\"		; Line continuation character?
beq  SkipSpaceCont	; Step to next line
dec  r5			; Point back to current character
bic  #&FF00,r0		; Ensure 8-bit byte
rts  pc

; Skip past line continuation comment
;
.SkipSpaceCont
cmpb (r5)+,#13
bne  SkipSpaceCont	; Skip to end of line
.SkipSpaceCR
cmpb (r5)+,#&FF		; End of program?
beq  cmdEND
inc  r5
inc  r5			; Step past line.lo, line.len
.SkipSpaceNext
movb (r5)+,r0
cmpb r0,#ASC"\"		; Found matching '\'?
beq  SkipSpaces		; Jump to continue skipping spaces
cmp  r0,#13		; Found end-of-line
beq  SkipSpaceCR	; Step to another next line
br   SkipSpaceNext


; Check for numeric characters
; ----------------------------
.CheckHexDigit
jsr  pc,CheckDigit	; Is it decimal digit?
bcc  CheckDigitExit	; CC=digit
bic  #&20,r0
cmp  r0,#ASC"A"
bcs  CheckDigitExit
cmp  #ASC"F",r0
rts  pc			; CC=digit

; Returns CC if digit, CS if nondigit
.CheckDigit
cmp r0,#ASC"0"     ; r0<'0' C=1, r0>='0' C=0
bcs CheckDigitExit ; Exit with CS if <'0'
cmp #ASC"9",r0     ; '9'<r0 C=1, '9'>=r0 C=0
                   ; r0>'9' C=1, r0<='9' C=0
.CheckDigitExit    ; Exit with CS if >'9'
rts pc

; Check for closing bracket
; -------------------------
; r5=>current char
.CheckClose
jsr  pc,SkipSpaces
.CheckClose1
cmpb r0,#ASC")"
bne  errMissingClose
inc  r5
rts  pc
.errMissingClose
jsr  pc,Error
equb 27,tknMissing,")",0
align


