clean:
rm -f rrqforth{,.fas,.map}
-DOCS := reference.adoc wordindex.adoc $( shell adoc/*.adoc )
+DOCS := reference.adoc wordindex.adoc $(shell echo adoc/*.adoc )
reference.html: $(DOCS)
asciidoc -bhtml ${@:.html=.adoc} > $@
-// rrqforth.asm: WORD p_zero_branch,'0BRANCH',fasm
+// contorl.asm: WORD p_zero_branch,'0BRANCH',fasm
anchor:p_zero_branch[]
"0BRANCH" is a function word that implements execution conditional by
means of optionally adding the subsequent branch offset, or not, to
-the point of execution. If the value, is 0 then the branch offset is
-added, and otherwise execution continues with the cell following the
-branch offset in the definition.
+the point of execution. If the value, v, is 0 then the branch offset
+is added, and otherwise execution continues with the cell following
+the branch offset in the definition.
--- /dev/null
+// control.asm: WORD p_true_branch,'1BRANCH',fasm
+
+anchor:p_1branch[]
+
+=== Word: 1BRANCH
+
+....
+Data stack: ( v -- )
+....
+
+"1BRANCH" is a function word that implements execution conditional by
+means of optionally adding the subsequent branch offset, or not, to
+the point of execution. If the value, v, is non-zero then the branch
+offset is added, and otherwise execution continues with the cell
+following the branch offset in the definition.
+
--- /dev/null
+// control.asm: WORD p_begin,'BEGIN',fasm
+
+anchor:p_begin[]
+
+=== Word: BEGIN
+
+....
+Data stack: Compiling: ( -- a 0 )
+....
+
+"BEGIN" is an immediate function word that is used together with
+<<p_ifbreak,IFBREAK>>, <<p_ifagain,IFAGAIN>> and <<p_end,END>> to
+implement structured execution control. BEGIN simply places the
+address for resolving branches back to this point during execution,
+and then a 0 as a marker so as to allow for an unknown number of block
+exit points.
-// rrqforth.asm: WORD p_branch,'BRANCH',fasm
+// control.asm: WORD p_branch,'BRANCH',fasm
anchor:p_branch[]
--- /dev/null
+// control.asm: WORD p_else,'ELSE',fasm
+
+anchor:p_else[]
+
+=== Word: ELSE
+
+....
+Data stack: Compiling: ( a -- a )
+....
+
+"ELSE" is an immediate function word that is used together with
+<<p_if,IF>> and <<p_then,THEN>> to implement structured execution
+control. ELSE lays out an unresolved unconditional branch as an ending
+for the "then-part" of the structured statement, and it then performs
+the branch resolution for the "else-part". To that end it replaces the
+stacked address which pin-points the foot address the branch offset to
+resolve, so that at execution time there is an appropriate conditional
+branch past the "then-part" and the "else-part" of the "structured
+statement".
--- /dev/null
+// control.asm: WORD p_begin,'BEGIN',fasm
+
+anchor:p_begin[]
+
+=== Word: BEGIN
+
+....
+Data stack: Compiling: ( a 0 * -- )
+....
+
+"END" is an immediate function word that is used together with
+<<p_begin,BEGIN>>, <<p_ifbreak,IFBREAK>> and <<p_ifagain,IFAGAIN>> to
+implement structured execution control. END processes the data stack
+to resolve any dangling <<p_ifbreak,IFBREAK>> branch offset for the
+block of the matching <<p_begin,BEGIN>>.
--- /dev/null
+// control.asm: WORD p_if,'IF',fasm
+
+anchor:p_if[]
+
+=== Word: IF
+
+....
+Data stack: Compiling: ( -- a )
+....
+
+"IF" is an immediate function word that is used together with
+<<p_else,ELSE>> and <<p_then,THEN>> to implement structured execution
+control. IF results in layout of a <<p_0branch,0BRANCH>> instruction
+with an unresolved branch offset, and places the address for resolving
+this instruction on the datastack. This address will then be resolved
+and asssigned by a subsequent <<p_else,ELSE>> or <<p_then,THEN>> so
+that at execution time there is an appropriate conditional branch past
+the "then-part" of the "structured statement".
+
--- /dev/null
+// control.asm: WORD p_ifagain,'IFAGAIN',fasm
+
+anchor:p_ifagain[]
+
+=== Word: IFAGAIN
+
+....
+Data stack: Compiling: ( -- a )
+....
+
+"IFAGAIN" is an immediate function word that is used together with
+<<p_begin,BEGIN>>, <<p_ifbreak,BREAK>> and <<p_end,END>> to implement
+structured execution control. IFAGAIN scans the datastack for the
+nearest preceding BEGIN marker and lays out a branch from this point
+the beginning of the block during execution.
--- /dev/null
+// control.asm: WORD p_ifbreak,'IFBREAK',fasm
+
+anchor:p_ifbreak[]
+
+=== Word: IFBREAK
+
+....
+Data stack: Compiling: ( -- a )
+....
+
+"IFBREAK" is an immediate function word that is used together with
+<<p_begin,BEGIN>>, <<p_ifagain,IFAGAIN>> and <<p_end,END>> to
+implement structured execution control. IFBREAK simply places the
+address for resolving branches from this point the end of the block
+during execution.
--- /dev/null
+// compile.asm: WORD p_quote,"'",fasm
+
+anchor:p_quote[]
+
+=== Word: '
+....
+data stack: ( -- cfa ) Input stream: word
+....
+
+"'" (single quote) is a function word that reads and find the next
+word on the input stream and pushes its cfa.
+
+
+
....
"STATE" is a variable word marking whether the stream evaluator is in
-compiling mode (1) or intepreting (0) mode.
+compiling mode (1) or interpreting (0) mode.
--- /dev/null
+// control.asm: WORD p_then,'THEN',fasm
+
+anchor:p_then[]
+
+=== Word: THEN
+
+....
+Data stack: Compiling: ( a -- )
+....
+
+"THEN" is an immediate function word that is used together with
+<<p_if,IF>> and <<p_else,ELSE>> to implement structured execution
+control. THEN performs the branch resolution for the stacked address
+which pinpoints the foot address the branch offset to resolve, so that
+at execution time there is an appropriate conditional branch past the
+"then-part" or the "else-part" of the "structured statement".
add rsi,8
next
- WORD p_literal_string,'S"',fasm ;; " (fool emacs)
+ WORD p_literal_string,'S"',fasm,IMMEDIATE ;; " (fool emacs)
;; ( -- char* n )
;; Save string on heap to make available at interpretation
;; not for interactive use!!
+ cmp qword [p_state_DFA],0
+ je p_literal_string_executing
+ 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
+ mov rdi,qword [p_here_DFA]
+ mov qword [rdi],rcx
+ add rdi,8
+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
+
+p_literal_string_executing:
mov rax,qword [rsi]
add rsi,8
push rsi
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:
--- /dev/null
+;;; This file defines execution control words
+
+ WORD p_branch,'BRANCH',fasm
+ ;; ( -- )
+ ;; Using subsequent inline cell as branch offset, branch
+ ;; accordingly
+ add rsi,qword [rsi]
+ add rsi,8
+ next
+
+ WORD p_zero_branch,'0BRANCH',fasm
+ ;; ( v -- )
+ ;; Using subsequent inline cell as branch offset, branch
+ ;; accordingly if the stacked value is zero, otherwise just
+ ;; skip over the branch offset
+ pop rax
+ cmp rax,0
+ jne p_zero_branch_SKIP
+ add rsi,qword [rsi]
+p_zero_branch_SKIP:
+ add rsi,8
+ next
+
+ WORD p_true_branch,'1BRANCH',fasm
+ ;; ( v -- )
+ ;; Using subsequent inline cell as branch offset, branch
+ ;; accordingly if the stacked value is non-zero, otherwise
+ ;; just skip over the branch offset
+ pop rax
+ cmp rax,0
+ je p_true_branch_SKIP
+ add rsi,qword [rsi]
+p_true_branch_SKIP:
+ add rsi,8
+ next
+
+ WORD p_if,'IF',fasm,IMMEDIATE
+ ;; Compiling: ( -- a )
+ ;; Adds a (0BRANCH 0) cell pair into the current definition,
+ ;; and the address for the subsequent cell on the datastack.
+ ;; This prepares for a subsequent THEN to resolve the
+ ;; conditional branch length.
+ mov rax,qword [p_here_DFA]
+ mov qword [rax],p_zero_branch_DFA
+ mov qword [rax+8],0
+ add rax,16
+ mov qword [p_here_DFA],rax
+ push rax
+ next
+
+ WORD p_then,'THEN',fasm,IMMEDIATE
+ ;; Compiling: ( a -- )
+ ;; Computes the byte difference from address a and current
+ ;; "HERE", and writes that at [a].
+ pop rax
+ mov rbx,qword [p_here_DFA]
+ sub rbx,rax
+ mov qword [rax-8],rbx
+ next
+
+ WORD p_else,'ELSE',fasm,IMMEDIATE
+ ;; Compiling: ( a1 -- a2 )
+ ;; To be used between IF and THEN to lay out an unresolved
+ ;; (BRANCH 0) cell pair that ends the "then-part", and resolve
+ ;; the pending (0BRANCH 0) distance to egin the "else-part" of
+ ;; the conditional.
+ mov rax,qword [p_here_DFA]
+ mov qword [rax],p_branch_DFA
+ mov qword [rax+8],0
+ add rax,16
+ mov qword [p_here_DFA],rax
+ pop rax
+ mov rbx,qword [p_here_DFA]
+ push rbx
+ sub rbx,rax
+ mov qword [rax-8],rbx
+ next
+
+ WORD p_begin,'BEGIN',fasm,IMMEDIATE
+ ;; Compiling: ( -- a 0 )
+ ;; Pushes current address as a return point, and a 0 to mark
+ ;; it.
+ push qword [p_here_DFA]
+ push qword 0
+ next
+
+ WORD p_ifbreak,'IFBREAK',fasm,IMMEDIATE
+ ;; ( -- a )
+ ;; Lays out a (1BRANCH 0) cell pair and marks the current
+ ;; address for later resolution
+ mov rax,qword [p_here_DFA]
+ mov qword [rax],p_true_branch_DFA
+ mov qword [rax+8],0
+ add rax,16
+ mov qword [p_here_DFA],rax
+ push rax
+ next
+
+ WORD p_ifagain,'IFAGAIN',fasm,IMMEDIATE
+ ;; ( a 0 * -- a 0 * )
+ ;; Lays out a (1BRANCH ?) cell pair to conditionally repeat
+ ;; from the prior BEGIN.
+ mov rax,qword [p_here_DFA]
+ mov qword [rax],p_true_branch_DFA
+ mov qword [rax+8],0
+ add rax,16
+ mov qword [p_here_DFA],rax
+ mov rbx,rsp
+p_ifagain_loop:
+ cmp qword [rbx],0
+ je p_ifagain_resolve
+ add rbx,8
+ jmp p_ifagain_loop
+p_ifagain_resolve:
+ mov rbx,qword [rbx+8]
+ sub rbx,rax
+ mov qword [rax-8],rbx
+ next
+
+ WORD p_end,'END',fasm,IMMEDIATE
+ ;; Compiling: ( a 0 * -- )
+ ;; Resolves all open branches for the preceding BEGIN and
+ ;; optional several IFBREAK
+ mov rax,rsp
+ cmp qword [rax],0
+ je p_end_resolve
+ add rax,8
+ jmp p_end_DFA
+p_end_resolve:
+ mov rax,qword [rax+8] ; address of BEGIN
+p_end_next:
+ pop rbx
+ cmp rbx,0
+ je p_end_ending
+ mov rcx,rax
+ sub rcx,rbx
+ mov qword [rbx-8],rcx
+ jmp p_end_next
+p_end_ending:
+ pop rbx
+ next
+
+
:author: Ralph Ronnquist <ralph.ronnquist@gmail.com>
:plus: +
-
== Compilation words
// include::compile.adoc[]
include::adoc/p_allot.adoc[]
include::adoc/p_literal.adoc[]
include::adoc/p_literal_string.adoc[]
include::adoc/p_number.adoc[]
+include::adoc/p_quote.adoc[]
include::adoc/p_right_bracket.adoc[]
include::adoc/p_semicolon.adoc[]
include::adoc/p_state.adoc[]
include::adoc/p_this_word.adoc[]
+//include::control.adoc[]
+include::adoc/p_0branch.adoc[]
+include::adoc/p_1branch.adoc[]
+include::adoc/p_begin.adoc[]
+include::adoc/p_branch.adoc[]
+include::adoc/p_else.adoc[]
+include::adoc/p_end.adoc[]
+include::adoc/p_if.adoc[]
+include::adoc/p_ifagain.adoc[]
+include::adoc/p_ifbreak.adoc[]
+include::adoc/p_then.adoc[]
+
== Logic operation words
//include::logic.adoc[]
include::adoc/p_0equal.adoc[]
mov eax,60
syscall
- WORD p_branch,'BRANCH',fasm
- ;; ( -- )
- ;; Using subsequent inline cell as branch offset, branch
- ;; accordingly
- add rsi,qword [rsi]
- add rsi,8
- next
-
- WORD p_zero_branch,'0BRANCH',fasm
- ;; ( v -- )
- ;; Using subsequent inline cell as branch offset, branch
- ;; accordingly if the stacked value is zero, otherwise just
- ;; skip over the branch offset
- pop rax
- cmp rax,0
- jne p_zero_branch_SKIP
- add rsi,qword [rsi]
-p_zero_branch_SKIP:
- add rsi,8
- next
-
;;; ========================================
;;; Core extension(s)
;segment readable writable executable
+include 'control.asm'
include 'wordlists.asm'
include 'memory.asm'
include 'stack.asm'
WORD p_double_quote,'"',fasm ;; " (fool emacs)
;; ( -- char* n )
- ;; Scan to double quote in stream buffer, putting thr string on PAD
+ ;; Scan to double quote in stream buffer, putting the string on PAD
pushr rsi
push p_pad_DFA
push 0
xref:p_Rget[R@] {nbsp}
xref:ef:p_Rgt[R>] {nbsp}
-
xref:data_stack[DATA-STACK] {nbsp}
xref:return_stack[RETURN-STACK] {nbsp}
{nbsp}
+xref:p_branch[BRANCH] {nbsp}
xref:p_0branch[0BRANCH] {nbsp}
+xref:p_1branch[1BRANCH] {nbsp}
{nbsp}
xref:p_2drop[2DROP] {nbsp}
xref:p_2dup[2DUP] {nbsp}
xref:inline_code[[ASM]] {nbsp}
xref:p_base[BASE] {nbsp}
-xref:p_branch[BRANCH] {nbsp}
+xref:p_begin[BEGIN] {nbsp}
xref:p_clear_stream[CLEAR-STREAM] {nbsp}
xref:p_create[CREATE] {nbsp}
xref:p_drop[DROP] {nbsp}
xref:p_dup[DUP] {nbsp}
+xref:p_else[ELSE] {nbsp}
xref:p_emit[EMIT] {nbsp}
+xref:p_end[END] {nbsp}
xref:p_evaluate_stream[EVALUATE-STREAM] {nbsp}
xref:p_execute[EXECUTE] {nbsp}
xref:p_exit[EXIT] {nbsp}
xref:p_here[HERE] {nbsp}
xref:p_hex[HEX] {nbsp}
+xref:p_if[IF] {nbsp}
+xref:p_ifagain[IFAGAIN] {nbsp}
+xref:p_ifbreak[IFBREAK] {nbsp}
xref:p_immediate[IMMEDIATE] {nbsp}
xref:p_literal[LIT] {nbsp}
xref:p_tell[TELL] {nbsp}
xref:p_terminate0[TERMINATE0] {nbsp}
+xref:p_then[THEN] {nbsp}
xref:p_this_word[THIS-WORD] {nbsp}
xref:p_true[TRUE] {nbsp}
xref:p_tuck[TUCK] {nbsp}