From bbc9ae464c9341aa0c96bb78046b313b8a7a2405 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Thu, 2 Apr 2026 14:11:26 +0200 Subject: [PATCH] Add Forth 2012 + WAFER Anki flashcard deck --- docs/wafer-anki.txt | 389 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 docs/wafer-anki.txt diff --git a/docs/wafer-anki.txt b/docs/wafer-anki.txt new file mode 100644 index 0000000..e0e8552 --- /dev/null +++ b/docs/wafer-anki.txt @@ -0,0 +1,389 @@ +#separator:tab +#html:true +#tags column:3 +#deck:Forth 2012 + WAFER +DUP ( x -- x x )
Copy top of stack. The workhorse of Forth — sets up operand reuse.
5 DUP * . \ 25 — classic square idiom
DUP 0< IF NEGATE THEN \ ABS pattern
WAFER: IR [Dup]. Peephole: OVER OVER → 2DUP. Eligible for stack-to-local promotion.
See: ?DUP 2DUP OVER core stack ir-primitive +DROP ( x -- )
Discard TOS. Used to consume unwanted results.
/MOD DROP \ keep only remainder = MOD
/MOD NIP \ keep only quotient = /
WAFER: IR [Drop]. Peephole: DROP DROP → 2DROP.
See: NIP 2DROP core stack ir-primitive +SWAP ( x1 x2 -- x2 x1 )
Exchange top two items. Reorders operands for non-commutative ops.
3 5 SWAP - . \ 2 (5-3)
WAFER: IR [Swap]. Common peephole target: SWAP DROP → NIP.
See: ROT 2SWAP core stack ir-primitive +OVER ( x1 x2 -- x1 x2 x1 )
Copy second item to top. Lets you access NOS without destroying stack order.
: MAX 2DUP < IF SWAP THEN DROP ;
WAFER: IR [Over]. Peephole: OVER OVER → 2DUP.
See: PICK TUCK DUP core stack ir-primitive +ROT ( x1 x2 x3 -- x2 x3 x1 )
Rotate third item to top. Brings buried item up; rarely elegant — consider refactoring if used heavily.
: -ROT ROT ROT ; \ reverse rotate idiom
WAFER: IR [Rot].
See: 2ROT -ROT core stack ir-primitive +?DUP ( x -- 0 | x x )
Duplicate only if nonzero. Eliminates a common DUP IF … DROP THEN pattern.
: SAFE/ ?DUP IF / ELSE DROP 0 THEN ;
WAFER: IR [QDup]. Single opcode, not a macro.
See: DUP IF core stack ir-primitive +PICK ( xu…x1 x0 u -- xu…x1 x0 xu )
Copy u-th item (0-indexed). 0 PICK = DUP, 1 PICK = OVER. Deep picks signal stack abuse — refactor with locals or return stack.
2 PICK \ copies third item to top
WAFER: Host function. Runtime bounds check.
See: DUP OVER core stack host-function +DEPTH ( -- +n )
Number of single-cell values on the data stack before DEPTH executed.
1 2 3 DEPTH . \ 3
WAFER: Host function. Computes (STACK_TOP - DSP) / 4.
See: FDEPTH .S core stack host-function +2DUP ( x1 x2 -- x1 x2 x1 x2 )
Duplicate top cell pair. Essential before consuming comparisons.
: MAX 2DUP < IF SWAP THEN DROP ;
WAFER: IR [TwoDup]. Peephole target: OVER OVER optimized to 2DUP.
See: DUP 2OVER 2DROP core stack ir-primitive +2DROP ( x1 x2 -- )
Drop top cell pair. Cleans up after double-cell operations.
S" hello" 2DROP \ discard c-addr u
WAFER: IR [TwoDrop]. Peephole: DROP DROP → 2DROP.
See: DROP 2DUP core stack ir-primitive +2SWAP ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
Exchange top two cell pairs. Used with double-cell numbers or string descriptors (c-addr u).
1 2 3 4 2SWAP \ leaves 3 4 1 2
WAFER: Host function.
See: SWAP 2OVER 2ROT core stack host-function +2OVER ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
Copy second cell pair over top pair. Mirror of OVER for double-width values.
WAFER: Host function.
See: OVER 2DUP 2SWAP core stack host-function ++ ( n1|u1 n2|u2 -- n3|u3 )
Add. Works identically for signed and unsigned (two's complement).
3 4 + . \ 7
WAFER: IR [Add]. Peephole: LIT(1) + → 1+. Strength reduction: LIT(2) * → 2*.
See: - 1+ D+ M+ core arithmetic ir-primitive +- ( n1|u1 n2|u2 -- n3|u3 )
Subtract (n1 minus n2).
10 3 - . \ 7
WAFER: IR [Sub]. Peephole: LIT(1) - → 1-.
See: + NEGATE D- core arithmetic ir-primitive +* ( n1|u1 n2|u2 -- n3|u3 )
Multiply. Result is the low-order cell of the double-cell product; use M* for full double result.
6 7 * . \ 42
WAFER: IR [Mul]. Strength reduction: LIT(2) * → LSHIFT(1), LIT(4) * → LSHIFT(2), etc.
See: M* UM* */ 2* core arithmetic ir-primitive +/ ( n1 n2 -- n3 )
Signed division. Implementation-defined rounding (symmetric in most systems). WAFER uses symmetric (truncate toward zero).
7 2 / . \ 3
-7 2 / . \ -3 (symmetric)
WAFER: IR [DivMod, Nip] — /MOD then keep quotient.
See: MOD /MOD FM/MOD SM/REM core arithmetic ir-primitive +MOD ( n1 n2 -- n3 )
Signed remainder. Sign follows division semantics (symmetric in WAFER).
7 3 MOD . \ 1
-7 3 MOD . \ -1 (symmetric)
WAFER: IR [DivMod, Drop] — /MOD then keep remainder.
See: / /MOD FM/MOD core arithmetic ir-primitive +/MOD ( n1 n2 -- n-rem n-quot )
Signed division with remainder. Remainder on top of quotient. Division semantics are implementation-defined.
7 3 /MOD . . \ 2 1 (quot=2, rem=1)
WAFER: IR [DivMod]. Maps to WASM i32.div_s + i32.rem_s. Core building block for / and MOD.
See: / MOD FM/MOD SM/REM UM/MOD core arithmetic ir-primitive +*/ ( n1 n2 n3 -- n4 )
Multiply then divide: (n1*n2)/n3. Intermediate result is double-cell, avoiding overflow. Essential for scaling and fixed-point.
355 113 */ \ approximates pi ratio
WAFER: Host function. Uses i64 intermediate.
See: */MOD M* core arithmetic host-function +*/MOD ( n1 n2 n3 -- n-rem n-quot )
Multiply then divmod: n1*n2 divided by n3, double-cell intermediate.
7 3 2 */MOD . . \ quot=10, rem=1
WAFER: Host function. Uses i64 intermediate.
See: */ /MOD core arithmetic host-function +NEGATE ( n -- -n )
Two's complement negation. Note: NEGATE of the most negative number overflows silently.
5 NEGATE . \ -5
-1 NEGATE . \ 1
WAFER: IR [Negate]. Implemented as 0 SWAP SUB in WASM.
See: ABS DNEGATE FNEGATE core arithmetic ir-primitive +ABS ( n -- u )
Absolute value. ABS of MIN-INT (most negative) returns MIN-INT (overflow).
-42 ABS . \ 42
WAFER: IR [Abs].
See: NEGATE DABS FABS core arithmetic ir-primitive +MIN ( n1 n2 -- n3 )
Signed minimum. For unsigned minimum, use custom logic with U<.
3 7 MIN . \ 3
WAFER: Host function.
See: MAX FMIN DMIN core arithmetic host-function +MAX ( n1 n2 -- n3 )
Signed maximum.
3 7 MAX . \ 7
WAFER: Host function.
See: MIN FMAX DMAX core arithmetic host-function +1+ ( n -- n+1 )
Increment by one. Faster than 1 +; common in address arithmetic and counters.
VARIABLE CTR : BUMP CTR @ 1+ CTR ! ;
WAFER: IR [PushI32(1), Add]. Peephole target: LIT(1) + → 1+.
See: 1- CELL+ CHAR+ core arithmetic ir-primitive +1- ( n -- n-1 )
Decrement by one.
10 BEGIN DUP . 1- DUP 0= UNTIL DROP
WAFER: IR [PushI32(1), Sub]. Peephole target: LIT(1) - → 1-.
See: 1+ core arithmetic ir-primitive +2* ( x -- x*2 )
Arithmetic left shift by 1. Equivalent to 1 LSHIFT. Works on both signed and unsigned.
WAFER: IR [PushI32(1), Lshift]. Strength reduction target: LIT(2) * → 2*.
See: 2/ LSHIFT D2* core arithmetic ir-primitive +2/ ( x -- x/2 )
Arithmetic right shift by 1 (sign-extending). NOT equivalent to 1 RSHIFT for negative numbers — RSHIFT is logical (zero-fill), 2/ preserves sign.
-7 2/ . \ -4 (rounds toward negative infinity)
WAFER: IR [ArithRshift]. Uses WASM i32.shr_s.
See: 2* RSHIFT D2/ core arithmetic ir-primitive +M* ( n1 n2 -- d )
Signed multiply producing double-cell result. No overflow possible. Foundation for */ and */MOD.
100000 100000 M* D. \ 10000000000
WAFER: Host function. Uses Rust i64 multiply, splits into lo/hi i32.
See: UM* * D+ M*/ core arithmetic host-function +UM* ( u1 u2 -- ud )
Unsigned multiply producing unsigned double-cell result.
WAFER: Host function. Uses Rust u64 multiply.
See: M* * core arithmetic host-function +UM/MOD ( ud u1 -- u-rem u-quot )
Unsigned double-cell by single-cell division. Foundation for pictured numeric output (#).
0 10 3 UM/MOD . . \ 3 1
WAFER: Host function.
See: FM/MOD SM/REM /MOD core arithmetic host-function +FM/MOD ( d n1 -- n-rem n-quot )
Floored division: quotient rounded toward negative infinity. Remainder has same sign as divisor. Preferred for modular arithmetic.
-7. 2 FM/MOD . . \ -4 1 (not -3 -1)
WAFER: Host function. Adjusts SM/REM result when signs differ.
See: SM/REM /MOD UM/MOD core arithmetic host-function +SM/REM ( d n1 -- n-rem n-quot )
Symmetric division: quotient truncated toward zero. Remainder has same sign as dividend. C-like semantics.
-7. 2 SM/REM . . \ -3 -1
WAFER: Host function. Direct WASM i32 div/rem.
See: FM/MOD /MOD UM/MOD core arithmetic host-function +S>D ( n -- d )
Sign-extend single to double. Pushes sign word (0 or -1) above n.
-1 S>D D. \ -1
5 S>D D. \ 5
WAFER: IR [StoD]. Uses WASM i32.shr_s by 31 for sign extension.
See: D>S D>F core conversion ir-primitive += ( x1 x2 -- flag )
True if equal. Returns well-formed flag (-1 or 0).
3 3 = . \ -1
3 4 = . \ 0
WAFER: IR [Eq]. Compiles to WASM i32.eq.
See: <> D= F= core comparison ir-primitive +< ( n1 n2 -- flag )
Signed less-than. Treats values as signed 32-bit integers.
3 5 < . \ -1
-1 0 < . \ -1
WAFER: IR [Lt]. Compiles to WASM i32.lt_s.
See: > U< 0< D< core comparison ir-primitive +> ( n1 n2 -- flag )
Signed greater-than.
5 3 > . \ -1
WAFER: IR [Gt]. Compiles to WASM i32.gt_s.
See: < U> 0> core comparison ir-primitive +U< ( u1 u2 -- flag )
Unsigned less-than. Treats values as unsigned. Critical: -1 (0xFFFFFFFF) is the largest unsigned value.
-1 0 U< . \ 0 (unsigned: -1 is max)
WAFER: IR [LtUnsigned]. Compiles to WASM i32.lt_u.
See: < U> DU< core comparison ir-primitive +0= ( x -- flag )
True if zero. Also serves as logical NOT for well-formed flags.
0 0= . \ -1
FALSE 0= . \ -1 (logical NOT)
WAFER: IR [ZeroEq]. Compiles to WASM i32.eqz.
See: 0< 0<> 0> core comparison ir-primitive +0< ( n -- flag )
True if negative (sign bit set).
-5 0< . \ -1
0 0< . \ 0
WAFER: IR [ZeroLt]. Tests sign bit.
See: 0= 0> 0<> core comparison ir-primitive +WITHIN ( n lo hi -- flag )
True if lo ≤ n < hi (unsigned comparison after subtracting lo). Works correctly even when range wraps around.
5 3 10 WITHIN . \ -1
3 3 10 WITHIN . \ -1 (inclusive low)
10 3 10 WITHIN . \ 0 (exclusive high)
WAFER: Host function.
See: < > U< core-ext comparison host-function +AND ( x1 x2 -- x3 )
Bitwise AND. For logical AND with flags, this works because -1 AND -1 = -1. Also used for masking bits.
0xFF 0x0F AND . \ 15
TRUE TRUE AND . \ -1
WAFER: IR [And]. Compiles to WASM i32.and.
See: OR XOR INVERT core logic ir-primitive +OR ( x1 x2 -- x3 )
Bitwise OR. Combines flag values and bit masks.
0xF0 0x0F OR . \ 255
WAFER: IR [Or]. Compiles to WASM i32.or.
See: AND XOR INVERT core logic ir-primitive +XOR ( x1 x2 -- x3 )
Bitwise exclusive OR. x x XOR yields 0. Useful for toggling bits.
0xFF 0x0F XOR . \ 240
WAFER: IR [Xor]. Compiles to WASM i32.xor.
See: AND OR INVERT core logic ir-primitive +INVERT ( x -- x' )
Bitwise NOT (one's complement). For flags: inverts all bits, so TRUE INVERT = FALSE and vice versa. NOT equivalent to logical NOT — use 0= for that.
0 INVERT . \ -1
WAFER: IR [Invert].
See: NEGATE 0= core logic ir-primitive +LSHIFT ( x1 u -- x2 )
Logical left shift by u bits. Undefined for u ≥ cell-width (32).
1 8 LSHIFT . \ 256
WAFER: IR [Lshift]. Compiles to WASM i32.shl.
See: RSHIFT 2* D2* core logic ir-primitive +RSHIFT ( x1 u -- x2 )
Logical right shift (zero-fill). NOT arithmetic shift — does not preserve sign. Use 2/ for signed division by 2.
256 8 RSHIFT . \ 1
-1 1 RSHIFT . \ 2147483647 (not -1!)
WAFER: IR [Rshift]. Compiles to WASM i32.shr_u.
See: LSHIFT 2/ core logic ir-primitive +@ ( a-addr -- x )
Fetch cell from aligned address. Address must be cell-aligned (4-byte in WAFER). Unaligned access is undefined.
VARIABLE X 42 X ! X @ . \ 42
WAFER: IR [Fetch]. Compiles to WASM i32.load. Address is byte offset into linear memory.
See: ! C@ 2@ F@ core memory-ops ir-primitive +! ( x a-addr -- )
Store cell to aligned address.
99 X !
WAFER: IR [Store]. Compiles to WASM i32.store.
See: @ C! 2! +! F! core memory-ops ir-primitive +C@ ( c-addr -- char )
Fetch single byte (zero-extended to cell).
S" ABC" DROP C@ . \ 65 (ASCII 'A')
WAFER: IR [CFetch]. Compiles to WASM i32.load8_u.
See: C! @ COUNT core memory-ops ir-primitive +C! ( char c-addr -- )
Store single byte (low 8 bits of char).
65 PAD C! PAD C@ . \ 65
WAFER: IR [CStore]. Compiles to WASM i32.store8.
See: C@ ! core memory-ops ir-primitive ++! ( n a-addr -- )
Add n to the cell at a-addr. Atomic read-modify-write idiom.
VARIABLE CTR 0 CTR ! 5 CTR +! CTR @ . \ 5
WAFER: IR [PlusStore]. Compiles to load + add + store sequence.
See: @ ! 1+ core memory-ops ir-primitive +2@ ( a-addr -- x1 x2 )
Fetch cell pair. x2 is from a-addr, x1 from a-addr+cell. Note: high cell is at lower address (big-endian pair order).
WAFER: Host function.
See: 2! @ 2DUP core memory-ops host-function +2! ( x1 x2 a-addr -- )
Store cell pair. x2 stored at a-addr, x1 at a-addr+cell.
WAFER: Host function.
See: 2@ ! 2DROP core memory-ops host-function +HERE ( -- addr )
Address of next available dictionary space. Moves as you ALLOT or comma.
HERE . \ shows current dictionary pointer
WAFER: Host function. Reads system variable at address 0x0C.
See: ALLOT , C, UNUSED core memory-ops host-function +ALLOT ( n -- )
Reserve n address units (bytes) at HERE. Negative values reclaim space.
CREATE BUFFER 100 ALLOT \ allocate 100 bytes
WAFER: Host function. Advances HERE pointer.
See: HERE CREATE , core memory-ops host-function +, (comma) ( x -- )
Compile cell value at HERE and advance HERE by one cell. Used to build data structures.
CREATE TABLE 1 , 2 , 3 ,
WAFER: Host function.
See: C, HERE ALLOT core memory-ops host-function +C, ( char -- )
Compile byte at HERE and advance HERE by one byte.
WAFER: Host function.
See: , HERE core memory-ops host-function +CELLS ( n -- n*cell )
Convert cell count to address units. Cell = 4 bytes in WAFER (32-bit).
10 CELLS . \ 40
WAFER: IR [PushI32(4), Mul]. Strength-reduced to 2 LSHIFT.
See: CELL+ CHARS FLOATS core memory-ops ir-primitive +CELL+ ( a-addr -- a-addr' )
Add one cell size. Steps to next cell in memory.
WAFER: IR [PushI32(4), Add].
See: CELLS CHAR+ core memory-ops ir-primitive +CHARS ( n -- n*char )
Convert character count to address units. In WAFER (byte-addressed), this is a no-op (1 char = 1 byte).
WAFER: IR [] (identity). CHARS is zero IR ops.
See: CHAR+ CELLS core memory-ops ir-primitive +CHAR+ ( c-addr -- c-addr' )
Add one character size (1 byte).
WAFER: IR [PushI32(1), Add].
See: CHARS CELL+ core memory-ops ir-primitive +ALIGNED ( addr -- a-addr )
Round up to next cell-aligned address. (addr + 3) AND NOT 3.
5 ALIGNED . \ 8
WAFER: IR [PushI32(3), Add, PushI32(3), Invert, And].
See: ALIGN FALIGNED core memory-ops ir-primitive +ALIGN ( -- )
Align HERE to cell boundary. Always call after storing non-cell data with C,.
WAFER: Host function. Sets HERE = ALIGNED(HERE).
See: ALIGNED FALIGN core memory-ops host-function +MOVE ( addr1 addr2 u -- )
Copy u bytes from addr1 to addr2. Handles overlapping regions correctly (like C memmove).
WAFER: Host function. Rust memcpy with overlap detection.
See: CMOVE CMOVE> FILL core memory-ops host-function +FILL ( c-addr u char -- )
Fill u bytes starting at c-addr with char.
PAD 10 42 FILL \ fill PAD with '*'
WAFER: Host function.
See: ERASE BLANK MOVE core memory-ops host-function +>R ( x -- ) ( R: -- x )
Push to return stack. Must be balanced with R> within same definition. Cannot cross control-flow boundaries (IF/THEN, DO/LOOP).
: 3RD >R >R DUP R> R> ROT ; \ copy third item
WAFER: IR [ToR]. Return stack at 0x1540-0x2540.
See: R> R@ 2>R core return-stack ir-primitive +R> ( -- x ) ( R: x -- )
Pop from return stack to data stack. Every >R must have a matching R>.
WAFER: IR [FromR].
See: >R R@ core return-stack ir-primitive +R@ ( -- x ) ( R: x -- x )
Copy top of return stack without consuming. Same as I inside a DO loop.
WAFER: IR [RFetch].
See: >R R> I core return-stack ir-primitive +IF Compilation: ( -- orig )
Runtime: ( x -- )

Conditional branch. Consumes flag; branches to ELSE or THEN if zero. Non-zero = true (any bits set).
: SIGN DUP 0< IF ." negative" ELSE ." non-negative" THEN ;
WAFER: Special token. Compiles to IR If{then,else} block. Nests arbitrarily.
See: ELSE THEN ?DUP core control-flow special-token +ELSE Compilation: ( orig1 -- orig2 )
Optional false branch of IF. Execution continues at THEN.
WAFER: Special token. Part of If{then,else} IR structure.
See: IF THEN core control-flow special-token +THEN Compilation: ( orig -- )
Resolve forward reference from IF or ELSE. Every IF needs exactly one THEN.
WAFER: Special token.
See: IF ELSE core control-flow special-token +DO Runtime: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
Begin counted loop. n2 is initial index, n1 is limit. Executes body at least once even if limit=index (use ?DO to skip).
10 0 DO I . LOOP \ prints 0 1 2 ... 9
WAFER: Special token. Compiles to IR DoLoop{body, is_plus:false}. Loop params on return stack.
See: LOOP +LOOP I J ?DO LEAVE UNLOOP core control-flow special-token +LOOP Runtime: ( -- ) ( R: loop-sys -- )
Increment index by 1. If index crosses the limit boundary, exit loop; otherwise branch to DO.
WAFER: Special token. End of DoLoop IR block.
See: DO +LOOP core control-flow special-token ++LOOP Runtime: ( n -- ) ( R: loop-sys -- )
Add n to index. Exits when index crosses limit boundary. Works with negative increments for counting down.
100 0 DO I . 10 +LOOP \ 0 10 20 ... 90
0 10 DO I . -1 +LOOP \ 10 9 8 ... 0
WAFER: Special token. Compiles DoLoop{is_plus:true}.
See: DO LOOP core control-flow special-token +I ( -- n ) ( R: loop-sys -- loop-sys )
Current loop index. Same as R@ inside DO…LOOP. Zero overhead — reads return stack directly.
5 0 DO I . LOOP \ 0 1 2 3 4
WAFER: IR [RFetch] (alias of R@).
See: J R@ LEAVE core control-flow ir-primitive +J ( -- n ) ( R: loop-sys1 loop-sys2 -- loop-sys1 loop-sys2 )
Outer loop index in nested DO loops. Accesses third item on return stack.
3 0 DO 3 0 DO I J * . LOOP LOOP
WAFER: Host function. Peeks 3 cells deep into return stack.
See: I core control-flow host-function +UNLOOP ( -- ) ( R: loop-sys -- )
Discard loop parameters from return stack. Required before EXIT inside a DO loop, otherwise return stack is corrupted.
: FIND-FIRST 10 0 DO I 5 = IF I UNLOOP EXIT THEN LOOP -1 ;
WAFER: IR [UnloopOp]. Drops 3 return stack cells (index, limit, leave-addr).
See: LEAVE EXIT core control-flow ir-primitive +LEAVE ( -- ) ( R: loop-sys -- )
Exit DO loop immediately. Execution continues after LOOP/+LOOP.
100 0 DO I 50 > IF LEAVE THEN LOOP
WAFER: Host function. Sets index = limit to force loop exit.
See: UNLOOP EXIT core control-flow host-function +BEGIN Compilation: ( -- dest )
Mark loop beginning. Used with UNTIL, WHILE/REPEAT, or AGAIN.
WAFER: Special token. Marks start of IR loop block.
See: UNTIL WHILE REPEAT AGAIN core control-flow special-token +UNTIL Runtime: ( x -- )
Loop back to BEGIN if false. Exit when true. Post-test loop (body executes at least once).
BEGIN DUP . 1- DUP 0= UNTIL DROP
WAFER: Special token. Compiles to IR BeginUntil{body}.
See: BEGIN WHILE REPEAT core control-flow special-token +WHILE Runtime: ( x -- )
Test condition mid-loop. If false, exit to after REPEAT. Pre-test when placed at start of loop body.
BEGIN DUP WHILE DUP . 1- REPEAT DROP
WAFER: Special token. Part of IR BeginWhileRepeat{test, body}.
See: BEGIN REPEAT UNTIL core control-flow special-token +REPEAT Compilation: ( -- )
Unconditional branch back to BEGIN. Loop continues at the WHILE test.
WAFER: Special token.
See: BEGIN WHILE core control-flow special-token +RECURSE Compilation: ( -- )
Compile a call to the currently-being-defined word. Because the word is HIDDEN during compilation, you can't use its name.
: FACTORIAL DUP 1 > IF DUP 1- RECURSE * ELSE DROP 1 THEN ;
WAFER: Special token. Emits IR Call(current_word_id). Eligible for tail-call optimization when last operation.
See: EXIT core control-flow special-token +EXIT ( -- )
Return from current word immediately. Inside DO loops, UNLOOP first! After EXIT, remaining code in the word is dead.
WAFER: Special token. Compiles IR Exit. DCE removes code after unconditional EXIT.
See: RECURSE UNLOOP ; LEAVE core control-flow special-token +: (colon) ( C: "<spaces>name" -- colon-sys )
Begin new word definition. Enters compile mode. The word is HIDDEN until ; reveals it.
: SQUARE DUP * ;
WAFER: Special token. Creates dictionary entry (HIDDEN), switches to compile mode, allocates new WordId.
See: ; :NONAME IMMEDIATE core defining special-token +; (semicolon) Compilation: ( colon-sys -- )
End word definition. Compiles EXIT, optimizes IR, generates WASM module, reveals word, returns to interpret mode.
WAFER: Special token. Triggers full pipeline: IR → optimize → codegen → wasmtime instantiate → reveal.
See: : EXIT core defining special-token +VARIABLE ( "<spaces>name" -- )
Create word that pushes address of a cell. Initialized to 0 in WAFER. Usage: VARIABLE X 42 X ! X @ .
WAFER: Special token. Allocates 4 bytes in user data space (starts at 0x10000). Word pushes the address.
See: CONSTANT VALUE CREATE 2VARIABLE core defining special-token +CONSTANT ( x "<spaces>name" -- )
Create word that pushes x. Immutable after creation — use VALUE if you need mutability.
42 CONSTANT ANSWER ANSWER . \ 42
WAFER: Special token. Compiled as IR PushI32(x). Inlined by optimizer.
See: VARIABLE VALUE 2CONSTANT FCONSTANT core defining special-token +CREATE ( "<spaces>name" -- )
Create a word that pushes the address of its data field. Foundation for all defining words. Use with DOES> for custom defining words.
CREATE TABLE 10 , 20 , 30 ,
TABLE 2 CELLS + @ . \ 30
WAFER: Special token. Allocates dictionary header, word pushes parameter field address.
See: DOES> ALLOT , VARIABLE core defining special-token +DOES> ( -- a-addr )
Define runtime behavior for words created by the enclosing defining word. Code after DOES> runs when a CREATE'd word executes, with the data address on stack.
: ARRAY CREATE CELLS ALLOT DOES> SWAP CELLS + ;
5 ARRAY X 42 3 X ! 3 X @ . \ 42
WAFER: Special token + host function (_DOES_PATCH_). Patches the child word's code field to run the DOES> body. Supports double-DOES>.
See: CREATE core defining special-token +IMMEDIATE ( -- )
Mark most recently defined word as immediate. Immediate words execute during compilation instead of being compiled. Used for compile-time computation and syntax extensions.
: [MOD] MOD ; IMMEDIATE
WAFER: Host function. Sets IMMEDIATE flag (0x80) in dictionary entry.
See: POSTPONE [ ] core defining host-function +. (dot) ( n -- )
Print signed integer followed by a space. Uses current BASE.
42 . \ prints "42 "
HEX 255 . \ prints "FF "
WAFER: Host function. Formats via Rust, appends to output buffer.
See: U. .R D. F. core io host-function +U. ( u -- )
Print unsigned integer followed by a space. Critical difference from . for values > MAX-INT.
-1 U. \ prints "4294967295 " (on 32-bit)
WAFER: Host function.
See: . U.R core io host-function +EMIT ( x -- )
Output character with code x. Low 8 bits used.
65 EMIT \ prints 'A'
: STARS 0 DO 42 EMIT LOOP ;
WAFER: IR [Emit]. Compiles to host call for output.
See: TYPE CR KEY core io ir-primitive +CR ( -- )
Output newline character.
WAFER: IR [Cr].
See: EMIT SPACE core io ir-primitive +SPACE ( -- )
Output single space (BL EMIT).
WAFER: IR [PushI32(32), Emit].
See: SPACES BL CR core io ir-primitive +SPACES ( n -- )
Output n spaces. If n ≤ 0, does nothing.
WAFER: Host function. Loop of EMIT(32).
See: SPACE core io host-function +TYPE ( c-addr u -- )
Output u characters starting at c-addr.
S" Hello" TYPE \ prints Hello
WAFER: IR [Type] / Host function.
See: EMIT ." S" core io host-function +." (dot-quote) Compilation: ( "ccc<quote>" -- )
Runtime: ( -- )

Compile and display string literal. In interpret mode, displays immediately.
: GREET ." Hello, World!" CR ;
WAFER: Special token. In compile mode, stores string in data space and compiles Type IR. In interpret mode, outputs immediately.
See: S" TYPE core io special-token +S" (s-quote) Compilation: ( "ccc<quote>" -- )
Runtime: ( -- c-addr u )

String literal. Pushes address and length. In interpret mode, string is transient (valid until next S" or buffer reuse).
S" Hello" TYPE
WAFER: Special token. Compile mode: stores in data space, compiles PushI32 pair. Interpret mode: stores at HERE temporarily.
See: ." S\" C" SLITERAL core io special-token +ACCEPT ( c-addr +n1 -- +n2 )
Read up to n1 characters into buffer at c-addr. Returns actual count n2. Implementation-defined line editing.
WAFER: Host function. Reads from input source.
See: KEY REFILL SOURCE core io host-function +KEY ( -- char )
Receive one character. Blocks until available. No echo.
WAFER: Host function.
See: KEY? ACCEPT EMIT core io host-function +.R ( n1 n2 -- )
Print n1 right-justified in field of n2 characters. Uses current BASE.
42 10 .R \ prints " 42"
WAFER: Host function.
See: . U.R D.R core-ext io host-function +CHAR ( "<spaces>name" -- char )
Parse word and push ASCII value of first character. Interpretation-time only.
CHAR A . \ 65
WAFER: Special token (interpret mode).
See: [CHAR] BL core parsing special-token +[CHAR] Compilation: ( "<spaces>name" -- )
Compile character literal. Immediate word — executes during compilation to push ASCII code.
: EMIT-A [CHAR] A EMIT ;
WAFER: Special token. Compiles IR PushI32(char_code).
See: CHAR LITERAL core parsing special-token +WORD ( char "<chars>ccc<char>" -- c-addr )
Parse using delimiter char. Returns counted string at HERE. Obsolescent — prefer PARSE-NAME.
CHAR | WORD COUNT TYPE \ parses until |
WAFER: Host function. Stores counted string at HERE.
See: PARSE PARSE-NAME FIND core parsing host-function +FIND ( c-addr -- c-addr 0 | xt 1 | xt -1 )
Search dictionary for counted string. Returns xt and 1 (immediate) or -1 (normal), or original addr and 0 if not found.
WAFER: Host function. Uses hash index for O(1) lookup.
See: ' WORD SEARCH-WORDLIST core parsing host-function +COUNT ( c-addr -- c-addr+1 u )
Convert counted string to addr-length pair. First byte is length.
WAFER: Host function.
See: WORD S" core parsing host-function +>NUMBER ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
Accumulate digits from string into double ud. Stops at first non-digit. u2=0 means entire string consumed.
0. S" 123" >NUMBER 2DROP D. \ 123
WAFER: Host function. Respects current BASE.
See: BASE core parsing host-function +EXECUTE ( i*x xt -- j*x )
Execute the word identified by execution token xt. Foundation for callbacks, dispatch tables, and deferred execution.
' DUP EXECUTE \ same as DUP
WAFER: IR [Execute]. Compiles to WASM call_indirect. The function table index is the xt.
See: ' ['] DEFER COMPILE, core compilation ir-primitive +' (tick) ( "<spaces>name" -- xt )
Parse word name and return its execution token. Interpretation-time only — use ['] in compile mode. Throws -13 if word not found.
' DUP EXECUTE \ executes DUP
WAFER: Host function. xt = function table index (WordId).
See: ['] EXECUTE >BODY FIND core compilation host-function +['] (bracket-tick) Compilation: ( "<spaces>name" -- )
Compile xt of next word as a literal. Immediate. Use inside definitions where ' would execute at compile time.
: DO-DUP ['] DUP EXECUTE ;
WAFER: Special token. Compiles IR PushI32(xt).
See: ' LITERAL POSTPONE core compilation special-token +>BODY ( xt -- a-addr )
Convert execution token to data-field address. Only valid for CREATE'd words. Result undefined for : definitions.
CREATE X 42 , ' X >BODY @ . \ 42
WAFER: Host function. Reads parameter field address from dictionary entry.
See: CREATE ' EXECUTE core compilation host-function +LITERAL Compilation: ( x -- )
Runtime: ( -- x )

Compile TOS as a literal. Immediate. Used in macros and [ ] sequences.
: CACHE-SIZE [ 64 1024 * ] LITERAL ;
WAFER: Special token. Compiles IR PushI32(x). Constant folding may further optimize.
See: 2LITERAL FLITERAL SLITERAL ['] core compilation special-token +POSTPONE Compilation: ( "<spaces>name" -- )
Defer compilation of next word. For immediate words: compiles their code. For non-immediate: compiles code that will compile them. The key mechanism for writing compile-time words.
: MY-IF POSTPONE IF ; IMMEDIATE
: [+] POSTPONE + ; IMMEDIATE
WAFER: Special token. Emits IR for immediate words directly; for non-immediate, emits LITERAL(xt) + COMPILE, sequence.
See: IMMEDIATE COMPILE, [COMPILE] core compilation special-token +[ (left-bracket) ( -- )
Switch to interpret mode during compilation. Lets you compute values at compile time.
: X [ 6 7 * ] LITERAL ; X . \ 42
WAFER: Special token. Sets STATE to 0. Immediate.
See: ] LITERAL STATE core compilation special-token +] (right-bracket) ( -- )
Switch to compile mode.
WAFER: Special token. Sets STATE to -1.
See: [ STATE core compilation special-token +EVALUATE ( i*x c-addr u -- j*x )
Interpret/compile the string as Forth source. Saves and restores input source specification. Powerful but dangerous — runtime code generation.
S" 2 3 +" EVALUATE . \ 5
WAFER: Host function. Recursively calls outer interpreter on the string.
See: SOURCE >IN core compilation host-function +ABORT ( i*x -- ) ( R: j*x -- )
Clear stacks and return to outer interpreter. Equivalent to -1 THROW.
WAFER: Host function.
See: ABORT" THROW QUIT core compilation host-function +ABORT" Compilation: ( "ccc<quote>" -- )
Runtime: ( i*x x -- | i*x )

If x is non-zero, display string and abort. Conditional abort with message.
: CHECK DUP 0< ABORT" negative!" ;
WAFER: Special token. Compiles as IF + string + ABORT sequence.
See: ABORT THROW core compilation special-token +QUIT ( -- )
Clear return stack, set interpret mode, enter outer interpreter loop. Does not clear data stack (unlike ABORT).
WAFER: Host function.
See: ABORT BYE core compilation host-function +STATE ( -- a-addr )
Address of compilation state flag. 0 = interpreting, non-zero = compiling. Do NOT use STATE to write mode-dependent words — use POSTPONE instead.
WAFER: IR primitive. Returns address of system variable at offset 0x00.
See: [ ] POSTPONE core compilation ir-primitive +BASE ( -- a-addr )
Address of current number base. Default 10 (decimal). Valid range 2-36.
HEX BASE @ . \ 10 (printed in hex = 16)
WAFER: IR primitive. System variable at offset 0x04.
See: DECIMAL HEX core compilation ir-primitive +>IN ( -- a-addr )
Address of input parse position. Offset into current input buffer. Manipulating >IN allows re-parsing (e.g., for POSTPONE).
WAFER: IR primitive. System variable at offset 0x08.
See: SOURCE WORD PARSE core compilation ir-primitive +SOURCE ( -- c-addr u )
Current input source buffer and length.
WAFER: Host function. Returns input buffer address and length.
See: >IN EVALUATE REFILL core compilation host-function +DECIMAL ( -- )
Set BASE to 10.
WAFER: Host function. Stores 10 to BASE variable.
See: HEX BASE core compilation host-function +BL ( -- char )
Push space character (32).
BL EMIT \ same as SPACE
WAFER: IR [PushI32(32)].
See: SPACE CHAR core compilation ir-primitive +TRUE ( -- true )
Well-formed true flag: -1 (all bits set). Any non-zero is logically true, but only -1 is canonical TRUE.
WAFER: IR [PushI32(-1)].
See: FALSE 0= AND OR core compilation ir-primitive +FALSE ( -- false )
Canonical false flag: 0.
WAFER: IR [PushI32(0)].
See: TRUE 0= core compilation ir-primitive +ENVIRONMENT? ( c-addr u -- false | i*x true )
Query implementation environment. Returns info about system capabilities.
S" MAX-N" ENVIRONMENT? IF . THEN
WAFER: Host function. Supports queries like MAX-N, MAX-U, ADDRESS-UNIT-BITS, STACK-CELLS, RETURN-STACK-CELLS. core compilation host-function +<# ( -- )
Begin pictured numeric output. Initializes the output buffer (grows right to left from PAD end).
: U. 0 <# #S #> TYPE SPACE ;
WAFER: Host function. Sets HLD pointer to end of PAD area.
See: # #S #> HOLD SIGN core pictured-numeric host-function +# (number-sign) ( ud1 -- ud2 )
Convert one digit of ud, prepend to pictured output. Divides ud by BASE, converts remainder to ASCII digit.
0 42 <# # # #> TYPE \ "42"
WAFER: Host function. Uses UM/MOD internally.
See: #S <# #> core pictured-numeric host-function +#S ( ud -- 0 0 )
Convert all remaining digits. Calls # repeatedly until ud is zero. Always generates at least one digit.
0 0 <# #S #> TYPE \ "0"
WAFER: Host function.
See: # <# #> core pictured-numeric host-function +#> ( xd -- c-addr u )
End pictured output. Drops the double number, returns buffer address and length. Buffer is transient.
WAFER: Host function.
See: <# # #S TYPE core pictured-numeric host-function +HOLD ( char -- )
Prepend character to pictured output. Used between <# and #> for custom formatting (decimal points, separators).
: D. TUCK DABS <# #S ROT SIGN #> TYPE SPACE ;
WAFER: Host function.
See: HOLDS SIGN <# core pictured-numeric host-function +SIGN ( n -- )
If n is negative, prepend '-' to pictured output. Must be called after #S (since output builds right to left, sign goes last).
WAFER: Host function.
See: HOLD <# #S core pictured-numeric host-function +NIP ( x1 x2 -- x2 )
Remove second item. Equivalent to SWAP DROP. Cleans up after you've extracted what you need from NOS.
/MOD NIP \ keep only quotient
WAFER: IR [Nip]. Peephole target: SWAP DROP → NIP.
See: DROP TUCK core-ext stack ir-primitive +TUCK ( x1 x2 -- x2 x1 x2 )
Copy TOS below second item. Equivalent to SWAP OVER. Useful when you need to save TOS before a consuming operation.
: !+ TUCK ! CELL+ ; \ store and advance
WAFER: IR [Tuck]. Peephole target: SWAP OVER → TUCK.
See: NIP OVER core-ext stack ir-primitive +0<> ( x -- flag )
True if not zero. Logical identity for non-canonical flags: normalizes any non-zero to TRUE.
42 0<> . \ -1
WAFER: IR [ZeroEq, ZeroEq] (double negate). Normalizes to well-formed flag.
See: 0= <> core-ext comparison ir-primitive +0> ( n -- flag )
True if strictly positive (greater than zero).
1 0> . \ -1
0 0> . \ 0
WAFER: IR [PushI32(0), Gt].
See: 0< 0= 0<> core-ext comparison ir-primitive +<> ( x1 x2 -- flag )
True if not equal. Complement of =.
WAFER: IR [NotEq].
See: = 0<> core-ext comparison ir-primitive +U> ( u1 u2 -- flag )
Unsigned greater-than.
WAFER: IR [LtUnsigned with swapped operands] or host function.
See: U< > core-ext comparison +2>R ( x1 x2 -- ) ( R: -- x1 x2 )
Push cell pair to return stack. Useful for saving double-cell values.
WAFER: IR [TwoToR].
See: 2R> 2R@ >R core-ext return-stack ir-primitive +2R> ( -- x1 x2 ) ( R: x1 x2 -- )
Pop cell pair from return stack.
WAFER: IR [TwoFromR].
See: 2>R 2R@ R> core-ext return-stack ir-primitive +2R@ ( -- x1 x2 ) ( R: x1 x2 -- x1 x2 )
Copy cell pair from return stack.
WAFER: IR [TwoRFetch].
See: 2>R 2R> R@ core-ext return-stack ir-primitive +VALUE ( x "<spaces>name" -- )
Create word that pushes x. Unlike CONSTANT, can be changed with TO. Cleaner than VARIABLE for simple storage.
42 VALUE ANSWER ANSWER . \ 42
99 TO ANSWER ANSWER . \ 99
WAFER: Special token. Stores in data space; TO modifies the stored value.
See: TO CONSTANT VARIABLE 2VALUE FVALUE core-ext defining special-token +TO Interpretation: ( x "<spaces>name" -- )
Compilation: ( "<spaces>name" -- )

Change a VALUE. Works at both interpret and compile time.
99 TO MY-VALUE
WAFER: Special token. Compiles store to VALUE's data address.
See: VALUE 2VALUE FVALUE core-ext defining special-token +DEFER ( "<spaces>name" -- )
Create word with deferred execution. Initially calls ABORT. Set with DEFER! or IS. Enables late binding and forward references.
DEFER GREET : SAY-HI ." Hi!" ; ' SAY-HI IS GREET
WAFER: Special token. Word calls through a stored xt.
See: DEFER! DEFER@ IS ACTION-OF core-ext defining special-token +DEFER! ( xt2 xt1 -- )
Store xt2 as the behavior of deferred word xt1.
' NEW-BEHAVIOR ' MY-DEFER DEFER!
WAFER: Host function.
See: DEFER DEFER@ IS core-ext defining host-function +DEFER@ ( xt1 -- xt2 )
Fetch the current xt stored in deferred word xt1.
WAFER: Host function.
See: DEFER DEFER! ACTION-OF core-ext defining host-function +IS Interpretation: ( xt "<spaces>name" -- )
Compilation: ( "<spaces>name" -- )

Set DEFER'd word or VALUE. Syntactic sugar for DEFER! with name lookup.
' NEW-IMPL IS MY-DEFER
WAFER: Special token. Resolves name, calls DEFER!.
See: DEFER TO ACTION-OF core-ext defining special-token +ACTION-OF Interpretation: ( "<spaces>name" -- xt )
Compilation: ( "<spaces>name" -- )

Get the xt currently assigned to a DEFER'd word. Compile-time: compiles code to push it at runtime.
WAFER: Special token.
See: DEFER@ IS core-ext defining special-token +?DO Runtime: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
Like DO but skips body if limit=index. Compiles as IF check + DO. Always prefer ?DO unless you know limit ≠ index.
: STARS 0 ?DO [CHAR] * EMIT LOOP ; \ 0 STARS does nothing
WAFER: Special token. Compiles as 2DUP = IF 2DROP ELSE DO ... LOOP THEN.
See: DO LOOP +LOOP core-ext control-flow special-token +AGAIN Compilation: ( -- )
Unconditional loop back to BEGIN. Infinite loop — exit with LEAVE, EXIT, or THROW.
: FOREVER BEGIN ." loop " AGAIN ; \ never returns
WAFER: Special token. Compiles to IR BeginAgain{body}.
See: BEGIN UNTIL WHILE core-ext control-flow special-token +CASE Compilation: ( -- case-sys )
Begin CASE structure. Multi-way conditional — Forth's switch statement.
: CHECK CASE
1 OF ." one" ENDOF
2 OF ." two" ENDOF
." other"
ENDCASE ;
WAFER: Special token. Compiles to nested IF/ELSE/THEN.
See: OF ENDOF ENDCASE core-ext control-flow special-token +OF Runtime: ( x1 x2 -- | x1 )
Compare TOS to case value. If equal, drop both and execute clause. If not, keep x1 and skip to ENDOF.
WAFER: Special token.
See: CASE ENDOF ENDCASE core-ext control-flow special-token +ENDOF Compilation: ( case-sys -- case-sys )
End an OF clause. Branches to after ENDCASE.
WAFER: Special token.
See: OF CASE ENDCASE core-ext control-flow special-token +ENDCASE Runtime: ( x -- )
End CASE structure. Drops the selector value.
WAFER: Special token.
See: CASE OF ENDOF core-ext control-flow special-token +PAD ( -- c-addr )
Address of transient scratch buffer (256 bytes in WAFER). Separate from dictionary and stacks. Used for string formatting.
WAFER: IR [PushI32(0x0440)]. Address is a compile-time constant.
See: HERE <# S" core-ext memory-ops ir-primitive +ERASE ( addr u -- )
Fill u bytes with zero. Equivalent to 0 FILL.
WAFER: Host function.
See: FILL BLANK core-ext memory-ops host-function +MARKER ( "<spaces>name" -- )
Create a snapshot. Executing the marker word restores dictionary to the state before the marker was created. Useful for development: redefine everything by calling the marker first.
MARKER CLEAN : FOO ." test" ; CLEAN \ FOO is forgotten
WAFER: Host function. Saves HERE and LATEST, restores on execution.
See: ALLOT HERE core-ext defining host-function +BUFFER: ( u "<spaces>name" -- )
Create word that pushes address of u-byte buffer. Like CREATE n ALLOT but more portable.
256 BUFFER: LINE-BUF
WAFER: Special token.
See: CREATE ALLOT VARIABLE core-ext defining special-token +:NONAME ( -- xt )
Begin anonymous word definition. Returns execution token. No dictionary entry created.
:NONAME DUP * ; CONSTANT SQUARE-XT
5 SQUARE-XT EXECUTE . \ 25
WAFER: Special token. Allocates WordId but no dictionary header.
See: : DEFER EXECUTE core-ext defining special-token +COMPILE, ( xt -- )
Append call to xt to current definition. Runtime compilation. Used by POSTPONE for non-immediate words.
WAFER: Host function. Appends IR Call(word_id) to compiling_ir.
See: POSTPONE LITERAL EXECUTE core-ext compilation host-function +C" Compilation: ( "ccc<quote>" -- )
Runtime: ( -- c-addr )

Counted string literal. First byte is length, followed by characters. Max 255 chars.
WAFER: Special token.
See: S" COUNT core-ext io special-token +S\" (s-backslash-quote) Compilation: ( "ccc<quote>" -- )
Runtime: ( -- c-addr u )

String literal with escape sequences: \n (newline), \t (tab), \\ (backslash), \" (quote), \0 (null), \x41 (hex byte).
S\" Hello\nWorld" TYPE
WAFER: Special token. Parses escape sequences at compile time.
See: S" core-ext io special-token +.( (dot-paren) ( "ccc<paren>" -- )
Display string immediately (delimited by closing paren). Immediate — works in both modes. Useful for compile-time messages.
.( Compiling... )
WAFER: Special token.
See: ." TYPE core-ext io special-token +\ (backslash) ( -- )
Line comment — skip rest of input line. Immediate.
: FOO DUP * ; \ this is a comment
WAFER: Special token. Sets >IN to end of input buffer.
See: ( core-ext parsing special-token +( (paren) ( "ccc<paren>" -- )
Block comment — skip until closing paren. Immediate. Can span multiple lines (if input provides them). Convention: stack comments in parentheses.
: FOO ( n -- n*n ) DUP * ;
WAFER: Special token.
See: \ core parsing special-token +PARSE ( char "ccc<char>" -- c-addr u )
Parse input delimited by char. Does not skip leading delimiters (unlike WORD). Returns pointer into input buffer.
WAFER: Host function.
See: PARSE-NAME WORD core-ext parsing host-function +PARSE-NAME ( "<spaces>name" -- c-addr u )
Parse whitespace-delimited name. Skips leading whitespace. Preferred over WORD for modern Forth.
WAFER: Host function.
See: PARSE WORD core-ext parsing host-function +REFILL ( -- flag )
Attempt to refill the input buffer. Returns TRUE if successful. Returns FALSE for string input (EVALUATE).
WAFER: Host function.
See: SOURCE EVALUATE core-ext parsing host-function +HOLDS ( c-addr u -- )
Prepend string to pictured numeric output. Like HOLD but for multiple characters at once.
WAFER: Host function.
See: HOLD <# #> core-ext pictured-numeric host-function +HEX ( -- )
Set BASE to 16.
HEX FF . \ 255 (in hex output: FF)
WAFER: Host function.
See: DECIMAL BASE core-ext compilation host-function +UNUSED ( -- u )
Number of address units remaining in data space.
WAFER: Host function.
See: HERE ALLOT core-ext memory-ops host-function +SOURCE-ID ( -- 0 | -1 )
Input source identifier: 0 for user input, -1 for EVALUATE string.
WAFER: Host function.
See: SOURCE EVALUATE core-ext compilation host-function +[COMPILE] Compilation: ( "<spaces>name" -- )
Obsolescent. Compile the immediately-following word even if it's immediate. Replaced by POSTPONE in modern Forth.
Not recommended. Use POSTPONE instead.
See: POSTPONE core-ext compilation +2CONSTANT ( x1 x2 "<spaces>name" -- )
Create word that pushes double-cell constant.
1000000. 2CONSTANT BIG
WAFER: Special token.
See: CONSTANT 2VARIABLE DCONSTANT core-ext defining special-token +2VARIABLE ( "<spaces>name" -- )
Create word that pushes address of double-cell variable.
WAFER: Special token. Allocates 8 bytes.
See: VARIABLE 2CONSTANT core-ext defining special-token +2VALUE ( x1 x2 "<spaces>name" -- )
Create word that pushes double-cell value. Change with TO.
WAFER: Special token.
See: VALUE 2CONSTANT TO double-ext defining special-token +2LITERAL Compilation: ( x1 x2 -- )
Runtime: ( -- x1 x2 )

Compile double-cell literal. Immediate.
WAFER: Special token. Compiles two IR PushI32 ops.
See: LITERAL FLITERAL double compilation special-token +D+ ( d1 d2 -- d3 )
Double-cell addition. Handles carry between low and high cells.
1. 2. D+ D. \ 3
WAFER: Host function. Uses Rust i64 arithmetic.
See: D- + M+ double arithmetic host-function +D- ( d1 d2 -- d3 )
Double-cell subtraction.
WAFER: Host function.
See: D+ - DNEGATE double arithmetic host-function +D. ( d -- )
Print signed double-cell number followed by space.
-1. D. \ -1
WAFER: Host function.
See: D.R . U. double io host-function +D.R ( d n -- )
Print double-cell number right-justified in n-character field.
WAFER: Host function.
See: D. .R double io host-function +D0= ( d -- flag )
True if double is zero. Both cells must be zero.
WAFER: Host function.
See: D0< 0= D= double comparison host-function +D0< ( d -- flag )
True if double is negative. Tests sign bit of high cell.
WAFER: Host function.
See: D0= 0< double comparison host-function +D= ( d1 d2 -- flag )
True if two doubles are equal.
WAFER: Host function.
See: D< = D0= double comparison host-function +D< ( d1 d2 -- flag )
Signed double less-than.
WAFER: Host function.
See: D= DU< < double comparison host-function +DU< ( ud1 ud2 -- flag )
Unsigned double less-than.
WAFER: Host function.
See: D< U< double comparison host-function +DNEGATE ( d -- -d )
Negate double-cell number. Two's complement across both cells.
WAFER: Host function.
See: NEGATE DABS double arithmetic host-function +DABS ( d -- ud )
Double-cell absolute value.
WAFER: Host function.
See: DNEGATE ABS double arithmetic host-function +D2* ( d -- d*2 )
Double-cell left shift by 1. Shifts carry between cells.
WAFER: Host function.
See: D2/ 2* double arithmetic host-function +D2/ ( d -- d/2 )
Double-cell arithmetic right shift by 1. Preserves sign.
WAFER: Host function.
See: D2* 2/ double arithmetic host-function +DMAX ( d1 d2 -- d3 )
Signed double-cell maximum.
WAFER: Host function.
See: DMIN MAX double arithmetic host-function +DMIN ( d1 d2 -- d3 )
Signed double-cell minimum.
WAFER: Host function.
See: DMAX MIN double arithmetic host-function +D>S ( d -- n )
Convert double to single by dropping high cell. Result is undefined if d doesn't fit in a single cell.
WAFER: IR primitive. Just drops the high cell.
See: S>D double-ext conversion ir-primitive +M+ ( d n -- d' )
Add single-cell to double-cell.
WAFER: Host function. Sign-extends n, then D+.
See: D+ + double arithmetic host-function +M*/ ( d1 n1 +n2 -- d2 )
Multiply double d1 by n1, divide by +n2. Triple-cell intermediate avoids overflow. n2 must be positive.
WAFER: Host function. Uses Rust i128 intermediate.
See: */ M* double arithmetic host-function +2ROT ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
Rotate third cell pair to top. The double-width version of ROT.
WAFER: Host function.
See: ROT 2SWAP 2OVER double stack host-function +CATCH ( i*x xt -- j*x 0 | i*x n )
Execute xt, catching any THROW. Returns 0 if no exception, or the throw code n. Saves and restores stacks on exception.
: SAFE ['] RISKY CATCH IF ." error!" THEN ;
WAFER: Host function. Saves DSP/RSP/FSP. Nested CATCH supported.
See: THROW ABORT exception control-flow host-function +THROW ( k*x n -- k*x | i*x n )
Throw exception n. If n=0, does nothing. If no matching CATCH, behaves as ABORT. Standard codes: -1 ABORT, -2 ABORT", -4 stack underflow, -13 undefined word.
: CHECK DUP 0< IF -24 THROW THEN ;
WAFER: Host function. Unwinds to nearest CATCH, restoring stacks.
See: CATCH ABORT ABORT" exception control-flow host-function +COMPARE ( c-addr1 u1 c-addr2 u2 -- n )
Compare two strings. Returns 0 if equal, -1 if first is less, +1 if first is greater. Lexicographic, case-sensitive.
S" ABC" S" ABD" COMPARE . \ -1
WAFER: Host function.
See: SEARCH S= string comparison host-function +SEARCH ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
Search string1 for string2. If found: c-addr3 points to match, flag=true. If not: original string1, flag=false.
S" Hello World" S" World" SEARCH . TYPE \ -1 World
WAFER: Host function.
See: COMPARE /STRING string parsing host-function +/STRING ( c-addr u n -- c-addr' u' )
Advance string by n characters. Adds n to c-addr, subtracts n from u.
S" Hello" 2 /STRING TYPE \ llo
WAFER: Host function.
See: SEARCH -TRAILING string memory-ops host-function +BLANK ( c-addr u -- )
Fill u bytes with spaces (BL). Equivalent to BL FILL.
WAFER: Host function.
See: FILL ERASE string memory-ops host-function +-TRAILING ( c-addr u1 -- c-addr u2 )
Remove trailing spaces. Adjusts length; address unchanged.
S" hello " -TRAILING TYPE . \ "hello" 5
WAFER: Host function.
See: /STRING BLANK string parsing host-function +CMOVE ( c-addr1 c-addr2 u -- )
Copy u bytes from addr1 to addr2, low address to high. Use when destination is lower than source (or non-overlapping).
WAFER: Host function.
See: CMOVE> MOVE string memory-ops host-function +CMOVE> ( c-addr1 c-addr2 u -- )
Copy u bytes from addr1 to addr2, high address to low. Use when destination is higher than source (overlapping).
WAFER: Host function.
See: CMOVE MOVE string memory-ops host-function +SLITERAL Compilation: ( c-addr u -- )
Runtime: ( -- c-addr u )

Compile string literal from stack. Immediate. Used in macros that produce strings at compile time.
WAFER: Special token.
See: S" LITERAL 2LITERAL string compilation special-token +FDROP ( F: r -- )
Drop top of float stack.
WAFER: Host function. Decrements FSP.
See: FDUP FSWAP DROP float stack host-function +FDUP ( F: r -- r r )
Duplicate top of float stack.
3.14e FDUP F* F. \ 9.8596 (pi squared approx)
WAFER: Host function.
See: FDROP FOVER DUP float stack host-function +FSWAP ( F: r1 r2 -- r2 r1 )
Exchange top two float stack items.
WAFER: Host function.
See: FROT FOVER SWAP float stack host-function +FOVER ( F: r1 r2 -- r1 r2 r1 )
Copy second float to top.
WAFER: Host function.
See: FDUP FSWAP OVER float stack host-function +FROT ( F: r1 r2 r3 -- r2 r3 r1 )
Rotate third float to top.
WAFER: Host function.
See: FSWAP ROT float stack host-function +FNIP ( F: r1 r2 -- r2 )
Remove second float.
WAFER: Host function.
See: FDROP NIP float stack host-function +FTUCK ( F: r1 r2 -- r2 r1 r2 )
Tuck top float below second.
WAFER: Host function.
See: FSWAP TUCK float stack host-function +FDEPTH ( -- +n )
Number of values on the float stack.
WAFER: Host function.
See: DEPTH float stack host-function +F+ ( F: r1 r2 -- r3 )
Float addition.
1.5e 2.5e F+ F. \ 4.0
WAFER: Host function. Uses f64 add.
See: F- F* D+ float arithmetic host-function +F- ( F: r1 r2 -- r3 )
Float subtraction (r1 minus r2).
WAFER: Host function.
See: F+ FNEGATE float arithmetic host-function +F* ( F: r1 r2 -- r3 )
Float multiplication.
3.0e 4.0e F* F. \ 12.0
WAFER: Host function.
See: F/ F** float arithmetic host-function +F/ ( F: r1 r2 -- r3 )
Float division. Division by zero produces ±Infinity per IEEE 754.
22.0e 7.0e F/ F. \ 3.142857
WAFER: Host function.
See: F* / float arithmetic host-function +FNEGATE ( F: r -- -r )
Negate float. Flips sign bit; works on ±0, ±Inf, NaN.
WAFER: Host function.
See: FABS NEGATE float arithmetic host-function +FABS ( F: r -- |r| )
Float absolute value.
WAFER: Host function.
See: FNEGATE ABS float arithmetic host-function +FMAX ( F: r1 r2 -- r3 )
Float maximum. NaN propagation is implementation-defined.
WAFER: Host function. Uses Rust f64::max.
See: FMIN MAX float arithmetic host-function +FMIN ( F: r1 r2 -- r3 )
Float minimum.
WAFER: Host function.
See: FMAX MIN float arithmetic host-function +FSQRT ( F: r -- r' )
Square root. Negative input produces NaN.
2.0e FSQRT F. \ 1.41421356...
WAFER: Host function. Uses Rust f64::sqrt.
See: F** FABS float-ext arithmetic host-function +FLOOR ( F: r -- r' )
Round toward negative infinity. Returns float, not integer.
3.7e FLOOR F. \ 3.0
-3.2e FLOOR F. \ -4.0
WAFER: Host function.
See: FROUND F>S float arithmetic host-function +FROUND ( F: r -- r' )
Round to nearest (banker's rounding: ties to even). Returns float.
2.5e FROUND F. \ 2.0 (ties to even)
3.5e FROUND F. \ 4.0
WAFER: Host function.
See: FLOOR F>S float arithmetic host-function +F** ( F: r1 r2 -- r3 )
Float exponentiation: r1 raised to r2.
2.0e 10.0e F** F. \ 1024.0
WAFER: Host function. Uses Rust f64::powf.
See: FSQRT FEXP float-ext arithmetic host-function +F0= ( F: r -- ) ( -- flag )
True if float is zero (positive or negative zero).
WAFER: Host function.
See: F0< F= 0= float comparison host-function +F0< ( F: r -- ) ( -- flag )
True if float is negative. Negative zero returns false.
WAFER: Host function.
See: F0= 0< float comparison host-function +F= ( F: r1 r2 -- ) ( -- flag )
True if floats are exactly equal. Beware: floating-point comparison with == is usually wrong. Prefer F~ for approximate comparison.
WAFER: Host function.
See: F~ F< = float comparison host-function +F< ( F: r1 r2 -- ) ( -- flag )
True if r1 < r2. NaN comparisons return false.
WAFER: Host function.
See: F= < float comparison host-function +F~ ( F: r1 r2 r3 -- ) ( -- flag )
Approximate float comparison. Three modes: r3>0: |r1-r2| < r3 (absolute). r3=0: exact bitwise equality. r3<0: |r1-r2| < |r3|*(|r1|+|r2|) (relative).
1.0e 3.0e F/ 3.0e F* 1.0e 1e-15 F~ . \ -1 (close enough)
WAFER: Host function.
See: F= F0= float-ext comparison host-function +F@ ( f-addr -- ) ( F: -- r )
Fetch 64-bit float from memory to float stack.
FVARIABLE X 3.14e X F! X F@ F.
WAFER: Host function. Reads 8 bytes as f64.
See: F! @ SF@ DF@ float memory-ops host-function +F! ( f-addr -- ) ( F: r -- )
Store 64-bit float from float stack to memory.
WAFER: Host function. Writes 8 bytes.
See: F@ ! SF! DF! float memory-ops host-function +SF@ ( sf-addr -- ) ( F: -- r )
Fetch 32-bit single-precision float, widen to f64.
WAFER: Host function.
See: SF! F@ DF@ float-ext memory-ops host-function +SF! ( sf-addr -- ) ( F: r -- )
Store float as 32-bit single-precision (truncating).
WAFER: Host function.
See: SF@ F! DF! float-ext memory-ops host-function +DF@ ( df-addr -- ) ( F: -- r )
Fetch 64-bit double-precision float. Same as F@ in WAFER (native float = f64).
WAFER: Host function. Identical to F@ since WAFER floats are f64.
See: DF! F@ SF@ float-ext memory-ops host-function +DF! ( df-addr -- ) ( F: r -- )
Store 64-bit double-precision float. Same as F! in WAFER.
WAFER: Host function.
See: DF@ F! SF! float-ext memory-ops host-function +FALIGNED ( addr -- f-addr )
Align address to float boundary (8 bytes).
WAFER: Host function.
See: FALIGN ALIGNED SFALIGNED DFALIGNED float memory-ops host-function +FALIGN ( -- )
Align HERE to float boundary.
WAFER: Host function.
See: FALIGNED ALIGN float memory-ops host-function +FLOAT+ ( f-addr -- f-addr' )
Add one float size (8 bytes) to address.
WAFER: Host function.
See: FLOATS CELL+ SFLOAT+ DFLOAT+ float memory-ops host-function +FLOATS ( n -- n*float )
Convert float count to address units. Multiplies by 8.
WAFER: Host function.
See: FLOAT+ CELLS float memory-ops host-function +SFALIGNED ( addr -- sf-addr )
Align to single-float boundary (4 bytes).
WAFER: Host function.
See: SFALIGN FALIGNED float-ext memory-ops host-function +SFALIGN ( -- )
Align HERE to single-float boundary.
WAFER: Host function.
See: SFALIGNED FALIGN float-ext memory-ops host-function +SFLOAT+ ( sf-addr -- sf-addr' )
Add single-float size (4 bytes).
WAFER: Host function.
See: SFLOATS FLOAT+ float-ext memory-ops host-function +SFLOATS ( n -- n*sfloat )
Convert single-float count to address units (×4).
WAFER: Host function.
See: SFLOAT+ FLOATS float-ext memory-ops host-function +DFALIGNED ( addr -- df-addr )
Align to double-float boundary (8 bytes).
WAFER: Host function.
See: DFALIGN FALIGNED float-ext memory-ops host-function +DFALIGN ( -- )
Align HERE to double-float boundary.
WAFER: Host function.
See: DFALIGNED FALIGN float-ext memory-ops host-function +DFLOAT+ ( df-addr -- df-addr' )
Add double-float size (8 bytes).
WAFER: Host function.
See: DFLOATS FLOAT+ float-ext memory-ops host-function +DFLOATS ( n -- n*dfloat )
Convert double-float count to address units (×8).
WAFER: Host function.
See: DFLOAT+ FLOATS float-ext memory-ops host-function +D>F ( d -- ) ( F: -- r )
Convert double-cell integer to float.
1000000. D>F F. \ 1000000.0
WAFER: Host function. Combines two i32 cells → i64 → f64.
See: F>D S>F float-ext conversion host-function +F>D ( F: r -- ) ( -- d )
Convert float to double-cell integer (truncate toward zero).
3.99e F>D D. \ 3
WAFER: Host function.
See: D>F F>S float-ext conversion host-function +S>F ( n -- ) ( F: -- r )
Convert single-cell signed integer to float.
42 S>F F. \ 42.0
WAFER: Host function.
See: F>S D>F S>D float-ext conversion host-function +F>S ( F: r -- ) ( -- n )
Convert float to single-cell integer (truncate toward zero). Undefined if out of range.
3.7e F>S . \ 3
WAFER: Host function.
See: S>F F>D FLOOR float-ext conversion host-function +>FLOAT ( c-addr u -- flag ) ( F: -- r | )
Parse string as float. If successful, push float and return true. Otherwise just return false. Accepts E notation.
S" 3.14" >FLOAT . F. \ -1 3.14
WAFER: Host function. Uses Rust f64 parser.
See: >NUMBER S>F float conversion host-function +FSIN ( F: r -- r' )
Sine (radians).
3.14159265e 2.0e F/ FSIN F. \ ≈1.0
WAFER: Host function. Uses Rust f64::sin.
See: FCOS FTAN FASIN FSINCOS float-ext trig host-function +FCOS ( F: r -- r' )
Cosine (radians).
0.0e FCOS F. \ 1.0
WAFER: Host function.
See: FSIN FTAN FACOS float-ext trig host-function +FTAN ( F: r -- r' )
Tangent (radians).
WAFER: Host function.
See: FSIN FCOS FATAN float-ext trig host-function +FASIN ( F: r -- r' )
Arc sine. Input range [-1, 1], output [-π/2, π/2].
WAFER: Host function.
See: FSIN FACOS FATAN float-ext trig host-function +FACOS ( F: r -- r' )
Arc cosine. Input [-1, 1], output [0, π].
WAFER: Host function.
See: FCOS FASIN float-ext trig host-function +FATAN ( F: r -- r' )
Arc tangent. Output (-π/2, π/2).
WAFER: Host function.
See: FATAN2 FTAN float-ext trig host-function +FATAN2 ( F: r1 r2 -- r3 )
Two-argument arc tangent: atan2(r1, r2). Returns angle in (-π, π]. Handles all quadrants correctly. r1 is y, r2 is x.
1.0e 0.0e FATAN2 F. \ ≈1.5708 (π/2)
WAFER: Host function.
See: FATAN FSIN FCOS float-ext trig host-function +FSINCOS ( F: r -- r-sin r-cos )
Compute both sine and cosine. More efficient than calling FSIN and FCOS separately.
WAFER: Host function.
See: FSIN FCOS float-ext trig host-function +FEXP ( F: r -- r' )
Natural exponential e^r.
1.0e FEXP F. \ ≈2.71828
WAFER: Host function.
See: FLN FEXPM1 FALOG float-ext arithmetic host-function +FEXPM1 ( F: r -- r' )
e^r - 1. More accurate than FEXP 1.0 F- for small r (avoids catastrophic cancellation).
1e-15 FEXPM1 F. \ ≈1e-15 (not 0.0)
WAFER: Host function.
See: FEXP FLNP1 float-ext arithmetic host-function +FLN ( F: r -- r' )
Natural logarithm. Domain: r > 0.
2.71828e FLN F. \ ≈1.0
WAFER: Host function.
See: FEXP FLOG FLNP1 float-ext arithmetic host-function +FLNP1 ( F: r -- r' )
ln(1+r). More accurate than 1.0 F+ FLN for small r.
WAFER: Host function.
See: FLN FEXPM1 float-ext arithmetic host-function +FLOG ( F: r -- r' )
Base-10 logarithm.
100.0e FLOG F. \ 2.0
WAFER: Host function.
See: FALOG FLN float-ext arithmetic host-function +FALOG ( F: r -- r' )
Base-10 antilogarithm: 10^r.
3.0e FALOG F. \ 1000.0
WAFER: Host function.
See: FLOG FEXP float-ext arithmetic host-function +FSINH ( F: r -- r' )
Hyperbolic sine.
WAFER: Host function. Uses Rust f64::sinh.
See: FCOSH FTANH FASINH float-ext trig host-function +FCOSH ( F: r -- r' )
Hyperbolic cosine. Always ≥ 1.
WAFER: Host function.
See: FSINH FTANH FACOSH float-ext trig host-function +FTANH ( F: r -- r' )
Hyperbolic tangent. Output range (-1, 1).
WAFER: Host function.
See: FSINH FCOSH FATANH float-ext trig host-function +FASINH ( F: r -- r' )
Inverse hyperbolic sine.
WAFER: Host function.
See: FSINH float-ext trig host-function +FACOSH ( F: r -- r' )
Inverse hyperbolic cosine. Domain: r ≥ 1.
WAFER: Host function.
See: FCOSH float-ext trig host-function +FATANH ( F: r -- r' )
Inverse hyperbolic tangent. Domain: |r| < 1.
WAFER: Host function.
See: FTANH float-ext trig host-function +F. (f-dot) ( F: r -- )
Print float in free-format with trailing space. Precision controlled by SET-PRECISION (default 6).
3.14159e F. \ 3.14159
WAFER: Host function. Uses Rust formatting.
See: FE. FS. PRECISION float-ext io host-function +FE. ( F: r -- )
Print float in engineering notation (exponent is multiple of 3).
12345.0e FE. \ 12.345E3
WAFER: Host function.
See: F. FS. float-ext io host-function +FS. ( F: r -- )
Print float in scientific notation (one digit before decimal).
12345.0e FS. \ 1.2345E4
WAFER: Host function.
See: F. FE. float-ext io host-function +PRECISION ( -- u )
Current number of significant digits for F. FE. FS. output.
WAFER: Host function. Default 6.
See: SET-PRECISION float-ext io host-function +SET-PRECISION ( u -- )
Set number of significant digits for float output.
15 SET-PRECISION 3.14159265358979e F.
WAFER: Host function.
See: PRECISION float-ext io host-function +REPRESENT ( c-addr u -- n flag1 flag2 ) ( F: r -- )
Convert float to digit string. Low-level building block for custom float formatting. n = decimal exponent, flag1 = valid, flag2 = negative.
WAFER: Host function.
See: F. <# float io host-function +FVARIABLE ( "<spaces>name" -- )
Create float variable (8 bytes). Access with F@ and F!.
FVARIABLE PI 3.14159265e PI F!
WAFER: Special token. Allocates 8 bytes in data space.
See: FCONSTANT FVALUE VARIABLE float defining special-token +FCONSTANT ( F: r -- ) ( "<spaces>name" -- )
Create float constant.
3.14159265358979e FCONSTANT PI
WAFER: Special token.
See: FVARIABLE FVALUE CONSTANT float defining special-token +FVALUE ( F: r -- ) ( "<spaces>name" -- )
Create float value. Change with TO.
0.0e FVALUE RESULT 3.14e TO RESULT
WAFER: Special token.
See: FCONSTANT FVARIABLE VALUE TO float-ext defining special-token +FLITERAL Compilation: ( F: r -- )
Runtime: ( F: -- r )

Compile float literal. Immediate. Used for compile-time float computation.
: PI [ 355e 113e F/ ] FLITERAL ;
WAFER: Special token. Compiles IR PushF64(r).
See: LITERAL 2LITERAL float compilation special-token +AT-XY ( u1 u2 -- )
Set cursor position. u1 = column, u2 = row (0-indexed). Sends ANSI escape sequence.
0 0 AT-XY ." top-left"
WAFER: Host function (if implemented). Facility word set. facility io host-function +KEY? ( -- flag )
True if a character is available from the input device (non-blocking check).
WAFER: Host function. Facility word set.
See: KEY EKEY? facility io host-function +PAGE ( -- )
Clear screen and move cursor to top-left. Implementation-specific escape sequence.
WAFER: Host function. Facility word set.
See: AT-XY CR facility io host-function +EKEY ( -- u )
Receive keyboard event (may include function keys, arrows). Extended key — wider than CHAR range.
WAFER: Host function. Facility EXT.
See: KEY EKEY? EKEY>CHAR facility-ext io host-function +EKEY>CHAR ( u -- u false | char true )
Convert extended key to character. Returns false if key has no character representation (function key).
WAFER: Host function. Facility EXT.
See: EKEY facility-ext io host-function +EKEY? ( -- flag )
Non-blocking check for extended key availability.
WAFER: Host function. Facility EXT.
See: KEY? EKEY facility-ext io host-function +EMIT? ( -- flag )
True if the output device is ready to accept a character.
WAFER: Host function. Facility EXT.
See: EMIT KEY? facility-ext io host-function +MS ( u -- )
Wait at least u milliseconds.
1000 MS \ pause 1 second
Facility EXT. facility-ext io +BEGIN-STRUCTURE ( "<spaces>name" -- addr 0 )
Begin defining a structure type. Pushes initial offset 0.
BEGIN-STRUCTURE POINT FIELD: X FIELD: Y END-STRUCTURE
Facility EXT. Enables type-safe struct-like memory layouts.
See: END-STRUCTURE FIELD: +FIELD facility-ext defining +END-STRUCTURE ( addr n -- )
Complete structure definition. Stores total size as a constant.
POINT . \ prints structure size (8 for two cells)
Facility EXT.
See: BEGIN-STRUCTURE FIELD: facility-ext defining +FIELD: ( n1 "<spaces>name" -- n2 )
Create cell-width field. Adds CELL to offset. Created word: ( addr -- addr' ).
BEGIN-STRUCTURE COLOR FIELD: R FIELD: G FIELD: B END-STRUCTURE
Facility EXT.
See: +FIELD CFIELD: facility-ext defining ++FIELD ( n1 n2 "<spaces>name" -- n3 )
Create field of arbitrary size n2 bytes. Most general field creator.
BEGIN-STRUCTURE FOO 8 +FIELD F1 END-STRUCTURE
Facility EXT.
See: FIELD: CFIELD: facility-ext defining +CFIELD: ( n1 "<spaces>name" -- n2 )
Create single-byte field. Like FIELD: but only 1 byte wide.
Facility EXT.
See: FIELD: +FIELD facility-ext defining +{: (open-brace-colon) ( -- )
Begin local variable declaration. Forth 2012 locals syntax. Items before | are initialized from stack; items after | are uninitialized.
: QUAD {: a b c x -- res :} a x * x * b x * + c + ;
WAFER: Special token. Locals word set. Names become local variables.
See: (LOCAL) locals defining special-token +(LOCAL) ( c-addr u -- )
Low-level local variable creation. Used by {: implementation. Rarely used directly.
Locals EXT. Implementation primitive for the locals subsystem.
See: {: locals-ext defining +ALLOCATE ( u -- a-addr ior )
Allocate u bytes of memory. Returns address and I/O result (0 = success). Memory is not in dictionary space.
100 ALLOCATE THROW \ a-addr on success
WAFER: Host function. Memory-Allocation word set. Uses Rust allocator.
See: FREE RESIZE memory memory-ops host-function +FREE ( a-addr -- ior )
Free previously allocated memory. ior 0 = success.
100 ALLOCATE THROW DUP ... FREE THROW
WAFER: Host function.
See: ALLOCATE RESIZE memory memory-ops host-function +RESIZE ( a-addr u -- a-addr' ior )
Resize allocated memory block. May move the block. Like C realloc.
WAFER: Host function.
See: ALLOCATE FREE memory memory-ops host-function +.S ( -- )
Non-destructive stack display. Shows all items on data stack without consuming them. Format: <n> x1 x2 ...
1 2 3 .S \ <3> 1 2 3
WAFER: Host function. Programming-Tools word set.
See: DEPTH . tools io host-function +? (question) ( a-addr -- )
Display contents of address. Short for @ .
VARIABLE X 42 X ! X ? \ 42
Programming-Tools word set.
See: @ . tools io +DUMP ( addr u -- )
Display u bytes of memory starting at addr in hex dump format.
HERE 64 DUMP
Programming-Tools word set.
See: .S ? tools io +SEE ( "<spaces>name" -- )
Decompile/disassemble word. Shows source-level or implementation-level representation.
SEE DUP
Programming-Tools EXT.
See: WORDS ' tools-ext io +WORDS ( -- )
List all words in current search order. Implementation-defined format.
WAFER: Host function. Programming-Tools EXT.
See: SEE ORDER tools-ext io host-function +BYE ( -- )
Exit Forth system. Returns to operating system.
WAFER: Handled in CLI REPL. Programming-Tools EXT.
See: QUIT ABORT tools-ext compilation +[IF] Compilation: ( flag -- )
Conditional compilation. If flag is false, skip to [ELSE] or [THEN]. Works at compile AND interpret time. Not nestable (unlike #ifdef).
TRUE [IF] : FOO ." yes" ; [THEN]
Programming-Tools EXT. Immediate.
See: [ELSE] [THEN] [DEFINED] tools-ext compilation +[ELSE] Compilation: ( -- )
Alternative branch for [IF].
Programming-Tools EXT. Immediate.
See: [IF] [THEN] tools-ext compilation +[THEN] Compilation: ( -- )
End conditional compilation block.
Programming-Tools EXT. Immediate.
See: [IF] [ELSE] tools-ext compilation +[DEFINED] ( "<spaces>name" -- flag )
True if word is defined. Used with [IF] for conditional compilation.
[DEFINED] FSIN [IF] .( Float math available ) [THEN]
Programming-Tools EXT. Immediate.
See: [UNDEFINED] [IF] tools-ext compilation +[UNDEFINED] ( "<spaces>name" -- flag )
True if word is NOT defined. Complement of [DEFINED].
[UNDEFINED] MY-WORD [IF] : MY-WORD ." default" ; [THEN]
Programming-Tools EXT. Immediate.
See: [DEFINED] [IF] tools-ext compilation +AHEAD Compilation: ( -- orig )
Unconditional forward branch. Resolved by THEN. Used in complex control structures.
Programming-Tools EXT.
See: IF THEN tools-ext control-flow +N>R ( i*n +n -- ) ( R: -- i*n +n )
Move n items plus count to return stack. Useful for saving/restoring variable-depth stack segments.
Programming-Tools EXT.
See: NR> >R tools-ext return-stack +NR> ( -- i*n +n ) ( R: i*n +n -- )
Restore items from return stack (reverse of N>R).
Programming-Tools EXT.
See: N>R R> tools-ext return-stack +SYNONYM ( "<spaces>newname" "<spaces>oldname" -- )
Create newname as an alias for oldname.
SYNONYM THIRD 2 PICK
Programming-Tools EXT.
See: DEFER tools-ext defining +FORTH-WORDLIST ( -- wid )
Return the wordlist ID of the FORTH vocabulary.
WAFER: Host function. Search-Order word set.
See: WORDLIST GET-ORDER search-order compilation host-function +WORDLIST ( -- wid )
Create a new empty wordlist. Returns its identifier.
WAFER: Host function. Search-Order word set.
See: FORTH-WORDLIST SET-ORDER search-order defining host-function +GET-ORDER ( -- widn...wid1 n )
Get the current search order as a stack of wordlist IDs and count.
WAFER: Host function.
See: SET-ORDER ORDER search-order compilation host-function +SET-ORDER ( widn...wid1 n -- )
Set the search order. n = -1 sets default (FORTH-WORDLIST only).
WAFER: Host function.
See: GET-ORDER ALSO ONLY search-order compilation host-function +GET-CURRENT ( -- wid )
Get the compilation wordlist (where new definitions go).
WAFER: Host function.
See: SET-CURRENT DEFINITIONS search-order compilation host-function +SET-CURRENT ( wid -- )
Set the compilation wordlist.
WAFER: Host function.
See: GET-CURRENT DEFINITIONS search-order compilation host-function +SEARCH-WORDLIST ( c-addr u wid -- 0 | xt 1 | xt -1 )
Search specific wordlist. Returns same as FIND but takes wordlist ID.
WAFER: Host function.
See: FIND FORTH-WORDLIST search-order parsing host-function +DEFINITIONS ( -- )
Set compilation wordlist to first in search order. Common after ALSO to direct definitions into a specific vocabulary.
WAFER: Host function.
See: SET-CURRENT GET-ORDER search-order compilation host-function +ALSO ( -- )
Duplicate first wordlist in search order. Typically followed by a vocabulary name to add it to search order.
ALSO MY-VOCAB
WAFER: Host function. Search-Order EXT.
See: ONLY PREVIOUS FORTH search-order-ext compilation host-function +ONLY ( -- )
Set search order to minimum (implementation-defined default). Usually just FORTH-WORDLIST.
WAFER: Host function. Search-Order EXT.
See: ALSO FORTH search-order-ext compilation host-function +FORTH ( -- )
Replace first wordlist in search order with FORTH-WORDLIST.
WAFER: Host function. Search-Order EXT.
See: ONLY ALSO search-order-ext compilation host-function +PREVIOUS ( -- )
Remove first wordlist from search order (reverse of ALSO).
WAFER: Host function. Search-Order EXT.
See: ALSO search-order-ext compilation host-function +ORDER ( -- )
Display current search order and compilation wordlist.
WAFER: Host function. Search-Order EXT.
See: GET-ORDER .S search-order-ext io host-function +BIN ( fam -- fam' )
Modify file access method for binary (no line-ending translation).
S" data.bin" R/O BIN OPEN-FILE THROW
File-Access word set. WAFER: Not implemented (requires WASI).
See: R/O R/W W/O file io not-implemented +R/O ( -- fam )
Read-only file access method.
File-Access. WAFER: Not implemented.
See: R/W W/O BIN file io not-implemented +R/W ( -- fam )
Read-write file access method.
File-Access. WAFER: Not implemented.
See: R/O W/O file io not-implemented +W/O ( -- fam )
Write-only file access method.
File-Access. WAFER: Not implemented.
See: R/O R/W file io not-implemented +OPEN-FILE ( c-addr u fam -- fileid ior )
Open existing file. Returns file ID and I/O result.
S" input.txt" R/O OPEN-FILE THROW
File-Access. WAFER: Not implemented.
See: CREATE-FILE CLOSE-FILE file io not-implemented +CREATE-FILE ( c-addr u fam -- fileid ior )
Create file (or truncate existing). Returns file ID.
File-Access. WAFER: Not implemented.
See: OPEN-FILE DELETE-FILE file io not-implemented +CLOSE-FILE ( fileid -- ior )
Close file.
File-Access. WAFER: Not implemented.
See: OPEN-FILE file io not-implemented +READ-FILE ( c-addr u1 fileid -- u2 ior )
Read up to u1 characters into buffer. u2 = actual chars read.
File-Access. WAFER: Not implemented.
See: WRITE-FILE READ-LINE file io not-implemented +READ-LINE ( c-addr u1 fileid -- u2 flag ior )
Read one line. flag = true if line read successfully (false at EOF).
File-Access. WAFER: Not implemented.
See: READ-FILE WRITE-LINE file io not-implemented +WRITE-FILE ( c-addr u fileid -- ior )
Write u characters to file.
File-Access. WAFER: Not implemented.
See: READ-FILE WRITE-LINE file io not-implemented +WRITE-LINE ( c-addr u fileid -- ior )
Write characters followed by line terminator.
File-Access. WAFER: Not implemented.
See: WRITE-FILE READ-LINE file io not-implemented +DELETE-FILE ( c-addr u -- ior )
Delete named file.
File-Access. WAFER: Not implemented.
See: CREATE-FILE file io not-implemented +FILE-POSITION ( fileid -- ud ior )
Get current file position as double-cell unsigned.
File-Access. WAFER: Not implemented.
See: REPOSITION-FILE FILE-SIZE file io not-implemented +FILE-SIZE ( fileid -- ud ior )
Get file size as double-cell unsigned.
File-Access. WAFER: Not implemented.
See: FILE-POSITION file io not-implemented +REPOSITION-FILE ( ud fileid -- ior )
Set file position (seek).
File-Access. WAFER: Not implemented.
See: FILE-POSITION file io not-implemented +RESIZE-FILE ( ud fileid -- ior )
Change file size. Truncates or extends.
File-Access. WAFER: Not implemented.
See: FILE-SIZE file io not-implemented +FLUSH-FILE ( fileid -- ior )
Flush file buffers to storage.
File-Access EXT. WAFER: Not implemented.
See: CLOSE-FILE file io not-implemented +INCLUDE-FILE ( i*x fileid -- j*x )
Interpret Forth source from file. Nests: included file can include others.
File-Access. WAFER: Not implemented.
See: INCLUDED REQUIRE file compilation not-implemented +INCLUDED ( i*x c-addr u -- j*x )
Open and interpret named file. Combines OPEN-FILE and INCLUDE-FILE.
S" library.fth" INCLUDED
File-Access. WAFER: Not implemented.
See: INCLUDE-FILE REQUIRE file compilation not-implemented +REQUIRE ( i*x "name" -- j*x )
Include file only if not already included. Prevents double-loading.
REQUIRE utils.fth
File-Access EXT. WAFER: Not implemented.
See: INCLUDED REQUIRED file-ext compilation not-implemented +REQUIRED ( i*x c-addr u -- j*x )
Stack-based version of REQUIRE.
File-Access EXT. WAFER: Not implemented.
See: REQUIRE INCLUDED file-ext compilation not-implemented +What is WAFER's compilation pipeline? Forth source → Outer interpreter → Vec<IrOp> → Optimizer (6 passes) → WASM codegen (wasm-encoder) → wasmtime instantiation
Each colon definition becomes its own WASM module. The module is instantiated immediately, and its function is added to the shared function table.
: SQUARE DUP * ; \ creates entire WASM module
Key insight: no bytecode interpreter. Every word runs as native machine code via Cranelift JIT. wafer architecture +What are WAFER's two kinds of primitives? IR primitives (~80 words): Defined as Vec<IrOp>, compiled to WASM like user words. Subject to all optimizations.
Host primitives (~120+ words): Rust closures with direct memory access via wasmtime Func::new. Used for I/O, complex logic, float ops.
register_primitive("DUP", false, vec![IrOp::Dup])?; // IR
register_host_primitive(".", false, func)?; // Host
IR primitives are faster (inlined, optimized). Host functions are more flexible (full Rust power). wafer architecture +What is WAFER's memory layout? 1 MiB initial (16 pages), 16 MiB max (256 pages)
0x0000 System vars (64B): STATE, BASE, >IN, HERE, LATEST, HLD
0x0040 Input buffer (1024B)
0x0440 PAD (256B)
0x0540 Data stack (4096B) — grows ↓ from 0x1540
0x1540 Return stack (4096B) — grows ↓ from 0x2540
0x2540 Float stack (2048B) — grows ↓ from 0x2D40
0x2D40 Dictionary (variable) — grows ↑
0x10000 User data space — grows ↑
All stacks grow downward. Cell = 4 bytes. Float = 8 bytes (f64). wafer architecture +How does WAFER implement word calling? Subroutine threading via WASM function table + call_indirect.
Every word has a unique WordId = index into the shared function table. Calling a word compiles to:
(i32.const <word_id>) (call_indirect (type ...))
All modules share: linear memory, globals (DSP, RSP, FSP), and the function table.
No interpreter loop. No token threading. Direct WASM function dispatch. wafer architecture +What is WAFER's dictionary structure? Linked list in linear memory (Vec<u8> in Rust).
+0: Link (4B) — address of previous entry (0 = end)
+4: Flags (1B) — IMMEDIATE(0x80) | HIDDEN(0x40) | len(0x1F)
+5: Name (N bytes, uppercase)
+5+N: Padding to 4-byte alignment
: Code field (4B) — function table index (WordId)
: Parameter field — data for VARIABLE/CONSTANT/DOES>
O(1) lookup via Rust HashMap index alongside the linked list. wafer architecture +What are WAFER's 6 IR optimization passes? 1. Peephole — pattern matching: OVER OVER → 2DUP, SWAP DROP → NIP, LIT(1) + → 1+
2. Constant folding — evaluate pure operations at compile time: LIT(3) LIT(4) + → LIT(7)
3. Strength reduction — replace expensive ops: LIT(2) * → LSHIFT(1), LIT(8) * → LSHIFT(3)
4. Dead code elimination — remove code after unconditional EXIT
5. Tail call detection — convert final Call before Exit to TailCall (reuses stack frame)
6. Inlining — inline small words (≤8 IR ops) at call site
All passes configurable via WaferConfig. Default: all enabled. wafer optimization +What is stack-to-local promotion? WAFER codegen optimization that maps Forth's memory stack to WASM locals for straight-line code (no control flow).
Instead of DSP load/store for every stack operation, values live in WASM locals that Cranelift maps to registers.
Effect: DUP * goes from ~30 WASM instructions to ~4.
7x speedup for arithmetic-heavy words.
Only applies to words without IF/DO/BEGIN. Phase 1 limitation.
Controlled by: WaferConfig::codegen.stack_to_local_promotion wafer optimization +What is WAFER's consolidation mode? Recompile all user-defined words into a single WASM module.
wafer --consolidate program.fth
wafer --consolidate -o output.wasm program.fth
Benefits:
• Direct call instead of call_indirect (no table lookup)
• Cranelift can inline across word boundaries
• Single module = single compilation unit
Use after interactive development for deployment. Not for REPL. wafer optimization +What is DSP caching in WAFER? Cache the dsp global variable in a WASM local at function entry. Write back only before calls and at exit.
Without caching: every stack operation reads/writes the global DSP, which is slow.
With caching: a local variable tracks DSP, only syncing when needed.
~30-40% fewer global access instructions.
Enabled by default. Pairs well with stack-to-local promotion. wafer optimization +What is batch compilation in WAFER? At startup, all ~80 IR primitives are compiled into a single WASM module instead of individual modules.
Without batching: 80 separate wasmtime compilations (~7ms boot).
With batching: 1 compilation (~0.6ms boot).
12x faster startup.
Implementation: batch_mode flag during register_primitives(), flush with batch_compile_deferred(). wafer optimization +How does WAFER handle the IrOp enum? ~50 opcodes representing the intermediate representation between Forth and WASM.
Categories:
• Literals: PushI32(i32), PushI64(i64), PushF64(f64)
• Stack: Dup, Drop, Swap, Over, Rot, Nip, Tuck
• Arithmetic: Add, Sub, Mul, DivMod, Negate, Abs
• Control: If{then,else}, DoLoop{body,is_plus}, BeginUntil{body}
• Calls: Call(WordId), TailCall(WordId), Execute, Exit
Nested control flow uses recursive Vec<IrOp> (tree structure, not flat). wafer architecture +How does WAFER handle DOES>? Two-phase mechanism:
1. At define-time: DOES> compiles the runtime body and saves its xt.
2. _DOES_PATCH_ (host function) patches the most recently CREATE'd word's code to call the DOES> body with the data address on stack.
: ARRAY CREATE CELLS ALLOT DOES> SWAP CELLS + ;
WAFER supports double-DOES> (redefining runtime behavior). The patched word pushes its parameter field address, then calls the DOES> code. wafer architecture +How are float literals compiled in WAFER? Float literals (e.g., 3.14e) compile to IrOp::PushF64(f64).
In interpret mode: the float is pushed directly to the float stack.
In compile mode: FLITERAL is automatically applied.
Syntax: any number containing . or E/e with no base prefix is parsed as float when BASE=10.
1.5e \ 1.5
1.5e2 \ 150.0
-3.14e0 \ -3.14
Note: Floats only parsed when BASE is DECIMAL. In HEX, "1.5e2" would be parsed as an integer. wafer architecture +What is WAFER's WaferConfig? Unified configuration for all optimization passes and codegen options.
WaferConfig {
opt: OptConfig { peephole, constant_fold, tail_call, strength_reduce, dce, inline }
codegen: CodegenOpts { stack_to_local_promotion }
}
Presets: WaferConfig::all() (all on, default), WaferConfig::none() (all off, for debugging).
let vm = ForthVM::new_with_config(WaferConfig::none())?; wafer architecture +How does WAFER handle CATCH/THROW? Nested exception frames with stack snapshot/restore.
CATCH: saves DSP, RSP, FSP. If the xt THROWs, stacks are restored to saved state, throw code is pushed.
THROW: if code ≠ 0, unwinds to nearest CATCH frame. If no CATCH, behaves like ABORT.
Standard codes: -1 (ABORT), -2 (ABORT"), -4 (stack underflow), -13 (undefined word), -14 (compile-only).
['] RISKY CATCH ?DUP IF ." Error: " . THEN
WAFER uses Rust-side exception handling — the throw code is returned through the host function boundary. wafer architecture +What is the CONSOLIDATE word? WAFER-specific word (not in Forth 2012). Recompiles all compiled definitions into a single WASM module with direct function calls. Equivalent to --consolidate CLI flag but callable from Forth code.
: FOO ... ; : BAR FOO FOO ; CONSOLIDATE
After CONSOLIDATE, all existing words use direct calls. New words still use call_indirect until next CONSOLIDATE. wafer architecture wafer-specific +What Forth 2012 word sets does WAFER implement? 12 of 14 at 100% compliance:
Core, Core-Ext, Double-Number, Exception, Facility, Floating-Point (+ Ext), Locals, Memory-Allocation, Programming-Tools, Search-Order, String
Not implemented (2):
File-Access (requires WASI), Extended-Character (Unicode)
392 tests: 380 unit + 1 benchmark + 11 compliance test modules.
cargo test -p wafer-core --test compliance wafer architecture +What is the difference between FM/MOD and SM/REM? FM/MOD: Floored division. Quotient rounds toward −∞. Remainder has same sign as divisor.
SM/REM: Symmetric division. Quotient truncates toward 0. Remainder has same sign as dividend. (C-like)
-7. 2 FM/MOD . . \ -4 1
-7. 2 SM/REM . . \ -3 -1
FM/MOD is preferred for modular arithmetic (always non-negative remainder with positive divisor). Forth 2012 leaves / and MOD implementation-defined. WAFER uses symmetric (SM/REM). patterns arithmetic +CREATE DOES> pattern The fundamental pattern for user-defined defining words in Forth.
CREATE allocates data. DOES> specifies runtime behavior. The child word pushes its data address, then executes the DOES> body.
: ARRAY ( n -- ) CREATE CELLS ALLOT DOES> ( n -- addr ) SWAP CELLS + ;
10 ARRAY DATA 42 3 DATA ! 3 DATA @ . \ 42
Other examples: tables, structs, state machines, OOP vtables.
Mastering CREATE DOES> is the bridge from Forth user to Forth metaprogrammer. patterns defining +Pictured numeric output pattern <# ... #> — right-to-left digit conversion.
Build output from least-significant digit. Use # for each digit, #S for remaining, HOLD for custom chars, SIGN for negative.
: DOLLARS ( n -- c-addr u )
S>D TUCK DABS <# # # [CHAR] . HOLD #S ROT SIGN [CHAR] $ HOLD #> ;
-1234 DOLLARS TYPE \ $-12.34
Always start with <#, end with #>. The double number is consumed by # and #S. patterns pictured-numeric +POSTPONE idiom for compile-time words POSTPONE defers compilation of a word to when the defining word's code runs.
For building syntax extensions and compile-time macros.
: MY-IF POSTPONE IF ; IMMEDIATE
: [+] POSTPONE + ; IMMEDIATE \ compiles + wherever [+] appears
For immediate words: POSTPONE compiles their behavior.
For non-immediate: POSTPONE compiles code that will compile them.
Replaces obsolescent [COMPILE] and COMPILE. The single tool for all compile-time word building. patterns compilation +VALUE/TO vs VARIABLE/@/! VALUE: cleaner syntax for simple storage. Access by name, update with TO.
VARIABLE: gives address, needed for +!, pointer passing, arrays.
42 VALUE X X . 99 TO X \ clean, reads like English
VARIABLE Y 42 Y ! Y @ . 5 Y +! \ address-based, more flexible
Rule of thumb: use VALUE unless you need the address. Use VARIABLE for data structures, pointer math, or +!. patterns defining +DEFER/IS pattern for late binding DEFER creates a word with swappable behavior. IS changes what it does.
DEFER GREET
: HELLO ." Hello!" ; ' HELLO IS GREET
: HI ." Hi!" ; ' HI IS GREET
Use cases: forward references, pluggable behavior, mock/stub in tests, state machines.
ACTION-OF retrieves current xt. DEFER@ and DEFER! are the low-level equivalents. patterns defining +Double-number literal syntax A trailing dot makes a number double-cell.
42. \ pushes double-cell (42 0) — note: this is NOT a float!
-1. \ pushes (-1 -1) — sign-extended
1000000. D. \ prints 1000000
Common confusion: 3.14 is NOT a float literal in standard Forth without the E. It's 314 as a double (the dot is inside the number). Use 3.14e or 3.14E0 for floats. patterns conversion +CATCH/THROW error handling pattern Structured exception handling. CATCH wraps an xt; THROW unwinds to it.
: SAFE ['] RISKY CATCH
CASE
0 OF ." ok" ENDOF
-1 OF ." aborted" ENDOF
." error: " DUP .
ENDCASE ;
THROW 0 is a no-op. Negative codes are standard (-1 ABORT, -2 ABORT", etc.). Positive codes are application-defined. patterns control-flow +:NONAME for anonymous execution Create unnamed word, get its xt. Perfect for callbacks and dispatch tables.
:NONAME DUP * ; CONSTANT SQUARE-XT
5 SQUARE-XT EXECUTE . \ 25
\ Dispatch table:
CREATE OPS :NONAME + ; , :NONAME - ; , :NONAME * ; ,
: DISPATCH CELLS OPS + @ EXECUTE ;
No dictionary entry is created. The xt is only accessible through the value on the stack at definition time. patterns defining +MARKER for interactive development Create a restore point. Execute the marker to forget everything defined after it.
MARKER CLEAN
: FOO ." v1" ; : BAR FOO ;
CLEAN \ FOO and BAR are forgotten
: FOO ." v2" ; \ redefine from scratch
Essential for REPL-driven development: mark, experiment, restore, repeat. Like an undo point for the dictionary. patterns defining +Loop idiom: 0 DO ... LOOP Standard counted loop. Index available via I (or J for outer loop).
: STARS 0 ?DO [CHAR] * EMIT LOOP ;
: TABLE 4 0 DO 4 0 DO I J * 4 .R LOOP CR LOOP ;
Use ?DO (not DO) when count might be 0. DO executes at least once even if limit=start. UNLOOP before EXIT in a loop. LEAVE exits immediately. patterns control-flow +EVALUATE for dynamic compilation Interpret a string as Forth source at runtime. Extremely powerful; use with care.
: RUN S" 2 3 + ." EVALUATE ; \ prints 5
\ Dynamic word creation:
: MAKE-CONST ( n "name" -- )
>R S" CONSTANT " R> ... ; \ simplified
SOURCE-ID returns -1 during EVALUATE. >IN and SOURCE reflect the evaluated string. Nesting is allowed. patterns compilation