feat(v4.0.0): . U. D. .R U.R D.R and SPACES
The number-printing words, on pictured output and TYPE, executed on the golden model at both cell widths against a C reference (ten bases, eleven field widths) and six recorded transcripts of the v3 binary. Each plain word is its .R word with a width of 0; all six share one tail. The field width waits in a variable, (W), so the picture runs no deeper than it does on its own: each word leaves its caller 4 data cells and 2 return entries. As v3, the .R words print a trailing space. Unlike v3, D. takes ( lo hi ), prints the whole double, and printing honours BASE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
40178098e9
commit
13335dcc9c
@@ -147,8 +147,8 @@ IF body1 ELSE body2 THEN → if L1 drop body1 jump L2
|
||||
times, as on the F18. `FOR ... UNEXT` is the same but the body must fit in one instruction word.
|
||||
|
||||
**Register conventions.** `A` and `B` are caller-saved. A word that uses them says so. Words in this
|
||||
document that clobber `A`: `@ ! +! -! 2@ 2! C@ C! UM* * UM/MOD Q.FROM-INT Q.TO-INT Q.* Q./ Q.EXP Q.SQRT Q.LOG Q.SIN Q.COS HOLD SIGN # #S TYPE SEND RECV`. Words that clobber `B`:
|
||||
`Q./ Q.EXP Q.SQRT Q.LOG Q.SIN Q.COS <# HOLD SIGN # #S #> EMIT CR SPACE TYPE SEND RECV`.
|
||||
document that clobber `A`: `@ ! +! -! 2@ 2! C@ C! UM* * UM/MOD Q.FROM-INT Q.TO-INT Q.* Q./ Q.EXP Q.SQRT Q.LOG Q.SIN Q.COS HOLD SIGN # #S . .R U. U.R D. D.R TYPE SEND RECV`. Words that clobber `B`:
|
||||
`Q./ Q.EXP Q.SQRT Q.LOG Q.SIN Q.COS <# HOLD SIGN # #S #> . .R U. U.R D. D.R EMIT CR SPACE SPACES TYPE SEND RECV`.
|
||||
|
||||
**Return-stack words** (`>R R> R@ 2>R 2R> 2R@ I J UNLOOP` and the loop runtimes) are always IN.
|
||||
|
||||
@@ -454,7 +454,8 @@ All output reaches the console through `EMIT` (DEV).
|
||||
| --- | --- | --- |
|
||||
| `<#` `#` `#S` `HOLD` `SIGN` `#>` | CAP | Pictured output over `UM/MOD` and a 64-byte hold buffer, filled backwards from its end `HEND` through the pointer `HLD`. Standard stack effects (v3 took its double low cell on top, and its tolerant `#>` popped `ud` only if present; neither is kept). Otherwise v3's behaviour: digits `0`–`9` then `A`–`Z`; `BASE` outside 2–36 reads as 10; 63 characters; `HOLD` of a value outside 0–255 or into a full buffer stores nothing and sets `NODE-ERROR` (D-13). Definitions below. Executed on the golden model (2026-10-03) against a C reference in bases 2, 3, 8, 10, 16, 36 and four invalid ones. `<# #S #>` leaves its caller 4 data cells and 3 return entries; the signed picture `dup push ABS 0 <# #S pop SIGN #>` leaves 2 return entries. `#`, `#S`, `HOLD` and `SIGN` clobber `A` and `B`. |
|
||||
| `HLD` | CAP | Variable: byte address of the first held character. |
|
||||
| `.` `.R` `U.` `U.R` `D.` `D.R` | CAP | Built on pictured output and `TYPE`. |
|
||||
| `.` `.R` `U.` `U.R` `D.` `D.R` | CAP | Built on pictured output and `TYPE`; definitions below. As v3: the number in the current base, then one space; the `.R` words right-justify it in `width` columns first, print a wider number whole, and pad nothing for `width <= 0`. (The space after the `.R` words is not FORTH-79; it is what v3 prints.) Where v4 parts from v3: a double is `( lo hi )`, where v3's `D.` took the low cell on top; `D.` prints the whole double, where v3 printed `DOUBLE-OVERFLOW` unless it fitted one signed cell (they agree whenever it does); printing honours the `BASE` variable, where v3 printed in a host copy that only `DECIMAL`, `HEX` and `OCTAL` set, so `n BASE !` changed v3's input base but not its output; and the number is built in the 63-character hold buffer, so a longer one — a 64-bit cell in base 2, a large double in a small base — loses its leading characters and sets `NODE-ERROR` (D-13), where v3 printed from a private 80-character buffer. Executed on the golden model (2026-10-03) against a C reference in the ten bases of the pictured-output test and eleven field widths, and against five transcripts of the v3 binary (a sixth, the extreme cells, at 64-bit cells). Each leaves its caller 4 data cells and 2 return entries. All clobber `A` and `B`. |
|
||||
| `(W)` | CAP | Variable: the field width of the `.R` words. Like `BASE` and `HLD`, it lives in node memory, so the width is on neither stack while the picture runs. |
|
||||
| `.S` | RET | No visible stack pointer (D-2). |
|
||||
| `?` | CAP | `@ .` |
|
||||
| `DUMP` | CAP | Loop over `@`/`C@` with pictured output. |
|
||||
@@ -485,6 +486,25 @@ next word rather than a call, so `C!` returns straight to their caller and two r
|
||||
are saved. `#` keeps the high quotient under the second division on the data stack, not on the
|
||||
return stack. `-ROT` is in line (`SWAP push SWAP pop`).
|
||||
|
||||
```forth
|
||||
\ number output. ABS is in line: -if A inv 1 + A:
|
||||
: .R ( n width -- )
|
||||
(W) b! !b dup push ABS 0 <# #S pop SIGN #> \ baddr u
|
||||
TAIL: (W) b! @b -if POS drop jump OUT \ width < 0
|
||||
POS: over - SPACES \ width - u spaces
|
||||
OUT: TYPE jump SPACE
|
||||
: . ( n -- ) 0 jump .R
|
||||
: U.R ( u width -- ) (W) b! !b 0 <# #S #> jump TAIL
|
||||
: U. ( u -- ) 0 jump U.R
|
||||
: D.R ( d width -- ) (W) b! !b dup push -if A DNEGATE A: <# #S pop SIGN #> jump TAIL
|
||||
: D. ( d -- ) 0 jump D.R
|
||||
```
|
||||
|
||||
There is one picture for signed singles, one for unsigned and one for doubles; each plain word is
|
||||
its `.R` word with a width of 0, entered by a jump, and all six share one tail, which ends in a jump
|
||||
to `SPACE`. The width is tested for sign before `width - u`, which could wrap for a very negative
|
||||
width and print a flood of spaces.
|
||||
|
||||
### 5.9 Strings, parsing, and input
|
||||
|
||||
| Word | Fate | Notes |
|
||||
@@ -523,7 +543,7 @@ return stack. `-ROT` is in line (`SWAP push SWAP pop`).
|
||||
| `TYPE` | CAP | `( baddr u -- )`. Loop of `C@ EMIT`, or one string message to the console node: `-if OK drop drop NODE-ERROR b! -1 !b ; OK: if DONE over C@ EMIT push 1 + pop -1 + jump OK DONE: drop drop ;` — nothing for `u = 0`; for `u < 0` nothing is printed and `NODE-ERROR` is set, where v3 printed nothing and raised its error flag. The address range is not checked (out-of-range addressing is still open, `node.h`). Executed on the golden model (2026-10-03). Leaves its caller 4 data cells and 3 return entries, the depth being `C@`'s as written. Clobbers `A` and `B`. |
|
||||
| `CR` | CAP | `10 EMIT`, as `10 jump EMIT` — executed on the golden model (2026-10-03). Character 10, as v3; the console turns it into a new line. |
|
||||
| `SPACE` | CAP | `BL EMIT`, as `32 jump EMIT` — executed on the golden model (2026-10-03). |
|
||||
| `SPACES` | CAP | `BEGIN dup 0> WHILE SPACE 1- REPEAT drop` |
|
||||
| `SPACES` | CAP | `( n -- )`: `-if L drop ; L: if DONE SPACE -1 + jump L DONE: drop ;` — `n` spaces, none for `n <= 0`, as v3. Executed on the golden model (2026-10-03), including a transcript of the v3 binary. Leaves its caller 7 data cells and 7 return entries. Clobbers `B`. |
|
||||
| `."` `(do-string)` | CC | Compiler words. |
|
||||
|
||||
### 5.11 Blocks and mass storage
|
||||
|
||||
Reference in New Issue
Block a user