From acf9c273a25b0e70b7da3dc6bfd8db73ce5dd3b7 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 24 Apr 2026 20:40:11 +0000 Subject: [PATCH] forth: BASE/DECIMAL/HEX/BIN/OCTAL (+9; Hayes 174/590) --- lib/forth/compiler.sx | 4 ++-- lib/forth/hayes-runner.sx | 3 +-- lib/forth/interpreter.sx | 2 +- lib/forth/runtime.sx | 19 ++++++++++++++- lib/forth/scoreboard.json | 2 +- lib/forth/scoreboard.md | 2 +- lib/forth/tests/test-phase4.sx | 42 ++++++++++++++++++++++++++++++++++ plans/forth-on-sx.md | 11 ++++++++- 8 files changed, 76 insertions(+), 9 deletions(-) diff --git a/lib/forth/compiler.sx b/lib/forth/compiler.sx index 6083c7dc..6eb00545 100644 --- a/lib/forth/compiler.sx +++ b/lib/forth/compiler.sx @@ -24,7 +24,7 @@ (forth-execute-word state w) (forth-compile-call state tok)) (let - ((n (forth-parse-number tok (get state "base")))) + ((n (forth-parse-number tok (get (get state "vars") "base")))) (if (not (nil? n)) (forth-compile-lit state n) @@ -219,7 +219,7 @@ (not (nil? w)) (forth-execute-word state w) (let - ((n (forth-parse-number tok (get state "base")))) + ((n (forth-parse-number tok (get (get state "vars") "base")))) (if (not (nil? n)) (forth-push state n) diff --git a/lib/forth/hayes-runner.sx b/lib/forth/hayes-runner.sx index c7515e67..22f22447 100644 --- a/lib/forth/hayes-runner.sx +++ b/lib/forth/hayes-runner.sx @@ -87,8 +87,7 @@ "actual" (str hayes-actual)))))))))) (forth-def-prim! state "TESTING" (fn (s) nil)) - (forth-def-prim! state "HEX" (fn (s) (dict-set! s "base" 16))) - (forth-def-prim! state "DECIMAL" (fn (s) (dict-set! s "base" 10))) + ;; HEX/DECIMAL are real primitives now (runtime.sx) — no stub needed. state)) (define diff --git a/lib/forth/interpreter.sx b/lib/forth/interpreter.sx index d019993e..4ffba3f1 100644 --- a/lib/forth/interpreter.sx +++ b/lib/forth/interpreter.sx @@ -17,7 +17,7 @@ (not (nil? w)) (forth-execute-word state w) (let - ((n (forth-parse-number tok (get state "base")))) + ((n (forth-parse-number tok (get (get state "vars") "base")))) (if (not (nil? n)) (forth-push state n) diff --git a/lib/forth/runtime.sx b/lib/forth/runtime.sx index 059b813b..3eecbf8c 100644 --- a/lib/forth/runtime.sx +++ b/lib/forth/runtime.sx @@ -18,8 +18,8 @@ (dict-set! s "output" "") (dict-set! s "compiling" false) (dict-set! s "current-def" nil) - (dict-set! s "base" 10) (dict-set! s "vars" (dict)) + (dict-set! (get s "vars") "base" 10) (dict-set! s "cstack" (list)) (dict-set! s "mem" (dict)) (dict-set! s "here" 0) @@ -538,6 +538,23 @@ (> n 0) (for-each (fn (_) (forth-emit-str s " ")) (range 0 n)))))) (forth-def-prim! state "BL" (fn (s) (forth-push s 32))) + (forth-def-prim! + state + "DECIMAL" + (fn (s) (dict-set! (get s "vars") "base" 10))) + (forth-def-prim! + state + "HEX" + (fn (s) (dict-set! (get s "vars") "base" 16))) + (forth-def-prim! + state + "BIN" + (fn (s) (dict-set! (get s "vars") "base" 2))) + (forth-def-prim! + state + "OCTAL" + (fn (s) (dict-set! (get s "vars") "base" 8))) + (forth-def-prim! state "BASE" (fn (s) (forth-push s "base"))) (forth-def-prim! state "I" (fn (s) (forth-push s (forth-rpeek s)))) (forth-def-prim! state diff --git a/lib/forth/scoreboard.json b/lib/forth/scoreboard.json index 452083a3..351d8517 100644 --- a/lib/forth/scoreboard.json +++ b/lib/forth/scoreboard.json @@ -1,6 +1,6 @@ { "source": "gerryjackson/forth2012-test-suite src/core.fr", - "generated_at": "2026-04-24T20:12:09Z", + "generated_at": "2026-04-24T20:39:51Z", "chunks_available": 638, "chunks_fed": 590, "total": 590, diff --git a/lib/forth/scoreboard.md b/lib/forth/scoreboard.md index 989c08f6..d22e89ac 100644 --- a/lib/forth/scoreboard.md +++ b/lib/forth/scoreboard.md @@ -11,7 +11,7 @@ | percent | 29% | - **Source**: `gerryjackson/forth2012-test-suite` `src/core.fr` -- **Generated**: 2026-04-24T20:12:09Z +- **Generated**: 2026-04-24T20:39:51Z - **Note**: completed A "chunk" is any preprocessed segment ending at a `}T` (every Hayes test diff --git a/lib/forth/tests/test-phase4.sx b/lib/forth/tests/test-phase4.sx index 5bdcce97..3bb3e8fc 100644 --- a/lib/forth/tests/test-phase4.sx +++ b/lib/forth/tests/test-phase4.sx @@ -171,6 +171,47 @@ ((r (forth-run "1000 2 ACCEPT"))) (let ((stk (nth r 2))) (forth-p4-assert "ACCEPT empty buf -> 0" (list 0) stk))))) +(define + forth-p4-base-tests + (fn + () + (forth-p4-check-top + "BASE default is 10" + "BASE @" + 10) + (forth-p4-check-top + "HEX switches base to 16" + "HEX BASE @" + 16) + (forth-p4-check-top + "DECIMAL resets to 10" + "HEX DECIMAL BASE @" + 10) + (forth-p4-check-top + "HEX parses 10 as 16" + "HEX 10" + 16) + (forth-p4-check-top + "HEX parses FF as 255" + "HEX FF" + 255) + (forth-p4-check-top + "DECIMAL parses 10 as 10" + "HEX DECIMAL 10" + 10) + (forth-p4-check-top + "BIN parses 1010 as 10" + "BIN 1010" + 10) + (forth-p4-check-top + "OCTAL parses 17 as 15" + "OCTAL 17" + 15) + (forth-p4-check-top + "BASE @ ; 16 BASE ! ; BASE @" + "BASE @ 16 BASE ! BASE @ SWAP DROP" + 16))) + (define forth-p4-run-all (fn @@ -185,6 +226,7 @@ (forth-p4-charplus-tests) (forth-p4-char-tests) (forth-p4-key-accept-tests) + (forth-p4-base-tests) (dict "passed" forth-p4-passed diff --git a/plans/forth-on-sx.md b/plans/forth-on-sx.md index 850ea9e7..13c2616c 100644 --- a/plans/forth-on-sx.md +++ b/plans/forth-on-sx.md @@ -80,7 +80,7 @@ Representation: ### Phase 4 — strings + more Core - [x] `S"`, `C"`, `."`, `TYPE`, `COUNT`, `CMOVE`, `FILL`, `BLANK` - [x] `CHAR`, `[CHAR]`, `KEY`, `ACCEPT` -- [ ] `BASE` manipulation: `DECIMAL`, `HEX` +- [x] `BASE` manipulation: `DECIMAL`, `HEX` - [ ] `DEPTH`, `SP@`, `SP!` - [ ] Drive Hayes Core pass-rate up @@ -99,6 +99,15 @@ Representation: _Newest first._ +- **Phase 4 — `BASE`/`DECIMAL`/`HEX`/`BIN`/`OCTAL` (+9; Hayes unchanged).** + Moved `base` from its top-level state slot into `state.vars["base"]` + so the regular `@`/`!`/VARIABLE machinery works on it. + `BASE` pushes the sentinel address `"base"`; `DECIMAL`/`HEX`/`BIN`/ + `OCTAL` are thin primitives that write into that slot. Parser + reads through `vars` now. Hayes unchanged because the runner had + already been stubbing `HEX`/`DECIMAL` — now real words, stubs + removed from `hayes-runner.sx`. + - **Phase 4 — `CHAR`/`[CHAR]`/`KEY`/`ACCEPT` (+7 / Hayes 168→174).** `CHAR` parses the next token and pushes the first-char code. `[CHAR]` is IMMEDIATE: in compile mode it embeds the code as a compiled push