From: Ralph Ronnquist Date: Fri, 28 May 2021 12:49:41 +0000 (+1000) Subject: adding execution control words X-Git-Url: https://git.rrq.au/?a=commitdiff_plain;h=d5a8f559318ac57934871a48e964bac18557b601;p=rrq%2Frrqforth.git adding execution control words --- diff --git a/Makefile b/Makefile index b60f0c7..5fa7614 100644 --- 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} > $@ diff --git a/adoc/p_0branch.adoc b/adoc/p_0branch.adoc index 4f396c3..27d338d 100644 --- a/adoc/p_0branch.adoc +++ b/adoc/p_0branch.adoc @@ -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 index 0000000..0483d00 --- /dev/null +++ b/adoc/p_1branch.adoc @@ -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 index 0000000..ca4f1af --- /dev/null +++ b/adoc/p_begin.adoc @@ -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 +<>, <> and <> 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. diff --git a/adoc/p_branch.adoc b/adoc/p_branch.adoc index 9e4d0d2..089e238 100644 --- a/adoc/p_branch.adoc +++ b/adoc/p_branch.adoc @@ -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 index 0000000..eb384da --- /dev/null +++ b/adoc/p_else.adoc @@ -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 +<> and <> 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 index 0000000..7421502 --- /dev/null +++ b/adoc/p_end.adoc @@ -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 +<>, <> and <> to +implement structured execution control. END processes the data stack +to resolve any dangling <> branch offset for the +block of the matching <>. diff --git a/adoc/p_if.adoc b/adoc/p_if.adoc new file mode 100644 index 0000000..3922157 --- /dev/null +++ b/adoc/p_if.adoc @@ -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 +<> and <> to implement structured execution +control. IF results in layout of a <> 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 <> or <> 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 index 0000000..921cabd --- /dev/null +++ b/adoc/p_ifagain.adoc @@ -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 +<>, <> and <> 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 index 0000000..2c274cd --- /dev/null +++ b/adoc/p_ifbreak.adoc @@ -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 +<>, <> and <> 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 index 0000000..7f4041c --- /dev/null +++ b/adoc/p_quote.adoc @@ -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. + + + diff --git a/adoc/p_state.adoc b/adoc/p_state.adoc index 62ed9c7..65e9578 100644 --- a/adoc/p_state.adoc +++ b/adoc/p_state.adoc @@ -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 index 0000000..0dda2ab --- /dev/null +++ b/adoc/p_then.adoc @@ -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 +<> and <> 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". diff --git a/compile.asm b/compile.asm index fa850d4..8e87bf8 100644 --- a/compile.asm +++ b/compile.asm @@ -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 index 0000000..e4051d7 --- /dev/null +++ b/control.asm @@ -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 + + diff --git a/reference.adoc b/reference.adoc index 832820d..573da60 100644 --- a/reference.adoc +++ b/reference.adoc @@ -2,7 +2,6 @@ :author: Ralph Ronnquist :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[] diff --git a/rrqforth.asm b/rrqforth.asm index fd37709..5d36030 100644 --- a/rrqforth.asm +++ b/rrqforth.asm @@ -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' diff --git a/stdio.asm b/stdio.asm index e7cb02c..865b7f0 100644 --- 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 diff --git a/wordindex.adoc b/wordindex.adoc index 6ee602e..cdd7b5b 100644 --- a/wordindex.adoc +++ b/wordindex.adoc @@ -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}