feat(v4.0.0): the defining and compiling words
The fourth layer of the compiler capsule. compile.v4: INTERPRET's loop, STATE [ ] : ; EXIT IMMEDIATE LITERAL COMPILE [COMPILE] ' EXECUTE, CREATE VARIABLE CONSTANT DOES>, and IF ELSE THEN BEGIN UNTIL AGAIN WHILE REPEAT DO ?DO LOOP +LOOP on a control-flow stack in memory. forth.v4: the first words of the vocabulary, the in-line ones. FORTH source now goes in and running code comes out. 49 programmes were run through the v3 binary and through this; every result agrees, bar COMPILE, which v3 cannot run. The code laid down for each control structure is word for word the expansion DECOMPOSITION.md gives. A line may have six values on the stack while it is interpreted, and words called from the interpreter may nest eight deep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
bbd1b4047f
commit
dac7ffac92
@@ -682,10 +682,10 @@ The storage service belongs to the Artemis role, now a device node.
|
|||||||
| Word | Fate |
|
| Word | Fate |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `FIND` | CC | `( -- xt \| 0 )`, FORTH-79 and v3 alike: the compilation address of the next word in the input stream, or 0 if it is not in the dictionary. `32 WORD` then a search from the newest entry back, skipping hidden ones; names are case sensitive, as v3, and 31 characters are significant (FORTH-79). Executed on the golden model's host node (2026-10-04) against a list kept in C, 300 entries. Leaves its caller 7 data cells and 5 return entries. |
|
| `FIND` | CC | `( -- xt \| 0 )`, FORTH-79 and v3 alike: the compilation address of the next word in the input stream, or 0 if it is not in the dictionary. `32 WORD` then a search from the newest entry back, skipping hidden ones; names are case sensitive, as v3, and 31 characters are significant (FORTH-79). Executed on the golden model's host node (2026-10-04) against a list kept in C, 300 entries. Leaves its caller 7 data cells and 5 return entries. |
|
||||||
| `'` | CC | `( -- addr )`, FORTH-79: the parameter field address of the next word in the input stream; not found is an error (0, and `NODE-ERROR` set). v3's `'` returned what `FIND` returns. For a word that is code the two are the same address; for a data word the parameter field is the cell after its code, which is what FORTH-79's `n ' NAME !` needs. Its compiling behaviour comes with the compiler words. Executed on the golden model's host node (2026-10-04). |
|
| `'` | CC | `( -- addr )`, FORTH-79: the parameter field address of the next word in the input stream; not found is an error (0, and `NODE-ERROR` set). v3's `'` returned what `FIND` returns. For a word that is code the two are the same address; for a data word the parameter field is the cell after its code, which is what FORTH-79's `n ' NAME !` needs. It is immediate: inside a definition the address is compiled as a literal (FORTH-79), where v3's `'` parsed when the definition ran. Executed on the golden model's host node (2026-10-04). |
|
||||||
| `>LINK` `LFA` `LINK>` `>NAME` `NFA` `NAME>` `CFA` `PFA` `>BODY` `TRAVERSE` | CC | The fields of an entry, all reached from its xt, as in v3 where the xt was the entry: `>LINK`/`LFA` the link's address, `LINK>` the older entry's xt, `>NAME`/`NFA` the byte address of the counted name, `NAME>` back to the xt, `CFA` the xt itself, `PFA`/`>BODY` the parameter field, `TRAVERSE` from a name's count byte to past its last character (for `n > 0`; otherwise unchanged, as v3). Executed on the golden model's host node (2026-10-04). |
|
| `>LINK` `LFA` `LINK>` `>NAME` `NFA` `NAME>` `CFA` `PFA` `>BODY` `TRAVERSE` | CC | The fields of an entry, all reached from its xt, as in v3 where the xt was the entry: `>LINK`/`LFA` the link's address, `LINK>` the older entry's xt, `>NAME`/`NFA` the byte address of the counted name, `NAME>` back to the xt, `CFA` the xt itself, `PFA`/`>BODY` the parameter field, `TRAVERSE` from a name's count byte to past its last character (for `n > 0`; otherwise unchanged, as v3). Executed on the golden model's host node (2026-10-04). |
|
||||||
| `SMUDGE` `HIDDEN` | CC | `SMUDGE` toggles the hidden flag of the newest entry; `HIDDEN` sets it. v3 refuses both outside compilation; that check comes with the compiler words. Executed on the golden model's host node (2026-10-04). |
|
| `SMUDGE` `HIDDEN` | CC | `SMUDGE` toggles the hidden flag of the newest entry; `HIDDEN` sets it. v3 refuses both outside compilation; that check comes with the compiler words. Executed on the golden model's host node (2026-10-04). |
|
||||||
| `INTERPRET` | CC | |
|
| `INTERPRET` | CC | FORTH-79; source in `v4/capsule/compile.v4`. Takes words from the input stream until it is exhausted: a word in the dictionary is executed, or, when compiling and not immediate, compiled; anything else must be a number in the current `BASE` (a single cell, with an optional leading minus), left on the stack or compiled as a literal. What is neither, or a compile-only word met while interpreting, abandons the line: compiling stops, the definition under way stays hidden, the rest of the input is skipped and `NODE-ERROR` is set (the message and the stack reset come with `QUIT`). Executed on the golden model's host node (2026-10-04). |
|
||||||
|
|
||||||
An entry, as `v4/capsule/dict.v4` builds it. A word's execution address (xt) is the address of its
|
An entry, as `v4/capsule/dict.v4` builds it. A word's execution address (xt) is the address of its
|
||||||
code, and everything else is found from it:
|
code, and everything else is found from it:
|
||||||
@@ -713,7 +713,7 @@ it, `xt + 1`; for any other word the parameter field is the code itself.
|
|||||||
| Word | Fate | Notes |
|
| Word | Fate | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `(` `\` | CC | `(` is `41 WORD drop`; `\` is `SPAN @ >IN !`. In `v4/capsule/input.v4` under the names `PAREN` and `BACKSLASH`. Executed on the golden model's host node (2026-10-04). |
|
| `(` `\` | CC | `(` is `41 WORD drop`; `\` is `SPAN @ >IN !`. In `v4/capsule/input.v4` under the names `PAREN` and `BACKSLASH`. Executed on the golden model's host node (2026-10-04). |
|
||||||
| `EXECUTE` | CAP | `push ;` (tail-jumps to the xt; the xt returns to `EXECUTE`'s caller) |
|
| `EXECUTE` | CAP | `push ;` (tail-jumps to the xt; the xt returns to `EXECUTE`'s caller). Executed on the golden model's host node (2026-10-04). |
|
||||||
| `NOP` | OP | `nop` |
|
| `NOP` | OP | `nop` |
|
||||||
| `QUIT` `ABORT` `ABORT"` `(ABORT")` `COLD` `WARM` | CC | |
|
| `QUIT` `ABORT` `ABORT"` `(ABORT")` `COLD` `WARM` | CC | |
|
||||||
| `BYE` `REBOOT` | HERA | |
|
| `BYE` `REBOOT` | HERA | |
|
||||||
@@ -732,10 +732,35 @@ it, `xt + 1`; for any other word the parameter field is the code itself.
|
|||||||
|
|
||||||
| Word | Fate | Notes |
|
| Word | Fate | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `:` `;` `CREATE` `VARIABLE` `CONSTANT` `DOES>` `IMMEDIATE` `STATE` `[` `]` `LITERAL` `COMPILE` `[COMPILE]` `FORGET` `FENCE` | CC | |
|
| `:` `;` `EXIT` `IMMEDIATE` `STATE` `[` `]` `LITERAL` `COMPILE` `[COMPILE]` | CC | Source in `v4/capsule/compile.v4`, all to FORTH-79. `:` makes an entry and starts compiling; the word cannot be found until `;`, so a redefinition can use the old word. `;` lays the return, reveals the word and stops compiling. `LITERAL` compiles the number on the stack when compiling. `COMPILE xxx` lays code that compiles `xxx` when the word it is in runs; `[COMPILE] xxx` compiles `xxx` though it is immediate. Executed on the golden model's host node (2026-10-04) against results recorded from the v3 binary; v3's `COMPILE` does not work (`: C1 COMPILE DUP ; IMMEDIATE : U3 C1 + ;` gives `DUP: Stack underflow`), reported, not fixed. |
|
||||||
|
| `CREATE` `VARIABLE` `CONSTANT` `DOES>` | CC | FORTH-79. A data word's code is one instruction word, a call to its run-time routine, and its parameter field is the cell after it: `(DOVAR)` is `pop ;` (the call's return address is the parameter field's address) and `(DOCON)` is `pop a! @ ;`. `VARIABLE` allots one cell, set to 0. `DOES>` lays a call to `(DOES)` and then `pop`: `(DOES)`, run by the defining word, rewrites the newest entry's code into a call to the code after it and returns from the defining word; that code's `pop` fetches the parameter field address. Executed on the golden model's host node (2026-10-04) against results recorded from the v3 binary. |
|
||||||
|
| `FORGET` `FENCE` | CC | |
|
||||||
| `LIT` | OP | `@p` |
|
| `LIT` | OP | `@p` |
|
||||||
| `does_rt` | RET | Internal helper; `DOES>` is implemented by the compiler capsule. |
|
| `does_rt` | RET | Internal helper; `DOES>` is implemented by the compiler capsule. |
|
||||||
|
|
||||||
|
**How a word is compiled.** v4 code is native: a colon definition is instruction words, and
|
||||||
|
compiling a word into one lays down a call to it. Two flags on an entry change that. An **in-line**
|
||||||
|
word's code is a straight run of opcodes and literals ending in `;`, and that run is copied in place
|
||||||
|
of a call; this is fate IN (§0), and everything that touches the return stack must be in line, since a
|
||||||
|
call would bury what it works on. A **compile-only** word may not be executed by the interpreter.
|
||||||
|
`v4/capsule/forth.v4` holds the first words of the vocabulary flagged this way (`DUP`, `+`, `>R`, `I`,
|
||||||
|
`LEAVE`, `@`, the in-line variables and so on).
|
||||||
|
|
||||||
|
**The short stacks (D-2) and the compiler.** The interpreter and compiler run on the same ten-cell and
|
||||||
|
nine-entry stacks as the user's words, with the user's values beneath them. Two consequences are
|
||||||
|
built into the capsule:
|
||||||
|
|
||||||
|
- Every word of the capsule keeps what it works on in memory and has at most three cells of its own on
|
||||||
|
the data stack. Measured on the golden model: a line may have **6 values on the stack** while the
|
||||||
|
interpreter reads its next word, and defining and running a word leaves 4 cells under it untouched.
|
||||||
|
- Words called from the interpreter may nest **8 deep**; a `DO` loop takes two return entries, so two
|
||||||
|
nested loops leave four. `*` is therefore not `UM* drop` on the host node but N steps of `+*` with
|
||||||
|
only the count on the return stack; it gives the same low cell (what `+*` loses at the top of `T`
|
||||||
|
takes N shifts to reach the bit that moves into `A`, and the loop ends first).
|
||||||
|
|
||||||
|
A programme that v3 runs with more than that on its stacks does not run here; that is D-2, not the
|
||||||
|
compiler.
|
||||||
|
|
||||||
**The code generator** (`v4/capsule/codegen.v4`) is what these words are built on. It packs opcodes,
|
**The code generator** (`v4/capsule/codegen.v4`) is what these words are built on. It packs opcodes,
|
||||||
literals and branches into instruction words at `HERE`, by the rules of §1.2 and §2: slots filled left
|
literals and branches into instruction words at `HERE`, by the rules of §1.2 and §2: slots filled left
|
||||||
to right, unused slots `nop`, a literal's value in the cell after its word, `;` `ex` and any branch
|
to right, unused slots `nop`, a literal's value in the cell after its word, `;` `ex` and any branch
|
||||||
@@ -761,7 +786,9 @@ lays down was then run.
|
|||||||
|
|
||||||
| Word | Fate | v4 definition / notes |
|
| Word | Fate | v4 definition / notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `IF` `ELSE` `THEN` `BEGIN` `UNTIL` `AGAIN` `WHILE` `REPEAT` `DO` `?DO` `LOOP` `+LOOP` `LEAVE` `CASE` `OF` `ENDOF` `ENDCASE` | CC | Compile-time structure words. Expansions per §2 and below. |
|
| `IF` `ELSE` `THEN` `BEGIN` `UNTIL` `AGAIN` `WHILE` `REPEAT` `DO` `?DO` `LOOP` `+LOOP` | CC | Compile-time structure words, immediate and compile-only; source in `v4/capsule/compile.v4`. Expansions per §2 and below. What an opening word leaves for the word that closes it goes on a **control-flow stack in memory** (32 cells), not on the data stack, with a number saying which word left it; a closing word that finds the wrong number, or nothing, abandons the line. A loop that tests at its end (`UNTIL`) must drop the flag on both ways out, so `BEGIN` lays `jump L0 Ld: drop L0:` and `UNTIL` lays `if Ld drop`. Executed on the golden model's host node (2026-10-04): the code laid down for each is word for word what the text assembler makes of the expansion given here, and the programmes run give what the v3 binary gave. |
|
||||||
|
| `LEAVE` `I` `J` `UNLOOP` | CC | In-line words (below), compile-only. |
|
||||||
|
| `CASE` `OF` `ENDOF` `ENDCASE` | CC | |
|
||||||
| `EXIT` | OP | `;` |
|
| `EXIT` | OP | `;` |
|
||||||
| `(BRANCH)` | OP | `jump` |
|
| `(BRANCH)` | OP | `jump` |
|
||||||
| `(0BRANCH)` | IN | `if L … drop` (§2) — executed on the golden model (2026-10-03) as `IF 1 ELSE 2 THEN`, including results recorded from the v3 binary. |
|
| `(0BRANCH)` | IN | `if L … drop` (§2) — executed on the golden model (2026-10-03) as `IF 1 ELSE 2 THEN`, including results recorded from the v3 binary. |
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
|||||||
|
\ forth.v4 -- the first words of the FORTH vocabulary: the ones that are
|
||||||
|
\ opcodes or short runs of them, and the variables that are in-line addresses.
|
||||||
|
\
|
||||||
|
\ Each is the definition DECOMPOSITION.md gives (sections 4, 5.1 - 5.5, 5.18).
|
||||||
|
\ A word flagged inline is copied into a definition in place of a call; the
|
||||||
|
\ ones that touch the return stack are compile-only as well. Rests on core.v4
|
||||||
|
\ and compile.v4's loader constants.
|
||||||
|
|
||||||
|
\ ---- stack ----
|
||||||
|
header DUP inline : DUP dup ;
|
||||||
|
header DROP inline : DROP drop ;
|
||||||
|
header OVER inline : OVER over ;
|
||||||
|
header SWAP inline : SWAP' SWAP ;
|
||||||
|
header ROT inline : ROT' ROT ;
|
||||||
|
header -ROT inline : -ROT SWAP push SWAP pop ;
|
||||||
|
header ?DUP : ?DUP if Z dup ; Z: ;
|
||||||
|
header 2DUP inline : 2DUP over over ;
|
||||||
|
header 2DROP inline : 2DROP drop drop ;
|
||||||
|
|
||||||
|
\ ---- return stack: in line, and only inside a definition ----
|
||||||
|
header >R inline compile-only : >R push ;
|
||||||
|
header R> inline compile-only : R> pop ;
|
||||||
|
header R@ inline compile-only : R@ pop dup push ;
|
||||||
|
header I inline compile-only : I pop dup push ;
|
||||||
|
header J inline compile-only : J pop pop pop dup push a! push push a ;
|
||||||
|
header LEAVE inline compile-only : LEAVE pop pop drop dup push push ;
|
||||||
|
header UNLOOP inline compile-only : UNLOOP pop drop pop drop ;
|
||||||
|
|
||||||
|
\ ---- memory ----
|
||||||
|
header @ inline : FETCH a! @ ;
|
||||||
|
header ! inline : STORE a! ! ;
|
||||||
|
header +! inline : +! a! @ + ! ;
|
||||||
|
header CELLS inline : CELLS ; \ an address unit is a cell (D-1)
|
||||||
|
|
||||||
|
\ ---- arithmetic ----
|
||||||
|
header + inline : PLUS + ;
|
||||||
|
header - inline : MINUS - ;
|
||||||
|
\ The low cell of the product, by N steps of +* with nothing but the count on
|
||||||
|
\ the return stack. UM* drop gives the same cell but needs two more return
|
||||||
|
\ entries, which a word inside two DO loops does not have (D-2). The low
|
||||||
|
\ cell is exact: what +* loses at the top of T (D-3) takes N shifts to reach
|
||||||
|
\ the bit that moves into A, and the loop ends first.
|
||||||
|
header * : STAR a! 0 N-1 FOR +* UNEXT drop drop a ;
|
||||||
|
header NEGATE inline : NEGATE' NEGATE ;
|
||||||
|
header 1+ inline : 1+ 1 + ;
|
||||||
|
header 1- inline : 1- -1 + ;
|
||||||
|
header 2+ inline : 2+ 2 + ;
|
||||||
|
header 2- inline : 2- -2 + ;
|
||||||
|
header 2* inline : TWO* 2* ;
|
||||||
|
header 2/ inline : TWO/ 2/ ;
|
||||||
|
|
||||||
|
\ ---- logic and comparison ----
|
||||||
|
header AND inline : AND and ;
|
||||||
|
header XOR inline : XOR xor ;
|
||||||
|
header OR inline : OR' OR ;
|
||||||
|
header 0= : 0= if L1 drop 0 ; L1: drop -1 ;
|
||||||
|
header 0< : 0< -if L1 drop -1 ; L1: drop 0 ;
|
||||||
|
header NOT : NOT jump 0=
|
||||||
|
header = : EQUALS xor jump 0=
|
||||||
|
header < : LESS
|
||||||
|
over over xor -if SAME drop drop jump 0<
|
||||||
|
SAME: drop - jump 0<
|
||||||
|
header > : GREATER SWAP jump LESS
|
||||||
|
|
||||||
|
\ ---- in-line addresses and constants ----
|
||||||
|
header BL inline : BL' BL ;
|
||||||
|
header TIB inline : TIB' TIB ;
|
||||||
|
header >IN inline : >IN' >IN ;
|
||||||
|
header SPAN inline : SPAN' SPAN ;
|
||||||
|
header BASE inline : BASE' BASE ;
|
||||||
|
header PAD inline : PAD' PAD ;
|
||||||
|
header STATE inline : STATE' STATE ;
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user