;; CREATE ( chars* n -- tfa )
;; Add the pstring as a new word in the current wordlist.
pushr rsi
- mov rax,qword [p_wordlist_DFA] ; Current word list
- mov rax,[rax] ; last word of current wordlist
+ mov rdx,qword [p_wordlist_DFA] ; Current word list
mov rbx,qword [p_here_DFA]
- mov [rbx],rax ; TFA of new word
+ mov rax,qword [rdx] ; set up tfa linking to previous word
+ mov qword [rbx],rax ;
mov qword [rbx+16],0 ; flags field
;; copy pname
pop rcx ; n
mov qword [rbx+24],rcx ; PFA (length)
pop rsi ; chars* (source)
lea rdi,[rbx+32] ; (dest)
- ;; clear DF
+ cld
p_create_COPY:
movsb
dec rcx
- jge p_create_COPY
+ jg p_create_COPY
mov byte [rdi],0 ; extra NUL
inc rdi
mov qword [rdi],rbx ; pTFA
add rdi,8
- mov qword [rdi],rbx ; OFF
+ mov qword [rdi],0 ; OFF
add rdi,8
mov qword [rbx+8],rdi ; pCFA
+ mov qword [rdi],dovariable ; CFA
add rdi,8
- mov qword [rdi],dovalue ;CFA
- add rdi,8
- mov qword [rax],rbx ; Install new word
mov qword [p_here_DFA],rdi ; allocate the space
+ mov qword [rdx],rbx ; Install new word (rdx still wordlist ptr)
push rbx
popr rsi
next
- WORD p_allot,'ALLOT',fasm
+ WORD p_allot,'ALLOT'
;; ( n -- )
;; Allocate n bytes on the heap
- pop rax
- add rax,qword [p_here_DFA]
- mov qword [p_here_DFA],rax
- next
+ dq p_here, p_put_plus, p_return
- WORD p_comma,',',fasm
+ WORD p_quote,"'"
+ ;; ( "word" -- cfa )
+ ;; Find the following word and push its cfa, or 0
+ dq p_input, p_get, p_read_word, p_find
+ BRANCH 0,p_quote_end
+ dq p_tfa2cfa
+p_quote_end:
+ dq p_return
+
+ WORD p_bracketed_quote,"[']",doforth,IMMEDIATE
+ ;; Compilation ( "word" -- cfa )
+ ;; Compile down " LIT value "
+ dq p_literal, p_literal, p_comma,p_quote, p_comma, p_return
+
+ WORD p_comma,','
;; ( v -- )
;; Put cell value onto the heap and advance "HERE"
- mov rax,qword [p_here_DFA]
- pop rbx
- mov qword [rax],rbx
- add rax,8
- mov qword [p_here_DFA],rax
- next
-
- WORD p_Ccomma,'C,',fasm
+ dq p_here, p_literal, 8, p_get_n_increment, p_put, p_return
+
+ WORD p_Ccomma,'C,'
;; ( c -- )
;; Put byte value onto the heap and advance "HERE"
- mov rax,qword [p_here_DFA]
- pop rbx
- mov byte [rax],bl
- inc rax
- mov qword [p_here_DFA],rax
- next
+ dq p_here, p_Cput, p_literal, 1, p_here, p_put_plus, p_return
- WORD p_does,'DOES>',fasm,IMMEDIATE
+ WORD p_does,"DOES>",fasm,IMMEDIATE
;; ( -- )
- ;; Change the "DOES offset" of latest compilation and assign
- ;; it the "dodoes" execution semantics,
- mov rax,qword [p_wordlist_DFA]
- mov rax,[rax] ; last word of current wordlist
+ ;; Change the "DOES offset" of most recent word and assign it
+ ;; the "dodoes" execution semantics that follows.
+ mov rax,qword [rsp]
+ mov rbx,rax
tfa2does rax ; *rax is the DOES offset field
- ;; offset = qword [p_here_DFA]) - (rax+2*8)
- mov rbx,qword [p_here_DFA]
- sub rbx,rax
- sub rbx,16
- mov qword [rax],rbx
+ tfa2dfa rbx
+ mov rcx,qword [p_here_DFA]
+ sub rcx,rbx
+ mov qword [rax],rcx ; save offset from DFA to HERE
mov qword [rax+8],dodoes
next
WORD p_literal,'LIT',fasm
;; ( -- v )
- ;; Push the value of successor cell onto stack, and skip it
+ ;; Push the value of successor cell onto stack, and skip it.
+ ;; not for interactive use!!
push qword [rsi]
add rsi,8
next
- WORD p_literal_string,'S"',fasm
- ;; " (fool emacs)
- ;; ( -- chars* n )
- ;; Push the value of successor cell onto stack, and skip it
+ WORD p_literal_string,'LIT-STRING',fasm
+ ;; ( -- char* n )
+ ;; Save NUL string length and pointer on heap to make
+ ;; available at interpretation. Not for interactive use!!
mov rax,qword [rsi]
add rsi,8
push rsi
- push rax
add rsi,rax
+ dec rax
+ push rax
next
-;;; ========================================
-;;; The text interpreter
+ WORD p_literal_string_compile,'S"',fasm,IMMEDIATE ;; " (fool emacs)
+ ;; ( "..." -- )
+ ;; Lay out a LIT-STRING and a NUL string with length
+ pushr rsi
+ mov rdi,qword [p_here_DFA]
+ mov qword [rdi],p_literal_string
+ add rdi,8
+ mov qword [p_here_DFA],rdi
+ DOFORTH p_double_quote
+ pop rcx
+ pop rsi
+ inc rcx ; include the terminating NUL in count
+ mov rdi,qword [p_here_DFA]
+ mov qword [rdi],rcx
+ add rdi,8
+ cld
+p_literal_string_copy:
+ dec rcx
+ jl p_literal_string_copied
+ movsb
+ jmp p_literal_string_copy
+p_literal_string_copied:
+ mov qword [p_here_DFA],rdi
+ popr rsi
+ next
+
WORD p_state,'STATE',dovariable
;; Interpretation state (0=interpreting, 1=compiling)
dq 0
WORD p_left_bracket,'[',fasm,IMMEDIATE
;; ( -- )
- ;; Change state to interpretation state.
+ ;; Change state to interpreting state.
mov qword[p_state_DFA],0
next
pushr rsi
pop rcx ; ( -- chars* )
pop rsi ; ( -- )
- xor rdi,rdi
+ xor rdi,rdi ; value
+ mov rbx,1 ; sign (byte 0=0 means negative)
+ cmp qword [p_base_DFA],10
+ jne p_number_LOOP
+ cmp byte [rsi],'-'
+ jne p_number_LOOP
+ mov rbx,0
+ inc rsi
+ dec rcx
+ jle p_number_BAD
p_number_LOOP:
- dec rbx
+ dec rcx
jl p_number_DONE
+ xor rax,rax ; clearing
lodsb
- mov bl,al ; into bl
- cmp bl,'0'
+ cmp al,'0'
jl p_number_BAD
- cmp bl,'9'
+ cmp al,'9'
jg p_number_ALPHA
- sub bl,'0'
+ sub al,'0'
p_number_CONSUME:
+ mov r8,rax
mov rax,rdi
- mul qword [p_base_DFA]
- add rax,rbx
+ mul qword [p_base_DFA] ; uses rdx:rax
+ add rax,r8
mov rdi,rax
jmp p_number_LOOP
p_number_ALPHA:
- cmp bl,'A'
+ cmp al,'A'
jl p_number_BAD
- cmp bl,'Z'
+ cmp al,'Z'
jg p_number_alpha
- sub bl,'A'-10
+ sub al,'A'-10
+ cmp rax,qword [p_base_DFA]
+ jge p_number_BAD
jmp p_number_CONSUME
p_number_alpha:
- cmp bl,'a'
+ cmp al,'a'
jl p_number_BAD
- cmp bl,'z'
+ cmp al,'z'
jg p_number_BAD
- sub bl,'a'-10
+ sub al,'a'-10
+ cmp rax,qword [p_base_DFA]
+ jge p_number_BAD
jmp p_number_CONSUME
p_number_BAD:
push qword 0
popr rsi
next
p_number_DONE:
+ cmp rbx,0
+ jne p_numper_POSITIVE
+ neg rdi
+p_numper_POSITIVE:
push rdi
push qword 1
popr rsi
next
+ WORD p_input,'INPUT',dovariable
+ ;; The current input stream for evaluate-stream
+ dq 0
+
WORD p_this_word,'THIS-WORD',dovariable
dq 0,0 ; ( n chars* )
WORD p_evaluate_stream,'EVALUATE-STREAM'
- ;; ( stream -- *?* flag )
+ ;; ( stream* -- *?* flag )
;; Execute the words from the given stream
;; returns 1 if stream ends and 0 if an unknown word is found
+ dq p_input, p_get, p_gtR ; save old stream on R-stack
+ dq p_input, p_put
+p_evaluate_stream_PROMPT:
+ dq p_verboseQ, p_get
+ BRANCH 0,p_evaluate_stream_LOOP
+ dq p_depth, p_dot
+ dq p_literal_string
+ STRING '> '
+ dq p_tell
+ dq p_input, p_get
+ dq p_clear_stream
p_evaluate_stream_LOOP:
- dq p_read_word ; ( -- chars* n )
+ dq p_input, p_get
+ dq p_read_word
dq p_dup
- BRANCH 0,p_evaluate_stream_END
- dq p_2dup ; ( -- chars* n chars* n )
- dq p_this_word ; ( -- chars* n chars* n p )
- dq p_2put ; ( -- chars* n )
- dq p_find ; ( -- [ chars* n 0 ]/[ tfa ] )
- dq p_dup ; ( -- [ chars* n 0 0 ]/[ tfa tfa ] )
- BRANCH 0,p_evaluate_stream_NOTWORD ; ( -- chars* n tfa/0 )
- dq p_execute ; ( -- chars* n tfa/0 )
- BRANCH ,p_evaluate_stream_LOOP
+ BRANCH 0,p_evaluate_stream_END ; branch if 0 on TOP
+ dq p_2dup, p_this_word, p_2put
+ dq p_find
+ dq p_dup
+ BRANCH 0,p_evaluate_stream_NOTWORD ; branch if 0 on TOP
+ dq p_state
+ dq p_get
+ BRANCH 0,p_evaluate_stream_INTERPRET
+ dq p_dup
+ dq p_tfa2flags_get
+ dq p_literal, 1 ; the immediate bit
+ dq p_and
+ BRANCH 0,p_evaluate_stream_COMPILE
+p_evaluate_stream_INTERPRET:
+ dq p_tfa2cfa
+ dq p_execute
+ BRANCH ,p_evaluate_stream_AFTER
+p_evaluate_stream_COMPILE:
+ dq p_tfa2cfa
+ dq p_comma
+ BRANCH ,p_evaluate_stream_AFTER
p_evaluate_stream_NOTWORD:
- dq p_drop ; ( -- chars* n )
- dq p_number ; ( -- [ 0 ]/[ v 1 ] )
+ dq p_drop
+ dq p_number
dq p_dup
- BRANCH 0,p_evaluate_stream_BAD
+ BRANCH 0,p_evaluate_stream_BAD ; branch if 0
dq p_drop
+ dq p_state, p_get
+ BRANCH 0,p_evaluate_stream_AFTER ; branch if 0
+ dq p_literal, p_literal
+ dq p_comma, p_comma
+p_evaluate_stream_AFTER:
+ dq p_input, p_get
+ dq p_stream_nchars
+ BRANCH 0,p_evaluate_stream_PROMPT
BRANCH ,p_evaluate_stream_LOOP
p_evaluate_stream_END:
- dq p_literal
- dq 1
+ dq p_2drop
+ dq p_literal, 1
p_evaluate_stream_BAD:
- dq p_exit
+ dq p_Rgt, p_input, p_put ; restore previous stream
+ dq p_literal,0, p_state, p_put ; set interactive mode
+ dq p_return
+
+ WORD p_colon,':'
+ ;; ( -- )
+ ;; Read next word as a new word into current wordlist, set it
+ ;; to be a doforth word, and set compiling mode.
+ dq p_literal, doforth
+ dq p_input, p_get
+ dq p_read_word
+ dq p_create
+ dq p_tfa2cfa
+ dq p_put
+ dq p_right_bracket
+ dq p_return
+
+ WORD p_semicolon,';',,IMMEDIATE
+ ;; ( -- )
+ ;; Lay out p_return, and set interpreting mode
+ dq p_literal, p_return, p_comma, p_left_bracket, p_return
+
+ WORD p_immediate,'IMMEDIATE',fasm,IMMEDIATE
+ ;; ( -- )
+ ;; Set "immediate flag" of the word being defined
+ mov rax,qword [p_wordlist_DFA]
+ mov rax,qword [rax] ; tfa of most recent word
+ mov qword [rax+16],1 ; set the flags field to 1
+ next
+
+ WORD p_load_buffer_size,'LOAD-BUFFER-SIZE',dovariable
+ ;; ( -- a )
+ ;; The buffer size (in bytes) used by LOAD-FILE
+ dq 15000
+
+ WORD p_open_file,'OPEN-FILE',fasm
+ ;; ( chaz* n -- fd )
+ ;; Open the nominated file
+ pushr rsi
+ add rsp,8 ; drop n ... assuming NUL-ended string
+ push qword 0
+ push qword 0
+ DOFORTH sys_open
+ popr rsi
+ next
+
+ WORD p_load_file,'LOAD-FILE'
+ ;; ( chaz* n -- )
+ dq p_open_file
+ dq p_dup, p_0less
+ BRANCH 1,p_load_file_badfile
+ dq p_load_buffer_size, p_get
+ dq p_stream, p_dup, p_gtR
+ dq p_evaluate_stream
+ dq p_Rgt, p_unstream
+ BRANCH ,p_load_file_exit
+p_load_file_badfile:
+ dq p_literal_string
+ STRING '** open file error: '
+ dq p_tell, p_dot, p_nl, p_emit
+ dq p_literal,1
+p_load_file_exit:
+ dq p_return