Author: Virgil Dupras <email@example.com>
Date: Fri, 2 Sep 2022 15:41:10 -0400
2 files changed, 163 insertions(+), 27 deletions(-)
diff --git a/fs/doc/dict.txt b/fs/doc/dict.txt
@@ -27,8 +27,10 @@ f -- flag
s -- string
w -- word
e -- entry
+m -- entry metadata
r -- range
u -- count
+c -- character, a 8-bit value
a b c -- order of elements matter
The description of the words can contain letters in between "*" characters,
@@ -36,6 +38,9 @@ indicating a special attribute:
*I* indicates an immediate word.
*B* indicates that it is "binary modulable".
+*C* indicates that the word can be compiled. Its description is its behavior in
+ interpret mode, but when in compile mode, it will "do the right thing" to
+ compile the same behvior.
@@ -69,6 +74,13 @@ MAIN Address containing the value of "main".
ABORT Address containing the value of "abort".
EMIT Address containing the value of "emit".
IN< Address containing the value of "in<".
+CELLSZ Size of a cell: 4
+CALLSZ The size in bytes of a native call.
@@ -90,8 +102,10 @@ main --
Stack words move elements around in PS and RS.
drop a --
+2drop a b --
dup a -- a a
?dup a -- a? a dup if a is nonzero.
+2dup a b -- a b a b
swap a b -- b a
over a b -- a b a
nip a b -- b
@@ -99,6 +113,13 @@ tuck a b -- b a b
rot a b c -- b c a
rot> a b c -- c a b
+rdrop -- *I* Compile a RS shrink of 4 bytes.
+r@ -- *I* Compile a push of current RS top to PS.
+r> -- *I* Equivalent to r@ rdrop
+>r -- *I* Compiles a RS grow of 4 bytes followed by a pop
+ of PS into that new RS space.
+rfree -- *I* Shrink RS by the current [rcnt] level and reset
+ [rcnt] to 0.
r+, n -- Compile a RS grow (n is negative) or shrink (n is
positive) operation by n bytes.
r', off -- Compile the yield of RSP with "off" offset applied to
@@ -127,15 +148,27 @@ width", a value that can be 1, 2 or 4 depending of the width of the operation.
16b -- *I* Set binary width to 16-bit
allot u -- Increase here by u.
+allot0 u -- Allot u and fill this space with zeroes.
move src dst u -- Copy u bytes from address src to address dst, moving
move, src u -- Copy u bytes to "here" and increase "here" by u.
+fill a u c -- Fill range [a, a+u] with byte c.
+align4 -- Allot 0, 1, 2 or 3 bytes so that "here" is divisible
+ by 4.
+nc, n -- Parse n numbers from input stream and write them as
+ 8-bit values.
+[c]? c a u -- i Search for character c in range [a, a+u] and yield its
+ index or -1 if not found.
-c@ --> 8b @
-c! --> 8b !
-c, --> 8b ,
+c@ --> 8b @
+c! --> 8b !
+c, --> 8b ,
+w@ --> 16b @
+w! --> 16b !
+c@+ --> 8b @+
+c!+ --> 8b !+
@@ -143,16 +176,24 @@ c, --> 8b ,
1- a -- a-1
+ a b -- a+b
- a b -- a-b
+-^ a b -- b-a
* a b -- a*b
/ a b -- a/b
/mod a b -- r q r is remainder, q is quotient
+mod a b -- n n is the remainder of a divided by b
+neg a -- -a
and a b -- n n is the result of a binary "and" of a and b
or a b -- n n is the result of a binary "or" of a and b
xor a b -- n n is the result of a binary "exclusive or" of a and b
+^ a -- n n is the result of "a -1 xor", flipping all bits.
lshift n u -- n Shift n by u bits to the left
rshift n u -- n Shift n by u bits to the right
+<< n -- n Shift n left by 1
+>> n -- n Shift n right by 1
<<c n -- n c Shift n left by 1, yielding c as the 32-bit carry bit
>>c n -- n c Shift n right by 1, yielding c as the 32-bit carry bit
+upcase c -- c If c is between "a" and "z", yield their upcase version.
+ Otherwise, yield c.
@@ -160,31 +201,62 @@ rshift n u -- n Shift n by u bits to the right
Other conditions yield f=0.
< a b -- f f=1 if a is lower than b
+> a b -- f f=1 if a is higher than b
= a b -- f f=1 if a equals b
+<> a b -- f f=1 if a is not equal to b
+>= a b -- f f=1 if a is higher than or equal to b
+<= a b -- f f=1 if a is lower than or equal to b
+0< a -- f f=1 if a is negative
+0>= a -- f f=1 if a is not negative
not a -- f f=1 if a is zero
bool a -- f f=1 if a is nonzero
+min a b -- n n is the lowest number between a and b.
+max a b -- n n is the highest number between a and b.
+=><= n l h -- f f=1 if n >= l and n <= h.
+?swap a b -- l h Sort a and b, putting the highest number on TOS.
= r1 r2 u -- f f=1 if memory ranges [r1, r1+u] and [r2, r2+u] have the
+s= s1 s2 -- f f=1 if s1 and s2 have the same length and content.
+noop -- Do nothing
bye -- Halt the machine.
quit -- Reset RS and return to the "main" loop.
abort -- Reset PS and quit.
execute a -- Call address a.
exit -- *I* Compile a return from call.
main -- The mainloop. Repeatedly call "word" and "runword".
-if -- a *I* Write an conditional branch. a is its target.
-then a -- *I* Make branch target point to here.
-else a1 -- a2 *I* Compile an unconditional branch and make supplied
- branch target point to after it.
-begin -- a *I* Yield a branch target.
-again a -- *I* Compile an unconditional branch to target.
-until a -- *I* Compile an conditional branch to target.
-next a -- *I* Compile a "next" branch to target.
leave -- *I* Set "next" counter so that we leave the loop at the
next "next" branch.
+[if] f -- If f=0, skip all following words until a "[then]" word is
+[then] -- No-op.
+Structured flow words are better explained in their interaction together rather
+than their individual effect and this is done in doc/usage. Below is a list of
+all the flow words for reference. All these words are immediate.
+if .. else .. then
+begin .. again
+begin .. until
+n >r begin .. next
+begin .. while .. repeat
+begin .. while .. while .. repeat .. else .. then
+n case .. of condition .. endof .. endcase
+## Linked list
+llnext ll -- ll Yield next LL element.
+llend ll -- ll Iterate LL until we reach the last element.
+llprev tgt ll -- ll From "ll", iterate LL until we reach the element when the
+ LL pointer points to "tgt".
+lladd ll -- ll Write a new LL element to here, yield it, then write its
+ address to the last element of "ll".
+llinsert 'll -- ll Given a *pointer* to a LL, write a new LL to here and
+ replace that first element in that pointer with the new
+ LL element.
+llcnt ll -- n Yield the number of elements in "ll".
@@ -198,13 +270,49 @@ e>w e -- w Yield a word reference (executable) from an entry.
entry s -- Create entry with name s in system dictionary.
code "x" -- Same as "entry", but reads name from input stream.
current -- w Yield the last word to be added to the system dictionary.
+emeta w -- m Yield the value of the "metadata" field of the entry
+ associated with word w.
+'emeta w -- 'm Same as "emeta", but yield the address of that field.
+wordlen w -- n Yield the length of the name of word w.
+wordname w -- a u Yields a range with the name of word w.
+.word w -- Emit name of word w.
+words -- Emit names of all words of the system dictionary.
+## Entry metadata
+An entry metadata is a linked list followed by a type id.
+emetatype m -- n Yield the type id of metadata m.
+'emetadata m -- a Yield the address of the "arbitrary data" part of m.
+findmeta typeid m -- m-or-0
+ Find a metadata element of type "typeid" in meta LL "m" and
+ yield this meta if found. Otherwise, yield 0.
+struct[ "x" -- Create new struct "x" and begin defining it.
+]struct -- Exit current struct definition.
+extends "x" -- Find struct "x" in system dictionary and make the next
+ defined struct extend it.
+sfield "x" -- Add a new struct field named "x".
+smethod "x" -- Add a new struct method named "x".
+structbind 'data "x y" --
+ Create a new binding named "x" that binds 'data to struct
+ named "y".
+rebind 'data 'bind --
+ Bind 'data to structbind 'bind.
key -- c Read next character from system interactive input source.
in< -- c Read next character from system input source.
emit c -- Emit character to system output destination.
+nl> -- Emit CR then LF.
+spc> -- Emit SPC.
rtype a u -- Emit characters in range [a, a+u].
+stype s -- Emit all characters in s.
+." x" -- *IC* Emit string x.
+abort" x" -- *IC* Emit string x then abort.
maybeword -- s-or-0 Try to read word from system input source and yield it as
a string if it could be read. If EOF (c = -1) is reached,
@@ -226,17 +334,45 @@ runword s -- Execute string s according to our general logic: compile it
Compiling words operate on a higher plane: they write native code to "here",
which can then be executed to have the desired effect.
-[ -- *I* Stop compiling. The following words will be interpreted.
-] -- Begin compiling. The following words will be compiled.
-: "x" -- Create entry x and begin compiling.
-; -- *I* Compile a return from call and then stop compiling.
-litn n -- Compile a literal with value n.
-execute, a -- Compile a call to address a.
-exit, -- Compile a return from call.
-compile "x" -- *I* Find word x and compile a compilation of a call to it.
-[compile] "x" -- *I* Find immediate word x and instead of executing it
- immediately as we would normally do, compile it as if it
- wasn't immediate.
-compiling -- f f=1 if we're currently compiling.
-immediate -- Make last added entry into an immediate entry.
+[ -- *I* Stop compiling. The following words will be interpreted.
+] -- Begin compiling. The following words will be compiled.
+: "x" -- Create entry x and begin compiling.
+; -- *I* Compile a return from call and then stop compiling.
+litn n -- Compile a literal with value n.
+execute, a -- Compile a call to address a.
+exit, -- Compile a return from call.
+compile "x" -- *I* Find word x and compile a compilation of a call to it.
+[compile] "x" -- *I* Find immediate word x and instead of executing it
+ immediately as we would normally do, compile it as if it
+ wasn't immediate.
+compiling -- f f=1 if we're currently compiling.
+immediate -- Make last added entry into an immediate entry.
+create "x" -- Create a new entry named "x" of type "cell".
+const n "x" -- Create a new constant named "x" of value n.
+doer "x" -- Create a new "doer" word, to be paired with does>.
+does> -- Begin compiling the runtime behavior of a doer word.
+does' w -- a Yields the address of the "data" part of a doer word w.
+value n "x" -- Create a new entry of type "value" with n as its initial
+ivalue a "x" -- Create a new entry of type "indirect value" with a being the
+ address holding the pointer to the value.
+alias "x y" -- Find word "x" in system dictionary and create entry "y" of
+ type "alias" pointing to it.
+ialias a "x" -- Create a new entry of type "indirect alias" with a being the
+ address holding the pointer to the word to execute.
+S" x" -- *IC* Yield string literal with contents "x".
+chain "x y" -- Create a new "chain" targeting alias "x" and chaining "y" to
+## "to" words
+The way "to" words work is that they compile their associated word right
+after a literal that yields the address of the word which obeys "to" semantics.
+to --> !
+to+ --> +!
+to' --> noop
+to@ --> @
+to@! --> @!
+to@+ --> @@+
+to!+ --> @!+
diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs
@@ -80,7 +80,7 @@ create toptr 0 ,
: w! 16b ! ;
: c@+ 8b @+ ;
: c!+ 8b !+ ;
-: fill ( a u b -- ) >r >r begin V1 swap c!+ next drop rdrop ;
+: fill ( a u c -- ) >r >r begin V1 swap c!+ next drop rdrop ;
: allot0 ( n -- ) HERE @ over 0 fill allot ;
: align4 ( -- ) HERE @ 4 mod ?dup if 4 -^ allot0 then ;
: nc, ( n -- ) >r begin word runword c, next ;