📄 interpreter.inc
字号:
; Butterfly BASIC - a BASIC interpreter for the MSP430
; Copyright (c) 2003, 2004 Paul Curtis
; email: plc@rowley.co.uk
; Butterfly Basic Register Usage
; ------------------------------
; R4 - current token taken from tokenized program image
; R5 - pointer to start of line currently executing
; R6 - pointer to current token within executing line
; R11 - for use exclusively by statement parsers
; R12/R13 - evaluation next on stack when entering binary operator routines
; R14/R15 - evaluation top of stack
#define tp r6
#define lp r5
#define BREAK 0x01
#define TIMER 0x02
; Hardware multiplier registers
#if 0
MPY equ 0x130
MPYS equ 0x132
MAC equ 0x134
MACS equ 0x136
OP2 equ 0x138
RESLO equ 0x13a
RESHI equ 0x13c
SUMEXT equ 0x13e
#endif
#define COMMAND_TOKENS 0
#define UNARY_TOKENS 1
#define MISC_TOKENS 2
#define BINARY_TOKENS 3
#define END_OF_RAM 0xa00
INCLUDELIB "c_sf"
; Keywords
#define T(SYM, STR, FUNC, PREC) _T SYM
_T macro X
X equ symval
symval set symval+1
endm
#define USER_TOKENS "user_tokens.inc"
symval set $80
FIRST_COMMAND_TOKEN equ symval
#undef PART
#define PART COMMAND_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
LAST_COMMAND_TOKEN equ symval-1
FIRST_UNARY_TOKEN equ symval
#undef PART
#define PART UNARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
LAST_UNARY_TOKEN equ symval-1
FIRST_MISC_TOKEN equ symval
#undef PART
#define PART MISC_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
LAST_MISC_TOKEN equ symval-1
FIRST_BINARY_TOKEN equ symval
#undef PART
#define PART BINARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
LAST_BINARY_TOKEN equ symval-1
LAST_TOKEN equ symval
; Token command table
#undef T
#define T(SYM, STR, FUNC, PREC) _C FUNC
_C macro X
dw X
endm
.code
cmdtab:
#undef PART
#define PART COMMAND_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
binarytab:
#undef PART
#define PART BINARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
unarytab:
#undef PART
#define PART UNARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
; Binary operator precedence table
#undef T
#define T(SYM, STR, FUNC, PREC) _P PREC
_P macro X
db X
endm
.code
operator_precedence:
dc.b 0
#undef PART
#define PART BINARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
; Keyword table
#undef T
#define T(SYM, STR, FUNC, PREC) _K STR
_K macro X
db X, 0
endm
.code
kwtab:
#undef PART
#define PART COMMAND_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
#undef PART
#define PART UNARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
#undef PART
#define PART MISC_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
#undef PART
#define PART BINARY_TOKENS
#include "../tokens.inc"
#include "user_tokens.inc"
; Variable storage
.bss
current_channel ds.b 1
trace_channel ds.b 1
trace_flags ds.b 1
even
vars ds.w 26*2 ; A to Z is 104 bytes
arrays ds.w 26*2 ; A() to Z() is 104 bytes; 2 bytes for address, 2 for dimension
ramtop ds.w 1
flashtop ds.w 1
break_tp ds.w 1 ; break vector
break_lp ds.w 1 ; start of line of last ON BREAK
data_lp ds.w 1 ; pointer to start of line of current DATA statement
data_tp ds.w 1 ; pointer for DATA statements on READ
cont_tp ds.w 1
cont_lp ds.w 1
flags ds.w 1
rndseed ds.w 2
auto_line ds.w 1 ; line number for AUTO
auto_inc ds.w 1 ; line increment for AUTO
convert_buffer ds.b 16
; This points to the (logical) first line of code in a user's program.
; As the program is edited, program_start will move to point to the
; lowest-numbered line number.
program_start ds.w 1
.code
even
reset::
; Zero the whole of UDATA
mov.w #SFB(UDATA0), r15
mov.w #SFE(UDATA0)-SFB(UDATA0), r13
reset_10:
mov.b #0, @r15
add.w #1, r15
sub.w #1, r13
jnz reset_10
; Entry point for cold start.
mov.w #WDTPW+WDTHOLD, &WDTCTL ; Turn off watchdog
mov.w #END_OF_RAM, sp ; Initialise stack
call #hw_init ; Initialise hardware environment
mov.b #1, ¤t_channel ; Default channel for output and tracing is #1
mov.b #1, &trace_channel
mov.b #0, &trace_flags ; Start by not tracing
; Sign on.
mov.w #copyright_message, r15
call #print_message
; Prepare memory and show how much there is to the user.
call #new
call #memory
; Initialise PRNG.
mov.w #25374, &rndseed[0]
mov.w #63398, &rndseed[1]
; Come out of AUTO mode and go to ready.
no_auto:
mov.w #0, &auto_line ; drop out of AUTO mode
; Entry point for main BASIC command entry loop
ready:
mov.w #1, r15 ; Select the default channel
call #select_channel
mov.w #ready_message, r15 ; Indicate we're ready to accept a command
call #print_message
mov.w &ramtop, r14 ; prepare to read string into ramtop
cmp.w #0, &auto_line ; under control of AUTO?
jz ready_20
mov.w &auto_line, r14 ; load line number
add.w &auto_inc, &auto_line ; update line number for next time round
jnc ready_05 ; did the line number wrap?
mov.w #0, &auto_line ; ...yes, come out of AUTO
ready_05:
mov.w #0, r15 ; zero extend for conversion
call #print_integer ; print it and also put it in the conversion buffer
mov.w #convert_buffer, r15 ; prepare to copy from convert buffer...
mov.w &ramtop, r14 ; ...to ramtop
ready_10:
mov.b @r15+, @r14 ; copy byte
add.w #1, r14 ; no auto increment on destination
cmp.b #0, -1(r15) ; end of string copied?
jnz ready_10 ; no, continue copying...
mov.b #' ', r15 ; prepare to
call #print_char ; print a space
mov.b r15, -1(r14) ; and put it in the buffer
ready_20:
call #get_string_00 ; read string to memory at R14
mov.w #0, lp ; we're not executing a line stored in flash, so errors don't report a line number
; Skip initial spaces
mov.w &ramtop, tp
interpreter_00:
mov.b @tp+, r4 ; Get character from buffer
cmp.b #' ', r4 ; if it's a space, ignore it
jz interpreter_00
sub.w #1, tp ; we've gone one too far with autoincrement, so adjust
cmp.b #0, r4 ; if nothing on the entered line...
jz no_auto ; ...just be silent, drop AUTO, and get another line
; Figure out whether this is an immediate command or a numbered line
call #is_digit
jc interpreter_20 ; if carry set, then a line with line number has been entered
; No line nunber, so this is an immediate command
mov.w #0, &auto_line ; come out of AUTO
call #tokenize ; tokenize put
mov.w &ramtop, tp ; start interpreting from the tokenized buffer
jmp chrget ; and execute
; Deal with a numbered line
interpreter_20:
add.w #1, tp ; point to next character
call #read_int ; read the line number into r15:r14...
push.w r14 ; ...but only use the lower 16 bits
sub.w #1, tp ; we've run one too far on the line number
mov.w tp, r9 ; save token pointer
call #tokenize ; tokenize the line
pop.w r14 ; restore the line number
mov.w #program_start, r11 ; pointer to previous line
; Come out of AUTO mode if no line
cmp.b #0, @r9 ; empty line?
jnz interpreter_30 ; ...no, process the line
cmp.w #0, &auto_line ; in AUTO mode?
jnz no_auto ; ...yes, drop AUTO mode and go to ready mode
; Copy line into flash
interpreter_30:
mov.w &flashtop, r10
mov.w r10, r7
mov.w r14, r4
add.w #2, r10
call #flash_write_word
add.w #2, r10
copy_line:
mov.b @r9+, r4
call #flash_write_byte
add.w #1, r10
cmp.w #0, r4
jnz copy_line
add.w #1, r10
bic.w #1, r10
mov.w r10, &flashtop
; Find line number in r14
mov.w #program_start, r11
mov.w &program_start, r15
cmp.w #0, r15
jz insert_new_line
jmp x_find_line_10
x_find_line_00:
mov.w r15, r11
mov.w @r15, r15
cmp.w #0, r15
jz insert_new_line
x_find_line_10:
cmp.w 2(r15), r14
jz replace_existing_line
jc x_find_line_00
; Insert line at r15.
insert_new_line:
cmp.b #0, 4(r7) ; Nothing to insert, i.e. deleting a non-existent line?
jz ready ; Yep, nothing to do.
; Point new line's foward pointer to point at next line.
mov.w r7, r10
mov.w @r11, r4
call #flash_write_word
; Update previous line's forward pointer to point here.
mov.w r7, r4
mov.w r11, r10
call #flash_write_word
jmp ready
replace_existing_line:
; Delete line entirely?
cmp.b #0, 4(r7)
jz delete_line
; Update previous line's forward pointer to point here.
mov.w @r15, r4 ; data to write
mov.w r7, r10 ; address to write at
call #flash_write_word
; Point previous line's forward pointer to point at next line.
mov.w r11, r10
mov.w r7, r4
call #flash_write_word
jmp ready
; Delete line
delete_line:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -