2ddca57f3f
The goal was to be able to implement "(" in forth, but I realised that my INTERPRET approach was wrong. Compiling the line beforehand is, after all, not good. I'll have to change it again.
89 lines
3.7 KiB
Plaintext
89 lines
3.7 KiB
Plaintext
Stack notation: "<stack before> -- <stack after>". Rightmost is top of stack
|
|
(TOS). For example, in "a b -- c d", b is TOS before, d is TOS after. "R:" means
|
|
that the Return Stack is modified.
|
|
|
|
DOES>: Used inside a colon definition that itself uses CREATE, DOES> transforms
|
|
that newly created word into a "does cell", that is, a regular cell ( when
|
|
called, puts the cell's addr on PS), but right after that, it executes words
|
|
that appear after the DOES>.
|
|
|
|
"does cells" always allocate 4 bytes (2 for the cell, 2 for the DOES> link) and
|
|
there is no need for ALLOT in colon definition.
|
|
|
|
At compile time, colon definition stops processing words when reaching the
|
|
DOES>.
|
|
|
|
Example: ": CONSTANT CREATE HERE @ ! DOES> @ ;"
|
|
|
|
Word references (wordref): When we say we have a "word reference", it's a
|
|
pointer to a words *code link*. For example, the label "PLUS:" in this unit is a
|
|
word reference. Why not refer to the beginning of the word struct? Because we
|
|
actually seldom refer to the name and prev link, except during compilation, so
|
|
defining "word reference" this way makes the code easier to understand.
|
|
|
|
Atom: A word of the type compiledWord contains, in its PF, a list of what we
|
|
call "atoms". Those atoms are most of the time word references, but they can
|
|
also be references to NUMBER and LIT.
|
|
|
|
*** Defining words ***
|
|
: x ... -- Define a new word
|
|
; R:I -- Exit a colon definition
|
|
ALLOT n -- Move HERE by n bytes
|
|
CREATE x -- Create cell named x. Doesn't allocate a PF.
|
|
CONSTANT x n -- Creates cell x that when called pushes its value
|
|
DOES> -- See description at top of file
|
|
IMMEDIATE -- Flag the latest defined word as immediate.
|
|
LITERAL n -- Inserts number from TOS as a literal
|
|
VARIABLE c -- Creates cell x with 2 bytes allocation.
|
|
|
|
*** Flow ***
|
|
ELSE -- Branch to THEN
|
|
EXECUTE a -- Execute wordref at addr a
|
|
IF n -- Branch to ELSE or THEN if n is zero
|
|
INTERPRET -- Get a line from stdin, compile it in tmp memory,
|
|
then execute the compiled contents.
|
|
QUIT R:drop -- Return to interpreter promp immediately
|
|
RECURSE R:I -- R:I-2 Run the current word again.
|
|
THEN -- Does nothing. Serves as a branching merker for IF
|
|
and ELSE.
|
|
|
|
*** Stack ***
|
|
DUP a -- a a
|
|
OVER a b -- a b a
|
|
SWAP a b -- b a
|
|
|
|
*** Memory ***
|
|
@ a -- n Set n to value at address a
|
|
! n a -- Store n in address a
|
|
? a -- Print value of addr a
|
|
+! n a -- Increase value of addr a by n
|
|
CURRENT -- n Set n to wordref of last added entry.
|
|
HERE -- a Push HERE's address
|
|
|
|
*** Arithmetic ***
|
|
|
|
+ a b -- c a + b -> c
|
|
- a b -- c a - b -> c
|
|
* a b -- c a * b -> c
|
|
/ a b -- c a / b -> c
|
|
|
|
*** Logic ***
|
|
= n1 n2 -- f Push true if n1 == n2
|
|
< n1 n2 -- f Push true if n1 < n2
|
|
> n1 n2 -- f Push true if n1 > n2
|
|
CMP n1 n2 -- n Compare n1 and n2 and set n to -1, 0, or 1.
|
|
n=0: a1=a2. n=1: a1>a2. n=-1: a1<a2.
|
|
NOT f -- f Push the logical opposite of f
|
|
|
|
*** Strings ***
|
|
LIT@ x -- a Read folloing LIT and push its addr to a
|
|
S= a1 a2 -- n Compare strings a1 and a2. See CMP
|
|
|
|
*** I/O ***
|
|
. n -- Print n in its decimal form
|
|
EMIT c -- Spit char c to stdout
|
|
KEY -- c Get char c from stdin
|
|
PC! c a -- Spit c to port a
|
|
PC@ a -- c Fetch c from port a
|
|
|