Make S" work inside compiled words
authorJonas Hvid <mail@johv.dk>
Sat, 3 Oct 2020 23:06:21 +0000 (01:06 +0200)
committerJonas Hvid <mail@johv.dk>
Sat, 3 Oct 2020 23:10:57 +0000 (01:10 +0200)
The approach we're using here is kinda silly and cause by the fact that I
wasn't/still aren't very familiar with Forth outside of trying to implement it
myself.

From doing a bit of reading, it sounds like S" is primarily intended to be used
inside definitions -- not at runtime. So now we use the old, weird S" (that has a
single static buffer and only works at runtime) to bootstrap the system, then
replace it with a more sensible S" that only works at compile time.

example.f
main.asm
sys.f

index 41993d73ba877de3f7c7c72491ecee6318a43d80..38cd6e4e69921d16fb6e9171b3129796161e085f 100644 (file)
--- a/example.f
+++ b/example.f
@@ -1,6 +1,3 @@
-( vim: syntax=forth
-)
-
 : FIB ( n -- Fn )
   0 1                            ( n a b )
   0                              ( n a b i )
   DUP 4 PICK = UNTIL
   DROP SWAP DROP SWAP DROP ;     ( a+b )
 
-S" HELLO-ADDR" CREATE
-S" Hello!" DUP ROT
-STORE-STRING
-: HELLO
-  ' HELLO-ADDR LIT, TELL NEWLINE ;
-
-HELLO
+: HELLO S" Hello!" TELL NEWLINE ;
 
-S" 10 FIB = " TELL
-10 FIB .U
-SPACE S" (Expected: 59)" TELL NEWLINE
+: TEST-FIB
+  S" 10 FIB = " TELL
+  10 FIB .U
+  SPACE S" (Expected: 59)" TELL NEWLINE ;
 
-TERMINATE
+HELLO
+TEST-FIB
index 537d0e8e6fe3e3728bc06704d8925001e27f739e..43eef7a7e52ab27a253ad343ec775ae83e0a8b22 100644 (file)
--- a/main.asm
+++ b/main.asm
@@ -160,6 +160,17 @@ forth_asm LIT, 'LIT'
   push rax
   next
 
+;; When LITSTRING is encountered while executing a word, it instead reads a
+;; string from the definition of that word, and places that string on the stack
+;; as (buffer, length).
+forth_asm LITSTRING, 'LITSTRING'
+  lodsb
+  push rsi ; Buffer
+  movzx rax, al
+  push rax ; Length
+  add rsi, rax ; Skip over string before resuming execution
+  next
+
 ;; Given a string (a pointer following by a size), return the location of the
 ;; dictionary entry for that word. If no such word exists, return 0.
 forth_asm FIND, 'FIND'
diff --git a/sys.f b/sys.f
index 38708d1e1a88f479264951bf154c85509583826d..6e7c8539bcdd67ea720b7faf5c2f15c8781b0880 100644 (file)
--- a/sys.f
+++ b/sys.f
@@ -75,6 +75,21 @@ EXIT [
     KEY
   10 = UNTIL ;
 
+\ So far, S" has only worked in immediate mode, which is backwards -- actually,
+\ the main use-case of this is as a compile-time word. Let's fix that.
+: S" IMMEDIATE
+  ' LITSTRING ,
+  HERE @ 0 C, \ We will put the length here
+  0
+  BEGIN
+    1 +
+    KEY DUP C,
+  34 = UNTIL
+  \ Remove final "
+    HERE @ 1 - HERE !
+    1 -
+  SWAP C! ;
+
 ( Compile the given string into the current word directly. )
 : STORE-STRING ( str len -- )
   BEGIN
@@ -89,7 +104,6 @@ EXIT [
 ( Read a number from standard input. )
 : READ-NUMBER READ-WORD PARSE-NUMBER ;
 
-S" Ready." TELL NEWLINE
+: RESTART S" Ready." TELL NEWLINE ;
+RESTART
 
-( vim: syntax=forth
-)