adding execution control words
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Fri, 28 May 2021 12:49:41 +0000 (22:49 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Fri, 28 May 2021 12:49:41 +0000 (22:49 +1000)
19 files changed:
Makefile
adoc/p_0branch.adoc
adoc/p_1branch.adoc [new file with mode: 0644]
adoc/p_begin.adoc [new file with mode: 0644]
adoc/p_branch.adoc
adoc/p_else.adoc [new file with mode: 0644]
adoc/p_end.adoc [new file with mode: 0644]
adoc/p_if.adoc [new file with mode: 0644]
adoc/p_ifagain.adoc [new file with mode: 0644]
adoc/p_ifbreak.adoc [new file with mode: 0644]
adoc/p_quote.adoc [new file with mode: 0644]
adoc/p_state.adoc
adoc/p_then.adoc [new file with mode: 0644]
compile.asm
control.asm [new file with mode: 0644]
reference.adoc
rrqforth.asm
stdio.asm
wordindex.adoc

index b60f0c77cee7707739eb67aac7a78bfdff517c67..5fa76143da87f11ad209c14bec7444a157f0b719 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ rrqforth: rrqforth.asm $(INCS)
 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} > $@
index 4f396c3b82e5d3f08b2f3f2a537f45d9827515d2..27d338d60515d9f95453d1ffff31d2ae36de97ca 100644 (file)
@@ -1,4 +1,4 @@
-// rrqforth.asm:       WORD p_zero_branch,'0BRANCH',fasm
+// contorl.asm:        WORD p_zero_branch,'0BRANCH',fasm
 
 anchor:p_zero_branch[]
 
@@ -10,7 +10,7 @@ Data stack: ( v -- )
 
 "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.
 
diff --git a/adoc/p_1branch.adoc b/adoc/p_1branch.adoc
new file mode 100644 (file)
index 0000000..0483d00
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
diff --git a/adoc/p_begin.adoc b/adoc/p_begin.adoc
new file mode 100644 (file)
index 0000000..ca4f1af
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
index 9e4d0d27c0fe5bc672899cd70b87ae538861f9f8..089e23867213f9164a4d23a9983e3b72ee9f1fd1 100644 (file)
@@ -1,4 +1,4 @@
-// rrqforth.asm:       WORD p_branch,'BRANCH',fasm
+// control.asm:        WORD p_branch,'BRANCH',fasm
 
 anchor:p_branch[]
 
diff --git a/adoc/p_else.adoc b/adoc/p_else.adoc
new file mode 100644 (file)
index 0000000..eb384da
--- /dev/null
@@ -0,0 +1,19 @@
+// 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".
diff --git a/adoc/p_end.adoc b/adoc/p_end.adoc
new file mode 100644 (file)
index 0000000..7421502
--- /dev/null
@@ -0,0 +1,15 @@
+// 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>>.
diff --git a/adoc/p_if.adoc b/adoc/p_if.adoc
new file mode 100644 (file)
index 0000000..3922157
--- /dev/null
@@ -0,0 +1,19 @@
+// 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".
+
diff --git a/adoc/p_ifagain.adoc b/adoc/p_ifagain.adoc
new file mode 100644 (file)
index 0000000..921cabd
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
diff --git a/adoc/p_ifbreak.adoc b/adoc/p_ifbreak.adoc
new file mode 100644 (file)
index 0000000..2c274cd
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
diff --git a/adoc/p_quote.adoc b/adoc/p_quote.adoc
new file mode 100644 (file)
index 0000000..7f4041c
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+
+
index 62ed9c79a8ffc1b2f999a1ed5b47823e675e5c8b..65e9578272421ea051f68eccec16641c875296c7 100644 (file)
@@ -9,6 +9,6 @@ Data stack: ( -- a )
 ....
 
 "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.
 
 
diff --git a/adoc/p_then.adoc b/adoc/p_then.adoc
new file mode 100644 (file)
index 0000000..0dda2ab
--- /dev/null
@@ -0,0 +1,16 @@
+// 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".
index fa850d404f16c15b96aa2b6b7df3c1f450c51143..8e87bf87012e2403217c7aa8e29963c79a41f70f 100644 (file)
@@ -115,10 +115,34 @@ p_quote_end:
        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
@@ -257,6 +281,7 @@ p_evaluate_stream_INTERPRET:
        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:
diff --git a/control.asm b/control.asm
new file mode 100644 (file)
index 0000000..e4051d7
--- /dev/null
@@ -0,0 +1,143 @@
+;;; 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
+
+       
index 832820de18b63cb6879ccf0584c660ffc3ad46c4..573da603cac081da69da2e0a5536749420b25ab8 100644 (file)
@@ -2,7 +2,6 @@
 :author: Ralph Ronnquist <ralph.ronnquist@gmail.com>
 :plus: +
 
-
 == Compilation words
 // include::compile.adoc[]
 include::adoc/p_allot.adoc[]
@@ -22,11 +21,24 @@ include::adoc/p_left_bracket.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[]
index fd377099761171f0f06149912e25882c9f3bfa98..5d360306df30648ac9d94d9d5a9618dd5b85a096 100644 (file)
@@ -147,32 +147,12 @@ terminate_special:
        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'
index e7cb02c610b99cce131c9ea8469d53f96f169489..865b7f0d6dcf462743d5284b197063e4d0953009 100644 (file)
--- a/stdio.asm
+++ b/stdio.asm
@@ -205,7 +205,7 @@ p_read_word_nomore:
 
        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
index 6ee602e6f6af878835a16fee8ce1c4e55a53c6b0..cdd7b5b67aac26c526b2192d080429acc28adb58 100644 (file)
@@ -30,11 +30,12 @@ xref:p_gtR[>R] {nbsp}
 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}
@@ -48,7 +49,7 @@ xref:p_args[ARGS] {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}
@@ -68,7 +69,9 @@ xref:p_dovariable[doVARIABLE] {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}
@@ -80,6 +83,9 @@ xref:p_forth[FORTH] {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}
@@ -117,6 +123,7 @@ xref:p_system[SYSTEM] {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}