📄 interpreter.inc
字号:
x_while_00:
call #eval_expr ; evaluate test expression
bis.w r14, r15
cmp.w #0, r15 ; result is zero?
jnz term ; ...no, continue loop
add.w #6, sp ; ...yes, drop loop type, tp, and lp
mov.w #T_WEND, r11 ; search for a matching WEND
call #find_control_match
jnc while_without_matching_end_while_error
mov.b @tp+, r4
jmp term
; WEND
x_wend:
cmp.w #T_WHILE, @sp ; is control structure WHILE?
jnz end_while_without_while_error; ...no, report error
mov.w 2(sp), lp ; ...yes, restore context to that following WHILE
mov.w 4(sp), tp
mov.b -1(tp), r4
jmp x_while_00 ; re-evaluate expression
; REPEAT ... UNTIL cond
x_repeat:
push.w tp ; stack interpreter's context
push.w lp
push.w #T_REPEAT ; indicate that this is a REPEAT loop
jmp term ; ensure that statement is correctly terminated
x_until:
cmp.w #T_REPEAT, @sp ; control structure is REPEAT?
jnz until_without_repeat_error ; ...no, report error
call #eval_expr ; ...yes, evaluate control expression
bis.w r14, r15
cmp.w #0, r15 ; result is true (non-zero)?
jnz x_until_10 ; ...yes, exit the repeat loop
mov.w 2(sp), lp ; ...no, restore interpreter context
mov.w 4(sp), tp
mov.b -1(tp), r4 ; prime R4 with character following REPEAT
jmp term ; ensure that statement is correctly terminated
x_until_10:
add.w #6, sp ; remove REPEAT context
jmp term ; ensure that statement is correctly terminated
; EXIT FOR
x_exit_for:
call #end_of_statement ; anything after EXIT FOR?
jnz syntax_error ; ...yes, syntax error
mov.w #T_FOR, r11 ; ...no, find a matching FOR loop
jmp x_exit_10
; EXIT REPEAT
x_exit_repeat:
call #end_of_statement ; anything after EXIT REPEAT?
jnz syntax_error ; ...yes, syntax error
mov.w #T_REPEAT, r11 ; ...no, find a matching REPEAT loop
jmp x_exit_10
; EXIT WHILE
x_exit_while:
call #end_of_statement ; anything after EXIT WHILE?
jnz syntax_error ; ...yes, syntax error
mov.w #T_WHILE, r11 ; ...no, find a matching WHILE loop
x_exit_10:
cmp.w @sp, r11 ; matched structure?
jz x_exit_30 ; ...yes, transfer control out of loop
cmp.w #T_END, @sp ; searched whole stack?
jz exit_not_in_loop_error ; ...yes, not found so emit invalid exit
cmp.w #T_GOSUB, @sp
jz exit_not_in_loop_error
cmp.w #T_RESUME, @sp
jz exit_not_in_loop_error
add.w #6, sp ; 6 bytes are stacked for WHILE/REPEAT loops
cmp.w #T_FOR, @sp
jnz x_exit_10
add.w #6, sp ; 12 bytes are stacked for a FOR loop
jmp x_exit_10
x_exit_30:
cmp.w #T_WHILE, r11 ; WHILE-WEND loop?
jnz x_exit_40
mov.w #T_WEND, r11 ; search for a matching WEND
x_exit_40:
cmp.w #T_FOR, r11 ; FOR-NEXT loop?
jnz x_exit_50
mov.w #T_NEXT, r11 ; search for a matching NEXT
x_exit_50:
cmp.w #T_REPEAT, r11 ; REPEAT-UNTIL loop?
jnz x_exit_60
mov.w #T_UNTIL, r11 ; search for a matching UNTIL
x_exit_60:
mov.w 2(sp), lp ; get token pointer and line pointer of
mov.w 4(sp), tp ; token immediately following WHILE/REPEAT/FOR
call #find_control_match
jnc exit_not_in_loop_error
mov.b @tp+, r4
add.w #6, sp ; remove structure parameters from stack
cmp.w #T_NEXT, r11 ; FOR-NEXT loop stores a bit more context
jnz term
add.w #6, sp
jmp term
find_control_match:
push.w lp ; save line pointer for error message if we can't find the endpoint
push.w #T_END ; push delimiter
find_control_match_00:
cmp.w #T_WHILE, r4 ; start of a WHILE-WEND?
jz open_control
cmp.w #T_FOR, r4 ; start of a FOR-NEXT?
jz open_control
cmp.w #T_REPEAT, r4 ; start of a REPEAT-UNTIL?
jz open_control
cmp.w #T_END, @sp ; everything closed?
jnz find_control_match_10
cmp.w r4, r11 ; matched the terminator we're looking for?
jnz find_control_match_10 ; no, try other terminators
add.w #4, sp ; remove T_END and lp from stack
setc
ret ; return with LP and TP set appropriately and C=1
find_control_match_10:
cmp.w #T_NEXT, r4 ; close FOR-NEXT structure?
jz close_for ; yes
cmp.w #T_WEND, r4 ; close WHILE-WEND structure?
jz close_while ; yes
cmp.w #T_UNTIL, r4 ; close REPEAT-UNTIL structure?
jz close_repeat ; yes
jmp open_control_00 ; no, consider next token
open_control:
push.w r4
open_control_00:
cmp.b #0, r4
mov.b @tp+, r4
jnz find_control_match_00
cmp.w #0, lp
jz unterminated_structure
mov.w @lp, lp
mov.w lp, tp
add.w #4, tp
mov.b @tp+, r4
jmp find_control_match_00
close_for:
pop.w r15
cmp.w #T_FOR, r15
jnz next_without_for_error
jmp open_control_00
close_while:
pop.w r15
cmp.w #T_WHILE, r15
jnz end_while_without_while_error
jmp open_control_00
close_repeat:
pop.w r15
cmp.w #T_REPEAT, r15
jnz until_without_repeat_error
jmp open_control_00
; Clear unclosed structures from stack
unterminated_structure:
mov.w @sp, r4 ; get the structure which is unterminated
unterminated_structure_10:
pop.w r15
cmp.w #T_END, r15
jnz unterminated_structure_10
pop.w lp
clrc
ret
; END
x_end:
call #end_of_statement ; anything after EXIT REPEAT?
jnz syntax_error ; ...yes, syntax error
mov.w #END_OF_RAM, sp ; FIXME
jmp ready ; ended, so terminate
; FOR var = init TO final
x_for:
call #is_letter
jnc syntax_error
mov.b @tp+, r7
cmp.w #T_EQ, r7
jnz syntax_error
sub.w #'A', r4
add.w r4, r4
add.w r4, r4
mov.w r4, r11
call #get_eval_expr
mov.w r14, vars(r11)
mov.w r15, vars+2(r11)
cmp.w #T_TO, r4
jnz syntax_error
call #get_eval_expr
push.w r15 ; limit +10
push.w r14 ; +8
push.w r11 ; variable offset +6
push.w tp ; token pointer +4
push.w lp ; +2
push.w #T_FOR
jmp term
x_next:
cmp.w #T_FOR, @sp ; is control structure FOR?
jnz next_without_for_error ; ...no, report error
mov.w 6(sp), r11 ; pointer to variable
add.w #1, vars(r11) ; increment variable
addc.w #0, vars+2(r11)
mov.w 8(sp), r14 ; get limit
mov.w 10(sp), r15
sub.w vars(r11), r14 ; subtract current value
subc.w vars+2(r11), r15
jnc x_next_terminate_loop ; if passed limit, terminate loop
mov.w 4(sp), tp ; restore context
mov.w 2(sp), lp
mov.b -1(tp), r4
jmp term ; continue with loop
x_next_terminate_loop:
add.w #6*2, sp ; remove FOR context
jmp term ; continue with statement after NEXT
; ON BREAK stmt
; ON X GOTO l1, l2, ... ELSE ...
x_on:
cmp.w #T_BREAK, r4 ; check for ON BREAK
jz x_on_break
call #eval_expr ; evaluate control expression X
mov.w r14, r11
cmp.w #T_GOTO, r4 ; require GOTO
jnz syntax_error
x_on_goto_00:
mov.b @tp+, r4 ; get token after GOTO
cmp.b #0, r4 ; on end of statement, continue execution
jz term
cmp.b #':', r4
jz term
cmp.b #T_ELSE, r4 ; got to end of list without a match, but have an ELSE?
jz x_if_10 ; ...yes, treat ELSE like IF's THEN allowing e.g. ELSE 100 or ELSE PRINT Y
call #eval_expr ; evaluate line number
sub.w #1, r11 ; this label index matches control expression?
jz x_goto_00 ; yes
cmp.b #',', r4 ; more in the list
jz x_on_goto_00 ; yep, try to match another
cmp.b #T_ELSE, r4 ; got to end of list without a match, but have an ELSE?
jz x_if_10 ; ...yes, treat ELSE like IF's THEN allowing e.g. ELSE 100 or ELSE PRINT Y
jmp term
x_on_break:
mov.w tp, &break_tp
mov.w lp, &break_lp
jmp x_rem
; IF expr THEN [stmt | number]
; IF expr [THEN] stmt
x_if:
call #eval_expr ; evaluate control expr
bis.w r14, r15 ; controlling expression is false?
cmp.w #0, r15
jz x_rem ; ...yes, skip whole line
cmp.w #T_THEN, r4 ; THEN?
jnz chrgot ; ...no, THEN is omitted, so next is a statement
x_if_10:
mov.b @tp+, r4 ; get token following THEN
call #is_digit ; is it a digit?
jc x_goto ; ...yes, assume it's a line number and use GOTO
jmp chrgot
; INPUT [#channel, ] [string,] var [, string], var...
x_input:
mov.w #1, r15 ; default to channel 1 if no channel number given
call #select_channel
cmp.w #'#', r4 ; channel number being specified?
jnz x_input_10 ; ...no, so just use default
call #get_eval_expr ; evaluate the channel number
mov.w r14, r15 ; only use the low 16 bits of the channel number
call #select_channel ; select the channel, error if it's bad
x_input_00:
call #check_comma ; a comma must come next
x_input_10:
cmp.b #'"', r4 ; string?
jnz x_input_20 ; ...no, it must be a variable
call #print_quoted_string ; print the prompt string
call #check_comma ; a comma must come next
jmp x_input_30 ; do the input
x_input_20:
mov.w #'?', r15 ; default prompt is just '?'
call #print_char
x_input_30:
call #varptr ; get variable we're inputting
cmp.w #4, r15 ; only allow READ on word variables
jnz syntax_error
x_input_35:
mov.w r14, r11 ; save for later use
call #get_string ; read the input to ramtop
mov.w &ramtop, r10 ; get ready to parse input
x_input_40:
mov.b @r10+, r4 ; get character from input buffer
cmp.b #' ', r4 ; space?
jz x_input_40 ; ...yes, skip them
cmp.b #0, r4 ; nothing on line?
jz x_input_50 ; ...no, try again
call #is_digit ; leading digit?
jnc x_input_50 ; ...no, print bad data error and try again
push.w tp ; save interpreter's token pointer
mov.w r10, tp ; prepare to parse number from buffer
call #read_int ; do the parsing
mov.w r14, @r11 ; store read value
mov.w r15, 2(r11)
pop.w tp ; restore interpreter's token pointer
mov.b -1(tp), r4 ; refresh context
call #end_of_statement ; end of statement looming?
jz term ; ...yes, execute next statement
jmp x_input_00
x_input_50:
mov.w #bad_input_error_message, r15; print bad input error
call #print_message
mov.w #'?', r15 ; repeat default prompt
call #print_char
jmp x_input_35 ; try again
; PRINT expr [, | ;] expr...
x_print:
mov.w #0, r11 ; r11 is "hold CR" flag
mov.w #1, r15 ; default to channel 1 if no channel number given
call #select_channel
cmp.w #'#', r4 ; channel number being specified?
jnz x_print_02 ; ...no, so just use default
call #get_eval_expr ; evaluate the channel number
mov.w r14, r15 ; only use the low 16 bits of the channel number
call #select_channel ; select the channel, error if it's bad
jmp x_print_50 ; see if ',' or anything terminates the statement early
x_print_00:
mov.b #9, r15 ; print tab on ','
call #print_char
x_print_01:
mov.b @tp+, r4 ; get next token
x_print_02:
cmp.w #T_AT, r4 ; AT?
jnz x_print_03 ; ...no, continue to decode it
call #get_eval_expr ; evaluate positional expression
call #print_at ; position cursor
jmp x_print_40 ; deal with terminators
x_print_03:
cmp.b #'"', r4 ; printing a string?
jne x_print_20 ; ...no, continue to decode it
call #print_quoted_string ; print the string
jmp x_print_35 ; continue parsing
x_print_10:
mov.b @tp+, r4 ; get next token
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -