📄 interpreter.inc
字号:
mov.w r11, r10
mov.w @r15, r4
call #flash_write_word
jmp ready
; NEW
x_new:
call #new
mov.w #END_OF_RAM, sp ; FIXME!
jmp ready
; Erase whole of flash
new:
mov.w #BREAK, &flags ; BREAK ON
call #clear ; zero variables
mov.w #user_flash_begin, r10 ; erase flash pages
x_new_00:
call #flash_erase_page
#ifndef SIMULATOR
add.w #0x200, r10
cmp.w #0xfe00, r10
jnz x_new_00
#endif
mov.w #user_flash_begin+4, &flashtop
mov.w #0, r4
mov.w #user_flash_begin, r10
call #flash_write_word
add.w #2, r10
call #flash_write_word
mov.w #0, &program_start
mov.w #0, lp
mov.w #ENDOF(UDATA0), &ramtop
ret
; RUN
x_run:
; Compute start line number
mov.w #0, r14 ; prepare to run from the start
cmp.b #0, r4 ; anything after RUN?
jz x_run_05 ; ...no, skip parsing the line number
call #read_int ; get line number to start from
; Re-initialise interpreter
x_run_05:
mov.w #BREAK, &flags ; allow break in processing
mov.w #END_OF_RAM, sp ; initialise stack pointer, clearing stack
mov.w #ENDOF(UDATA0), &ramtop ; initialise TOP
mov.w #0, &break_tp ; remove ON BREAK handler
mov.w #0, &break_lp
call #clear ; zero variables on run
; Before running, check structural integrity of program
mov.w &program_start, lp ; get start of program into lp
cmp.w #0, lp ; any program in flash?
jz ready ; ...no, nothing to run
mov.w lp, tp ; point tp to the start of the first line
add.w #4, tp
mov.b @tp+, r4 ; get first token from program
mov.w #LAST_TOKEN, r11 ; special token for find_control_match
call #find_control_match ; ensure loops match
jc x_run_10 ; if controls match, that's great
cmp.w #T_END, r4 ; END on its own?
jnz syntax_error ; ...no, then it's a syntax error
x_run_10:
mov.w &program_start, lp ; get start of program
mov.w lp, tp ; point to start of line
push.w #T_END ; delimit nothing on stack (no loops, no RESUME)
cmp.w #0, r14 ; run from start?
jz next_line ; ...yes, get first line
jmp x_goto_00
term:
cmp.b #':', r4 ; statement separator?
jeq chrget ; ...yes, start interpreting next statement
cmp.b #0, r4 ; end of line?
jeq term_10 ; ...yes, skip to next line
cmp.b #T_TICK, r4 ; comment?
jz x_rem ; ...yes, treat as REM
jmp syntax_error ; ...no, can't be anything other than an error
term_10:
cmp.w #0, lp ; at end of line, interpreting in immediate mode?
jeq ready ; ...yes, go back to ready loop
skip_line:
mov.w @lp, tp ; point tp to the next line to interpret by following forward link
mov.w tp, lp ; save start of line in lp
cmp.w #0, tp ; run off end of program?
jz ready ; ...yes, return to ready loop
next_line:
add.w #4, tp ; skip over line number and link
chrget:
mov.b @tp+, r4
chrgot:
; Break-in processing.
bit.w #BREAK, &flags ; break-ins enabled?
jz chrgot_20 ; ...no, carry on with life
BRKTEST chrgot_20
cmp.w #0, &break_tp ; ON BREAK set?
jz x_stop ; ...no, stop execution
mov.w tp, &cont_tp ; save current context for CONTINUE
mov.w lp, &cont_lp
mov.w &break_tp, tp ; activate ON BREAK context
mov.w &break_lp, lp
jmp chrget ; start ON BREAK processing
chrgot_20:
#if 0
bit.w #TIMER, &flags ; timer fired?
jz chrgot_30 ; no, continue execution
bic.w #TIMER, &flags ; reset timer fired flag
cmp.w #0, &timer_tp ; an ON TIMER handler set?
jz chrgot_30 ; no, ignore timer event
push.w sr ; save current context
dint
push.w tp
push.w lp
push.w #T_RESUME ; flag RESUME needed
mov.w &timer_tp, tp ; transfer to ON TIMER context
mov.w &timer_lp, lp
jmp chrget
chrgot_30:
#endif
cmp.b #0, r4
jz skip_line
jge chrgot_10
; Evaluate statement
next_00:
cmp.w #LAST_COMMAND_TOKEN+1, r4
jc syntax_error
add.b r4, r4
mov.b r4, r11
mov.b @tp+, r4
br cmdtab(r11)
chrgot_10:
cmp.b #':', r4
jz chrget
; LET var = expr
; LET var(index) = expr
x_let:
call #varptr ; parse variable and get its address into R14
mov.w r14, r11 ; save variable address
push.w r15 ; save variable size
cmp.b #T_EQ, r4 ; '=' follows?
jnz syntax_error ; ...no, syntax error
call #get_eval_expr ; evaluate the expression
pop.w r12 ; restore varibale designation
cmp.w #2, r12 ; assigning 16 bits?
jz x_let_20 ; ...yes
cmp.w #4, r12 ; assigning 32 bits?
jz x_let_10 ; ...yes
mov.b r14, @r11 ; must be 8 bits then
jmp term ; ensure that statement is correctly terminated
x_let_10:
mov.w r15, 2(r11) ; store high part of 32-bit value
x_let_20:
mov.w r14, @r11 ; store low part of 32-bit value or 16 bit value
jmp term ; ensure that statement is correctly terminated
; REM comment
x_rem:
cmp.w #0, lp ; Special REM in immediate mode
jz ready ; if in immediate mode, just say we're ready
jmp skip_line ; if in program mode, skip to the next line
; POKE address, byte
x_poke:
call #eval_expr ; evaluate address
mov.w r14, r11 ; ...and only use the low 16 bits
call #check_comma ; check ',' present
call #eval_expr ; evaluate byte
mov.b r14, @r11 ; do the poke
jmp term ; ensure that statement is correctly terminated
; DPOKE address, byte
x_dpoke:
call #eval_expr ; evaluate address
bic.w #0, r14 ; ensure address is word aligned
mov.w r14, r11 ; ...and only use the low 16 bits
call #check_comma ; check ',' present
call #eval_expr ; evaluate byte
mov.w r14, @r11 ; do the dpoke
jmp term ; ensure that statement is correctly terminated
; CLEAR
x_clear:
call #clear ; zero variables
jmp term ; ensure that statement is correctly terminated
; Clear variables and arrays to zero and restore data pointer
clear:
mov.w #ENDOF(UDATA0), &ramtop ; reset TOP
mov.w #0, r11 ; Clear A through Z
x_clear_10:
mov.w #0, vars(r11)
mov.w #0, arrays(r11)
add.w #2, r11
cmp.w #26*4, r11
jnz x_clear_10
mov.w #0, &data_lp
mov.w #0, &data_tp ; restore to start of program
ret
; RESTORE
; RESTORE line
x_restore:
mov.w #0, &data_tp ; by default, restore to start of program
call #end_of_statement ; end of statement?
jz term ; ...yes, just restore to start of program
call #read_int ; get line number to restore to
mov.w tp, r11 ; save where we are in the program
call #find_line ; find the line in the program, setting R15
mov.w r15, tp ; tp is always used to search the program
mov.w tp, &data_lp ; save start of line
call #find_data_statement ; find the next DATA statement
mov.w tp, &data_tp ; save DATA statement pointer
mov.w r11, tp ; restore the interpreting tp
mov.b -1(tp), r4 ; restore interpreting token
jmp term ; and check termination
; Find the next DATA statement after R15
find_data_statement:
cmp.w #0, tp ; fallen off end of program?
jz out_of_data_error ; ...yes, then out of data
add.w #4, tp ; skip over line number and forward pointer
find_data_statement_10:
mov.b @tp+, r4 ; get first token of statement
cmp.b #T_DATA, r4 ; is this a DATA statement?
jz find_data_statement_return ; ...yes, found it so return
call #skip_statement ; ...no, skip this statament
find_data_statement_20: ; entry point from READ
cmp.b #0, r4 ; need to skip over line number and forward pointer?
jnz find_data_statement_10 ; ...no, continue searching for the data statement
mov.w &data_lp, tp ; ...yes, so skip them
mov.w @tp, tp ; follow forward pointer
mov.w tp, &data_lp ; save start of line
jmp find_data_statement ; skip past header bytes
find_data_statement_return:
ret
; READ var, var...
x_read:
mov.w tp, r11 ; save tp as we'll use tp to search for DATA statements
mov.w &data_tp, tp ; any data?
cmp.w #0, tp
jnz x_read_10 ; yes, go to next data item
mov.w &program_start, tp ; search from start of program
mov.w tp, &data_lp
call #find_data_statement ; find data statement
mov.w tp, &data_tp
x_read_10:
mov.b @tp+, r4 ; prime for read
cmp.b #',', r4 ; comma?
jz x_read_10 ; ...yes, just skip it
call #end_of_statement ; come to end of DATA statement?
jnz x_read_20 ; ...no, read value from program
call #find_data_statement_20 ; ...yes, find next DATA statement
jmp x_read_10 ; and see if anything in this DATA statement
x_read_20:
call #read_int ; read value
sub.w #1, tp ; tp already advanced, so bring it back
mov.w tp, &data_tp ; save for next read
mov.w r11, tp ; restore interpreter's tp
mov.b -1(tp), r4 ; prime token
push.w r15 ; save read value on stack
push.w r14
call #varptr ; compute variable's address
cmp.w #4, r15 ; only allow READ on word variables
jnz syntax_error
pop.w 0(r14) ; store read value to variable
pop.w 2(r14)
cmp.w #',', r4 ; more to read?
jnz term ; ...no, terminate statement
mov.b @tp+, r4 ; prime next token
jmp x_read ; and read again
; DATA ...
x_data:
call #skip_statement ; skip the statement
jmp term ; continue with the following statement
; Skip the current statement, and point to the following statement
skip_statement:
cmp.b #0, r4 ; end of line?
jz skip_statement_return ; ...yes, we've skipped it
cmp.b #':', r4 ; separator?
jz skip_statement_return ; ...yes, we've skipped it
cmp.b #T_TICK, r4 ; remark?
jz skip_statement_10 ; ...yes, skip to end of line
cmp.b #T_REM, r4 ; remark?
jz skip_statement_10 ; ...yes, skip to end of line
mov.b @tp+, r4 ; get next token in statement
jmp skip_statement ; and continue searching for the end of the statement
skip_statement_10:
mov.b @tp+, r4 ; get next token
cmp.b #0, r4 ; end of line?
jnz skip_statement_10 ; ...no, still skipping remark
skip_statement_return:
ret
; DIM var1(n1), var2(n2)
x_dim:
call #is_letter ; dimensioning a valid array name?
jnc syntax_error ; ...no, it's a syntax error
mov.w r4, r11 ; save variable name for later
mov.b @tp+, r4 ; '(' next?
cmp.b #'(', r4
jnz syntax_error ; ...no, it's a syntax error
call #eval_unary ; get number of elements
cmp.w #0, r15 ; high word non-zero?
jnz out_of_memory_error ; ...yes, far too much memory required
cmp.w #16384, r14 ; more than 64/4 = 16K elements?
jc out_of_memory_error ; ...yes, array too big so report as out of memory
add.w #1, r14 ; DIM X(10) means X has 11 elements, 0 through 10
mov.w r14, r9 ; save maximum index
add.w r14, r14 ; compute number of 32-bit elements
add.w r14, r14
mov.w &ramtop, r15 ; 16-bit align TOP
add.w #1, r15
bic.w #1, r15
mov.w r15, r10 ; save start address of array in R10
add.w r14, r15 ; compute new TOP
mov.w sp, r14 ; gap between SP and TOP must be at least 32 bytes
sub.w #32, r14
cmp.w r14, r15 ; gap too small?
jc out_of_memory_error ; ...yes, report out of memory
mov.w r15, &ramtop ; ...no, set new TOP
sub.w #'A', r11 ; compute index into array table
add.w r11, r11
add.w r11, r11
mov.w r10, arrays(r11) ; set array start address
mov.w r9, arrays+2(r11) ; set array maximum index
cmp.b #',', @tp ; dimension another array?
jnz term ; no, check termination
add.w #1, tp ; skip '.'
mov.b @tp+, r4 ; get array name
jmp x_dim ; and dimension again
; WHILE cond ... END WHILE
x_while:
push.w tp ; stack interpreter's context
push.w lp
push.w #T_WHILE ; indicate that this is a WHILE loop
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -