about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authornratan <narenratan@gmail.com>2019-11-03 18:39:09 +0000
committernratan <narenratan@gmail.com>2019-11-03 18:39:09 +0000
commit47ab3e9e83210929097ed400ff29be40895fa586 (patch)
tree89ccbaed146bf1eb70fc1fc9c788e55864678abf
downloadjonesforth_arm64_apl-47ab3e9e83210929097ed400ff29be40895fa586.tar.gz
First commit
-rw-r--r--README.md41
-rw-r--r--ascii.f56
-rw-r--r--examples/combinators.f144
-rw-r--r--examples/continuations.f98
-rw-r--r--examples/defining_words.f37
-rw-r--r--examples/exceptions.f11
-rw-r--r--examples/sockets.f39
-rw-r--r--jonesforth.S250
-rw-r--r--jonesforth.f192
-rw-r--r--original_jonesforth/Makefile50
-rw-r--r--original_jonesforth/README3
-rw-r--r--original_jonesforth/jonesforth.S2313
-rw-r--r--original_jonesforth/jonesforth.f1788
-rw-r--r--original_jonesforth/perf_dupdrop.c33
-rw-r--r--original_jonesforth/perf_dupdrop.f79
-rw-r--r--original_jonesforth/test_assembler.f19
-rw-r--r--original_jonesforth/test_assembler.f.out8
-rw-r--r--original_jonesforth/test_comparison.f73
-rw-r--r--original_jonesforth/test_comparison.f.out70
-rw-r--r--original_jonesforth/test_exception.f13
-rw-r--r--original_jonesforth/test_exception.f.out6
-rw-r--r--original_jonesforth/test_number.f11
-rw-r--r--original_jonesforth/test_number.f.out5
-rw-r--r--original_jonesforth/test_read_file.f24
-rw-r--r--original_jonesforth/test_read_file.f.out7
-rw-r--r--original_jonesforth/test_stack.f17
-rw-r--r--original_jonesforth/test_stack.f.out11
-rw-r--r--original_jonesforth/test_stack_trace.f9
-rw-r--r--original_jonesforth/test_stack_trace.f.out6
29 files changed, 5413 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4cab30e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+*JonesForth ARM64 with APL symbols*
+
+This is an ARMv8 AArch64 version of Richard W.M. Jones' original x86 JonesForth.
+I have added a few things including:
+
+    - Defining words
+    - Combinators
+    - Delimited continuations
+
+Also I have used the APL character set.
+
+The pizza is in the examples dir but by way of garlic bread:
+
+∇ ε ( ⌈⌊ ⊤ - ↑ ∥) ↓ ∇   / Define ε as Euclid's algorithm /          
+
+∇ λ ◁ , ▷ @ ⍎ ∇         / A defining word λ which names anonymous functions /
+
+3 ⊂ ↑ ⊃ ⊂ + ⊃ cat ⍎     / Double three using the cat combinator /
+
+1 2 3 4 ⊂ × ⟦ + - ⊃ ⟧ ⍎ / Capture '+ -' in a delimited continuation with ⟦ ⟧ /
+
+ASCII equivalents for APL-character words are defined in ascii.f (they are the
+corresponding Forth words where applicable so ascii.f makes a handy glossary).
+
+
+You can compile and run with
+
+    gcc -nostdlib jonesforth.S
+
+    cat jonesforth.f - | ./a.out
+
+and run the the examples like
+
+    cat jonesforth.f examples/sockets.f - | ./a.out
+
+You may need to
+
+    stty iutf8
+
+if your terminal isn't set up to handle utf8 by default.
+
diff --git a/ascii.f b/ascii.f
new file mode 100644
index 0000000..aef8e29
--- /dev/null
+++ b/ascii.f
@@ -0,0 +1,56 @@
+/ ASCII equivalents for APL-character words /
+
+∇ DROP      ↓       ∇
+∇ DUP       ↑       ∇
+∇ 2DROP     2↓      ∇
+∇ 2DUP      2↑      ∇
+∇ ROT       ⌽       ∇
+∇ -ROT      -⌽      ∇
+∇ SWAP      ↕       ∇
+∇ OVER      ⊤       ∇
+
+∇ *         ×       ∇
+∇ %         ÷       ∇
+∇ MAX       ⌈       ∇
+∇ MIN       ⌊       ∇
+∇ %MOD      ÷MOD    ∇
+
+∇ !=        ≠       ∇
+∇ <=        ≤       ∇
+∇ >=        ≥       ∇
+∇ AND       ∧       ∇
+∇ OR        ∨       ∇
+∇ XOR       ⊕       ∇
+
+∇ 40ROT     40⌽     ∇
+∇ 20ROT     20⌽     ∇
+∇ 10ROT     10⌽     ∇
+∇ 1ROT      1⌽      ∇
+∇ ROR       ⌽>      ∇
+
+∇ RDROP     R↓      ∇
+∇ RDUP      R↑      ∇
+
+∇ EXECUTE   ⍎       ∇
+
+∇ ||        ∥       ∇
+∇ ||)       ∥)      ∇
+
+∇ MAXMIN    ⌈⌊      ∇
+
+∇ NONAME    ⊂       ∇
+
+∇ CODE      ∆       ∇
+∇ <>        ⋄       ∇
+∇ <BUILDS   ◁       ∇
+∇ DOES>     ▷       ∇
+
+∇ LAMBDA    λ       ∇
+
+∇ [[        ⟦       ∇
+∇ ]]        ⟧       ∇
+
+∇ READ      ⍇       ∇
+∇ WRITE     ⍈       ∇
+∇ OPEN      ⍐       ∇
+∇ CLOSE     ⍗       ∇
diff --git a/examples/combinators.f b/examples/combinators.f
new file mode 100644
index 0000000..21f75e8
--- /dev/null
+++ b/examples/combinators.f
@@ -0,0 +1,144 @@
+/ Combinators /
+/ Following Brent Kerby's 'The Theory of Concatenative Combinators' (TCC) /
+
+/ Everything below doubles 3 /
+
+3 ↑ +                   / Double 3 /
+
+3 ⊂ ↑ + ⊃ ⍎             / Push execution token to stack, execute it /
+
+3 ⊂ ↑ + ⊃ unit ⍎ ⍎      / Push execution token, wrap with unit, unwrap with ⍎, execute with ⍎ /
+
+3 ⊂ ↑ ⊃ ⊂ + ⊃ cat ⍎     / Push separate execution tokens for ↑ and +, combine with cat, execute with ⍎ /
+
+3 ⊂ + ⊃ ⊂ ↑ ⊃ ↕ cat ⍎   / Push executions for + and ↑, swap order with ↕, combine with cat, execute /
+
+/ The examples above illustrate the definitions of the combinators /
+/ The combinators also satisfy some interesting identities /
+/ For example 
+
+                unit ≡ ⊂⊃ cons
+
+so this also doubles 3: /
+
+3 ⊂ ↑ + ⊃ ⊂⊃ cons ⍎ ⍎
+
+/ We can define a unit' which does this: /
+
+∇ unit' ⊂⊃ cons ∇
+
+3 ⊂ ↑ + ⊃ unit' ⍎ ⍎
+
+/ The following also doubles three: /
+
+3 ⊂ ↑ ⊃ ⊂ + ⊃ ⊂ ⍎ ⊃ ⊂ dip ⍎ ⊃ cons cons cons ⍎
+
+/ This is because of the identity
+
+        cat ≡ ⊂ ⍎ ⊃ ⊂ dip ⍎ ⊃ cons cons cons
+
+We can define a new cat' which does this:
+/
+
+⊂ dip ⍎ ⊃ ⊂ ⍎ ⊃ ∇ cat' LITERAL LITERAL cons cons cons ∇
+
+/ The LITERALs just compile the execution tokens in the definition of cat' /
+
+3 ⊂ ↑ ⊃ ⊂ + ⊃ cat' ⍎
+
+/ Also cons can be written in terms of cat,
+
+        cons ≡ ⊂ unit ⊃ dip cat
+
+giving /
+
+⊂ unit ⊃ ∇ cons' LITERAL dip cat ∇
+
+3 ⊂ ↑ + ⊃ ⊂⊃ cons' ⍎ ⍎
+
+/ swap ≡ unit dip /
+
+∇ swap' unit dip ∇
+
+3 ⊂ + ⊃ ⊂ ↑ ⊃ swap' cat ⍎
+
+∇ dip' ↕ unit cat ⍎ ∇
+
+3 ⊂ + ⊃ ⊂ ↑ ⊃ unit dip' cat ⍎
+
+/ ⍎ ≡ ↑ dip ↓ /                 ∇ ⍎'    ↑ dip ↓ ∇
+/ ⍎ ≡ ⊂⊃ unit dip dip ↓ /       ∇ ⍎''   ⊂⊃ unit dip dip ↓ ∇
+/ ⍎ ≡ ⊂⊃ unit dip dip dip /     ∇ ⍎'''  ⊂⊃ unit dip dip dip ∇
+
+3 ⊂ ↑ + ⊃ ⍎'
+
+3 ⊂ ↑ + ⊃ ⍎''
+
+3 ⊂ ↑ + ⊃ ⍎'''
+
+/ Lambdas /
+/ λ (written \ in TCC) can be implemented as a Forth defining word /
+
+∇ λ ◁ , ▷ @ ⍎ ∇
+
+/ dip ≡ λ a λ b a ⊂ b ⊃ /
+
+3 ⊂ + ⊃ ⊂ ↑ ⊃ unit λ a λ b a ⊂ b ⊃ cat ⍎
+
+/ End of scope ($ in TCC) can be done with HIDE a /
+
+∇ $ HIDE ∇
+
+/ An Abstraction Algorithm /
+/ TCC gives an algorithm to eliminate λ's from combinators. Applying it /
+/ gives the equivalence of /
+
+/ λ a b a ⊂ c a ⊃   ≡   ⊂ b ⊃ dip ↑ ⊂ ⍎ ⊃ dip ⊂ c ⊃ ⊂ dip ⍎ ⊃ cons cons /
+/ ( lambda )                    ( no lambda ) /
+
+/ For example, letting b be ↑ and c be + and trying each of the above /
+/ combinators on a stack with 2 ⊂ 1+ ⊃ on ( adding an ⍎ at the end of /
+/ both to test the effect of the ⊂ c a ⊃ left on top of the stack) /
+
+⊂ ↑ ⊃ ⊂ + ⊃ λ c λ b
+        2 ⊂ 1+ ⊃     λ a b a ⊂ c a ⊃ ⍎
+        2 ⊂ 1+ ⊃     ⊂ b ⊃ dip ↑ ⊂ ⍎ ⊃ dip ⊂ c ⊃ ⊂ dip ⍎ ⊃ cons cons ⍎
+
+/ Both give 6 since in this case both lines are equivalent to 2 ↑ 1+ + 1+ /
+
+/ The sip Combinator /
+/ ⊂ b ⊃ ⊂ a ⊃ sip   ≡   ⊂ b ⊃ a ⊂ b ⊃ /
+
+/ ↑ ≡ ⊂⊃ sip /
+3 ⊂⊃ sip +
+
+/ dip ≡ λ a ⊂ ↓ a ⊃ sip /
+3 ⊂ + ⊃ ⊂ ↑ ⊃ unit   λ a ⊂ ↓ a ⊃ sip   cat ⍎
+
+/ dip ≡ ⊂ ↓ ↓ ⊃ ⊂ sip ⍎ ⊃ cons cons sip /
+3 ⊂ + ⊃ ⊂ ↑ ⊃ unit   ⊂ ↓ ↓ ⊃ ⊂ sip ⍎ ⊃ cons cons sip   cat ⍎
+
+/ Applicative Combinators /
+
+∇ w ['] ↑ dip ⍎ ∇
+∇ k ['] ↓ dip ⍎ ∇
+∇ b ['] cons dip ⍎ ∇
+∇ c ['] ↕ dip ⍎ ∇
+
+∇ s >R ⊤ ↕ cons ↕ R> ⍎ ∇
+
+/ ↑    ≡ ⊂⊃ w /
+/ ↓    ≡ ⊂⊃ k /
+/ cons ≡ ⊂⊃ b /
+/ ↕    ≡ ⊂⊃ c /
+
+3 ⊂⊃ w +
+3 ↑ ↑ ⊂⊃ k +
+3 ⊂ ↑ + ⊃ ⊂⊃  ⊂⊃ b  ⍎ ⍎
+3 ⊂ + ⊃ ⊂ ↑ ⊃ ⊂⊃ c cat ⍎
+
+/ b ≡ ⊂ k ⊃ ⊂ s ⊃ ⊂ k ⊃ cons s /
+
+⊂ k ⊃ ⊂ s ⊃ ⊂ k ⊃ ∇ b' LITERAL LITERAL LITERAL cons s ∇
+
+3 ⊂ ↑ + ⊃ ⊂⊃  ⊂⊃ b'  ⍎ ⍎
diff --git a/examples/continuations.f b/examples/continuations.f
new file mode 100644
index 0000000..1ea66bf
--- /dev/null
+++ b/examples/continuations.f
@@ -0,0 +1,98 @@
+/ Delimited continuations /
+/
+When THROWing an exception we unwind the return stack and ignore all the return
+addresses until the marker left by CATCH. But we can instead compile them into a
+word which when run will push them onto the return stack - and so do the work we
+have skipped by THROWing the exception. This word is called a delimited
+continuation. We can leave its execution token on top of the data stack.
+
+The following four lines all calculate the same thing:
+/
+
+1 2 3 4 × + -                           / Initial calculation /
+
+1 2 3 4 ⊂ × + - ⊃ ⍎                     / Push an execution token for the whole calculation and execute it /
+
+1 2 3 4 ⊂ × ⟦ + - ⊃ ⟧ ⍎                 / Do the ×, push an execution token for the + -, execute it /
+
+1 2 3 4 ⊂ × + ⟦ - ⊃ ⟧ ⍎                 / Do the × +, push an execution token for the -, execute it /
+
+/
+The continuation works even if the [[ is further down
+the return stack, e.g.
+/
+
+∇ new+ + ⟦ 42 EMIT ∇                    / Word containing ⟦ /
+
+1 2 3 4 ⊂ × new+ - ⊃ ⟧                  / Do the × and new+ up to ⟦ (so just the +), push xt for rest of work /
+⍎                                       / Execute rest of work, i.e. do rest of new+ (prints B) and the - /
+
+/
+The continuation is just like any execution token; in particular it can be
+manipulated with combinators. For example to execute it twice we can use ↑ cat
+/
+
+1 2 3 4 5 × + - -                       / Initial calculation /
+
+1 2 3 4 5 ⊂ × + ⟦ - ⊃ ⟧ ↑ cat   ⍎       / Capture - in continuation, make execution token to do it twice, execute it /
+
+1 2 3 4 5 ⊂ × new+ - ⊃ ⟧ ↑ cat ⍎        / Prints B twice since continuation executed twice /
+
+
+
+/
+Below are some examples illustrating how to execute Forth words by pushing their
+corresponding return addresses to the return stack. They're probably unnecessary
+but they are the experiments I did before writing [[ and ]] so I have left them
+in in case they help anyone else.
+/
+
+∇ α ↑ ∇                 / Example Forth words /
+∇ β × ∇
+
+3 α β                   / α β is just ↑ ×, squares 3 /
+
+∇ ρ find >CFA 8+ ∇      / ρ gets return stack address corresponding to a word /
+
+ρ α CONST rα            / Return stack addresses of α and β /
+ρ β CONST rβ
+
+∇ ψ rβ >R rα >R ∇       / ψ pushes addresses rβ and rα onto return stack /
+
+3 ψ                     / ψ does the same thing as α β /
+
+/
+We can execute a Forth word by directly pushing the corresponding return stack
+address onto the return stack.
+
+We can even jump inside words by adding an offset to their return address.
+/
+
+∇ γ 8+ NEG ∇
+ρ γ 8+ CONST rγ+
+
+∇ ω rγ+ >R ∇
+
+3 γ                     / Gives 3 8+ NEG /
+3 ω                     / Gives 3 NEG /
+
+/
+If all the addresses are the first in Forth words it is simpler to let DOCOL do
+the work.
+/
+
+rβ 8- rα 8- ∇ ψ' [ , , ] ∇
+
+3 ψ'                    / ψ' does the same thing as ψ /
+
+/
+This doesn't work trying to jump into a word since in this case there is no
+DOCOL 8 bytes before the return address, e.g.
+/
+
+rγ+ 8- ∇ ω' [ , ] ∇     / ω' doesn't work! /
+
+∇ ψω rγ+ >R rβ >R rα >R ∇
+
+3 ψω                    / Gives 3 ↑ × NEG /
+
diff --git a/examples/defining_words.f b/examples/defining_words.f
new file mode 100644
index 0000000..f871a58
--- /dev/null
+++ b/examples/defining_words.f
@@ -0,0 +1,37 @@
+/ Defining words examples /
+
+∇ VECTOR ◁ CELLS ALLOT ▷ ↕ CELLS + ∇
+
+/
+When a vector β is being defined as 'N VECTOR β' all that happens is N cells
+are allotted to store its elements.
+When it is used as 'i β' it returns the address of its ith element.
+/
+
+2 VECTOR β      / Define a length 2 vector β /
+
+6 0 β !         / β ≡ 6 7 /
+7 1 β !
+
+0 β ? CR        / Check the elements of β /
+1 β ? CR
+
+∇ ARRAY ◁ ⊤ , × CELLS ALLOT ▷ ↑ @ ⌽ × CELLS + ↕ CELLS + 8+ ∇
+
+/
+When an array is being defined as 'N M ARRAY μ' the value of N is stored in the
+header and N×M cells are allotted for its elements.
+When it is used as 'i j μ' it returns the address of its (i,j) element.
+/
+
+2 2 ARRAY μ     / Define a 2×2 array μ /
+
+6 0 0 μ !       / μ ≡ 6 7 /
+7 0 1 μ !       /     8 9 /
+8 1 0 μ !
+9 1 1 μ !
+
+0 0 μ ? CR      / Check the elements of μ /
+0 1 μ ? CR
+1 0 μ ? CR
+1 1 μ ? CR
diff --git a/examples/exceptions.f b/examples/exceptions.f
new file mode 100644
index 0000000..3e51316
--- /dev/null
+++ b/examples/exceptions.f
@@ -0,0 +1,11 @@
+/ Exceptions examples /
+
+∇ SHOW .S CR CLEAR ∇            / Print then clear stack /
+
+1 2 ⊂ + ⊃ ⍎                     / Just runs + / SHOW
+
+1 2 ⊂ + 0 THROW ⊃ CATCH         / Runs +, no exception thrown → 0 pushed to stack / SHOW
+
+1 2 ⊂ + ABORT ⊃ CATCH           / Exception -1 thrown → Stack rewound, -1 pushed to stack / SHOW
+
+1 2 ⊂ + ABORT ⊃ ⍎               / Uncaught exception /
diff --git a/examples/sockets.f b/examples/sockets.f
new file mode 100644
index 0000000..55611db
--- /dev/null
+++ b/examples/sockets.f
@@ -0,0 +1,39 @@
+/ Socket syscalls examples /
+/ Based on Beej's Guide to Network Programming /
+
+/ Socket syscalls /
+∇ SOCKET C6 3 SYS ∇     ∇ TSOC 0 1 2 SOCKET ∇
+∇ LISTEN C9 2 SYS ∇     ∇ LIS 0 ↕ LISTEN ↓ ∇
+∇ BIND C8 3 SYS ∇       ∇ BIN 10 ↕ ⌽ BIND ↓ ∇
+∇ CONNECT CB 3 SYS ∇    ∇ CON 10 ↕ ⌽ CONNECT ↓ ∇
+∇ ACCEPT CA 3 SYS ∇     ∇ ACC 0 0 ⌽ ACCEPT ∇
+
+/ PORT builds port struct /
+/ e.g. FA0 PORT leaves port struct for port 4000 on the stack /
+∇ PORT 10⌽ 10 << 2 + ∇ / n→n /
+
+/ TCP client and server /
+/ Try running in separate JonesForth processes as e.g. FA0 PORT SERVER and FA0 PORT CLIENT /
+
+∇ SERVER / n→ /
+        H ! TSOC ↑ ↑ H BIN LIS
+        ( ↑ ACC S" Weasel attack!" ↕ ⌽ ⍈ ." Accepted" CR ∥) ∇
+
+∇ CLIENT / n→ /
+        H ! TSOC ↑ H CON
+        10 H ⌽ ⍇ H ↕ TELL ∇
+
+/ UDP talker and listener /
+∇ USOC 0 2 2 SOCKET ∇
+∇ SENDTO CE 6 SYS ∇
+∇ RECVFROM CF 6 SYS ∇
+VAR &10
+10 &10 !
+
+∇ LISTENER
+H ! USOC ↑ H BIN
+>R &10 H 0 10 H 20 + R> RECVFROM
+H 20 + ↕ TELL ∇
+
+∇ TALKER
+H ! USOC >R 10 H 0 S" Weasel" ↕ R> SENDTO ∇
diff --git a/jonesforth.S b/jonesforth.S
new file mode 100644
index 0000000..c585eff
--- /dev/null
+++ b/jonesforth.S
@@ -0,0 +1,250 @@
+// JonesForth ARM64 (ARMv8 AArch64)
+// Richard W.M. Jones' original x86 JonesForth available at http://git.annexia.org/?p=jonesforth.git
+
+// Pointers
+#define	D x19 			// Data stack pointer
+#define	R x20 			// Return stack pointer
+#define I x21			// Instruction pointer
+#define J x22			// Codeword pointer
+
+#define S x23			// State
+#define H x24			// Here pointer
+#define L x25			// Latest pointer
+
+#define D0 x26			// Data stack top pointer
+#define R0 x27			// Return stack top pointer
+
+#define PDOC x28		// DOCOL pointer
+#define PLIT x29		// LIT pointer
+
+#define W x12			// Word register
+#define F x13			// Find register
+#define N x14			// Number register
+
+#define B x15			// Buffer pointer
+#define K x16			// Key pointer
+#define E x17			// End pointer
+#define OUTB x11		// Output buffer pointer
+
+// Stack macros
+.macro push s,x; str \x,[\s,-8]!; .endm		// e.g. push D,x0 pushes x0 to data stack
+.macro push2 s,x,y; stp \y,\x,[\s,-16]!; .endm	// One instruction, two pushes!
+.macro pop s,x; ldr \x,[\s],8; .endm		// e.g. pop R,I pops instruction pointer from return stack
+.macro pop2 s,x,y; ldp \x,\y,[\s],16; .endm	// One instruction, two pops!
+
+// Definition macros
+.macro def x				// Define assembly word
+	.data; .align 3
+"l\x":	.xword link; .set link, "l\x"	// Dictionary pointer (to last word defined)
+	.ascii "\x"; .align 3		// 8-byte name
+"\x":	.xword "c\x"			// Codeword - points to assembly code defined below
+	.text
+"c\x": 	; .endm				// Assembly code follows
+
+.macro defw x				// Define Forth word
+	.data; .align 3
+"l\x":	.xword link; .set link, "l\x"	// Dictionary pointer
+	.ascii "\x"; .align 3		// 8-byte name
+"\x":	.xword docol; .endm		// Codeword - docol points to code which runs the Forth words to follow
+
+.set link, 0				// link points to last defined word; it is updated by def and defw
+
+// Forthisms
+.macro NEXT; ldr J,[I],8; ldr x0,[J]; br x0; .endm	// Run next word (ends assembly words)
+docol:	push R,I; add I,J,8; NEXT			// Code to run a Forth word (the one found after J)
+def EXIT; pop R,I; NEXT					// Finish running a Forth word, run next word
+def LIT; ldr x0,[I],8; push D,x0; NEXT			// Push following literal number to stack and skip it
+
+// Assembly functions
+// Stack manipulation
+def ↓; add D,D,8; NEXT;							def ↑; ldr x0,[D]; push D,x0; NEXT
+def 2↓; add D,D,16; NEXT;						def 2↑; ldp x0,x1,[D]; push2 D,x1,x0; NEXT
+def ⌽; pop2 D,x0,x1; pop D,x2; push2 D,x1,x0; push D,x2; NEXT;		def -⌽; pop2 D,x0,x1; pop D,x2; push2 D,x0,x2; push D,x1; NEXT
+def ↕; pop2 D,x0,x1; push2 D,x0,x1; NEXT;				def ⊤; ldr x0,[D,8]; push D,x0; NEXT;
+
+// Arithmetic
+def +; pop2 D,x0,x1; add x0,x1,x0; push D,x0; NEXT;			def -; pop2 D,x0,x1; sub x0,x1,x0; push D,x0; NEXT
+def ×; pop2 D,x0,x1; mul x0,x1,x0; push D,x0; NEXT;			def ÷; pop2 D,x0,x1; sdiv x0,x1,x0; push D,x0; NEXT
+def ⌈; pop2 D,x0,x1; cmp x1,x0; csel x0,x1,x0,gt; push D,x0; NEXT;	def ⌊; pop2 D,x0,x1; cmp x1,x0; csel x0,x1,x0,lt; push D,x0; NEXT
+def 1+; pop D,x0; add x0,x0,1; push D,x0; NEXT;				def 1-; pop D,x0; sub x0,x0,1; push D,x0; NEXT
+def 8+; pop D,x0; add x0,x0,8; push D,x0; NEXT;				def 8-; pop D,x0; sub x0,x0,8; push D,x0; NEXT
+def ÷MOD; pop2 D x0,x1; sdiv x2,x1,x0; msub x1,x0,x2,x1; push2 D,x1,x2; NEXT
+
+// Logic
+def "="; pop2 D,x0,x1; cmp x1,x0; cset x0,eq; push D,x0; NEXT;		def ≠; pop2 D,x0,x1; cmp x1,x0; cset x0,ne; push D,x0; NEXT
+def <; pop2 D,x0,x1; cmp x1,x0; cset x0,lt; push D,x0; NEXT;		def >; pop2 D,x0,x1; cmp x1,x0; cset x0,gt; push D,x0; NEXT
+def ≤; pop2 D,x0,x1; cmp x1,x0; cset x0,le; push D,x0; NEXT;		def ≥; pop2 D,x0,x1; cmp x1,x0; cset x0,ge; push D,x0; NEXT
+def "0="; pop D,x0; cmp x0,0; cset x0,eq; push D,x0; NEXT;		def 0≠; pop D,x0; cmp x0,0; cset x0,ne; push D,x0; NEXT
+def 0<; pop D,x0; cmp x0,0; cset x0,lt; push D,x0; NEXT;		def 0>; pop D,x0; cmp x0,0; cset x0,gt; push D,x0; NEXT
+def 0≤; pop D,x0; cmp x0,0; cset x0,le; push D,x0; NEXT;		def 0≥; pop D,x0; cmp x0,0; cset x0,ge; push D,x0; NEXT
+def ∧; pop2 D,x0,x1; and x0,x1,x0; push D,x0; NEXT;			def ∨; pop2 D,x0,x1; orr x0,x1,x0; push D,x0; NEXT
+def ~; pop D,x0; mvn x0,x0; push D,x0; NEXT;				def ⊕; pop2 D,x0,x1; eor x0,x1,x0; push D,x0; NEXT
+
+// Bitwise operations
+def 40⌽; pop D,x0; rev x0,x0; push D,x0; NEXT;				def 20⌽; pop D,x0; rev32 x0,x0; push D,x0; NEXT
+def 10⌽; pop D,x0; rev16 x0,x0; push D,x0; NEXT;			def 1⌽; pop D,x0; rbit x0,x0; push D,x0; NEXT
+def >>;	pop2 D,x0,x1; lsr x0,x1,x0; push D,x0; NEXT;			def <<;	pop2 D,x0,x1; lsl x0,x1,x0; push D,x0; NEXT
+def ⌽>;	pop2 D,x0,x1; ror x0,x1,x0; push D,x0; NEXT
+
+// Memory
+def !; pop2 D,x0,x1; str x1,[x0]; NEXT;					def @; pop D,x0; ldr x0,[x0]; push D,x0; NEXT
+def +!; pop2 D,x0,x1; ldr x2,[x0]; add x1,x2,x1; str x1,[x0]; NEXT;	def -!; pop2 D,x0,x1; ldr x2,[x0]; sub x1,x2,x1; str x1,[x0]; NEXT
+def C!; pop2 D,x0,x1; strb w1,[x0]; NEXT;				def C@; pop D,x0; ldrb w0,[x0]; push D,x0; NEXT
+
+def MOVE; pop2 D,x0,x1; pop D,x2; 1:ldr x3,[x1],8; str x3,[x2],8; sub x0,x0,1; cbnz x0,1b; NEXT
+def CMOVE; pop2 D,x0,x1; pop D,x2; 1:ldrb w3,[x1],1; strb w3,[x2],1; sub x0,x0,1; cbnz x0,1b; NEXT
+
+// Return stack
+def ">R"; pop D,x0; push R,x0; NEXT;					def "R>"; pop R,x0; push D,x0; NEXT
+def "R↓"; add R,R,8; NEXT;						def "R↑"; ldr x0,[R]; push R,x0; NEXT
+
+// Register values
+def "D"; mov x0,D; push D,x0; NEXT; 					def "D!"; pop D,x0; mov D,x0; NEXT
+def "R"; push D,R; NEXT; 						def "R!"; pop D,R; NEXT
+def "H"; push D,H; NEXT; 						def "H!"; pop D,H; NEXT
+def "L"; push D,L; NEXT; 						def "L!"; pop D,L; NEXT
+def "S"; push D,S; NEXT; 						def "S!"; pop D,S; NEXT
+
+def "D0"; push D,D0; NEXT
+def "R0"; push D,R0; NEXT
+def DOCOL; push D,PDOC; NEXT
+
+def KEY; bl key; push D,x0; NEXT;
+
+key:	cmp K,E; b.ge fill; ldrb w0,[K],1; ret			// Fill buffer if exhausted and read next character
+fill:	mov x0,0; mov x1,B; mov x2,4096; mov x8,63; svc 0	// stdin, buffer start, buffer size, read syscall
+	add E,B,x0; mov K,B					// Update E, reset K
+	cbnz x0,key; mov x8,93; svc 0				// Exit 0 if no characters read
+
+	.bss
+b:	.space 4096						// Input buffer
+outb:	.space 16						// Output buffer
+
+def EMIT; mov x0,1; mov x1,D; mov x2,1; mov x8,64; svc 0; add D,D,8; NEXT	// Write top of stack to stdout
+
+// The word macro loads next the next input word into W register
+// It leaves N register ready to convert the word into a number (byte order ready to treat 42 as 00000042)
+.macro word
+	mov N,0							// Zero number register
+1:	bl key; cmp w0,' '; ble 1b;				// Skip leading whitespace
+2: 	add N,x0,N,lsl 8; bl key; cmp w0,' '; bgt 2b		// Add bytes until next whitespace
+3:	clz x0,N; and x0,x0,~7; lsl W,N,x0; rev W,W; .endm	// Match byte arrangement of names loaded from memory in W
+
+def WORD; word; NEXT
+
+// Vector registers holding constants (for ASCII ←→ number conversion)
+#define VC0A v8
+#define VC0F v9
+#define VC20 v10
+#define VC30 v11
+#define VC37 v12
+#define VC41 v13
+
+.macro number	// characters → number
+	mov v2.2d[0],N; cmeq v0.8b,v2.8b,0; bsl v0.8b,VC30.8b,v2.8b		// Fill null bytes with '0'
+	sub v1.8b,v0.8b,VC30.8b; sub v2.8b,v0.8b,VC37.8b			// Calculate values from characters
+	cmge v3.8b,v0.8b,VC41.8b; bsl v3.8b,v2.8b,v1.8b				// Conditionally select values from 0-9 or A-F
+	ushr v4.2d,v3.2d,4; add v3.8b,v3.8b,v4.8b; uzp1 v3.8b,v3.8b,v3.8b	// Pack half bytes into bytes (01 0A → 1A)
+	mov w14,v3.s[1]; .endm							// Store number in lower half of N
+
+.macro unnumber	// number → characters
+	orr x0,N,1; clz x0,x0; and x0,x0,~7; movn x1,0; lsl x0,x1,x0; mov v2.2d[0],x0; zip1 v2.16b,v2.16b,v2.16b
+	rev N,N; mov v0.2d[0],N
+	ushr v1.8b,v0.8b,4; zip1 v0.16b,v1.16b,v0.16b; and v0.16b,v0.16b,VC0F.16b
+	cmge v1.16b,v0.16b,VC0A.16b; bsl v1.16b,VC37.16b,VC30.16b; add v1.16b,v0.16b,v1.16b
+	bsl v2.16b,v1.16b,VC20.16b; st1 {v2.16b},[OUTB]; .endm
+
+def NUMBER; number; push D,N; NEXT
+
+def U.; pop D,N; unnumber					// Print number on top of stack
+	mov x0,1; mov x1,OUTB; mov x2,16; mov x8,64; svc 0
+	NEXT
+
+.set FIMMED, 0x80	// Immediate flag (stored in top bit of last byte of a name)
+
+.macro find				// Search dictionary for word in W
+	mov F,L					// Start searching at latest word defined
+1:	cbz F,2f				// Stop if end of dictionary reached
+	ldr x0,[F,8]; bic x0,x0,FIMMED<<56	// Load name and zero immediate bit
+	cmp x0,W; beq 2f			// Stop if word matches
+	ldr F,[F]; b 1b				// Otherwise loop
+2:	; .endm
+
+def FIND; find; push D,F; NEXT
+
+def MINTERP					// Minimal interpreter - no compiling (not used below)
+	word; find; cbz F,mnum			// Search for word; if not found convert it to a number
+	add J,F,16; ldr x0,[J]; br x0		// If word found, get its codeword and execute
+mnum:	number; push D,N; NEXT
+
+defw QUIT; .xword "R0","R!",INTERP,BR,-16	// Top loop - Reset return stack, interpret, repeat
+
+def ALIGN; add H,H,7; and H,H,~7; NEXT		// Round H up to next word boundary
+
+def CREATE; stp L,W,[H],16; sub L,H,16; NEXT	// Store link pointer and name Here, updating Here and Latest
+
+def ","; pop D,x0; str x0,[H],8; NEXT		// Store word at H
+def ",,"; pop D,x0; str w0,[H],4; NEXT		// Store half word at H
+def "C,"; pop D,x0; strb w0,[H],1; NEXT		// Store byte at H
+
+def "[\x0\x0\x0\x0\x0\x0\x80"; mov S,0; NEXT 	// [ starts compiling (defined with immediate flag)
+
+def "]"; mov S,1; NEXT				// ] Stops compiling
+
+// : creates a Forth word header (like defw) and starts compiling
+defw ":"; .xword ALIGN,WORD,CREATE,LIT,docol,",","]",EXIT
+
+// ; appends EXIT and stops compiling (immediate)
+defw ";\x0\x0\x0\x0\x0\x0\x80"; .xword LIT,EXIT,",","[\x0\x0\x0\x0\x0\x0\x80",EXIT
+
+// I sets immediate flag of latest word defined (I is itself immediate)
+def "I\x0\x0\x0\x0\x0\x0\x80"; ldr x0,[L,8]; eor x0,x0,FIMMED<<56; str x0,[L,8]; NEXT
+
+def "'"; ldr x0,[I],8; push D,x0; NEXT		// ' pushes next word to data stack and skips it
+
+def BR; ldr x0,[I]; add I,x0,I; NEXT		// Unconditional branch
+def BZ; pop D,x0; cbz x0,cBR; add I,I,8; NEXT	// Branch if zero
+def BNZ; pop D,x0; cbnz x0,cBR; add I,I,8; NEXT	// Branch if non-zero
+
+def LITS; ldr x0,[I],8; push2 D,I,x0; add I,I,x0; add I,I,8; and I,I,~7; NEXT	// Push string literal address+length to stack
+def TELL; mov x0,1; pop2 D,x2,x1; mov x8,64; svc 0; NEXT			// Print string
+
+def INTERP
+	word; find; cbz F,num			// Search for word; if not found, it is a number
+	add J,F,16; cbz S,ex			// Get codeword pointer; if not compiling, execute word
+	ldr x0,[J,-8]; tbnz x0,63,ex		// Check if word is immediate; if so execute it
+	str J,[H],8; NEXT			// Else just compile word
+num:	number; cbnz S,lit; push D,N; NEXT	// Convert to number; if compiling, compile literal, else push to stack
+lit:	stp PLIT,N,[H],16; NEXT			// Compile two words LIT N
+ex:	ldr x0,[J]; br x0			// Get codeword and execute it
+
+def CHAR; word; and x0,W,0xFF; push D,x0; NEXT	// Push first character of next input word
+
+def ⍎; pop D,J; ldr x0,[J]; br x0		// Execute (use top of stack as a codeword pointer)
+
+def "/\x0\x0\x0\x0\x0\x0\x80"; skip: bl key; cmp x0,'/'; bne skip; NEXT		// Use / for comments, e.g. / comment /
+
+def SYS	// n SYS performs syscall with n arguments
+	pop2 D,x9,x8; ldp x0,x1,[D]; ldp x2,x3,[D,16]; ldp x4,x5,[D,32]
+	svc 0; add D,D,x9,lsl 3; push D,x0; NEXT
+
+	.text
+	.globl _start
+_start:	mov D,sp					// Initialize Data stack pointer
+	adr R,Rtop;					// Initialize Return stack pointer
+	adr I,first					// Initialize Instruction pointer
+	mov S,0						// Initialize State
+	adr H,Dstart; adr L,lSYS			// Initialize Here and Latest pointers
+	adr B,b; mov K,B; mov E,B			// Initialize Buffer, Key, End pointers
+	adr OUTB,outb					// Initialize output buffer pointer
+	mov D0,D; mov R0,R				// Initialize stack top pointers
+	adr PLIT,LIT; adr PDOC,docol			// Initialize LIT and DOCOL pointers
+	movi VC0A.16b,10; movi VC0F.16b,0x0F		// Initialize constant vector registers
+	movi VC20.16b,32; movi VC30.16b,'0'
+	movi VC37.16b,55; movi VC41.16b,65
+	NEXT						// Start interpreter
+
+	.data
+first:	.xword QUIT
+	.bss
+	.align 3; Dstart: .space 16384; Rtop:		// Space for data area (pointed to by H) and return stack
diff --git a/jonesforth.f b/jonesforth.f
new file mode 100644
index 0000000..91af0d8
--- /dev/null
+++ b/jonesforth.f
@@ -0,0 +1,192 @@
+/ JonesForth ARM64 /
+/ based on Richard W.M. Jones' original x86 JonesForth /
+
+/ In stack comments n, a, and x are used to mean: /
+/       n | number              /
+/       a | address             /
+/       x | execution token     /
+
+: MOD ÷MOD ↓ ;                          / nn→n modulo by dropping quotient from ÷MOD /
+: NEG 0 ↕ - ;                           / n→n negate /
+
+: CR 0A EMIT ;                          / Print newline /
+: SPACE 20 EMIT ;                       / Print space /
+
+: find WORD FIND ;                      / find next word in input /
+: create WORD CREATE 0 , ;              / Create word header with next word as name, codeword pointer 0 /
+: ,LIT ' LIT , , ;                      / n→ Compile literal number /
+: LITERAL I ,LIT ;                      / n→ Compile literal number (immediate) /
+: >CFA 8+ 8+ ;                          / n→n Compute codeword address from dictionary pointer address /
+: >DFA >CFA 8+ ;                        / n→n Compute address of first word in definition from dictionary pointer address /
+: [COMP] I find >CFA , ;                / Compile an immediate word /
+
+/ Character constants /
+: '"' [ CHAR " ] LITERAL ;              / →n '"' pushes 22 (ASCII ") to the stack /
+: '-' [ CHAR - ] LITERAL ;              / →n '-' pushes 2D (ASCII -) to the stack /
+
+/ Control structures /
+: { I ' BZ , H 0 , ;                    / { A } does A if top of stack (TOS) is true /
+: } I ↑ H ↕ - ↕ ! ;
+: | I ' BR , H 0 , ↕ ↑ H ↕ - ↕ ! ;      / { A | B } does A if TOS true, B if false /
+
+: ( I H ;                               / ( A ∥ B ) does B while A gives true /
+: ∥ I ' BZ , H 0 , ;
+: ) I ' BR , ↕ H - , ↑ H ↕ - ↕ ! ;
+
+: ∥) I ' BNZ , H - , ;                  / ( A ∥) does A until false /
+: 1∥) I ' BR , H - , ;                  / ( A 1∥) does A indefinitely /
+
+: ∇ I S { [COMP] ; | : } ;              / ∇ starts and ends definitions /
+
+∇ . ↑ 0≥ { U. | NEG U. '-' EMIT } ∇     / n→ Print signed number /
+
+∇ ¯ I S { H 8- ↑ @ NEG ↕ ! | NEG } ∇    / n→n Compile time negate /
+
+∇ SPACES ( ↑ ∥ SPACE 1- ) ↓ ∇           / n→ Print n spaces /
+
+∇ .S D ( ↑ D0 < ∥ ↑ @ . CR 8+ ) ↓ ∇     / Print the stack /
+
+∇ ⌈⌊ 2↑ > { ↕ } ∇                       / nn→nn Sort top two elements of stack /
+
+∇ ε ( ⌈⌊ ⊤ - ↑ ∥) ↓ ∇                   / nn→n Euclid's algorithm for greatest common divisor /
+
+∇ ? @ . ∇                               / a→ Print contents of memory address /
+
+∇ WITHIN -⌽ ⊤ ≤ { > | 2↓ 0 } ∇          / nnn→n Check if number lies in range /
+
+∇ DEPTH D D0 ↕ - 8 ÷ ∇                  / →n Current stack depth /
+
+∇ CLEAR D0 D! ∇                         / Clear stack /
+
+/ Strings /
+∇ S" I ' LITS , H 0 , ( KEY ↑ '"' ≠ ∥ C, ) ↓ ↑ H ↕ - 8- ↕ ! 0 C, ALIGN ∇ / Compile a string in a word /
+∇ ." I S { [COMP] S" ' TELL , | ( KEY ↑ '"' ≠ ∥ EMIT ) ↓ } ∇             / Print a string /
+
+/ Constants and variables /
+∇ CONST WORD CREATE DOCOL , ' LIT , , ' EXIT , ∇
+∇ ALLOT H + H! ∇ / n→ /
+∇ CELLS 8 × ∇ / n→n /
+∇ VAR H 1 CELLS ALLOT CONST ∇
+
+/ Values /
+∇ VALUE WORD CREATE DOCOL , ' LIT , , ' EXIT , ∇
+∇ TO I find >DFA 8+ S {  ' LIT , , ' ! , | ! } ∇
+∇ +TO I find >DFA 8+ S {  ' LIT , , ' +! , | +! } ∇
+
+/ Dictionary /
+∇ ID. @ 1 1⌽ ~ ∧ H ! H 8 TELL ∇         / a→ Print name at address a (masking immediate bit) /
+∇ WORDS L ( ↑ 8+ ID. SPACE @ ↑ ∥) ↓ ∇   / Print all words in dictionary /
+∇ FORGET find ↑ @ L! H! ∇               / forget all words after next word in input stream /
+
+∇ 1DUMP ↑ U. SPACE @ 40⌽ U. ∇ / a→ /
+∇ DUMP ( ↑ ∥ ↕ ↑ 1DUMP CR 8+ ↕ 1- ) 2↓ ∇ / an→ /
+
+∇ INDATA? [ find EXIT ] LITERAL [ find MOD 4000 + ] LITERAL WITHIN ∇                    / a→n Check if address is in data area /
+∇ CEXIT [ find EXIT >CFA ] LITERAL ∇                                                    / →a  Codeword address of EXIT /
+∇ SEE find >DFA ( ↑ @ CEXIT ≠ ∥ ↑ ↑ 1DUMP SPACE @ ↑ INDATA? { 8- ID. | . } CR 8+ ) ↓ ∇  / Decompile a word (try printing names of words, print literals) /
+
+/ Execution tokens /
+∇ ⊂ H DOCOL , ] ∇       / →x Start compiling anonymous word /
+∇ ⊃ I [COMP] ; ∇        /    Finish compiling anonymous word /
+⊂ ⊃ ∇ ⊂⊃ LITERAL ∇      / →x Push execution token for anonymous word which does nothing /
+∇ ['] I ' LIT , ∇       / Compile execution token of next word in input /
+
+/ Combinators - see combinators.f /
+∇ unit H ↕ DOCOL , ,LIT ' EXIT , ∇                      / x→x /
+∇ cat H -⌽ ↕ DOCOL , ,LIT ' ⍎ , ,LIT ' ⍎ , ' EXIT , ∇   / xx→x /
+∇ cons H -⌽ ↕ DOCOL , ,LIT ,LIT ' ⍎ , ' EXIT , ∇        / xx→x /
+∇ dip ↕ >R ⍎ R> ∇
+∇ sip ⊤ >R ⍎ R> ∇
+
+/ Assembler /
+∇ ∆ WORD CREATE H 8+ , ∇        / Create header for assembly word; codeword points to cell following it /
+
+∇ .dr B << ∨ 5 << ∨ ∇           / nnn→n build opcode for register data-processing instruction /
+∇ .di 5 << ∨ 5 << ∨ ∇           / nnn→n build opcode for immediate data-processing instruction /
+∇ .li 1FF ∧ 7 << ∨ 5 << ∨ ∇     / nnn→n build opcode for immediate load or store instruction /
+
+/ Data processing instructions (register) nnn→n /
+∇ add .dr 8B000000 ∨ ∇  ∇ sub .dr CB000000 ∨ ∇
+∇ and .dr 8A000000 ∨ ∇  ∇ orr .dr AA000000 ∨ ∇
+
+/ Data processing instructions (immediate) nnn→n /
+∇ addi .di 91000000 ∨ ∇ ∇ subi .di D1000000 ∨ ∇
+
+/ Load and store instructions (immediate) nnn→n /
+∇ ldr .li F8400000 ∨ ∇  ∇ str .li F8000000 ∨ ∇
+
+/ Set post- and pre- index flags for load and store instructions /
+∇ post 400 ∨ ∇          ∇ pre C00 ∨ ∇           / n→n /
+
+∇ pop 8 ldr post ∇      ∇ push 8 ¯ str pre ∇    / nn→n /
+
+∇ .D 13 ∇ ∇ .R 14 ∇ ∇ .I 15 ∇ ∇ .J 16 ∇ / Register numbers for D,R,I,J pointers /
+
+∇ NEXT .J .I 8 ldr post ,, 0 .J 0 ldr ,, D61F0000 ,, ALIGN ∇ / Code for NEXT (hex opcode is for the branch b 0) /
+
+/ Example defining 7+ with the assembler /
+∆ 7+ 0 .D pop ,, 0 0 7 addi ,, 0 .D push ,, NEXT
+
+/ Defining words - see R.G. Loeliger's Threaded Interpretive Languages book /
+∇ SCODE L >CFA ! ∇              / a→ Store address as codeword of latest word defined (used to set behaviour of word when run) /
+∇ ⋄ I H 20 + ,LIT ' SCODE , ∇   / ⋄ compiles code to overwrite the latest word's codeword with the address following the word containing ⋄ /
+
+/ Example defining words whose actions are defined with the assembler /
+∇ CONST' create , ⋄ ∇ 0 .J 8 ldr ,, 0 .D push ,, NEXT
+∇ 2CONST create , , ⋄ ∇ 0 .J 8 ldr ,, 1 .J 10 ldr ,, 0 .D push ,, 1 .D push ,, NEXT
+∇ VAR' create 0 , ⋄ ∇ 0 .J 8 addi ,, 0 .D push ,, NEXT
+
+/ ◁ and ▷ let you define the action of the defined words in Forth rather than assembler - see defining_words.f /
+∇ ◁ create 0 , ∇
+∇ ▷ R> L >CFA 8+ ! ⋄ ∇ .I .R push ,, 0 .J 10 addi ,, 0 .D push ,, .I .J 8 ldr ,, NEXT
+
+/ Example defining words with their actions specified in Forth (also see defining_words.f) /
+∇ CONST'' ◁ , ▷ @ ∇
+∇ VAR'' ◁ , ▷ ∇
+
+/ λ allows us to name an execution token (see combinators.f) /
+∇ λ ◁ , ▷ @ ⍎ ∇
+
+/ Exceptions /
+/ Data stack restored after exception using a stack of stacks - see exceptions.f /
+VAR SS                                                          / Stack-stack pointer /
+D0 10 CELLS - CONST SS0                                         / Initial stack-stack pointer /
+SS0 SS !                                                        / Initialize SS /
+∇ SPUSH 10 CELLS SS -! DEPTH SS0 ! SS @ SS0 10 MOVE ∇           / Push current stack to stack-stack /
+∇ SPOP D0 SS0 @ CELLS - D! SS0 SS @ 10 MOVE 10 CELLS SS +! ∇    / Pop stack from stack-stack /
+∇ S↓ 10 CELLS SS +! ∇                                           / Drop top stack-stack stack /
+
+∇ MARKER S↓ ∇
+∇ CATCH ' MARKER 8+ >R SPUSH ⍎ ∇
+∇ THROW ↑ { R ( ↑ R0 8- < ∥ ↑ @ ' MARKER 8+ = { 8+ R! >R SPOP ↓ R> EXIT } 8+ ) ↓ ." Uncaught throw" CR QUIT } ∇
+∇ ABORT 1 ¯ THROW ∇
+
+∇ TRACE R ( ↑ R0 8- < ∥ ↑ @ ↑ H ! U. CR 8+ ) ↓ ∇ / Print addresses currently on return stack (no attempt to decompile them) /
+
+/ Delimited continuations - see continuations.f /
+∇ RCOMP H DOCOL , >R ( 2↑ ≤ ∥ ↑ @ ,LIT ' >R , 8- ) 2↓ R> ' EXIT , ∇             / aa→x Compile word pushing addresses to return stack /
+∇ ⟦ R ↑ ( ↑ R0 8- < ∥ ↑ @ ' MARKER 8+ = { ↑ 8+ R! 10 - CR RCOMP EXIT } 8+ ) ∇   / Start capturing a continuation /
+∇ ⟧ ' MARKER 8+ >R ⍎ ∇                                                          / Finish capturing a continuation /
+
+/ C Strings /
+∇ STRLEN ↑ ( ↑ C@ ∥ 1+ ) ↕ - ∇ / a→n Get length of null terminated string /
+
+/ Environment /
+∇ ARGC D0 @ ∇
+∇ ARGV 1+ CELLS D0 + @ ↑ STRLEN ∇
+∇ ENV ARGC 2 + CELLS D0 + ∇
+
+/ Syscalls /
+∇ _EXIT 5D 2 SYS ∇
+∇ BYE 0 _EXIT ∇
+
+∇ ⍇ 3F 3 SYS ∇          / read  /
+∇ ⍈ 40 3 SYS ∇          / write /
+∇ ⍐ 64 ¯ 38 4 SYS ∇     / open  /
+∇ ⍗ 39 1 SYS ∇          / close /
+
+∇ UNAME A0 1 SYS ∇
+∇ OS H UNAME ↓ H 40 TELL ∇
+∇ HOSTNAME H UNAME ↓ H 41 + 40 TELL ∇
+
+." ⍋ JONESFORTH ARM64 ⍋" CR
diff --git a/original_jonesforth/Makefile b/original_jonesforth/Makefile
new file mode 100644
index 0000000..77d90d1
--- /dev/null
+++ b/original_jonesforth/Makefile
@@ -0,0 +1,50 @@
+# $Id: Makefile,v 1.9 2007-10-22 18:53:12 rich Exp $
+
+#BUILD_ID_NONE := -Wl,--build-id=none 
+BUILD_ID_NONE := 
+
+SHELL	:= /bin/bash
+
+all:	jonesforth
+
+jonesforth: jonesforth.S
+	gcc -m32 -nostdlib -static $(BUILD_ID_NONE) -o $@ $<
+
+run:
+	cat jonesforth.f $(PROG) - | ./jonesforth
+
+clean:
+	rm -f jonesforth perf_dupdrop *~ core .test_*
+
+# Tests.
+
+TESTS	:= $(patsubst %.f,%.test,$(wildcard test_*.f))
+
+test check: $(TESTS)
+
+test_%.test: test_%.f jonesforth
+	@echo -n "$< ... "
+	@rm -f .$@
+	@cat <(echo ': TEST-MODE ;') jonesforth.f $< <(echo 'TEST') | \
+	  ./jonesforth 2>&1 | \
+	  sed 's/DSP=[0-9]*//g' > .$@
+	@diff -u .$@ $<.out
+	@rm -f .$@
+	@echo "ok"
+
+# Performance.
+
+perf_dupdrop: perf_dupdrop.c
+	gcc -O3 -Wall -Werror -o $@ $<
+
+run_perf_dupdrop: jonesforth
+	cat <(echo ': TEST-MODE ;') jonesforth.f perf_dupdrop.f | ./jonesforth
+
+.SUFFIXES: .f .test
+.PHONY: test check run run_perf_dupdrop
+
+remote:
+	scp jonesforth.S jonesforth.f rjones@oirase:Desktop/
+	ssh rjones@oirase sh -c '"rm -f Desktop/jonesforth; \
+	  gcc -m32 -nostdlib -static -Wl,-Ttext,0 -o Desktop/jonesforth Desktop/jonesforth.S; \
+	  cat Desktop/jonesforth.f - | Desktop/jonesforth arg1 arg2 arg3"'
diff --git a/original_jonesforth/README b/original_jonesforth/README
new file mode 100644
index 0000000..f10f725
--- /dev/null
+++ b/original_jonesforth/README
@@ -0,0 +1,3 @@
+This is a mirror of Richard WM Jones's excellent literate x86 assembly
+implementation of Forth, more on which here:
+http://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/
diff --git a/original_jonesforth/jonesforth.S b/original_jonesforth/jonesforth.S
new file mode 100644
index 0000000..45e6e85
--- /dev/null
+++ b/original_jonesforth/jonesforth.S
@@ -0,0 +1,2313 @@
+/*	A sometimes minimal FORTH compiler and tutorial for Linux / i386 systems. -*- asm -*-
+	By Richard W.M. Jones <rich@annexia.org> http://annexia.org/forth
+	This is PUBLIC DOMAIN (see public domain release statement below).
+	$Id: jonesforth.S,v 1.47 2009-09-11 08:33:13 rich Exp $
+
+	gcc -m32 -nostdlib -static -Wl,-Ttext,0 -Wl,--build-id=none -o jonesforth jonesforth.S
+*/
+	.set JONES_VERSION,47
+/*
+	INTRODUCTION ----------------------------------------------------------------------
+
+	FORTH is one of those alien languages which most working programmers regard in the same
+	way as Haskell, LISP, and so on.  Something so strange that they'd rather any thoughts
+	of it just go away so they can get on with writing this paying code.  But that's wrong
+	and if you care at all about programming then you should at least understand all these
+	languages, even if you will never use them.
+
+	LISP is the ultimate high-level language, and features from LISP are being added every
+	decade to the more common languages.  But FORTH is in some ways the ultimate in low level
+	programming.  Out of the box it lacks features like dynamic memory management and even
+	strings.  In fact, at its primitive level it lacks even basic concepts like IF-statements
+	and loops.
+
+	Why then would you want to learn FORTH?  There are several very good reasons.  First
+	and foremost, FORTH is minimal.  You really can write a complete FORTH in, say, 2000
+	lines of code.  I don't just mean a FORTH program, I mean a complete FORTH operating
+	system, environment and language.  You could boot such a FORTH on a bare PC and it would
+	come up with a prompt where you could start doing useful work.  The FORTH you have here
+	isn't minimal and uses a Linux process as its 'base PC' (both for the purposes of making
+	it a good tutorial). It's possible to completely understand the system.  Who can say they
+	completely understand how Linux works, or gcc?
+
+	Secondly FORTH has a peculiar bootstrapping property.  By that I mean that after writing
+	a little bit of assembly to talk to the hardware and implement a few primitives, all the
+	rest of the language and compiler is written in FORTH itself.  Remember I said before
+	that FORTH lacked IF-statements and loops?  Well of course it doesn't really because
+	such a lanuage would be useless, but my point was rather that IF-statements and loops are
+	written in FORTH itself.
+
+	Now of course this is common in other languages as well, and in those languages we call
+	them 'libraries'.  For example in C, 'printf' is a library function written in C.  But
+	in FORTH this goes way beyond mere libraries.  Can you imagine writing C's 'if' in C?
+	And that brings me to my third reason: If you can write 'if' in FORTH, then why restrict
+	yourself to the usual if/while/for/switch constructs?  You want a construct that iterates
+	over every other element in a list of numbers?  You can add it to the language.  What
+	about an operator which pulls in variables directly from a configuration file and makes
+	them available as FORTH variables?  Or how about adding Makefile-like dependencies to
+	the language?  No problem in FORTH.  How about modifying the FORTH compiler to allow
+	complex inlining strategies -- simple.  This concept isn't common in programming languages,
+	but it has a name (in fact two names): "macros" (by which I mean LISP-style macros, not
+	the lame C preprocessor) and "domain specific languages" (DSLs).
+
+	This tutorial isn't about learning FORTH as the language.  I'll point you to some references
+	you should read if you're not familiar with using FORTH.  This tutorial is about how to
+	write FORTH.  In fact, until you understand how FORTH is written, you'll have only a very
+	superficial understanding of how to use it.
+
+	So if you're not familiar with FORTH or want to refresh your memory here are some online
+	references to read:
+
+	http://en.wikipedia.org/wiki/Forth_%28programming_language%29
+
+	http://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm
+
+	http://wiki.laptop.org/go/Forth_Lessons
+
+	http://www.albany.net/~hello/simple.htm
+
+	Here is another "Why FORTH?" essay: http://www.jwdt.com/~paysan/why-forth.html
+
+	Discussion and criticism of this FORTH here: http://lambda-the-ultimate.org/node/2452
+
+	ACKNOWLEDGEMENTS ----------------------------------------------------------------------
+
+	This code draws heavily on the design of LINA FORTH (http://home.hccnet.nl/a.w.m.van.der.horst/lina.html)
+	by Albert van der Horst.  Any similarities in the code are probably not accidental.
+
+	Some parts of this FORTH are also based on this IOCCC entry from 1992:
+	http://ftp.funet.fi/pub/doc/IOCCC/1992/buzzard.2.design.
+	I was very proud when Sean Barrett, the original author of the IOCCC entry, commented in the LtU thread
+	http://lambda-the-ultimate.org/node/2452#comment-36818 about this FORTH.
+
+	And finally I'd like to acknowledge the (possibly forgotten?) authors of ARTIC FORTH because their
+	original program which I still have on original cassette tape kept nagging away at me all these years.
+	http://en.wikipedia.org/wiki/Artic_Software
+
+	PUBLIC DOMAIN ----------------------------------------------------------------------
+
+	I, the copyright holder of this work, hereby release it into the public domain. This applies worldwide.
+
+	In case this is not legally possible, I grant any entity the right to use this work for any purpose,
+	without any conditions, unless such conditions are required by law.
+
+	SETTING UP ----------------------------------------------------------------------
+
+	Let's get a few housekeeping things out of the way.  Firstly because I need to draw lots of
+	ASCII-art diagrams to explain concepts, the best way to look at this is using a window which
+	uses a fixed width font and is at least this wide:
+
+ <------------------------------------------------------------------------------------------------------------------------>
+
+	Secondly make sure TABS are set to 8 characters.  The following should be a vertical
+	line.  If not, sort out your tabs.
+
+		|
+	        |
+	    	|
+
+	Thirdly I assume that your screen is at least 50 characters high.
+
+	ASSEMBLING ----------------------------------------------------------------------
+
+	If you want to actually run this FORTH, rather than just read it, you will need Linux on an
+	i386.  Linux because instead of programming directly to the hardware on a bare PC which I
+	could have done, I went for a simpler tutorial by assuming that the 'hardware' is a Linux
+	process with a few basic system calls (read, write and exit and that's about all).  i386
+	is needed because I had to write the assembly for a processor, and i386 is by far the most
+	common.  (Of course when I say 'i386', any 32- or 64-bit x86 processor will do.  I'm compiling
+	this on a 64 bit AMD Opteron).
+
+	Again, to assemble this you will need gcc and gas (the GNU assembler).  The commands to
+	assemble and run the code (save this file as 'jonesforth.S') are:
+
+	gcc -m32 -nostdlib -static -Wl,-Ttext,0 -Wl,--build-id=none -o jonesforth jonesforth.S
+	cat jonesforth.f - | ./jonesforth
+
+	If you want to run your own FORTH programs you can do:
+
+	cat jonesforth.f myprog.f | ./jonesforth
+
+	If you want to load your own FORTH code and then continue reading user commands, you can do:
+
+	cat jonesforth.f myfunctions.f - | ./jonesforth
+
+	ASSEMBLER ----------------------------------------------------------------------
+
+	(You can just skip to the next section -- you don't need to be able to read assembler to
+	follow this tutorial).
+
+	However if you do want to read the assembly code here are a few notes about gas (the GNU assembler):
+
+	(1) Register names are prefixed with '%', so %eax is the 32 bit i386 accumulator.  The registers
+	    available on i386 are: %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp and %esp, and most of them
+	    have special purposes.
+
+	(2) Add, mov, etc. take arguments in the form SRC,DEST.  So mov %eax,%ecx moves %eax -> %ecx
+
+	(3) Constants are prefixed with '$', and you mustn't forget it!  If you forget it then it
+	    causes a read from memory instead, so:
+	    mov $2,%eax		moves number 2 into %eax
+	    mov 2,%eax		reads the 32 bit word from address 2 into %eax (ie. most likely a mistake)
+
+	(4) gas has a funky syntax for local labels, where '1f' (etc.) means label '1:' "forwards"
+	    and '1b' (etc.) means label '1:' "backwards".  Notice that these labels might be mistaken
+	    for hex numbers (eg. you might confuse 1b with $0x1b).
+
+	(5) 'ja' is "jump if above", 'jb' for "jump if below", 'je' "jump if equal" etc.
+
+	(6) gas has a reasonably nice .macro syntax, and I use them a lot to make the code shorter and
+	    less repetitive.
+
+	For more help reading the assembler, do "info gas" at the Linux prompt.
+
+	Now the tutorial starts in earnest.
+
+	THE DICTIONARY ----------------------------------------------------------------------
+
+	In FORTH as you will know, functions are called "words", and just as in other languages they
+	have a name and a definition.  Here are two FORTH words:
+
+	: DOUBLE DUP + ;		\ name is "DOUBLE", definition is "DUP +"
+	: QUADRUPLE DOUBLE DOUBLE ;	\ name is "QUADRUPLE", definition is "DOUBLE DOUBLE"
+
+	Words, both built-in ones and ones which the programmer defines later, are stored in a dictionary
+	which is just a linked list of dictionary entries.
+
+	<--- DICTIONARY ENTRY (HEADER) ----------------------->
+	+------------------------+--------+---------- - - - - +----------- - - - -
+	| LINK POINTER           | LENGTH/| NAME	      | DEFINITION
+	|			 | FLAGS  |     	      |
+	+--- (4 bytes) ----------+- byte -+- n bytes  - - - - +----------- - - - -
+
+	I'll come to the definition of the word later.  For now just look at the header.  The first
+	4 bytes are the link pointer.  This points back to the previous word in the dictionary, or, for
+	the first word in the dictionary it is just a NULL pointer.  Then comes a length/flags byte.
+	The length of the word can be up to 31 characters (5 bits used) and the top three bits are used
+	for various flags which I'll come to later.  This is followed by the name itself, and in this
+	implementation the name is rounded up to a multiple of 4 bytes by padding it with zero bytes.
+	That's just to ensure that the definition starts on a 32 bit boundary.
+
+	A FORTH variable called LATEST contains a pointer to the most recently defined word, in
+	other words, the head of this linked list.
+
+	DOUBLE and QUADRUPLE might look like this:
+
+	  pointer to previous word
+	   ^
+	   |
+	+--|------+---+---+---+---+---+---+---+---+------------- - - - -
+	| LINK    | 6 | D | O | U | B | L | E | 0 | (definition ...)
+	+---------+---+---+---+---+---+---+---+---+------------- - - - -
+           ^       len                         padding
+	   |
+	+--|------+---+---+---+---+---+---+---+---+---+---+---+---+------------- - - - -
+	| LINK    | 9 | Q | U | A | D | R | U | P | L | E | 0 | 0 | (definition ...)
+	+---------+---+---+---+---+---+---+---+---+---+---+---+---+------------- - - - -
+           ^       len                                     padding
+           |
+           |
+	  LATEST
+
+	You should be able to see from this how you might implement functions to find a word in
+	the dictionary (just walk along the dictionary entries starting at LATEST and matching
+	the names until you either find a match or hit the NULL pointer at the end of the dictionary);
+	and add a word to the dictionary (create a new definition, set its LINK to LATEST, and set
+	LATEST to point to the new word).  We'll see precisely these functions implemented in
+	assembly code later on.
+
+	One interesting consequence of using a linked list is that you can redefine words, and
+	a newer definition of a word overrides an older one.  This is an important concept in
+	FORTH because it means that any word (even "built-in" or "standard" words) can be
+	overridden with a new definition, either to enhance it, to make it faster or even to
+	disable it.  However because of the way that FORTH words get compiled, which you'll
+	understand below, words defined using the old definition of a word continue to use
+	the old definition.  Only words defined after the new definition use the new definition.
+
+	DIRECT THREADED CODE ----------------------------------------------------------------------
+
+	Now we'll get to the really crucial bit in understanding FORTH, so go and get a cup of tea
+	or coffee and settle down.  It's fair to say that if you don't understand this section, then you
+	won't "get" how FORTH works, and that would be a failure on my part for not explaining it well.
+	So if after reading this section a few times you don't understand it, please email me
+	(rich@annexia.org).
+
+	Let's talk first about what "threaded code" means.  Imagine a peculiar version of C where
+	you are only allowed to call functions without arguments.  (Don't worry for now that such a
+	language would be completely useless!)  So in our peculiar C, code would look like this:
+
+	f ()
+	{
+	  a ();
+	  b ();
+	  c ();
+	}
+
+	and so on.  How would a function, say 'f' above, be compiled by a standard C compiler?
+	Probably into assembly code like this.  On the right hand side I've written the actual
+	i386 machine code.
+
+	f:
+	  CALL a			E8 08 00 00 00
+	  CALL b			E8 1C 00 00 00
+	  CALL c			E8 2C 00 00 00
+	  ; ignore the return from the function for now
+
+	"E8" is the x86 machine code to "CALL" a function.  In the first 20 years of computing
+	memory was hideously expensive and we might have worried about the wasted space being used
+	by the repeated "E8" bytes.  We can save 20% in code size (and therefore, in expensive memory)
+	by compressing this into just:
+
+	08 00 00 00		Just the function addresses, without
+	1C 00 00 00		the CALL prefix.
+	2C 00 00 00
+
+	On a 16-bit machine like the ones which originally ran FORTH the savings are even greater - 33%.
+
+	[Historical note: If the execution model that FORTH uses looks strange from the following
+	paragraphs, then it was motivated entirely by the need to save memory on early computers.
+	This code compression isn't so important now when our machines have more memory in their L1
+	caches than those early computers had in total, but the execution model still has some
+	useful properties].
+
+	Of course this code won't run directly on the CPU any more.  Instead we need to write an
+	interpreter which takes each set of bytes and calls it.
+
+	On an i386 machine it turns out that we can write this interpreter rather easily, in just
+	two assembly instructions which turn into just 3 bytes of machine code.  Let's store the
+	pointer to the next word to execute in the %esi register:
+
+		08 00 00 00	<- We're executing this one now.  %esi is the _next_ one to execute.
+	%esi -> 1C 00 00 00
+		2C 00 00 00
+
+	The all-important i386 instruction is called LODSL (or in Intel manuals, LODSW).  It does
+	two things.  Firstly it reads the memory at %esi into the accumulator (%eax).  Secondly it
+	increments %esi by 4 bytes.  So after LODSL, the situation now looks like this:
+
+		08 00 00 00	<- We're still executing this one
+		1C 00 00 00	<- %eax now contains this address (0x0000001C)
+	%esi -> 2C 00 00 00
+
+	Now we just need to jump to the address in %eax.  This is again just a single x86 instruction
+	written JMP *(%eax).  And after doing the jump, the situation looks like:
+
+		08 00 00 00
+		1C 00 00 00	<- Now we're executing this subroutine.
+	%esi -> 2C 00 00 00
+
+	To make this work, each subroutine is followed by the two instructions 'LODSL; JMP *(%eax)'
+	which literally make the jump to the next subroutine.
+
+	And that brings us to our first piece of actual code!  Well, it's a macro.
+*/
+
+/* NEXT macro. */
+	.macro NEXT
+	lodsl
+	jmp *(%eax)
+	.endm
+
+/*	The macro is called NEXT.  That's a FORTH-ism.  It expands to those two instructions.
+
+	Every FORTH primitive that we write has to be ended by NEXT.  Think of it kind of like
+	a return.
+
+	The above describes what is known as direct threaded code.
+
+	To sum up: We compress our function calls down to a list of addresses and use a somewhat
+	magical macro to act as a "jump to next function in the list".  We also use one register (%esi)
+	to act as a kind of instruction pointer, pointing to the next function in the list.
+
+	I'll just give you a hint of what is to come by saying that a FORTH definition such as:
+
+	: QUADRUPLE DOUBLE DOUBLE ;
+
+	actually compiles (almost, not precisely but we'll see why in a moment) to a list of
+	function addresses for DOUBLE, DOUBLE and a special function called EXIT to finish off.
+
+	At this point, REALLY EAGLE-EYED ASSEMBLY EXPERTS are saying "JONES, YOU'VE MADE A MISTAKE!".
+
+	I lied about JMP *(%eax).  
+
+	INDIRECT THREADED CODE ----------------------------------------------------------------------
+
+	It turns out that direct threaded code is interesting but only if you want to just execute
+	a list of functions written in assembly language.  So QUADRUPLE would work only if DOUBLE
+	was an assembly language function.  In the direct threaded code, QUADRUPLE would look like:
+
+		+------------------+
+		| addr of DOUBLE  --------------------> (assembly code to do the double)
+		+------------------+                    NEXT
+	%esi ->	| addr of DOUBLE   |
+		+------------------+
+
+	We can add an extra indirection to allow us to run both words written in assembly language
+	(primitives written for speed) and words written in FORTH themselves as lists of addresses.
+
+	The extra indirection is the reason for the brackets in JMP *(%eax).
+
+	Let's have a look at how QUADRUPLE and DOUBLE really look in FORTH:
+
+	        : QUADRUPLE DOUBLE DOUBLE ;
+
+		+------------------+
+		| codeword         |		   : DOUBLE DUP + ;
+		+------------------+
+		| addr of DOUBLE  ---------------> +------------------+
+		+------------------+               | codeword         |
+		| addr of DOUBLE   |		   +------------------+
+		+------------------+	   	   | addr of DUP   --------------> +------------------+
+		| addr of EXIT	   |		   +------------------+            | codeword      -------+
+		+------------------+	   %esi -> | addr of +     --------+	   +------------------+   |
+						   +------------------+	   |	   | assembly to    <-----+
+						   | addr of EXIT     |    |       | implement DUP    |
+						   +------------------+	   |	   |	..	      |
+									   |	   |    ..            |
+									   |	   | NEXT             |
+									   |	   +------------------+
+									   |
+									   +-----> +------------------+
+										   | codeword      -------+
+										   +------------------+   |
+										   | assembly to   <------+
+										   | implement +      |
+										   | 	..            |
+										   | 	..            |
+										   | NEXT      	      |
+										   +------------------+
+
+	This is the part where you may need an extra cup of tea/coffee/favourite caffeinated
+	beverage.  What has changed is that I've added an extra pointer to the beginning of
+	the definitions.  In FORTH this is sometimes called the "codeword".  The codeword is
+	a pointer to the interpreter to run the function.  For primitives written in
+	assembly language, the "interpreter" just points to the actual assembly code itself.
+	They don't need interpreting, they just run.
+
+	In words written in FORTH (like QUADRUPLE and DOUBLE), the codeword points to an interpreter
+	function.
+
+	I'll show you the interpreter function shortly, but let's recall our indirect
+	JMP *(%eax) with the "extra" brackets.  Take the case where we're executing DOUBLE
+	as shown, and DUP has been called.  Note that %esi is pointing to the address of +
+
+	The assembly code for DUP eventually does a NEXT.  That:
+
+	(1) reads the address of + into %eax		%eax points to the codeword of +
+	(2) increments %esi by 4
+	(3) jumps to the indirect %eax			jumps to the address in the codeword of +,
+							ie. the assembly code to implement +
+
+		+------------------+
+		| codeword         |
+		+------------------+
+		| addr of DOUBLE  ---------------> +------------------+
+		+------------------+               | codeword         |
+		| addr of DOUBLE   |		   +------------------+
+		+------------------+	   	   | addr of DUP   --------------> +------------------+
+		| addr of EXIT	   |		   +------------------+            | codeword      -------+
+		+------------------+	   	   | addr of +     --------+	   +------------------+   |
+						   +------------------+	   |	   | assembly to    <-----+
+					   %esi -> | addr of EXIT     |    |       | implement DUP    |
+						   +------------------+	   |	   |	..	      |
+									   |	   |    ..            |
+									   |	   | NEXT             |
+									   |	   +------------------+
+									   |
+									   +-----> +------------------+
+										   | codeword      -------+
+										   +------------------+   |
+									now we're  | assembly to    <-----+
+									executing  | implement +      |
+									this	   | 	..            |
+									function   | 	..            |
+										   | NEXT      	      |
+										   +------------------+
+
+	So I hope that I've convinced you that NEXT does roughly what you'd expect.  This is
+	indirect threaded code.
+
+	I've glossed over four things.  I wonder if you can guess without reading on what they are?
+
+	.
+	.
+	.
+
+	My list of four things are: (1) What does "EXIT" do?  (2) which is related to (1) is how do
+	you call into a function, ie. how does %esi start off pointing at part of QUADRUPLE, but
+	then point at part of DOUBLE.  (3) What goes in the codeword for the words which are written
+	in FORTH?  (4) How do you compile a function which does anything except call other functions
+	ie. a function which contains a number like : DOUBLE 2 * ; ?
+
+	THE INTERPRETER AND RETURN STACK ------------------------------------------------------------
+
+	Going at these in no particular order, let's talk about issues (3) and (2), the interpreter
+	and the return stack.
+
+	Words which are defined in FORTH need a codeword which points to a little bit of code to
+	give them a "helping hand" in life.  They don't need much, but they do need what is known
+	as an "interpreter", although it doesn't really "interpret" in the same way that, say,
+	Java bytecode used to be interpreted (ie. slowly).  This interpreter just sets up a few
+	machine registers so that the word can then execute at full speed using the indirect
+	threaded model above.
+
+	One of the things that needs to happen when QUADRUPLE calls DOUBLE is that we save the old
+	%esi ("instruction pointer") and create a new one pointing to the first word in DOUBLE.
+	Because we will need to restore the old %esi at the end of DOUBLE (this is, after all, like
+	a function call), we will need a stack to store these "return addresses" (old values of %esi).
+
+	As you will have seen in the background documentation, FORTH has two stacks, an ordinary
+	stack for parameters, and a return stack which is a bit more mysterious.  But our return
+	stack is just the stack I talked about in the previous paragraph, used to save %esi when
+	calling from a FORTH word into another FORTH word.
+
+	In this FORTH, we are using the normal stack pointer (%esp) for the parameter stack.
+	We will use the i386's "other" stack pointer (%ebp, usually called the "frame pointer")
+	for our return stack.
+
+	I've got two macros which just wrap up the details of using %ebp for the return stack.
+	You use them as for example "PUSHRSP %eax" (push %eax on the return stack) or "POPRSP %ebx"
+	(pop top of return stack into %ebx).
+*/
+
+/* Macros to deal with the return stack. */
+	.macro PUSHRSP reg
+	lea -4(%ebp),%ebp	// push reg on to return stack
+	movl \reg,(%ebp)
+	.endm
+
+	.macro POPRSP reg
+	mov (%ebp),\reg		// pop top of return stack to reg
+	lea 4(%ebp),%ebp
+	.endm
+
+/*
+	And with that we can now talk about the interpreter.
+
+	In FORTH the interpreter function is often called DOCOL (I think it means "DO COLON" because
+	all FORTH definitions start with a colon, as in : DOUBLE DUP + ;
+
+	The "interpreter" (it's not really "interpreting") just needs to push the old %esi on the
+	stack and set %esi to the first word in the definition.  Remember that we jumped to the
+	function using JMP *(%eax)?  Well a consequence of that is that conveniently %eax contains
+	the address of this codeword, so just by adding 4 to it we get the address of the first
+	data word.  Finally after setting up %esi, it just does NEXT which causes that first word
+	to run.
+*/
+
+/* DOCOL - the interpreter! */
+	.text
+	.align 4
+DOCOL:
+	PUSHRSP %esi		// push %esi on to the return stack
+	addl $4,%eax		// %eax points to codeword, so make
+	movl %eax,%esi		// %esi point to first data word
+	NEXT
+
+/*
+	Just to make this absolutely clear, let's see how DOCOL works when jumping from QUADRUPLE
+	into DOUBLE:
+
+		QUADRUPLE:
+		+------------------+
+		| codeword         |
+		+------------------+		   DOUBLE:
+		| addr of DOUBLE  ---------------> +------------------+
+		+------------------+       %eax -> | addr of DOCOL    |
+	%esi ->	| addr of DOUBLE   |		   +------------------+
+		+------------------+	   	   | addr of DUP      |
+		| addr of EXIT	   |		   +------------------+
+		+------------------+               | etc.             |
+
+	First, the call to DOUBLE calls DOCOL (the codeword of DOUBLE).  DOCOL does this:  It
+	pushes the old %esi on the return stack.  %eax points to the codeword of DOUBLE, so we
+	just add 4 on to it to get our new %esi:
+
+		QUADRUPLE:
+		+------------------+
+		| codeword         |
+		+------------------+		   DOUBLE:
+		| addr of DOUBLE  ---------------> +------------------+
+top of return	+------------------+       %eax -> | addr of DOCOL    |
+stack points ->	| addr of DOUBLE   |	   + 4 =   +------------------+
+		+------------------+	   %esi -> | addr of DUP      |
+		| addr of EXIT	   |		   +------------------+
+		+------------------+               | etc.             |
+
+	Then we do NEXT, and because of the magic of threaded code that increments %esi again
+	and calls DUP.
+
+	Well, it seems to work.
+
+	One minor point here.  Because DOCOL is the first bit of assembly actually to be defined
+	in this file (the others were just macros), and because I usually compile this code with the
+	text segment starting at address 0, DOCOL has address 0.  So if you are disassembling the
+	code and see a word with a codeword of 0, you will immediately know that the word is
+	written in FORTH (it's not an assembler primitive) and so uses DOCOL as the interpreter.
+
+	STARTING UP ----------------------------------------------------------------------
+
+	Now let's get down to nuts and bolts.  When we start the program we need to set up
+	a few things like the return stack.  But as soon as we can, we want to jump into FORTH
+	code (albeit much of the "early" FORTH code will still need to be written as
+	assembly language primitives).
+
+	This is what the set up code does.  Does a tiny bit of house-keeping, sets up the
+	separate return stack (NB: Linux gives us the ordinary parameter stack already), then
+	immediately jumps to a FORTH word called QUIT.  Despite its name, QUIT doesn't quit
+	anything.  It resets some internal state and starts reading and interpreting commands.
+	(The reason it is called QUIT is because you can call QUIT from your own FORTH code
+	to "quit" your program and go back to interpreting).
+*/
+
+/* Assembler entry point. */
+	.text
+	.globl _start
+_start:
+	cld
+	mov %esp,var_S0		// Save the initial data stack pointer in FORTH variable S0.
+	mov $return_stack_top,%ebp // Initialise the return stack.
+	call set_up_data_segment
+
+	mov $cold_start,%esi	// Initialise interpreter.
+	NEXT			// Run interpreter!
+
+	.section .rodata
+cold_start:			// High-level code without a codeword.
+	.int QUIT
+
+/*
+	BUILT-IN WORDS ----------------------------------------------------------------------
+
+	Remember our dictionary entries (headers)?  Let's bring those together with the codeword
+	and data words to see how : DOUBLE DUP + ; really looks in memory.
+
+	  pointer to previous word
+	   ^
+	   |
+	+--|------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+--|---------+------------+------------+
+           ^       len                         pad  codeword      |
+	   |							  V
+	  LINK in next word				points to codeword of DUP
+	
+	Initially we can't just write ": DOUBLE DUP + ;" (ie. that literal string) here because we
+	don't yet have anything to read the string, break it up at spaces, parse each word, etc. etc.
+	So instead we will have to define built-in words using the GNU assembler data constructors
+	(like .int, .byte, .string, .ascii and so on -- look them up in the gas info page if you are
+	unsure of them).
+
+	The long way would be:
+
+	.int <link to previous word>
+	.byte 6			// len
+	.ascii "DOUBLE"		// string
+	.byte 0			// padding
+DOUBLE: .int DOCOL		// codeword
+	.int DUP		// pointer to codeword of DUP
+	.int PLUS		// pointer to codeword of +
+	.int EXIT		// pointer to codeword of EXIT
+
+	That's going to get quite tedious rather quickly, so here I define an assembler macro
+	so that I can just write:
+
+	defword "DOUBLE",6,,DOUBLE
+	.int DUP,PLUS,EXIT
+
+	and I'll get exactly the same effect.
+
+	Don't worry too much about the exact implementation details of this macro - it's complicated!
+*/
+
+/* Flags - these are discussed later. */
+	.set F_IMMED,0x80
+	.set F_HIDDEN,0x20
+	.set F_LENMASK,0x1f	// length mask
+
+	// Store the chain of links.
+	.set link,0
+
+	.macro defword name, namelen, flags=0, label
+	.section .rodata
+	.align 4
+	.globl name_\label
+name_\label :
+	.int link		// link
+	.set link,name_\label
+	.byte \flags+\namelen	// flags + length byte
+	.ascii "\name"		// the name
+	.align 4		// padding to next 4 byte boundary
+	.globl \label
+\label :
+	.int DOCOL		// codeword - the interpreter
+	// list of word pointers follow
+	.endm
+
+/*
+	Similarly I want a way to write words written in assembly language.  There will quite a few
+	of these to start with because, well, everything has to start in assembly before there's
+	enough "infrastructure" to be able to start writing FORTH words, but also I want to define
+	some common FORTH words in assembly language for speed, even though I could write them in FORTH.
+
+	This is what DUP looks like in memory:
+
+	  pointer to previous word
+	   ^
+	   |
+	+--|------+---+---+---+---+------------+
+	| LINK    | 3 | D | U | P | code_DUP ---------------------> points to the assembly
+	+---------+---+---+---+---+------------+		    code used to write DUP,
+           ^       len              codeword			    which ends with NEXT.
+	   |
+	  LINK in next word
+
+	Again, for brevity in writing the header I'm going to write an assembler macro called defcode.
+	As with defword above, don't worry about the complicated details of the macro.
+*/
+
+	.macro defcode name, namelen, flags=0, label
+	.section .rodata
+	.align 4
+	.globl name_\label
+name_\label :
+	.int link		// link
+	.set link,name_\label
+	.byte \flags+\namelen	// flags + length byte
+	.ascii "\name"		// the name
+	.align 4		// padding to next 4 byte boundary
+	.globl \label
+\label :
+	.int code_\label	// codeword
+	.text
+	//.align 4
+	.globl code_\label
+code_\label :			// assembler code follows
+	.endm
+
+/*
+	Now some easy FORTH primitives.  These are written in assembly for speed.  If you understand
+	i386 assembly language then it is worth reading these.  However if you don't understand assembly
+	you can skip the details.
+*/
+
+	defcode "DROP",4,,DROP
+	pop %eax		// drop top of stack
+	NEXT
+
+	defcode "SWAP",4,,SWAP
+	pop %eax		// swap top two elements on stack
+	pop %ebx
+	push %eax
+	push %ebx
+	NEXT
+
+	defcode "DUP",3,,DUP
+	mov (%esp),%eax		// duplicate top of stack
+	push %eax
+	NEXT
+
+	defcode "OVER",4,,OVER
+	mov 4(%esp),%eax	// get the second element of stack
+	push %eax		// and push it on top
+	NEXT
+
+	defcode "ROT",3,,ROT
+	pop %eax
+	pop %ebx
+	pop %ecx
+	push %ebx
+	push %eax
+	push %ecx
+	NEXT
+
+	defcode "-ROT",4,,NROT
+	pop %eax
+	pop %ebx
+	pop %ecx
+	push %eax
+	push %ecx
+	push %ebx
+	NEXT
+
+	defcode "2DROP",5,,TWODROP // drop top two elements of stack
+	pop %eax
+	pop %eax
+	NEXT
+
+	defcode "2DUP",4,,TWODUP // duplicate top two elements of stack
+	mov (%esp),%eax
+	mov 4(%esp),%ebx
+	push %ebx
+	push %eax
+	NEXT
+
+	defcode "2SWAP",5,,TWOSWAP // swap top two pairs of elements of stack
+	pop %eax
+	pop %ebx
+	pop %ecx
+	pop %edx
+	push %ebx
+	push %eax
+	push %edx
+	push %ecx
+	NEXT
+
+	defcode "?DUP",4,,QDUP	// duplicate top of stack if non-zero
+	movl (%esp),%eax
+	test %eax,%eax
+	jz 1f
+	push %eax
+1:	NEXT
+
+	defcode "1+",2,,INCR
+	incl (%esp)		// increment top of stack
+	NEXT
+
+	defcode "1-",2,,DECR
+	decl (%esp)		// decrement top of stack
+	NEXT
+
+	defcode "4+",2,,INCR4
+	addl $4,(%esp)		// add 4 to top of stack
+	NEXT
+
+	defcode "4-",2,,DECR4
+	subl $4,(%esp)		// subtract 4 from top of stack
+	NEXT
+
+	defcode "+",1,,ADD
+	pop %eax		// get top of stack
+	addl %eax,(%esp)	// and add it to next word on stack
+	NEXT
+
+	defcode "-",1,,SUB
+	pop %eax		// get top of stack
+	subl %eax,(%esp)	// and subtract it from next word on stack
+	NEXT
+
+	defcode "*",1,,MUL
+	pop %eax
+	pop %ebx
+	imull %ebx,%eax
+	push %eax		// ignore overflow
+	NEXT
+
+/*
+	In this FORTH, only /MOD is primitive.  Later we will define the / and MOD words in
+	terms of the primitive /MOD.  The design of the i386 assembly instruction idiv which
+	leaves both quotient and remainder makes this the obvious choice.
+*/
+
+	defcode "/MOD",4,,DIVMOD
+	xor %edx,%edx
+	pop %ebx
+	pop %eax
+	idivl %ebx
+	push %edx		// push remainder
+	push %eax		// push quotient
+	NEXT
+
+/*
+	Lots of comparison operations like =, <, >, etc..
+
+	ANS FORTH says that the comparison words should return all (binary) 1's for
+	TRUE and all 0's for FALSE.  However this is a bit of a strange convention
+	so this FORTH breaks it and returns the more normal (for C programmers ...)
+	1 meaning TRUE and 0 meaning FALSE.
+*/
+
+	defcode "=",1,,EQU	// top two words are equal?
+	pop %eax
+	pop %ebx
+	cmp %ebx,%eax
+	sete %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "<>",2,,NEQU	// top two words are not equal?
+	pop %eax
+	pop %ebx
+	cmp %ebx,%eax
+	setne %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "<",1,,LT
+	pop %eax
+	pop %ebx
+	cmp %eax,%ebx
+	setl %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode ">",1,,GT
+	pop %eax
+	pop %ebx
+	cmp %eax,%ebx
+	setg %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "<=",2,,LE
+	pop %eax
+	pop %ebx
+	cmp %eax,%ebx
+	setle %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode ">=",2,,GE
+	pop %eax
+	pop %ebx
+	cmp %eax,%ebx
+	setge %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "0=",2,,ZEQU	// top of stack equals 0?
+	pop %eax
+	test %eax,%eax
+	setz %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "0<>",3,,ZNEQU	// top of stack not 0?
+	pop %eax
+	test %eax,%eax
+	setnz %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "0<",2,,ZLT	// comparisons with 0
+	pop %eax
+	test %eax,%eax
+	setl %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "0>",2,,ZGT
+	pop %eax
+	test %eax,%eax
+	setg %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "0<=",3,,ZLE
+	pop %eax
+	test %eax,%eax
+	setle %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "0>=",3,,ZGE
+	pop %eax
+	test %eax,%eax
+	setge %al
+	movzbl %al,%eax
+	pushl %eax
+	NEXT
+
+	defcode "AND",3,,AND	// bitwise AND
+	pop %eax
+	andl %eax,(%esp)
+	NEXT
+
+	defcode "OR",2,,OR	// bitwise OR
+	pop %eax
+	orl %eax,(%esp)
+	NEXT
+
+	defcode "XOR",3,,XOR	// bitwise XOR
+	pop %eax
+	xorl %eax,(%esp)
+	NEXT
+
+	defcode "INVERT",6,,INVERT // this is the FORTH bitwise "NOT" function (cf. NEGATE and NOT)
+	notl (%esp)
+	NEXT
+
+/*
+	RETURNING FROM FORTH WORDS ----------------------------------------------------------------------
+
+	Time to talk about what happens when we EXIT a function.  In this diagram QUADRUPLE has called
+	DOUBLE, and DOUBLE is about to exit (look at where %esi is pointing):
+
+		QUADRUPLE
+		+------------------+
+		| codeword         |
+		+------------------+		   DOUBLE
+		| addr of DOUBLE  ---------------> +------------------+
+		+------------------+               | codeword         |
+		| addr of DOUBLE   |		   +------------------+
+		+------------------+	   	   | addr of DUP      |
+		| addr of EXIT	   |		   +------------------+
+		+------------------+	   	   | addr of +        |
+						   +------------------+
+					   %esi -> | addr of EXIT     |
+						   +------------------+
+
+	What happens when the + function does NEXT?  Well, the following code is executed.
+*/
+
+	defcode "EXIT",4,,EXIT
+	POPRSP %esi		// pop return stack into %esi
+	NEXT
+
+/*
+	EXIT gets the old %esi which we saved from before on the return stack, and puts it in %esi.
+	So after this (but just before NEXT) we get:
+
+		QUADRUPLE
+		+------------------+
+		| codeword         |
+		+------------------+		   DOUBLE
+		| addr of DOUBLE  ---------------> +------------------+
+		+------------------+               | codeword         |
+	%esi ->	| addr of DOUBLE   |		   +------------------+
+		+------------------+	   	   | addr of DUP      |
+		| addr of EXIT	   |		   +------------------+
+		+------------------+	   	   | addr of +        |
+						   +------------------+
+						   | addr of EXIT     |
+						   +------------------+
+
+	And NEXT just completes the job by, well, in this case just by calling DOUBLE again :-)
+
+	LITERALS ----------------------------------------------------------------------
+
+	The final point I "glossed over" before was how to deal with functions that do anything
+	apart from calling other functions.  For example, suppose that DOUBLE was defined like this:
+
+	: DOUBLE 2 * ;
+
+	It does the same thing, but how do we compile it since it contains the literal 2?  One way
+	would be to have a function called "2" (which you'd have to write in assembler), but you'd need
+	a function for every single literal that you wanted to use.
+
+	FORTH solves this by compiling the function using a special word called LIT:
+
+	+---------------------------+-------+-------+-------+-------+-------+
+	| (usual header of DOUBLE)  | DOCOL | LIT   | 2     | *     | EXIT  |
+	+---------------------------+-------+-------+-------+-------+-------+
+
+	LIT is executed in the normal way, but what it does next is definitely not normal.  It
+	looks at %esi (which now points to the number 2), grabs it, pushes it on the stack, then
+	manipulates %esi in order to skip the number as if it had never been there.
+
+	What's neat is that the whole grab/manipulate can be done using a single byte single
+	i386 instruction, our old friend LODSL.  Rather than me drawing more ASCII-art diagrams,
+	see if you can find out how LIT works:
+*/
+
+	defcode "LIT",3,,LIT
+	// %esi points to the next command, but in this case it points to the next
+	// literal 32 bit integer.  Get that literal into %eax and increment %esi.
+	// On x86, it's a convenient single byte instruction!  (cf. NEXT macro)
+	lodsl
+	push %eax		// push the literal number on to stack
+	NEXT
+
+/*
+	MEMORY ----------------------------------------------------------------------
+
+	As important point about FORTH is that it gives you direct access to the lowest levels
+	of the machine.  Manipulating memory directly is done frequently in FORTH, and these are
+	the primitive words for doing it.
+*/
+
+	defcode "!",1,,STORE
+	pop %ebx		// address to store at
+	pop %eax		// data to store there
+	mov %eax,(%ebx)		// store it
+	NEXT
+
+	defcode "@",1,,FETCH
+	pop %ebx		// address to fetch
+	mov (%ebx),%eax		// fetch it
+	push %eax		// push value onto stack
+	NEXT
+
+	defcode "+!",2,,ADDSTORE
+	pop %ebx		// address
+	pop %eax		// the amount to add
+	addl %eax,(%ebx)	// add it
+	NEXT
+
+	defcode "-!",2,,SUBSTORE
+	pop %ebx		// address
+	pop %eax		// the amount to subtract
+	subl %eax,(%ebx)	// add it
+	NEXT
+
+/*
+	! and @ (STORE and FETCH) store 32-bit words.  It's also useful to be able to read and write bytes
+	so we also define standard words C@ and C!.
+
+	Byte-oriented operations only work on architectures which permit them (i386 is one of those).
+ */
+
+	defcode "C!",2,,STOREBYTE
+	pop %ebx		// address to store at
+	pop %eax		// data to store there
+	movb %al,(%ebx)		// store it
+	NEXT
+
+	defcode "C@",2,,FETCHBYTE
+	pop %ebx		// address to fetch
+	xor %eax,%eax
+	movb (%ebx),%al		// fetch it
+	push %eax		// push value onto stack
+	NEXT
+
+/* C@C! is a useful byte copy primitive. */
+	defcode "C@C!",4,,CCOPY
+	movl 4(%esp),%ebx	// source address
+	movb (%ebx),%al		// get source character
+	pop %edi		// destination address
+	stosb			// copy to destination
+	push %edi		// increment destination address
+	incl 4(%esp)		// increment source address
+	NEXT
+
+/* and CMOVE is a block copy operation. */
+	defcode "CMOVE",5,,CMOVE
+	mov %esi,%edx		// preserve %esi
+	pop %ecx		// length
+	pop %edi		// destination address
+	pop %esi		// source address
+	rep movsb		// copy source to destination
+	mov %edx,%esi		// restore %esi
+	NEXT
+
+/*
+	BUILT-IN VARIABLES ----------------------------------------------------------------------
+
+	These are some built-in variables and related standard FORTH words.  Of these, the only one that we
+	have discussed so far was LATEST, which points to the last (most recently defined) word in the
+	FORTH dictionary.  LATEST is also a FORTH word which pushes the address of LATEST (the variable)
+	on to the stack, so you can read or write it using @ and ! operators.  For example, to print
+	the current value of LATEST (and this can apply to any FORTH variable) you would do:
+
+	LATEST @ . CR
+
+	To make defining variables shorter, I'm using a macro called defvar, similar to defword and
+	defcode above.  (In fact the defvar macro uses defcode to do the dictionary header).
+*/
+
+	.macro defvar name, namelen, flags=0, label, initial=0
+	defcode \name,\namelen,\flags,\label
+	push $var_\name
+	NEXT
+	.data
+	.align 4
+var_\name :
+	.int \initial
+	.endm
+
+/*
+	The built-in variables are:
+
+	STATE		Is the interpreter executing code (0) or compiling a word (non-zero)?
+	LATEST		Points to the latest (most recently defined) word in the dictionary.
+	HERE		Points to the next free byte of memory.  When compiling, compiled words go here.
+	S0		Stores the address of the top of the parameter stack.
+	BASE		The current base for printing and reading numbers.
+
+*/
+	defvar "STATE",5,,STATE
+	defvar "HERE",4,,HERE
+	defvar "LATEST",6,,LATEST,name_SYSCALL0 // SYSCALL0 must be last in built-in dictionary
+	defvar "S0",2,,SZ
+	defvar "BASE",4,,BASE,10
+
+/*
+	BUILT-IN CONSTANTS ----------------------------------------------------------------------
+
+	It's also useful to expose a few constants to FORTH.  When the word is executed it pushes a
+	constant value on the stack.
+
+	The built-in constants are:
+
+	VERSION		Is the current version of this FORTH.
+	R0		The address of the top of the return stack.
+	DOCOL		Pointer to DOCOL.
+	F_IMMED		The IMMEDIATE flag's actual value.
+	F_HIDDEN	The HIDDEN flag's actual value.
+	F_LENMASK	The length mask in the flags/len byte.
+
+	SYS_*		and the numeric codes of various Linux syscalls (from <asm/unistd.h>)
+*/
+
+//#include <asm-i386/unistd.h>	// you might need this instead
+#include <asm/unistd.h>
+
+	.macro defconst name, namelen, flags=0, label, value
+	defcode \name,\namelen,\flags,\label
+	push $\value
+	NEXT
+	.endm
+
+	defconst "VERSION",7,,VERSION,JONES_VERSION
+	defconst "R0",2,,RZ,return_stack_top
+	defconst "DOCOL",5,,__DOCOL,DOCOL
+	defconst "F_IMMED",7,,__F_IMMED,F_IMMED
+	defconst "F_HIDDEN",8,,__F_HIDDEN,F_HIDDEN
+	defconst "F_LENMASK",9,,__F_LENMASK,F_LENMASK
+
+	defconst "SYS_EXIT",8,,SYS_EXIT,__NR_exit
+	defconst "SYS_OPEN",8,,SYS_OPEN,__NR_open
+	defconst "SYS_CLOSE",9,,SYS_CLOSE,__NR_close
+	defconst "SYS_READ",8,,SYS_READ,__NR_read
+	defconst "SYS_WRITE",9,,SYS_WRITE,__NR_write
+	defconst "SYS_CREAT",9,,SYS_CREAT,__NR_creat
+	defconst "SYS_BRK",7,,SYS_BRK,__NR_brk
+
+	defconst "O_RDONLY",8,,__O_RDONLY,0
+	defconst "O_WRONLY",8,,__O_WRONLY,1
+	defconst "O_RDWR",6,,__O_RDWR,2
+	defconst "O_CREAT",7,,__O_CREAT,0100
+	defconst "O_EXCL",6,,__O_EXCL,0200
+	defconst "O_TRUNC",7,,__O_TRUNC,01000
+	defconst "O_APPEND",8,,__O_APPEND,02000
+	defconst "O_NONBLOCK",10,,__O_NONBLOCK,04000
+
+/*
+	RETURN STACK ----------------------------------------------------------------------
+
+	These words allow you to access the return stack.  Recall that the register %ebp always points to
+	the top of the return stack.
+*/
+
+	defcode ">R",2,,TOR
+	pop %eax		// pop parameter stack into %eax
+	PUSHRSP %eax		// push it on to the return stack
+	NEXT
+
+	defcode "R>",2,,FROMR
+	POPRSP %eax		// pop return stack on to %eax
+	push %eax		// and push on to parameter stack
+	NEXT
+
+	defcode "RSP@",4,,RSPFETCH
+	push %ebp
+	NEXT
+
+	defcode "RSP!",4,,RSPSTORE
+	pop %ebp
+	NEXT
+
+	defcode "RDROP",5,,RDROP
+	addl $4,%ebp		// pop return stack and throw away
+	NEXT
+
+/*
+	PARAMETER (DATA) STACK ----------------------------------------------------------------------
+
+	These functions allow you to manipulate the parameter stack.  Recall that Linux sets up the parameter
+	stack for us, and it is accessed through %esp.
+*/
+
+	defcode "DSP@",4,,DSPFETCH
+	mov %esp,%eax
+	push %eax
+	NEXT
+
+	defcode "DSP!",4,,DSPSTORE
+	pop %esp
+	NEXT
+
+/*
+	INPUT AND OUTPUT ----------------------------------------------------------------------
+
+	These are our first really meaty/complicated FORTH primitives.  I have chosen to write them in
+	assembler, but surprisingly in "real" FORTH implementations these are often written in terms
+	of more fundamental FORTH primitives.  I chose to avoid that because I think that just obscures
+	the implementation.  After all, you may not understand assembler but you can just think of it
+	as an opaque block of code that does what it says.
+
+	Let's discuss input first.
+
+	The FORTH word KEY reads the next byte from stdin (and pushes it on the parameter stack).
+	So if KEY is called and someone hits the space key, then the number 32 (ASCII code of space)
+	is pushed on the stack.
+
+	In FORTH there is no distinction between reading code and reading input.  We might be reading
+	and compiling code, we might be reading words to execute, we might be asking for the user
+	to type their name -- ultimately it all comes in through KEY.
+
+	The implementation of KEY uses an input buffer of a certain size (defined at the end of this
+	file).  It calls the Linux read(2) system call to fill this buffer and tracks its position
+	in the buffer using a couple of variables, and if it runs out of input buffer then it refills
+	it automatically.  The other thing that KEY does is if it detects that stdin has closed, it
+	exits the program, which is why when you hit ^D the FORTH system cleanly exits.
+
+     buffer			      bufftop
+	|				 |
+	V				 V
+	+-------------------------------+--------------------------------------+
+	| INPUT READ FROM STDIN ....... | unused part of the buffer            |
+	+-------------------------------+--------------------------------------+
+	                  ^
+			  |
+		       currkey (next character to read)
+
+	<---------------------- BUFFER_SIZE (4096 bytes) ---------------------->
+*/
+
+	defcode "KEY",3,,KEY
+	call _KEY
+	push %eax		// push return value on stack
+	NEXT
+_KEY:
+	mov (currkey),%ebx
+	cmp (bufftop),%ebx
+	jge 1f			// exhausted the input buffer?
+	xor %eax,%eax
+	mov (%ebx),%al		// get next key from input buffer
+	inc %ebx
+	mov %ebx,(currkey)	// increment currkey
+	ret
+
+1:	// Out of input; use read(2) to fetch more input from stdin.
+	xor %ebx,%ebx		// 1st param: stdin
+	mov $buffer,%ecx	// 2nd param: buffer
+	mov %ecx,currkey
+	mov $BUFFER_SIZE,%edx	// 3rd param: max length
+	mov $__NR_read,%eax	// syscall: read
+	int $0x80
+	test %eax,%eax		// If %eax <= 0, then exit.
+	jbe 2f
+	addl %eax,%ecx		// buffer+%eax = bufftop
+	mov %ecx,bufftop
+	jmp _KEY
+
+2:	// Error or end of input: exit the program.
+	xor %ebx,%ebx
+	mov $__NR_exit,%eax	// syscall: exit
+	int $0x80
+
+	.data
+	.align 4
+currkey:
+	.int buffer		// Current place in input buffer (next character to read).
+bufftop:
+	.int buffer		// Last valid data in input buffer + 1.
+
+/*
+	By contrast, output is much simpler.  The FORTH word EMIT writes out a single byte to stdout.
+	This implementation just uses the write system call.  No attempt is made to buffer output, but
+	it would be a good exercise to add it.
+*/
+
+	defcode "EMIT",4,,EMIT
+	pop %eax
+	call _EMIT
+	NEXT
+_EMIT:
+	mov $1,%ebx		// 1st param: stdout
+
+	// write needs the address of the byte to write
+	mov %al,emit_scratch
+	mov $emit_scratch,%ecx	// 2nd param: address
+
+	mov $1,%edx		// 3rd param: nbytes = 1
+
+	mov $__NR_write,%eax	// write syscall
+	int $0x80
+	ret
+
+	.data			// NB: easier to fit in the .data section
+emit_scratch:
+	.space 1		// scratch used by EMIT
+
+/*
+	Back to input, WORD is a FORTH word which reads the next full word of input.
+
+	What it does in detail is that it first skips any blanks (spaces, tabs, newlines and so on).
+	Then it calls KEY to read characters into an internal buffer until it hits a blank.  Then it
+	calculates the length of the word it read and returns the address and the length as
+	two words on the stack (with the length at the top of stack).
+
+	Notice that WORD has a single internal buffer which it overwrites each time (rather like
+	a static C string).  Also notice that WORD's internal buffer is just 32 bytes long and
+	there is NO checking for overflow.  31 bytes happens to be the maximum length of a
+	FORTH word that we support, and that is what WORD is used for: to read FORTH words when
+	we are compiling and executing code.  The returned strings are not NUL-terminated.
+
+	Start address+length is the normal way to represent strings in FORTH (not ending in an
+	ASCII NUL character as in C), and so FORTH strings can contain any character including NULs
+	and can be any length.
+
+	WORD is not suitable for just reading strings (eg. user input) because of all the above
+	peculiarities and limitations.
+
+	Note that when executing, you'll see:
+	WORD FOO
+	which puts "FOO" and length 3 on the stack, but when compiling:
+	: BAR WORD FOO ;
+	is an error (or at least it doesn't do what you might expect).  Later we'll talk about compiling
+	and immediate mode, and you'll understand why.
+*/
+
+	defcode "WORD",4,,WORD
+	call _WORD
+	push %edi		// push base address
+	push %ecx		// push length
+	NEXT
+
+_WORD:
+	/* Search for first non-blank character.  Also skip \ comments. */
+1:
+	call _KEY		// get next key, returned in %eax
+	cmpb $'\\',%al		// start of a comment?
+	je 3f			// if so, skip the comment
+	cmpb $' ',%al
+	jbe 1b			// if so, keep looking
+
+	/* Search for the end of the word, storing chars as we go. */
+	mov $word_buffer,%edi	// pointer to return buffer
+2:
+	stosb			// add character to return buffer
+	call _KEY		// get next key, returned in %al
+	cmpb $' ',%al		// is blank?
+	ja 2b			// if not, keep looping
+
+	/* Return the word (well, the static buffer) and length. */
+	sub $word_buffer,%edi
+	mov %edi,%ecx		// return length of the word
+	mov $word_buffer,%edi	// return address of the word
+	ret
+
+	/* Code to skip \ comments to end of the current line. */
+3:
+	call _KEY
+	cmpb $'\n',%al		// end of line yet?
+	jne 3b
+	jmp 1b
+
+	.data			// NB: easier to fit in the .data section
+	// A static buffer where WORD returns.  Subsequent calls
+	// overwrite this buffer.  Maximum word length is 32 chars.
+word_buffer:
+	.space 32
+
+/*
+	As well as reading in words we'll need to read in numbers and for that we are using a function
+	called NUMBER.  This parses a numeric string such as one returned by WORD and pushes the
+	number on the parameter stack.
+
+	The function uses the variable BASE as the base (radix) for conversion, so for example if
+	BASE is 2 then we expect a binary number.  Normally BASE is 10.
+
+	If the word starts with a '-' character then the returned value is negative.
+
+	If the string can't be parsed as a number (or contains characters outside the current BASE)
+	then we need to return an error indication.  So NUMBER actually returns two items on the stack.
+	At the top of stack we return the number of unconverted characters (ie. if 0 then all characters
+	were converted, so there is no error).  Second from top of stack is the parsed number or a
+	partial value if there was an error.
+*/
+	defcode "NUMBER",6,,NUMBER
+	pop %ecx		// length of string
+	pop %edi		// start address of string
+	call _NUMBER
+	push %eax		// parsed number
+	push %ecx		// number of unparsed characters (0 = no error)
+	NEXT
+
+_NUMBER:
+	xor %eax,%eax
+	xor %ebx,%ebx
+
+	test %ecx,%ecx		// trying to parse a zero-length string is an error, but will return 0.
+	jz 5f
+
+	movl var_BASE,%edx	// get BASE (in %dl)
+
+	// Check if first character is '-'.
+	movb (%edi),%bl		// %bl = first character in string
+	inc %edi
+	push %eax		// push 0 on stack
+	cmpb $'-',%bl		// negative number?
+	jnz 2f
+	pop %eax
+	push %ebx		// push <> 0 on stack, indicating negative
+	dec %ecx
+	jnz 1f
+	pop %ebx		// error: string is only '-'.
+	movl $1,%ecx
+	ret
+
+	// Loop reading digits.
+1:	imull %edx,%eax		// %eax *= BASE
+	movb (%edi),%bl		// %bl = next character in string
+	inc %edi
+
+	// Convert 0-9, A-Z to a number 0-35.
+2:	subb $'0',%bl		// < '0'?
+	jb 4f
+	cmp $10,%bl		// <= '9'?
+	jb 3f
+	subb $17,%bl		// < 'A'? (17 is 'A'-'0')
+	jb 4f
+	addb $10,%bl
+
+3:	cmp %dl,%bl		// >= BASE?
+	jge 4f
+
+	// OK, so add it to %eax and loop.
+	add %ebx,%eax
+	dec %ecx
+	jnz 1b
+
+	// Negate the result if first character was '-' (saved on the stack).
+4:	pop %ebx
+	test %ebx,%ebx
+	jz 5f
+	neg %eax
+
+5:	ret
+
+/*
+	DICTIONARY LOOK UPS ----------------------------------------------------------------------
+
+	We're building up to our prelude on how FORTH code is compiled, but first we need yet more infrastructure.
+
+	The FORTH word FIND takes a string (a word as parsed by WORD -- see above) and looks it up in the
+	dictionary.  What it actually returns is the address of the dictionary header, if it finds it,
+	or 0 if it didn't.
+
+	So if DOUBLE is defined in the dictionary, then WORD DOUBLE FIND returns the following pointer:
+
+    pointer to this
+	|
+	|
+	V
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+
+	See also >CFA and >DFA.
+
+	FIND doesn't find dictionary entries which are flagged as HIDDEN.  See below for why.
+*/
+
+	defcode "FIND",4,,FIND
+	pop %ecx		// %ecx = length
+	pop %edi		// %edi = address
+	call _FIND
+	push %eax		// %eax = address of dictionary entry (or NULL)
+	NEXT
+
+_FIND:
+	push %esi		// Save %esi so we can use it in string comparison.
+
+	// Now we start searching backwards through the dictionary for this word.
+	mov var_LATEST,%edx	// LATEST points to name header of the latest word in the dictionary
+1:	test %edx,%edx		// NULL pointer?  (end of the linked list)
+	je 4f
+
+	// Compare the length expected and the length of the word.
+	// Note that if the F_HIDDEN flag is set on the word, then by a bit of trickery
+	// this won't pick the word (the length will appear to be wrong).
+	xor %eax,%eax
+	movb 4(%edx),%al	// %al = flags+length field
+	andb $(F_HIDDEN|F_LENMASK),%al // %al = name length
+	cmpb %cl,%al		// Length is the same?
+	jne 2f
+
+	// Compare the strings in detail.
+	push %ecx		// Save the length
+	push %edi		// Save the address (repe cmpsb will move this pointer)
+	lea 5(%edx),%esi	// Dictionary string we are checking against.
+	repe cmpsb		// Compare the strings.
+	pop %edi
+	pop %ecx
+	jne 2f			// Not the same.
+
+	// The strings are the same - return the header pointer in %eax
+	pop %esi
+	mov %edx,%eax
+	ret
+
+2:	mov (%edx),%edx		// Move back through the link field to the previous word
+	jmp 1b			// .. and loop.
+
+4:	// Not found.
+	pop %esi
+	xor %eax,%eax		// Return zero to indicate not found.
+	ret
+
+/*
+	FIND returns the dictionary pointer, but when compiling we need the codeword pointer (recall
+	that FORTH definitions are compiled into lists of codeword pointers).  The standard FORTH
+	word >CFA turns a dictionary pointer into a codeword pointer.
+
+	The example below shows the result of:
+
+		WORD DOUBLE FIND >CFA
+
+	FIND returns a pointer to this
+	|				>CFA converts it to a pointer to this
+	|					   |
+	V					   V
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+						   codeword
+
+	Notes:
+
+	Because names vary in length, this isn't just a simple increment.
+
+	In this FORTH you cannot easily turn a codeword pointer back into a dictionary entry pointer, but
+	that is not true in most FORTH implementations where they store a back pointer in the definition
+	(with an obvious memory/complexity cost).  The reason they do this is that it is useful to be
+	able to go backwards (codeword -> dictionary entry) in order to decompile FORTH definitions
+	quickly.
+
+	What does CFA stand for?  My best guess is "Code Field Address".
+*/
+
+	defcode ">CFA",4,,TCFA
+	pop %edi
+	call _TCFA
+	push %edi
+	NEXT
+_TCFA:
+	xor %eax,%eax
+	add $4,%edi		// Skip link pointer.
+	movb (%edi),%al		// Load flags+len into %al.
+	inc %edi		// Skip flags+len byte.
+	andb $F_LENMASK,%al	// Just the length, not the flags.
+	add %eax,%edi		// Skip the name.
+	addl $3,%edi		// The codeword is 4-byte aligned.
+	andl $~3,%edi
+	ret
+
+/*
+	Related to >CFA is >DFA which takes a dictionary entry address as returned by FIND and
+	returns a pointer to the first data field.
+
+	FIND returns a pointer to this
+	|				>CFA converts it to a pointer to this
+	|					   |
+	|					   |	>DFA converts it to a pointer to this
+	|					   |		 |
+	V					   V		 V
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+						   codeword
+
+	(Note to those following the source of FIG-FORTH / ciforth: My >DFA definition is
+	different from theirs, because they have an extra indirection).
+
+	You can see that >DFA is easily defined in FORTH just by adding 4 to the result of >CFA.
+*/
+
+	defword ">DFA",4,,TDFA
+	.int TCFA		// >CFA		(get code field address)
+	.int INCR4		// 4+		(add 4 to it to get to next word)
+	.int EXIT		// EXIT		(return from FORTH word)
+
+/*
+	COMPILING ----------------------------------------------------------------------
+
+	Now we'll talk about how FORTH compiles words.  Recall that a word definition looks like this:
+
+		: DOUBLE DUP + ;
+
+	and we have to turn this into:
+
+	  pointer to previous word
+	   ^
+	   |
+	+--|------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+--|---------+------------+------------+
+           ^       len                         pad  codeword      |
+	   |							  V
+	  LATEST points here				points to codeword of DUP
+
+	There are several problems to solve.  Where to put the new word?  How do we read words?  How
+	do we define the words : (COLON) and ; (SEMICOLON)?
+
+	FORTH solves this rather elegantly and as you might expect in a very low-level way which
+	allows you to change how the compiler works on your own code.
+
+	FORTH has an INTERPRET function (a true interpreter this time, not DOCOL) which runs in a
+	loop, reading words (using WORD), looking them up (using FIND), turning them into codeword
+	pointers (using >CFA) and deciding what to do with them.
+
+	What it does depends on the mode of the interpreter (in variable STATE).
+
+	When STATE is zero, the interpreter just runs each word as it looks them up.  This is known as
+	immediate mode.
+
+	The interesting stuff happens when STATE is non-zero -- compiling mode.  In this mode the
+	interpreter appends the codeword pointer to user memory (the HERE variable points to the next
+	free byte of user memory -- see DATA SEGMENT section below).
+
+	So you may be able to see how we could define : (COLON).  The general plan is:
+
+	(1) Use WORD to read the name of the function being defined.
+
+	(2) Construct the dictionary entry -- just the header part -- in user memory:
+
+    pointer to previous word (from LATEST)			+-- Afterwards, HERE points here, where
+	   ^							|   the interpreter will start appending
+	   |							V   codewords.
+	+--|------+---+---+---+---+---+---+---+---+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      |
+	+---------+---+---+---+---+---+---+---+---+------------+
+                   len                         pad  codeword
+
+	(3) Set LATEST to point to the newly defined word, ...
+
+	(4) .. and most importantly leave HERE pointing just after the new codeword.  This is where
+	    the interpreter will append codewords.
+
+	(5) Set STATE to 1.  This goes into compile mode so the interpreter starts appending codewords to
+	    our partially-formed header.
+
+	After : has run, our input is here:
+
+	: DOUBLE DUP + ;
+	         ^
+		 |
+		Next byte returned by KEY will be the 'D' character of DUP
+
+	so the interpreter (now it's in compile mode, so I guess it's really the compiler) reads "DUP",
+	looks it up in the dictionary, gets its codeword pointer, and appends it:
+
+									     +-- HERE updated to point here.
+									     |
+									     V
+	+---------+---+---+---+---+---+---+---+---+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+
+                   len                         pad  codeword
+
+	Next we read +, get the codeword pointer, and append it:
+
+											  +-- HERE updated to point here.
+											  |
+											  V
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+
+                   len                         pad  codeword
+
+	The issue is what happens next.  Obviously what we _don't_ want to happen is that we
+	read ";" and compile it and go on compiling everything afterwards.
+
+	At this point, FORTH uses a trick.  Remember the length byte in the dictionary definition
+	isn't just a plain length byte, but can also contain flags.  One flag is called the
+	IMMEDIATE flag (F_IMMED in this code).  If a word in the dictionary is flagged as
+	IMMEDIATE then the interpreter runs it immediately _even if it's in compile mode_.
+
+	This is how the word ; (SEMICOLON) works -- as a word flagged in the dictionary as IMMEDIATE.
+
+	And all it does is append the codeword for EXIT on to the current definition and switch
+	back to immediate mode (set STATE back to 0).  Shortly we'll see the actual definition
+	of ; and we'll see that it's really a very simple definition, declared IMMEDIATE.
+
+	After the interpreter reads ; and executes it 'immediately', we get this:
+
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+                   len                         pad  codeword					       ^
+												       |
+												      HERE
+	STATE is set to 0.
+
+	And that's it, job done, our new definition is compiled, and we're back in immediate mode
+	just reading and executing words, perhaps including a call to test our new word DOUBLE.
+
+	The only last wrinkle in this is that while our word was being compiled, it was in a
+	half-finished state.  We certainly wouldn't want DOUBLE to be called somehow during
+	this time.  There are several ways to stop this from happening, but in FORTH what we
+	do is flag the word with the HIDDEN flag (F_HIDDEN in this code) just while it is
+	being compiled.  This prevents FIND from finding it, and thus in theory stops any
+	chance of it being called.
+
+	The above explains how compiling, : (COLON) and ; (SEMICOLON) works and in a moment I'm
+	going to define them.  The : (COLON) function can be made a little bit more general by writing
+	it in two parts.  The first part, called CREATE, makes just the header:
+
+						   +-- Afterwards, HERE points here.
+						   |
+						   V
+	+---------+---+---+---+---+---+---+---+---+
+	| LINK    | 6 | D | O | U | B | L | E | 0 |
+	+---------+---+---+---+---+---+---+---+---+
+                   len                         pad
+
+	and the second part, the actual definition of : (COLON), calls CREATE and appends the
+	DOCOL codeword, so leaving:
+
+								+-- Afterwards, HERE points here.
+								|
+								V
+	+---------+---+---+---+---+---+---+---+---+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      |
+	+---------+---+---+---+---+---+---+---+---+------------+
+                   len                         pad  codeword
+
+	CREATE is a standard FORTH word and the advantage of this split is that we can reuse it to
+	create other types of words (not just ones which contain code, but words which contain variables,
+	constants and other data).
+*/
+
+	defcode "CREATE",6,,CREATE
+
+	// Get the name length and address.
+	pop %ecx		// %ecx = length
+	pop %ebx		// %ebx = address of name
+
+	// Link pointer.
+	movl var_HERE,%edi	// %edi is the address of the header
+	movl var_LATEST,%eax	// Get link pointer
+	stosl			// and store it in the header.
+
+	// Length byte and the word itself.
+	mov %cl,%al		// Get the length.
+	stosb			// Store the length/flags byte.
+	push %esi
+	mov %ebx,%esi		// %esi = word
+	rep movsb		// Copy the word
+	pop %esi
+	addl $3,%edi		// Align to next 4 byte boundary.
+	andl $~3,%edi
+
+	// Update LATEST and HERE.
+	movl var_HERE,%eax
+	movl %eax,var_LATEST
+	movl %edi,var_HERE
+	NEXT
+
+/*
+	Because I want to define : (COLON) in FORTH, not assembler, we need a few more FORTH words
+	to use.
+
+	The first is , (COMMA) which is a standard FORTH word which appends a 32 bit integer to the user
+	memory pointed to by HERE, and adds 4 to HERE.  So the action of , (COMMA) is:
+
+							previous value of HERE
+								 |
+								 V
+	+---------+---+---+---+---+---+---+---+---+-- - - - - --+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 |             |  <data>    |
+	+---------+---+---+---+---+---+---+---+---+-- - - - - --+------------+
+                   len                         pad		              ^
+									      |
+									new value of HERE
+
+	and <data> is whatever 32 bit integer was at the top of the stack.
+
+	, (COMMA) is quite a fundamental operation when compiling.  It is used to append codewords
+	to the current word that is being compiled.
+*/
+
+	defcode ",",1,,COMMA
+	pop %eax		// Code pointer to store.
+	call _COMMA
+	NEXT
+_COMMA:
+	movl var_HERE,%edi	// HERE
+	stosl			// Store it.
+	movl %edi,var_HERE	// Update HERE (incremented)
+	ret
+
+/*
+	Our definitions of : (COLON) and ; (SEMICOLON) will need to switch to and from compile mode.
+
+	Immediate mode vs. compile mode is stored in the global variable STATE, and by updating this
+	variable we can switch between the two modes.
+
+	For various reasons which may become apparent later, FORTH defines two standard words called
+	[ and ] (LBRAC and RBRAC) which switch between modes:
+
+	Word	Assembler	Action		Effect
+	[	LBRAC		STATE := 0	Switch to immediate mode.
+	]	RBRAC		STATE := 1	Switch to compile mode.
+
+	[ (LBRAC) is an IMMEDIATE word.  The reason is as follows: If we are in compile mode and the
+	interpreter saw [ then it would compile it rather than running it.  We would never be able to
+	switch back to immediate mode!  So we flag the word as IMMEDIATE so that even in compile mode
+	the word runs immediately, switching us back to immediate mode.
+*/
+
+	defcode "[",1,F_IMMED,LBRAC
+	xor %eax,%eax
+	movl %eax,var_STATE	// Set STATE to 0.
+	NEXT
+
+	defcode "]",1,,RBRAC
+	movl $1,var_STATE	// Set STATE to 1.
+	NEXT
+
+/*
+	Now we can define : (COLON) using CREATE.  It just calls CREATE, appends DOCOL (the codeword), sets
+	the word HIDDEN and goes into compile mode.
+*/
+
+	defword ":",1,,COLON
+	.int WORD		// Get the name of the new word
+	.int CREATE		// CREATE the dictionary entry / header
+	.int LIT, DOCOL, COMMA	// Append DOCOL  (the codeword).
+	.int LATEST, FETCH, HIDDEN // Make the word hidden (see below for definition).
+	.int RBRAC		// Go into compile mode.
+	.int EXIT		// Return from the function.
+
+/*
+	; (SEMICOLON) is also elegantly simple.  Notice the F_IMMED flag.
+*/
+
+	defword ";",1,F_IMMED,SEMICOLON
+	.int LIT, EXIT, COMMA	// Append EXIT (so the word will return).
+	.int LATEST, FETCH, HIDDEN // Toggle hidden flag -- unhide the word (see below for definition).
+	.int LBRAC		// Go back to IMMEDIATE mode.
+	.int EXIT		// Return from the function.
+
+/*
+	EXTENDING THE COMPILER ----------------------------------------------------------------------
+
+	Words flagged with IMMEDIATE (F_IMMED) aren't just for the FORTH compiler to use.  You can define
+	your own IMMEDIATE words too, and this is a crucial aspect when extending basic FORTH, because
+	it allows you in effect to extend the compiler itself.  Does gcc let you do that?
+
+	Standard FORTH words like IF, WHILE, ." and so on are all written as extensions to the basic
+	compiler, and are all IMMEDIATE words.
+
+	The IMMEDIATE word toggles the F_IMMED (IMMEDIATE flag) on the most recently defined word,
+	or on the current word if you call it in the middle of a definition.
+
+	Typical usage is:
+
+	: MYIMMEDWORD IMMEDIATE
+		...definition...
+	;
+
+	but some FORTH programmers write this instead:
+
+	: MYIMMEDWORD
+		...definition...
+	; IMMEDIATE
+
+	The two usages are equivalent, to a first approximation.
+*/
+
+	defcode "IMMEDIATE",9,F_IMMED,IMMEDIATE
+	movl var_LATEST,%edi	// LATEST word.
+	addl $4,%edi		// Point to name/flags byte.
+	xorb $F_IMMED,(%edi)	// Toggle the IMMED bit.
+	NEXT
+
+/*
+	'addr HIDDEN' toggles the hidden flag (F_HIDDEN) of the word defined at addr.  To hide the
+	most recently defined word (used above in : and ; definitions) you would do:
+
+		LATEST @ HIDDEN
+
+	'HIDE word' toggles the flag on a named 'word'.
+
+	Setting this flag stops the word from being found by FIND, and so can be used to make 'private'
+	words.  For example, to break up a large word into smaller parts you might do:
+
+		: SUB1 ... subword ... ;
+		: SUB2 ... subword ... ;
+		: SUB3 ... subword ... ;
+		: MAIN ... defined in terms of SUB1, SUB2, SUB3 ... ;
+		HIDE SUB1
+		HIDE SUB2
+		HIDE SUB3
+
+	After this, only MAIN is 'exported' or seen by the rest of the program.
+*/
+
+	defcode "HIDDEN",6,,HIDDEN
+	pop %edi		// Dictionary entry.
+	addl $4,%edi		// Point to name/flags byte.
+	xorb $F_HIDDEN,(%edi)	// Toggle the HIDDEN bit.
+	NEXT
+
+	defword "HIDE",4,,HIDE
+	.int WORD		// Get the word (after HIDE).
+	.int FIND		// Look up in the dictionary.
+	.int HIDDEN		// Set F_HIDDEN flag.
+	.int EXIT		// Return.
+
+/*
+	' (TICK) is a standard FORTH word which returns the codeword pointer of the next word.
+
+	The common usage is:
+
+	' FOO ,
+
+	which appends the codeword of FOO to the current word we are defining (this only works in compiled code).
+
+	You tend to use ' in IMMEDIATE words.  For example an alternate (and rather useless) way to define
+	a literal 2 might be:
+
+	: LIT2 IMMEDIATE
+		' LIT ,		\ Appends LIT to the currently-being-defined word
+		2 ,		\ Appends the number 2 to the currently-being-defined word
+	;
+
+	So you could do:
+
+	: DOUBLE LIT2 * ;
+
+	(If you don't understand how LIT2 works, then you should review the material about compiling words
+	and immediate mode).
+
+	This definition of ' uses a cheat which I copied from buzzard92.  As a result it only works in
+	compiled code.  It is possible to write a version of ' based on WORD, FIND, >CFA which works in
+	immediate mode too.
+*/
+	defcode "'",1,,TICK
+	lodsl			// Get the address of the next word and skip it.
+	pushl %eax		// Push it on the stack.
+	NEXT
+
+/*
+	BRANCHING ----------------------------------------------------------------------
+
+	It turns out that all you need in order to define looping constructs, IF-statements, etc.
+	are two primitives.
+
+	BRANCH is an unconditional branch. 0BRANCH is a conditional branch (it only branches if the
+	top of stack is zero).
+
+	The diagram below shows how BRANCH works in some imaginary compiled word.  When BRANCH executes,
+	%esi starts by pointing to the offset field (compare to LIT above):
+
+	+---------------------+-------+---- - - ---+------------+------------+---- - - - ----+------------+
+	| (Dictionary header) | DOCOL |            | BRANCH     | offset     | (skipped)     | word       |
+	+---------------------+-------+---- - - ---+------------+-----|------+---- - - - ----+------------+
+								   ^  |			      ^
+								   |  |			      |
+								   |  +-----------------------+
+								  %esi added to offset
+
+	The offset is added to %esi to make the new %esi, and the result is that when NEXT runs, execution
+	continues at the branch target.  Negative offsets work as expected.
+
+	0BRANCH is the same except the branch happens conditionally.
+
+	Now standard FORTH words such as IF, THEN, ELSE, WHILE, REPEAT, etc. can be implemented entirely
+	in FORTH.  They are IMMEDIATE words which append various combinations of BRANCH or 0BRANCH
+	into the word currently being compiled.
+
+	As an example, code written like this:
+
+		condition-code IF true-part THEN rest-code
+
+	compiles to:
+
+		condition-code 0BRANCH OFFSET true-part rest-code
+					  |		^
+					  |		|
+					  +-------------+
+*/
+
+	defcode "BRANCH",6,,BRANCH
+	add (%esi),%esi		// add the offset to the instruction pointer
+	NEXT
+
+	defcode "0BRANCH",7,,ZBRANCH
+	pop %eax
+	test %eax,%eax		// top of stack is zero?
+	jz code_BRANCH		// if so, jump back to the branch function above
+	lodsl			// otherwise we need to skip the offset
+	NEXT
+
+/*
+	LITERAL STRINGS ----------------------------------------------------------------------
+
+	LITSTRING is a primitive used to implement the ." and S" operators (which are written in
+	FORTH).  See the definition of those operators later.
+
+	TELL just prints a string.  It's more efficient to define this in assembly because we
+	can make it a single Linux syscall.
+*/
+
+	defcode "LITSTRING",9,,LITSTRING
+	lodsl			// get the length of the string
+	push %esi		// push the address of the start of the string
+	push %eax		// push it on the stack
+	addl %eax,%esi		// skip past the string
+ 	addl $3,%esi		// but round up to next 4 byte boundary
+	andl $~3,%esi
+	NEXT
+
+	defcode "TELL",4,,TELL
+	mov $1,%ebx		// 1st param: stdout
+	pop %edx		// 3rd param: length of string
+	pop %ecx		// 2nd param: address of string
+	mov $__NR_write,%eax	// write syscall
+	int $0x80
+	NEXT
+
+/*
+	QUIT AND INTERPRET ----------------------------------------------------------------------
+
+	QUIT is the first FORTH function called, almost immediately after the FORTH system "boots".
+	As explained before, QUIT doesn't "quit" anything.  It does some initialisation (in particular
+	it clears the return stack) and it calls INTERPRET in a loop to interpret commands.  The
+	reason it is called QUIT is because you can call it from your own FORTH words in order to
+	"quit" your program and start again at the user prompt.
+
+	INTERPRET is the FORTH interpreter ("toploop", "toplevel" or "REPL" might be a more accurate
+	description -- see: http://en.wikipedia.org/wiki/REPL).
+*/
+
+	// QUIT must not return (ie. must not call EXIT).
+	defword "QUIT",4,,QUIT
+	.int RZ,RSPSTORE	// R0 RSP!, clear the return stack
+	.int INTERPRET		// interpret the next word
+	.int BRANCH,-8		// and loop (indefinitely)
+
+/*
+	This interpreter is pretty simple, but remember that in FORTH you can always override
+	it later with a more powerful one!
+ */
+	defcode "INTERPRET",9,,INTERPRET
+	call _WORD		// Returns %ecx = length, %edi = pointer to word.
+
+	// Is it in the dictionary?
+	xor %eax,%eax
+	movl %eax,interpret_is_lit // Not a literal number (not yet anyway ...)
+	call _FIND		// Returns %eax = pointer to header or 0 if not found.
+	test %eax,%eax		// Found?
+	jz 1f
+
+	// In the dictionary.  Is it an IMMEDIATE codeword?
+	mov %eax,%edi		// %edi = dictionary entry
+	movb 4(%edi),%al	// Get name+flags.
+	push %ax		// Just save it for now.
+	call _TCFA		// Convert dictionary entry (in %edi) to codeword pointer.
+	pop %ax
+	andb $F_IMMED,%al	// Is IMMED flag set?
+	mov %edi,%eax
+	jnz 4f			// If IMMED, jump straight to executing.
+
+	jmp 2f
+
+1:	// Not in the dictionary (not a word) so assume it's a literal number.
+	incl interpret_is_lit
+	call _NUMBER		// Returns the parsed number in %eax, %ecx > 0 if error
+	test %ecx,%ecx
+	jnz 6f
+	mov %eax,%ebx
+	mov $LIT,%eax		// The word is LIT
+
+2:	// Are we compiling or executing?
+	movl var_STATE,%edx
+	test %edx,%edx
+	jz 4f			// Jump if executing.
+
+	// Compiling - just append the word to the current dictionary definition.
+	call _COMMA
+	mov interpret_is_lit,%ecx // Was it a literal?
+	test %ecx,%ecx
+	jz 3f
+	mov %ebx,%eax		// Yes, so LIT is followed by a number.
+	call _COMMA
+3:	NEXT
+
+4:	// Executing - run it!
+	mov interpret_is_lit,%ecx // Literal?
+	test %ecx,%ecx		// Literal?
+	jnz 5f
+
+	// Not a literal, execute it now.  This never returns, but the codeword will
+	// eventually call NEXT which will reenter the loop in QUIT.
+	jmp *(%eax)
+
+5:	// Executing a literal, which means push it on the stack.
+	push %ebx
+	NEXT
+
+6:	// Parse error (not a known word or a number in the current BASE).
+	// Print an error message followed by up to 40 characters of context.
+	mov $2,%ebx		// 1st param: stderr
+	mov $errmsg,%ecx	// 2nd param: error message
+	mov $errmsgend-errmsg,%edx // 3rd param: length of string
+	mov $__NR_write,%eax	// write syscall
+	int $0x80
+
+	mov (currkey),%ecx	// the error occurred just before currkey position
+	mov %ecx,%edx
+	sub $buffer,%edx	// %edx = currkey - buffer (length in buffer before currkey)
+	cmp $40,%edx		// if > 40, then print only 40 characters
+	jle 7f
+	mov $40,%edx
+7:	sub %edx,%ecx		// %ecx = start of area to print, %edx = length
+	mov $__NR_write,%eax	// write syscall
+	int $0x80
+
+	mov $errmsgnl,%ecx	// newline
+	mov $1,%edx
+	mov $__NR_write,%eax	// write syscall
+	int $0x80
+
+	NEXT
+
+	.section .rodata
+errmsg: .ascii "PARSE ERROR: "
+errmsgend:
+errmsgnl: .ascii "\n"
+
+	.data			// NB: easier to fit in the .data section
+	.align 4
+interpret_is_lit:
+	.int 0			// Flag used to record if reading a literal
+
+/*
+	ODDS AND ENDS ----------------------------------------------------------------------
+
+	CHAR puts the ASCII code of the first character of the following word on the stack.  For example
+	CHAR A puts 65 on the stack.
+
+	EXECUTE is used to run execution tokens.  See the discussion of execution tokens in the
+	FORTH code for more details.
+
+	SYSCALL0, SYSCALL1, SYSCALL2, SYSCALL3 make a standard Linux system call.  (See <asm/unistd.h>
+	for a list of system call numbers).  As their name suggests these forms take between 0 and 3
+	syscall parameters, plus the system call number.
+
+	In this FORTH, SYSCALL0 must be the last word in the built-in (assembler) dictionary because we
+	initialise the LATEST variable to point to it.  This means that if you want to extend the assembler
+	part, you must put new words before SYSCALL0, or else change how LATEST is initialised.
+*/
+
+	defcode "CHAR",4,,CHAR
+	call _WORD		// Returns %ecx = length, %edi = pointer to word.
+	xor %eax,%eax
+	movb (%edi),%al		// Get the first character of the word.
+	push %eax		// Push it onto the stack.
+	NEXT
+
+	defcode "EXECUTE",7,,EXECUTE
+	pop %eax		// Get xt into %eax
+	jmp *(%eax)		// and jump to it.
+				// After xt runs its NEXT will continue executing the current word.
+
+	defcode "SYSCALL3",8,,SYSCALL3
+	pop %eax		// System call number (see <asm/unistd.h>)
+	pop %ebx		// First parameter.
+	pop %ecx		// Second parameter
+	pop %edx		// Third parameter
+	int $0x80
+	push %eax		// Result (negative for -errno)
+	NEXT
+
+	defcode "SYSCALL2",8,,SYSCALL2
+	pop %eax		// System call number (see <asm/unistd.h>)
+	pop %ebx		// First parameter.
+	pop %ecx		// Second parameter
+	int $0x80
+	push %eax		// Result (negative for -errno)
+	NEXT
+
+	defcode "SYSCALL1",8,,SYSCALL1
+	pop %eax		// System call number (see <asm/unistd.h>)
+	pop %ebx		// First parameter.
+	int $0x80
+	push %eax		// Result (negative for -errno)
+	NEXT
+
+	defcode "SYSCALL0",8,,SYSCALL0
+	pop %eax		// System call number (see <asm/unistd.h>)
+	int $0x80
+	push %eax		// Result (negative for -errno)
+	NEXT
+
+/*
+	DATA SEGMENT ----------------------------------------------------------------------
+
+	Here we set up the Linux data segment, used for user definitions and variously known as just
+	the 'data segment', 'user memory' or 'user definitions area'.  It is an area of memory which
+	grows upwards and stores both newly-defined FORTH words and global variables of various
+	sorts.
+
+	It is completely analogous to the C heap, except there is no generalised 'malloc' and 'free'
+	(but as with everything in FORTH, writing such functions would just be a Simple Matter
+	Of Programming).  Instead in normal use the data segment just grows upwards as new FORTH
+	words are defined/appended to it.
+
+	There are various "features" of the GNU toolchain which make setting up the data segment
+	more complicated than it really needs to be.  One is the GNU linker which inserts a random
+	"build ID" segment.  Another is Address Space Randomization which means we can't tell
+	where the kernel will choose to place the data segment (or the stack for that matter).
+
+	Therefore writing this set_up_data_segment assembler routine is a little more complicated
+	than it really needs to be.  We ask the Linux kernel where it thinks the data segment starts
+	using the brk(2) system call, then ask it to reserve some initial space (also using brk(2)).
+
+	You don't need to worry about this code.
+*/
+	.text
+	.set INITIAL_DATA_SEGMENT_SIZE,65536
+set_up_data_segment:
+	xor %ebx,%ebx		// Call brk(0)
+	movl $__NR_brk,%eax
+	int $0x80
+	movl %eax,var_HERE	// Initialise HERE to point at beginning of data segment.
+	addl $INITIAL_DATA_SEGMENT_SIZE,%eax	// Reserve nn bytes of memory for initial data segment.
+	movl %eax,%ebx		// Call brk(HERE+INITIAL_DATA_SEGMENT_SIZE)
+	movl $__NR_brk,%eax
+	int $0x80
+	ret
+
+/*
+	We allocate static buffers for the return static and input buffer (used when
+	reading in files and text that the user types in).
+*/
+	.set RETURN_STACK_SIZE,8192
+	.set BUFFER_SIZE,4096
+
+	.bss
+/* FORTH return stack. */
+	.align 4096
+return_stack:
+	.space RETURN_STACK_SIZE
+return_stack_top:		// Initial top of return stack.
+
+/* This is used as a temporary input buffer when reading from files or the terminal. */
+	.align 4096
+buffer:
+	.space BUFFER_SIZE
+
+/*
+	START OF FORTH CODE ----------------------------------------------------------------------
+
+	We've now reached the stage where the FORTH system is running and self-hosting.  All further
+	words can be written as FORTH itself, including words like IF, THEN, .", etc which in most
+	languages would be considered rather fundamental.
+
+	I used to append this here in the assembly file, but I got sick of fighting against gas's
+	crack-smoking (lack of) multiline string syntax.  So now that is in a separate file called
+	jonesforth.f
+
+	If you don't already have that file, download it from http://annexia.org/forth in order
+	to continue the tutorial.
+*/
+
+/* END OF jonesforth.S */
diff --git a/original_jonesforth/jonesforth.f b/original_jonesforth/jonesforth.f
new file mode 100644
index 0000000..5c13095
--- /dev/null
+++ b/original_jonesforth/jonesforth.f
@@ -0,0 +1,1788 @@
+\ -*- text -*-
+\	A sometimes minimal FORTH compiler and tutorial for Linux / i386 systems. -*- asm -*-
+\	By Richard W.M. Jones <rich@annexia.org> http://annexia.org/forth
+\	This is PUBLIC DOMAIN (see public domain release statement below).
+\	$Id: jonesforth.f,v 1.18 2009-09-11 08:32:33 rich Exp $
+\
+\	The first part of this tutorial is in jonesforth.S.  Get if from http://annexia.org/forth
+\
+\	PUBLIC DOMAIN ----------------------------------------------------------------------
+\
+\	I, the copyright holder of this work, hereby release it into the public domain. This applies worldwide.
+\
+\	In case this is not legally possible, I grant any entity the right to use this work for any purpose,
+\	without any conditions, unless such conditions are required by law.
+\
+\	SETTING UP ----------------------------------------------------------------------
+\
+\	Let's get a few housekeeping things out of the way.  Firstly because I need to draw lots of
+\	ASCII-art diagrams to explain concepts, the best way to look at this is using a window which
+\	uses a fixed width font and is at least this wide:
+\
+\<------------------------------------------------------------------------------------------------------------------------>
+\
+\	Secondly make sure TABS are set to 8 characters.  The following should be a vertical
+\	line.  If not, sort out your tabs.
+\
+\		|
+\	        |
+\	    	|
+\
+\	Thirdly I assume that your screen is at least 50 characters high.
+\
+\	START OF FORTH CODE ----------------------------------------------------------------------
+\
+\	We've now reached the stage where the FORTH system is running and self-hosting.  All further
+\	words can be written as FORTH itself, including words like IF, THEN, .", etc which in most
+\	languages would be considered rather fundamental.
+\
+\	Some notes about the code:
+\
+\	I use indenting to show structure.  The amount of whitespace has no meaning to FORTH however
+\	except that you must use at least one whitespace character between words, and words themselves
+\	cannot contain whitespace.
+\
+\	FORTH is case-sensitive.  Use capslock!
+
+\ The primitive word /MOD (DIVMOD) leaves both the quotient and the remainder on the stack.  (On
+\ i386, the idivl instruction gives both anyway).  Now we can define the / and MOD in terms of /MOD
+\ and a few other primitives.
+: / /MOD SWAP DROP ;
+: MOD /MOD DROP ;
+
+\ Define some character constants
+: '\n' 10 ;
+: BL   32 ; \ BL (BLank) is a standard FORTH word for space.
+
+\ CR prints a carriage return
+: CR '\n' EMIT ;
+
+\ SPACE prints a space
+: SPACE BL EMIT ;
+
+\ NEGATE leaves the negative of a number on the stack.
+: NEGATE 0 SWAP - ;
+
+\ Standard words for booleans.
+: TRUE  1 ;
+: FALSE 0 ;
+: NOT   0= ;
+
+\ LITERAL takes whatever is on the stack and compiles LIT <foo>
+: LITERAL IMMEDIATE
+	' LIT ,		\ compile LIT
+	,		\ compile the literal itself (from the stack)
+	;
+
+\ Now we can use [ and ] to insert literals which are calculated at compile time.  (Recall that
+\ [ and ] are the FORTH words which switch into and out of immediate mode.)
+\ Within definitions, use [ ... ] LITERAL anywhere that '...' is a constant expression which you
+\ would rather only compute once (at compile time, rather than calculating it each time your word runs).
+: ':'
+	[		\ go into immediate mode (temporarily)
+	CHAR :		\ push the number 58 (ASCII code of colon) on the parameter stack
+	]		\ go back to compile mode
+	LITERAL		\ compile LIT 58 as the definition of ':' word
+;
+
+\ A few more character constants defined the same way as above.
+: ';' [ CHAR ; ] LITERAL ;
+: '(' [ CHAR ( ] LITERAL ;
+: ')' [ CHAR ) ] LITERAL ;
+: '"' [ CHAR " ] LITERAL ;
+: 'A' [ CHAR A ] LITERAL ;
+: '0' [ CHAR 0 ] LITERAL ;
+: '-' [ CHAR - ] LITERAL ;
+: '.' [ CHAR . ] LITERAL ;
+
+\ While compiling, '[COMPILE] word' compiles 'word' if it would otherwise be IMMEDIATE.
+: [COMPILE] IMMEDIATE
+	WORD		\ get the next word
+	FIND		\ find it in the dictionary
+	>CFA		\ get its codeword
+	,		\ and compile that
+;
+
+\ RECURSE makes a recursive call to the current word that is being compiled.
+\
+\ Normally while a word is being compiled, it is marked HIDDEN so that references to the
+\ same word within are calls to the previous definition of the word.  However we still have
+\ access to the word which we are currently compiling through the LATEST pointer so we
+\ can use that to compile a recursive call.
+: RECURSE IMMEDIATE
+	LATEST @	\ LATEST points to the word being compiled at the moment
+	>CFA		\ get the codeword
+	,		\ compile it
+;
+
+\	CONTROL STRUCTURES ----------------------------------------------------------------------
+\
+\ So far we have defined only very simple definitions.  Before we can go further, we really need to
+\ make some control structures, like IF ... THEN and loops.  Luckily we can define arbitrary control
+\ structures directly in FORTH.
+\
+\ Please note that the control structures as I have defined them here will only work inside compiled
+\ words.  If you try to type in expressions using IF, etc. in immediate mode, then they won't work.
+\ Making these work in immediate mode is left as an exercise for the reader.
+
+\ condition IF true-part THEN rest
+\	-- compiles to: --> condition 0BRANCH OFFSET true-part rest
+\	where OFFSET is the offset of 'rest'
+\ condition IF true-part ELSE false-part THEN
+\ 	-- compiles to: --> condition 0BRANCH OFFSET true-part BRANCH OFFSET2 false-part rest
+\	where OFFSET if the offset of false-part and OFFSET2 is the offset of rest
+
+\ IF is an IMMEDIATE word which compiles 0BRANCH followed by a dummy offset, and places
+\ the address of the 0BRANCH on the stack.  Later when we see THEN, we pop that address
+\ off the stack, calculate the offset, and back-fill the offset.
+: IF IMMEDIATE
+	' 0BRANCH ,	\ compile 0BRANCH
+	HERE @		\ save location of the offset on the stack
+	0 ,		\ compile a dummy offset
+;
+
+: THEN IMMEDIATE
+	DUP
+	HERE @ SWAP -	\ calculate the offset from the address saved on the stack
+	SWAP !		\ store the offset in the back-filled location
+;
+
+: ELSE IMMEDIATE
+	' BRANCH ,	\ definite branch to just over the false-part
+	HERE @		\ save location of the offset on the stack
+	0 ,		\ compile a dummy offset
+	SWAP		\ now back-fill the original (IF) offset
+	DUP		\ same as for THEN word above
+	HERE @ SWAP -
+	SWAP !
+;
+
+\ BEGIN loop-part condition UNTIL
+\	-- compiles to: --> loop-part condition 0BRANCH OFFSET
+\	where OFFSET points back to the loop-part
+\ This is like do { loop-part } while (condition) in the C language
+: BEGIN IMMEDIATE
+	HERE @		\ save location on the stack
+;
+
+: UNTIL IMMEDIATE
+	' 0BRANCH ,	\ compile 0BRANCH
+	HERE @ -	\ calculate the offset from the address saved on the stack
+	,		\ compile the offset here
+;
+
+\ BEGIN loop-part AGAIN
+\	-- compiles to: --> loop-part BRANCH OFFSET
+\	where OFFSET points back to the loop-part
+\ In other words, an infinite loop which can only be returned from with EXIT
+: AGAIN IMMEDIATE
+	' BRANCH ,	\ compile BRANCH
+	HERE @ -	\ calculate the offset back
+	,		\ compile the offset here
+;
+
+\ BEGIN condition WHILE loop-part REPEAT
+\	-- compiles to: --> condition 0BRANCH OFFSET2 loop-part BRANCH OFFSET
+\	where OFFSET points back to condition (the beginning) and OFFSET2 points to after the whole piece of code
+\ So this is like a while (condition) { loop-part } loop in the C language
+: WHILE IMMEDIATE
+	' 0BRANCH ,	\ compile 0BRANCH
+	HERE @		\ save location of the offset2 on the stack
+	0 ,		\ compile a dummy offset2
+;
+
+: REPEAT IMMEDIATE
+	' BRANCH ,	\ compile BRANCH
+	SWAP		\ get the original offset (from BEGIN)
+	HERE @ - ,	\ and compile it after BRANCH
+	DUP
+	HERE @ SWAP -	\ calculate the offset2
+	SWAP !		\ and back-fill it in the original location
+;
+
+\ UNLESS is the same as IF but the test is reversed.
+\
+\ Note the use of [COMPILE]: Since IF is IMMEDIATE we don't want it to be executed while UNLESS
+\ is compiling, but while UNLESS is running (which happens to be when whatever word using UNLESS is
+\ being compiled -- whew!).  So we use [COMPILE] to reverse the effect of marking IF as immediate.
+\ This trick is generally used when we want to write our own control words without having to
+\ implement them all in terms of the primitives 0BRANCH and BRANCH, but instead reusing simpler
+\ control words like (in this instance) IF.
+: UNLESS IMMEDIATE
+	' NOT ,		\ compile NOT (to reverse the test)
+	[COMPILE] IF	\ continue by calling the normal IF
+;
+
+\	COMMENTS ----------------------------------------------------------------------
+\
+\ FORTH allows ( ... ) as comments within function definitions.  This works by having an IMMEDIATE
+\ word called ( which just drops input characters until it hits the corresponding ).
+: ( IMMEDIATE
+	1		\ allowed nested parens by keeping track of depth
+	BEGIN
+		KEY		\ read next character
+		DUP '(' = IF	\ open paren?
+			DROP		\ drop the open paren
+			1+		\ depth increases
+		ELSE
+			')' = IF	\ close paren?
+				1-		\ depth decreases
+			THEN
+		THEN
+	DUP 0= UNTIL		\ continue until we reach matching close paren, depth 0
+	DROP		\ drop the depth counter
+;
+
+(
+	From now on we can use ( ... ) for comments.
+
+	STACK NOTATION ----------------------------------------------------------------------
+
+	In FORTH style we can also use ( ... -- ... ) to show the effects that a word has on the
+	parameter stack.  For example:
+
+	( n -- )	means that the word consumes an integer (n) from the parameter stack.
+	( b a -- c )	means that the word uses two integers (a and b, where a is at the top of stack)
+				and returns a single integer (c).
+	( -- )		means the word has no effect on the stack
+)
+
+( Some more complicated stack examples, showing the stack notation. )
+: NIP ( x y -- y ) SWAP DROP ;
+: TUCK ( x y -- y x y ) SWAP OVER ;
+: PICK ( x_u ... x_1 x_0 u -- x_u ... x_1 x_0 x_u )
+	1+		( add one because of 'u' on the stack )
+	4 *		( multiply by the word size )
+	DSP@ +		( add to the stack pointer )
+	@    		( and fetch )
+;
+
+( With the looping constructs, we can now write SPACES, which writes n spaces to stdout. )
+: SPACES	( n -- )
+	BEGIN
+		DUP 0>		( while n > 0 )
+	WHILE
+		SPACE		( print a space )
+		1-		( until we count down to 0 )
+	REPEAT
+	DROP
+;
+
+( Standard words for manipulating BASE. )
+: DECIMAL ( -- ) 10 BASE ! ;
+: HEX ( -- ) 16 BASE ! ;
+
+(
+	PRINTING NUMBERS ----------------------------------------------------------------------
+
+	The standard FORTH word . (DOT) is very important.  It takes the number at the top
+	of the stack and prints it out.  However first I'm going to implement some lower-level
+	FORTH words:
+
+	U.R	( u width -- )	which prints an unsigned number, padded to a certain width
+	U.	( u -- )	which prints an unsigned number
+	.R	( n width -- )	which prints a signed number, padded to a certain width.
+
+	For example:
+		-123 6 .R
+	will print out these characters:
+		<space> <space> - 1 2 3
+
+	In other words, the number padded left to a certain number of characters.
+
+	The full number is printed even if it is wider than width, and this is what allows us to
+	define the ordinary functions U. and . (we just set width to zero knowing that the full
+	number will be printed anyway).
+
+	Another wrinkle of . and friends is that they obey the current base in the variable BASE.
+	BASE can be anything in the range 2 to 36.
+
+	While we're defining . &c we can also define .S which is a useful debugging tool.  This
+	word prints the current stack (non-destructively) from top to bottom.
+)
+
+( This is the underlying recursive definition of U. )
+: U.		( u -- )
+	BASE @ /MOD	( width rem quot )
+	?DUP IF			( if quotient <> 0 then )
+		RECURSE		( print the quotient )
+	THEN
+
+	( print the remainder )
+	DUP 10 < IF
+		'0'		( decimal digits 0..9 )
+	ELSE
+		10 -		( hex and beyond digits A..Z )
+		'A'
+	THEN
+	+
+	EMIT
+;
+
+(
+	FORTH word .S prints the contents of the stack.  It doesn't alter the stack.
+	Very useful for debugging.
+)
+: .S		( -- )
+	DSP@		( get current stack pointer )
+	BEGIN
+		DUP S0 @ <
+	WHILE
+		DUP @ U.	( print the stack element )
+		SPACE
+		4+		( move up )
+	REPEAT
+	DROP
+;
+
+( This word returns the width (in characters) of an unsigned number in the current base )
+: UWIDTH	( u -- width )
+	BASE @ /	( rem quot )
+	?DUP IF		( if quotient <> 0 then )
+		RECURSE 1+	( return 1+recursive call )
+	ELSE
+		1		( return 1 )
+	THEN
+;
+
+: U.R		( u width -- )
+	SWAP		( width u )
+	DUP		( width u u )
+	UWIDTH		( width u uwidth )
+	ROT		( u uwidth width )
+	SWAP -		( u width-uwidth )
+	( At this point if the requested width is narrower, we'll have a negative number on the stack.
+	  Otherwise the number on the stack is the number of spaces to print.  But SPACES won't print
+	  a negative number of spaces anyway, so it's now safe to call SPACES ... )
+	SPACES
+	( ... and then call the underlying implementation of U. )
+	U.
+;
+
+(
+	.R prints a signed number, padded to a certain width.  We can't just print the sign
+	and call U.R because we want the sign to be next to the number ('-123' instead of '-  123').
+)
+: .R		( n width -- )
+	SWAP		( width n )
+	DUP 0< IF
+		NEGATE		( width u )
+		1		( save a flag to remember that it was negative | width n 1 )
+		SWAP		( width 1 u )
+		ROT		( 1 u width )
+		1-		( 1 u width-1 )
+	ELSE
+		0		( width u 0 )
+		SWAP		( width 0 u )
+		ROT		( 0 u width )
+	THEN
+	SWAP		( flag width u )
+	DUP		( flag width u u )
+	UWIDTH		( flag width u uwidth )
+	ROT		( flag u uwidth width )
+	SWAP -		( flag u width-uwidth )
+
+	SPACES		( flag u )
+	SWAP		( u flag )
+
+	IF			( was it negative? print the - character )
+		'-' EMIT
+	THEN
+
+	U.
+;
+
+( Finally we can define word . in terms of .R, with a trailing space. )
+: . 0 .R SPACE ;
+
+( The real U., note the trailing space. )
+: U. U. SPACE ;
+
+( ? fetches the integer at an address and prints it. )
+: ? ( addr -- ) @ . ;
+
+( c a b WITHIN returns true if a <= c and c < b )
+(  or define without ifs: OVER - >R - R>  U<  )
+: WITHIN
+	-ROT		( b c a )
+	OVER		( b c a c )
+	<= IF
+		> IF		( b c -- )
+			TRUE
+		ELSE
+			FALSE
+		THEN
+	ELSE
+		2DROP		( b c -- )
+		FALSE
+	THEN
+;
+
+( DEPTH returns the depth of the stack. )
+: DEPTH		( -- n )
+	S0 @ DSP@ -
+	4-			( adjust because S0 was on the stack when we pushed DSP )
+;
+
+(
+	ALIGNED takes an address and rounds it up (aligns it) to the next 4 byte boundary.
+)
+: ALIGNED	( addr -- addr )
+	3 + 3 INVERT AND	( (addr+3) & ~3 )
+;
+
+(
+	ALIGN aligns the HERE pointer, so the next word appended will be aligned properly.
+)
+: ALIGN HERE @ ALIGNED HERE ! ;
+
+(
+	STRINGS ----------------------------------------------------------------------
+
+	S" string" is used in FORTH to define strings.  It leaves the address of the string and
+	its length on the stack, (length at the top of stack).  The space following S" is the normal
+	space between FORTH words and is not a part of the string.
+
+	This is tricky to define because it has to do different things depending on whether
+	we are compiling or in immediate mode.  (Thus the word is marked IMMEDIATE so it can
+	detect this and do different things).
+
+	In compile mode we append
+		LITSTRING <string length> <string rounded up 4 bytes>
+	to the current word.  The primitive LITSTRING does the right thing when the current
+	word is executed.
+
+	In immediate mode there isn't a particularly good place to put the string, but in this
+	case we put the string at HERE (but we _don't_ change HERE).  This is meant as a temporary
+	location, likely to be overwritten soon after.
+)
+( C, appends a byte to the current compiled word. )
+: C,
+	HERE @ C!	( store the character in the compiled image )
+	1 HERE +!	( increment HERE pointer by 1 byte )
+;
+
+: S" IMMEDIATE		( -- addr len )
+	STATE @ IF	( compiling? )
+		' LITSTRING ,	( compile LITSTRING )
+		HERE @		( save the address of the length word on the stack )
+		0 ,		( dummy length - we don't know what it is yet )
+		BEGIN
+			KEY 		( get next character of the string )
+			DUP '"' <>
+		WHILE
+			C,		( copy character )
+		REPEAT
+		DROP		( drop the double quote character at the end )
+		DUP		( get the saved address of the length word )
+		HERE @ SWAP -	( calculate the length )
+		4-		( subtract 4 (because we measured from the start of the length word) )
+		SWAP !		( and back-fill the length location )
+		ALIGN		( round up to next multiple of 4 bytes for the remaining code )
+	ELSE		( immediate mode )
+		HERE @		( get the start address of the temporary space )
+		BEGIN
+			KEY
+			DUP '"' <>
+		WHILE
+			OVER C!		( save next character )
+			1+		( increment address )
+		REPEAT
+		DROP		( drop the final " character )
+		HERE @ -	( calculate the length )
+		HERE @		( push the start address )
+		SWAP 		( addr len )
+	THEN
+;
+
+(
+	." is the print string operator in FORTH.  Example: ." Something to print"
+	The space after the operator is the ordinary space required between words and is not
+	a part of what is printed.
+
+	In immediate mode we just keep reading characters and printing them until we get to
+	the next double quote.
+
+	In compile mode we use S" to store the string, then add TELL afterwards:
+		LITSTRING <string length> <string rounded up to 4 bytes> TELL
+
+	It may be interesting to note the use of [COMPILE] to turn the call to the immediate
+	word S" into compilation of that word.  It compiles it into the definition of .",
+	not into the definition of the word being compiled when this is running (complicated
+	enough for you?)
+)
+: ." IMMEDIATE		( -- )
+	STATE @ IF	( compiling? )
+		[COMPILE] S"	( read the string, and compile LITSTRING, etc. )
+		' TELL ,	( compile the final TELL )
+	ELSE
+		( In immediate mode, just read characters and print them until we get
+		  to the ending double quote. )
+		BEGIN
+			KEY
+			DUP '"' = IF
+				DROP	( drop the double quote character )
+				EXIT	( return from this function )
+			THEN
+			EMIT
+		AGAIN
+	THEN
+;
+
+(
+	CONSTANTS AND VARIABLES ----------------------------------------------------------------------
+
+	In FORTH, global constants and variables are defined like this:
+
+	10 CONSTANT TEN		when TEN is executed, it leaves the integer 10 on the stack
+	VARIABLE VAR		when VAR is executed, it leaves the address of VAR on the stack
+
+	Constants can be read but not written, eg:
+
+	TEN . CR		prints 10
+
+	You can read a variable (in this example called VAR) by doing:
+
+	VAR @			leaves the value of VAR on the stack
+	VAR @ . CR		prints the value of VAR
+	VAR ? CR		same as above, since ? is the same as @ .
+
+	and update the variable by doing:
+
+	20 VAR !		sets VAR to 20
+
+	Note that variables are uninitialised (but see VALUE later on which provides initialised
+	variables with a slightly simpler syntax).
+
+	How can we define the words CONSTANT and VARIABLE?
+
+	The trick is to define a new word for the variable itself (eg. if the variable was called
+	'VAR' then we would define a new word called VAR).  This is easy to do because we exposed
+	dictionary entry creation through the CREATE word (part of the definition of : above).
+	A call to WORD [TEN] CREATE (where [TEN] means that "TEN" is the next word in the input)
+	leaves the dictionary entry:
+
+				   +--- HERE
+				   |
+				   V
+	+---------+---+---+---+---+
+	| LINK    | 3 | T | E | N |
+	+---------+---+---+---+---+
+                   len
+
+	For CONSTANT we can continue by appending DOCOL (the codeword), then LIT followed by
+	the constant itself and then EXIT, forming a little word definition that returns the
+	constant:
+
+	+---------+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 3 | T | E | N | DOCOL      | LIT        | 10         | EXIT       |
+	+---------+---+---+---+---+------------+------------+------------+------------+
+                   len              codeword
+
+	Notice that this word definition is exactly the same as you would have got if you had
+	written : TEN 10 ;
+
+	Note for people reading the code below: DOCOL is a constant word which we defined in the
+	assembler part which returns the value of the assembler symbol of the same name.
+)
+: CONSTANT
+	WORD		( get the name (the name follows CONSTANT) )
+	CREATE		( make the dictionary entry )
+	DOCOL ,		( append DOCOL (the codeword field of this word) )
+	' LIT ,		( append the codeword LIT )
+	,		( append the value on the top of the stack )
+	' EXIT ,	( append the codeword EXIT )
+;
+
+(
+	VARIABLE is a little bit harder because we need somewhere to put the variable.  There is
+	nothing particularly special about the user memory (the area of memory pointed to by HERE
+	where we have previously just stored new word definitions).  We can slice off bits of this
+	memory area to store anything we want, so one possible definition of VARIABLE might create
+	this:
+
+	   +--------------------------------------------------------------+
+	   |								  |
+	   V								  |
+	+---------+---------+---+---+---+---+------------+------------+---|--------+------------+
+	| <var>   | LINK    | 3 | V | A | R | DOCOL      | LIT        | <addr var> | EXIT       |
+	+---------+---------+---+---+---+---+------------+------------+------------+------------+
+        		     len              codeword
+
+	where <var> is the place to store the variable, and <addr var> points back to it.
+
+	To make this more general let's define a couple of words which we can use to allocate
+	arbitrary memory from the user memory.
+
+	First ALLOT, where n ALLOT allocates n bytes of memory.  (Note when calling this that
+	it's a very good idea to make sure that n is a multiple of 4, or at least that next time
+	a word is compiled that HERE has been left as a multiple of 4).
+)
+: ALLOT		( n -- addr )
+	HERE @ SWAP	( here n )
+	HERE +!		( adds n to HERE, after this the old value of HERE is still on the stack )
+;
+
+(
+	Second, CELLS.  In FORTH the phrase 'n CELLS ALLOT' means allocate n integers of whatever size
+	is the natural size for integers on this machine architecture.  On this 32 bit machine therefore
+	CELLS just multiplies the top of stack by 4.
+)
+: CELLS ( n -- n ) 4 * ;
+
+(
+	So now we can define VARIABLE easily in much the same way as CONSTANT above.  Refer to the
+	diagram above to see what the word that this creates will look like.
+)
+: VARIABLE
+	1 CELLS ALLOT	( allocate 1 cell of memory, push the pointer to this memory )
+	WORD CREATE	( make the dictionary entry (the name follows VARIABLE) )
+	DOCOL ,		( append DOCOL (the codeword field of this word) )
+	' LIT ,		( append the codeword LIT )
+	,		( append the pointer to the new memory )
+	' EXIT ,	( append the codeword EXIT )
+;
+
+(
+	VALUES ----------------------------------------------------------------------
+
+	VALUEs are like VARIABLEs but with a simpler syntax.  You would generally use them when you
+	want a variable which is read often, and written infrequently.
+
+	20 VALUE VAL 	creates VAL with initial value 20
+	VAL		pushes the value (20) directly on the stack
+	30 TO VAL	updates VAL, setting it to 30
+	VAL		pushes the value (30) directly on the stack
+
+	Notice that 'VAL' on its own doesn't return the address of the value, but the value itself,
+	making values simpler and more obvious to use than variables (no indirection through '@').
+	The price is a more complicated implementation, although despite the complexity there is no
+	performance penalty at runtime.
+
+	A naive implementation of 'TO' would be quite slow, involving a dictionary search each time.
+	But because this is FORTH we have complete control of the compiler so we can compile TO more
+	efficiently, turning:
+		TO VAL
+	into:
+		LIT <addr> !
+	and calculating <addr> (the address of the value) at compile time.
+
+	Now this is the clever bit.  We'll compile our value like this:
+
+	+---------+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 3 | V | A | L | DOCOL      | LIT        | <value>    | EXIT       |
+	+---------+---+---+---+---+------------+------------+------------+------------+
+                   len              codeword
+
+	where <value> is the actual value itself.  Note that when VAL executes, it will push the
+	value on the stack, which is what we want.
+
+	But what will TO use for the address <addr>?  Why of course a pointer to that <value>:
+
+		code compiled	- - - - --+------------+------------+------------+-- - - - -
+		by TO VAL		  | LIT        | <addr>     | !          |
+				- - - - --+------------+-----|------+------------+-- - - - -
+							     |
+							     V
+	+---------+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 3 | V | A | L | DOCOL      | LIT        | <value>    | EXIT       |
+	+---------+---+---+---+---+------------+------------+------------+------------+
+                   len              codeword
+
+	In other words, this is a kind of self-modifying code.
+
+	(Note to the people who want to modify this FORTH to add inlining: values defined this
+	way cannot be inlined).
+)
+: VALUE		( n -- )
+	WORD CREATE	( make the dictionary entry (the name follows VALUE) )
+	DOCOL ,		( append DOCOL )
+	' LIT ,		( append the codeword LIT )
+	,		( append the initial value )
+	' EXIT ,	( append the codeword EXIT )
+;
+
+: TO IMMEDIATE	( n -- )
+	WORD		( get the name of the value )
+	FIND		( look it up in the dictionary )
+	>DFA		( get a pointer to the first data field (the 'LIT') )
+	4+		( increment to point at the value )
+	STATE @ IF	( compiling? )
+		' LIT ,		( compile LIT )
+		,		( compile the address of the value )
+		' ! ,		( compile ! )
+	ELSE		( immediate mode )
+		!		( update it straightaway )
+	THEN
+;
+
+( x +TO VAL adds x to VAL )
+: +TO IMMEDIATE
+	WORD		( get the name of the value )
+	FIND		( look it up in the dictionary )
+	>DFA		( get a pointer to the first data field (the 'LIT') )
+	4+		( increment to point at the value )
+	STATE @ IF	( compiling? )
+		' LIT ,		( compile LIT )
+		,		( compile the address of the value )
+		' +! ,		( compile +! )
+	ELSE		( immediate mode )
+		+!		( update it straightaway )
+	THEN
+;
+
+(
+	PRINTING THE DICTIONARY ----------------------------------------------------------------------
+
+	ID. takes an address of a dictionary entry and prints the word's name.
+
+	For example: LATEST @ ID. would print the name of the last word that was defined.
+)
+: ID.
+	4+		( skip over the link pointer )
+	DUP C@		( get the flags/length byte )
+	F_LENMASK AND	( mask out the flags - just want the length )
+
+	BEGIN
+		DUP 0>		( length > 0? )
+	WHILE
+		SWAP 1+		( addr len -- len addr+1 )
+		DUP C@		( len addr -- len addr char | get the next character)
+		EMIT		( len addr char -- len addr | and print it)
+		SWAP 1-		( len addr -- addr len-1    | subtract one from length )
+	REPEAT
+	2DROP		( len addr -- )
+;
+
+(
+	'WORD word FIND ?HIDDEN' returns true if 'word' is flagged as hidden.
+
+	'WORD word FIND ?IMMEDIATE' returns true if 'word' is flagged as immediate.
+)
+: ?HIDDEN
+	4+		( skip over the link pointer )
+	C@		( get the flags/length byte )
+	F_HIDDEN AND	( mask the F_HIDDEN flag and return it (as a truth value) )
+;
+: ?IMMEDIATE
+	4+		( skip over the link pointer )
+	C@		( get the flags/length byte )
+	F_IMMED AND	( mask the F_IMMED flag and return it (as a truth value) )
+;
+
+(
+	WORDS prints all the words defined in the dictionary, starting with the word defined most recently.
+	However it doesn't print hidden words.
+
+	The implementation simply iterates backwards from LATEST using the link pointers.
+)
+: WORDS
+	LATEST @	( start at LATEST dictionary entry )
+	BEGIN
+		?DUP		( while link pointer is not null )
+	WHILE
+		DUP ?HIDDEN NOT IF	( ignore hidden words )
+			DUP ID.		( but if not hidden, print the word )
+			SPACE
+		THEN
+		@		( dereference the link pointer - go to previous word )
+	REPEAT
+	CR
+;
+
+(
+	FORGET ----------------------------------------------------------------------
+
+	So far we have only allocated words and memory.  FORTH provides a rather primitive method
+	to deallocate.
+
+	'FORGET word' deletes the definition of 'word' from the dictionary and everything defined
+	after it, including any variables and other memory allocated after.
+
+	The implementation is very simple - we look up the word (which returns the dictionary entry
+	address).  Then we set HERE to point to that address, so in effect all future allocations
+	and definitions will overwrite memory starting at the word.  We also need to set LATEST to
+	point to the previous word.
+
+	Note that you cannot FORGET built-in words (well, you can try but it will probably cause
+	a segfault).
+
+	XXX: Because we wrote VARIABLE to store the variable in memory allocated before the word,
+	in the current implementation VARIABLE FOO FORGET FOO will leak 1 cell of memory.
+)
+: FORGET
+	WORD FIND	( find the word, gets the dictionary entry address )
+	DUP @ LATEST !	( set LATEST to point to the previous word )
+	HERE !		( and store HERE with the dictionary address )
+;
+
+(
+	DUMP ----------------------------------------------------------------------
+
+	DUMP is used to dump out the contents of memory, in the 'traditional' hexdump format.
+
+	Notice that the parameters to DUMP (address, length) are compatible with string words
+	such as WORD and S".
+
+	You can dump out the raw code for the last word you defined by doing something like:
+
+		LATEST @ 128 DUMP
+)
+: DUMP		( addr len -- )
+	BASE @ -ROT		( save the current BASE at the bottom of the stack )
+	HEX			( and switch to hexadecimal mode )
+
+	BEGIN
+		?DUP		( while len > 0 )
+	WHILE
+		OVER 8 U.R	( print the address )
+		SPACE
+
+		( print up to 16 words on this line )
+		2DUP		( addr len addr len )
+		1- 15 AND 1+	( addr len addr linelen )
+		BEGIN
+			?DUP		( while linelen > 0 )
+		WHILE
+			SWAP		( addr len linelen addr )
+			DUP C@		( addr len linelen addr byte )
+			2 .R SPACE	( print the byte )
+			1+ SWAP 1-	( addr len linelen addr -- addr len addr+1 linelen-1 )
+		REPEAT
+		DROP		( addr len )
+
+		( print the ASCII equivalents )
+		2DUP 1- 15 AND 1+ ( addr len addr linelen )
+		BEGIN
+			?DUP		( while linelen > 0)
+		WHILE
+			SWAP		( addr len linelen addr )
+			DUP C@		( addr len linelen addr byte )
+			DUP 32 128 WITHIN IF	( 32 <= c < 128? )
+				EMIT
+			ELSE
+				DROP '.' EMIT
+			THEN
+			1+ SWAP 1-	( addr len linelen addr -- addr len addr+1 linelen-1 )
+		REPEAT
+		DROP		( addr len )
+		CR
+
+		DUP 1- 15 AND 1+ ( addr len linelen )
+		TUCK		( addr linelen len linelen )
+		-		( addr linelen len-linelen )
+		>R + R>		( addr+linelen len-linelen )
+	REPEAT
+
+	DROP			( restore stack )
+	BASE !			( restore saved BASE )
+;
+
+(
+	CASE ----------------------------------------------------------------------
+
+	CASE...ENDCASE is how we do switch statements in FORTH.  There is no generally
+	agreed syntax for this, so I've gone for the syntax mandated by the ISO standard
+	FORTH (ANS-FORTH).
+
+		( some value on the stack )
+		CASE
+		test1 OF ... ENDOF
+		test2 OF ... ENDOF
+		testn OF ... ENDOF
+		... ( default case )
+		ENDCASE
+
+	The CASE statement tests the value on the stack by comparing it for equality with
+	test1, test2, ..., testn and executes the matching piece of code within OF ... ENDOF.
+	If none of the test values match then the default case is executed.  Inside the ... of
+	the default case, the value is still at the top of stack (it is implicitly DROP-ed
+	by ENDCASE).  When ENDOF is executed it jumps after ENDCASE (ie. there is no "fall-through"
+	and no need for a break statement like in C).
+
+	The default case may be omitted.  In fact the tests may also be omitted so that you
+	just have a default case, although this is probably not very useful.
+
+	An example (assuming that 'q', etc. are words which push the ASCII value of the letter
+	on the stack):
+
+		0 VALUE QUIT
+		0 VALUE SLEEP
+		KEY CASE
+			'q' OF 1 TO QUIT ENDOF
+			's' OF 1 TO SLEEP ENDOF
+			( default case: )
+			." Sorry, I didn't understand key <" DUP EMIT ." >, try again." CR
+		ENDCASE
+
+	(In some versions of FORTH, more advanced tests are supported, such as ranges, etc.
+	Other versions of FORTH need you to write OTHERWISE to indicate the default case.
+	As I said above, this FORTH tries to follow the ANS FORTH standard).
+
+	The implementation of CASE...ENDCASE is somewhat non-trivial.  I'm following the
+	implementations from here:
+	http://www.uni-giessen.de/faq/archiv/forthfaq.case_endcase/msg00000.html
+
+	The general plan is to compile the code as a series of IF statements:
+
+	CASE				(push 0 on the immediate-mode parameter stack)
+	test1 OF ... ENDOF		test1 OVER = IF DROP ... ELSE
+	test2 OF ... ENDOF		test2 OVER = IF DROP ... ELSE
+	testn OF ... ENDOF		testn OVER = IF DROP ... ELSE
+	... ( default case )		...
+	ENDCASE				DROP THEN [THEN [THEN ...]]
+
+	The CASE statement pushes 0 on the immediate-mode parameter stack, and that number
+	is used to count how many THEN statements we need when we get to ENDCASE so that each
+	IF has a matching THEN.  The counting is done implicitly.  If you recall from the
+	implementation above of IF, each IF pushes a code address on the immediate-mode stack,
+	and these addresses are non-zero, so by the time we get to ENDCASE the stack contains
+	some number of non-zeroes, followed by a zero.  The number of non-zeroes is how many
+	times IF has been called, so how many times we need to match it with THEN.
+
+	This code uses [COMPILE] so that we compile calls to IF, ELSE, THEN instead of
+	actually calling them while we're compiling the words below.
+
+	As is the case with all of our control structures, they only work within word
+	definitions, not in immediate mode.
+)
+: CASE IMMEDIATE
+	0		( push 0 to mark the bottom of the stack )
+;
+
+: OF IMMEDIATE
+	' OVER ,	( compile OVER )
+	' = ,		( compile = )
+	[COMPILE] IF	( compile IF )
+	' DROP ,  	( compile DROP )
+;
+
+: ENDOF IMMEDIATE
+	[COMPILE] ELSE	( ENDOF is the same as ELSE )
+;
+
+: ENDCASE IMMEDIATE
+	' DROP ,	( compile DROP )
+
+	( keep compiling THEN until we get to our zero marker )
+	BEGIN
+		?DUP
+	WHILE
+		[COMPILE] THEN
+	REPEAT
+;
+
+(
+	DECOMPILER ----------------------------------------------------------------------
+
+	CFA> is the opposite of >CFA.  It takes a codeword and tries to find the matching
+	dictionary definition.  (In truth, it works with any pointer into a word, not just
+	the codeword pointer, and this is needed to do stack traces).
+
+	In this FORTH this is not so easy.  In fact we have to search through the dictionary
+	because we don't have a convenient back-pointer (as is often the case in other versions
+	of FORTH).  Because of this search, CFA> should not be used when performance is critical,
+	so it is only used for debugging tools such as the decompiler and printing stack
+	traces.
+
+	This word returns 0 if it doesn't find a match.
+)
+: CFA>
+	LATEST @	( start at LATEST dictionary entry )
+	BEGIN
+		?DUP		( while link pointer is not null )
+	WHILE
+		2DUP SWAP	( cfa curr curr cfa )
+		< IF		( current dictionary entry < cfa? )
+			NIP		( leave curr dictionary entry on the stack )
+			EXIT
+		THEN
+		@		( follow link pointer back )
+	REPEAT
+	DROP		( restore stack )
+	0		( sorry, nothing found )
+;
+
+(
+	SEE decompiles a FORTH word.
+
+	We search for the dictionary entry of the word, then search again for the next
+	word (effectively, the end of the compiled word).  This results in two pointers:
+
+	+---------+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 3 | T | E | N | DOCOL      | LIT        | 10         | EXIT       |
+	+---------+---+---+---+---+------------+------------+------------+------------+
+	 ^									       ^
+	 |									       |
+	Start of word							      End of word
+
+	With this information we can have a go at decompiling the word.  We need to
+	recognise "meta-words" like LIT, LITSTRING, BRANCH, etc. and treat those separately.
+)
+: SEE
+	WORD FIND	( find the dictionary entry to decompile )
+
+	( Now we search again, looking for the next word in the dictionary.  This gives us
+	  the length of the word that we will be decompiling.  (Well, mostly it does). )
+	HERE @		( address of the end of the last compiled word )
+	LATEST @	( word last curr )
+	BEGIN
+		2 PICK		( word last curr word )
+		OVER		( word last curr word curr )
+		<>		( word last curr word<>curr? )
+	WHILE			( word last curr )
+		NIP		( word curr )
+		DUP @		( word curr prev (which becomes: word last curr) )
+	REPEAT
+
+	DROP		( at this point, the stack is: start-of-word end-of-word )
+	SWAP		( end-of-word start-of-word )
+
+	( begin the definition with : NAME [IMMEDIATE] )
+	':' EMIT SPACE DUP ID. SPACE
+	DUP ?IMMEDIATE IF ." IMMEDIATE " THEN
+
+	>DFA		( get the data address, ie. points after DOCOL | end-of-word start-of-data )
+
+	( now we start decompiling until we hit the end of the word )
+	BEGIN		( end start )
+		2DUP >
+	WHILE
+		DUP @		( end start codeword )
+
+		CASE
+		' LIT OF		( is it LIT ? )
+			4 + DUP @		( get next word which is the integer constant )
+			.			( and print it )
+		ENDOF
+		' LITSTRING OF		( is it LITSTRING ? )
+			[ CHAR S ] LITERAL EMIT '"' EMIT SPACE ( print S"<space> )
+			4 + DUP @		( get the length word )
+			SWAP 4 + SWAP		( end start+4 length )
+			2DUP TELL		( print the string )
+			'"' EMIT SPACE		( finish the string with a final quote )
+			+ ALIGNED		( end start+4+len, aligned )
+			4 -			( because we're about to add 4 below )
+		ENDOF
+		' 0BRANCH OF		( is it 0BRANCH ? )
+			." 0BRANCH ( "
+			4 + DUP @		( print the offset )
+			.
+			." ) "
+		ENDOF
+		' BRANCH OF		( is it BRANCH ? )
+			." BRANCH ( "
+			4 + DUP @		( print the offset )
+			.
+			." ) "
+		ENDOF
+		' ' OF			( is it ' (TICK) ? )
+			[ CHAR ' ] LITERAL EMIT SPACE
+			4 + DUP @		( get the next codeword )
+			CFA>			( and force it to be printed as a dictionary entry )
+			ID. SPACE
+		ENDOF
+		' EXIT OF		( is it EXIT? )
+			( We expect the last word to be EXIT, and if it is then we don't print it
+			  because EXIT is normally implied by ;.  EXIT can also appear in the middle
+			  of words, and then it needs to be printed. )
+			2DUP			( end start end start )
+			4 +			( end start end start+4 )
+			<> IF			( end start | we're not at the end )
+				." EXIT "
+			THEN
+		ENDOF
+					( default case: )
+			DUP			( in the default case we always need to DUP before using )
+			CFA>			( look up the codeword to get the dictionary entry )
+			ID. SPACE		( and print it )
+		ENDCASE
+
+		4 +		( end start+4 )
+	REPEAT
+
+	';' EMIT CR
+
+	2DROP		( restore stack )
+;
+
+(
+	EXECUTION TOKENS ----------------------------------------------------------------------
+
+	Standard FORTH defines a concept called an 'execution token' (or 'xt') which is very
+	similar to a function pointer in C.  We map the execution token to a codeword address.
+
+			execution token of DOUBLE is the address of this codeword
+						    |
+						    V
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+	| LINK    | 6 | D | O | U | B | L | E | 0 | DOCOL      | DUP        | +          | EXIT       |
+	+---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+                   len                         pad  codeword					       ^
+
+	There is one assembler primitive for execution tokens, EXECUTE ( xt -- ), which runs them.
+
+	You can make an execution token for an existing word the long way using >CFA,
+	ie: WORD [foo] FIND >CFA will push the xt for foo onto the stack where foo is the
+	next word in input.  So a very slow way to run DOUBLE might be:
+
+		: DOUBLE DUP + ;
+		: SLOW WORD FIND >CFA EXECUTE ;
+		5 SLOW DOUBLE . CR	\ prints 10
+
+	We also offer a simpler and faster way to get the execution token of any word FOO:
+
+		['] FOO
+
+	(Exercises for readers: (1) What is the difference between ['] FOO and ' FOO?
+	(2) What is the relationship between ', ['] and LIT?)
+
+	More useful is to define anonymous words and/or to assign xt's to variables.
+
+	To define an anonymous word (and push its xt on the stack) use :NONAME ... ; as in this
+	example:
+
+		:NONAME ." anon word was called" CR ;	\ pushes xt on the stack
+		DUP EXECUTE EXECUTE			\ executes the anon word twice
+
+	Stack parameters work as expected:
+
+		:NONAME ." called with parameter " . CR ;
+		DUP
+		10 SWAP EXECUTE		\ prints 'called with parameter 10'
+		20 SWAP EXECUTE		\ prints 'called with parameter 20'
+
+	Notice that the above code has a memory leak: the anonymous word is still compiled
+	into the data segment, so even if you lose track of the xt, the word continues to
+	occupy memory.  A good way to keep track of the xt and thus avoid the memory leak is
+	to assign it to a CONSTANT, VARIABLE or VALUE:
+
+		0 VALUE ANON
+		:NONAME ." anon word was called" CR ; TO ANON
+		ANON EXECUTE
+		ANON EXECUTE
+
+	Another use of :NONAME is to create an array of functions which can be called quickly
+	(think: fast switch statement).  This example is adapted from the ANS FORTH standard:
+
+		10 CELLS ALLOT CONSTANT CMD-TABLE
+		: SET-CMD CELLS CMD-TABLE + ! ;
+		: CALL-CMD CELLS CMD-TABLE + @ EXECUTE ;
+
+		:NONAME ." alternate 0 was called" CR ;	 0 SET-CMD
+		:NONAME ." alternate 1 was called" CR ;	 1 SET-CMD
+			\ etc...
+		:NONAME ." alternate 9 was called" CR ;	 9 SET-CMD
+
+		0 CALL-CMD
+		1 CALL-CMD
+)
+
+: :NONAME
+	0 0 CREATE	( create a word with no name - we need a dictionary header because ; expects it )
+	HERE @		( current HERE value is the address of the codeword, ie. the xt )
+	DOCOL ,		( compile DOCOL (the codeword) )
+	]		( go into compile mode )
+;
+
+: ['] IMMEDIATE
+	' LIT ,		( compile LIT )
+;
+
+(
+	EXCEPTIONS ----------------------------------------------------------------------
+
+	Amazingly enough, exceptions can be implemented directly in FORTH, in fact rather easily.
+
+	The general usage is as follows:
+
+		: FOO ( n -- ) THROW ;
+
+		: TEST-EXCEPTIONS
+			25 ['] FOO CATCH	\ execute 25 FOO, catching any exception
+			?DUP IF
+				." called FOO and it threw exception number: "
+				. CR
+				DROP		\ we have to drop the argument of FOO (25)
+			THEN
+		;
+		\ prints: called FOO and it threw exception number: 25
+
+	CATCH runs an execution token and detects whether it throws any exception or not.  The
+	stack signature of CATCH is rather complicated:
+
+		( a_n-1 ... a_1 a_0 xt -- r_m-1 ... r_1 r_0 0 )		if xt did NOT throw an exception
+		( a_n-1 ... a_1 a_0 xt -- ?_n-1 ... ?_1 ?_0 e )		if xt DID throw exception 'e'
+
+	where a_i and r_i are the (arbitrary number of) argument and return stack contents
+	before and after xt is EXECUTEd.  Notice in particular the case where an exception
+	is thrown, the stack pointer is restored so that there are n of _something_ on the
+	stack in the positions where the arguments a_i used to be.  We don't really guarantee
+	what is on the stack -- perhaps the original arguments, and perhaps other nonsense --
+	it largely depends on the implementation of the word that was executed.
+
+	THROW, ABORT and a few others throw exceptions.
+
+	Exception numbers are non-zero integers.  By convention the positive numbers can be used
+	for app-specific exceptions and the negative numbers have certain meanings defined in
+	the ANS FORTH standard.  (For example, -1 is the exception thrown by ABORT).
+
+	0 THROW does nothing.  This is the stack signature of THROW:
+
+		( 0 -- )
+		( * e -- ?_n-1 ... ?_1 ?_0 e )	the stack is restored to the state from the corresponding CATCH
+
+	The implementation hangs on the definitions of CATCH and THROW and the state shared
+	between them.
+
+	Up to this point, the return stack has consisted merely of a list of return addresses,
+	with the top of the return stack being the return address where we will resume executing
+	when the current word EXITs.  However CATCH will push a more complicated 'exception stack
+	frame' on the return stack.  The exception stack frame records some things about the
+	state of execution at the time that CATCH was called.
+
+	When called, THROW walks up the return stack (the process is called 'unwinding') until
+	it finds the exception stack frame.  It then uses the data in the exception stack frame
+	to restore the state allowing execution to continue after the matching CATCH.  (If it
+	unwinds the stack and doesn't find the exception stack frame then it prints a message
+	and drops back to the prompt, which is also normal behaviour for so-called 'uncaught
+	exceptions').
+
+	This is what the exception stack frame looks like.  (As is conventional, the return stack
+	is shown growing downwards from higher to lower memory addresses).
+
+		+------------------------------+
+		| return address from CATCH    |   Notice this is already on the
+		|                              |   return stack when CATCH is called.
+		+------------------------------+
+		| original parameter stack     |
+		| pointer                      |
+		+------------------------------+  ^
+		| exception stack marker       |  |
+		| (EXCEPTION-MARKER)           |  |   Direction of stack
+		+------------------------------+  |   unwinding by THROW.
+						  |
+						  |
+
+	The EXCEPTION-MARKER marks the entry as being an exception stack frame rather than an
+	ordinary return address, and it is this which THROW "notices" as it is unwinding the
+	stack.  (If you want to implement more advanced exceptions such as TRY...WITH then
+	you'll need to use a different value of marker if you want the old and new exception stack
+	frame layouts to coexist).
+
+	What happens if the executed word doesn't throw an exception?  It will eventually
+	return and call EXCEPTION-MARKER, so EXCEPTION-MARKER had better do something sensible
+	without us needing to modify EXIT.  This nicely gives us a suitable definition of
+	EXCEPTION-MARKER, namely a function that just drops the stack frame and itself
+	returns (thus "returning" from the original CATCH).
+
+	One thing to take from this is that exceptions are a relatively lightweight mechanism
+	in FORTH.
+)
+
+: EXCEPTION-MARKER
+	RDROP			( drop the original parameter stack pointer )
+	0			( there was no exception, this is the normal return path )
+;
+
+: CATCH		( xt -- exn? )
+	DSP@ 4+ >R		( save parameter stack pointer (+4 because of xt) on the return stack )
+	' EXCEPTION-MARKER 4+	( push the address of the RDROP inside EXCEPTION-MARKER ... )
+	>R			( ... on to the return stack so it acts like a return address )
+	EXECUTE			( execute the nested function )
+;
+
+: THROW		( n -- )
+	?DUP IF			( only act if the exception code <> 0 )
+		RSP@ 			( get return stack pointer )
+		BEGIN
+			DUP R0 4- <		( RSP < R0 )
+		WHILE
+			DUP @			( get the return stack entry )
+			' EXCEPTION-MARKER 4+ = IF	( found the EXCEPTION-MARKER on the return stack )
+				4+			( skip the EXCEPTION-MARKER on the return stack )
+				RSP!			( restore the return stack pointer )
+
+				( Restore the parameter stack. )
+				DUP DUP DUP		( reserve some working space so the stack for this word
+							  doesn't coincide with the part of the stack being restored )
+				R>			( get the saved parameter stack pointer | n dsp )
+				4-			( reserve space on the stack to store n )
+				SWAP OVER		( dsp n dsp )
+				!			( write n on the stack )
+				DSP! EXIT		( restore the parameter stack pointer, immediately exit )
+			THEN
+			4+
+		REPEAT
+
+		( No matching catch - print a message and restart the INTERPRETer. )
+		DROP
+
+		CASE
+		0 1- OF	( ABORT )
+			." ABORTED" CR
+		ENDOF
+			( default case )
+			." UNCAUGHT THROW "
+			DUP . CR
+		ENDCASE
+		QUIT
+	THEN
+;
+
+: ABORT		( -- )
+	0 1- THROW
+;
+
+( Print a stack trace by walking up the return stack. )
+: PRINT-STACK-TRACE
+	RSP@				( start at caller of this function )
+	BEGIN
+		DUP R0 4- <		( RSP < R0 )
+	WHILE
+		DUP @			( get the return stack entry )
+		CASE
+		' EXCEPTION-MARKER 4+ OF	( is it the exception stack frame? )
+			." CATCH ( DSP="
+			4+ DUP @ U.		( print saved stack pointer )
+			." ) "
+		ENDOF
+						( default case )
+			DUP
+			CFA>			( look up the codeword to get the dictionary entry )
+			?DUP IF			( and print it )
+				2DUP			( dea addr dea )
+				ID.			( print word from dictionary entry )
+				[ CHAR + ] LITERAL EMIT
+				SWAP >DFA 4+ - .	( print offset )
+			THEN
+		ENDCASE
+		4+			( move up the stack )
+	REPEAT
+	DROP
+	CR
+;
+
+(
+	C STRINGS ----------------------------------------------------------------------
+
+	FORTH strings are represented by a start address and length kept on the stack or in memory.
+
+	Most FORTHs don't handle C strings, but we need them in order to access the process arguments
+	and environment left on the stack by the Linux kernel, and to make some system calls.
+
+	Operation	Input		Output		FORTH word	Notes
+	----------------------------------------------------------------------
+
+	Create FORTH string		addr len	S" ..."
+
+	Create C string			c-addr		Z" ..."
+
+	C -> FORTH	c-addr		addr len	DUP STRLEN
+
+	FORTH -> C	addr len	c-addr		CSTRING		Allocated in a temporary buffer, so
+									should be consumed / copied immediately.
+									FORTH string should not contain NULs.
+
+	For example, DUP STRLEN TELL prints a C string.
+)
+
+(
+	Z" .." is like S" ..." except that the string is terminated by an ASCII NUL character.
+
+	To make it more like a C string, at runtime Z" just leaves the address of the string
+	on the stack (not address & length as with S").  To implement this we need to add the
+	extra NUL to the string and also a DROP instruction afterwards.  Apart from that the
+	implementation just a modified S".
+)
+: Z" IMMEDIATE
+	STATE @ IF	( compiling? )
+		' LITSTRING ,	( compile LITSTRING )
+		HERE @		( save the address of the length word on the stack )
+		0 ,		( dummy length - we don't know what it is yet )
+		BEGIN
+			KEY 		( get next character of the string )
+			DUP '"' <>
+		WHILE
+			HERE @ C!	( store the character in the compiled image )
+			1 HERE +!	( increment HERE pointer by 1 byte )
+		REPEAT
+		0 HERE @ C!	( add the ASCII NUL byte )
+		1 HERE +!
+		DROP		( drop the double quote character at the end )
+		DUP		( get the saved address of the length word )
+		HERE @ SWAP -	( calculate the length )
+		4-		( subtract 4 (because we measured from the start of the length word) )
+		SWAP !		( and back-fill the length location )
+		ALIGN		( round up to next multiple of 4 bytes for the remaining code )
+		' DROP ,	( compile DROP (to drop the length) )
+	ELSE		( immediate mode )
+		HERE @		( get the start address of the temporary space )
+		BEGIN
+			KEY
+			DUP '"' <>
+		WHILE
+			OVER C!		( save next character )
+			1+		( increment address )
+		REPEAT
+		DROP		( drop the final " character )
+		0 SWAP C!	( store final ASCII NUL )
+		HERE @		( push the start address )
+	THEN
+;
+
+: STRLEN 	( str -- len )
+	DUP		( save start address )
+	BEGIN
+		DUP C@ 0<>	( zero byte found? )
+	WHILE
+		1+
+	REPEAT
+
+	SWAP -		( calculate the length )
+;
+
+: CSTRING	( addr len -- c-addr )
+	SWAP OVER	( len saddr len )
+	HERE @ SWAP	( len saddr daddr len )
+	CMOVE		( len )
+
+	HERE @ +	( daddr+len )
+	0 SWAP C!	( store terminating NUL char )
+
+	HERE @ 		( push start address )
+;
+
+(
+	THE ENVIRONMENT ----------------------------------------------------------------------
+
+	Linux makes the process arguments and environment available to us on the stack.
+
+	The top of stack pointer is saved by the early assembler code when we start up in the FORTH
+	variable S0, and starting at this pointer we can read out the command line arguments and the
+	environment.
+
+	Starting at S0, S0 itself points to argc (the number of command line arguments).
+
+	S0+4 points to argv[0], S0+8 points to argv[1] etc up to argv[argc-1].
+
+	argv[argc] is a NULL pointer.
+
+	After that the stack contains environment variables, a set of pointers to strings of the
+	form NAME=VALUE and on until we get to another NULL pointer.
+
+	The first word that we define, ARGC, pushes the number of command line arguments (note that
+	as with C argc, this includes the name of the command).
+)
+: ARGC
+	S0 @ @
+;
+
+(
+	n ARGV gets the nth command line argument.
+
+	For example to print the command name you would do:
+		0 ARGV TELL CR
+)
+: ARGV ( n -- str u )
+	1+ CELLS S0 @ +	( get the address of argv[n] entry )
+	@		( get the address of the string )
+	DUP STRLEN	( and get its length / turn it into a FORTH string )
+;
+
+(
+	ENVIRON returns the address of the first environment string.  The list of strings ends
+	with a NULL pointer.
+
+	For example to print the first string in the environment you could do:
+		ENVIRON @ DUP STRLEN TELL
+)
+: ENVIRON	( -- addr )
+	ARGC		( number of command line parameters on the stack to skip )
+	2 +		( skip command line count and NULL pointer after the command line args )
+	CELLS		( convert to an offset )
+	S0 @ +		( add to base stack address )
+;
+
+(
+	SYSTEM CALLS AND FILES  ----------------------------------------------------------------------
+
+	Miscellaneous words related to system calls, and standard access to files.
+)
+
+( BYE exits by calling the Linux exit(2) syscall. )
+: BYE		( -- )
+	0		( return code (0) )
+	SYS_EXIT	( system call number )
+	SYSCALL1
+;
+
+(
+	UNUSED returns the number of cells remaining in the user memory (data segment).
+
+	For our implementation we will use Linux brk(2) system call to find out the end
+	of the data segment and subtract HERE from it.
+)
+: GET-BRK	( -- brkpoint )
+	0 SYS_BRK SYSCALL1	( call brk(0) )
+;
+
+: UNUSED	( -- n )
+	GET-BRK		( get end of data segment according to the kernel )
+	HERE @		( get current position in data segment )
+	-
+	4 /		( returns number of cells )
+;
+
+(
+	MORECORE increases the data segment by the specified number of (4 byte) cells.
+
+	NB. The number of cells requested should normally be a multiple of 1024.  The
+	reason is that Linux can't extend the data segment by less than a single page
+	(4096 bytes or 1024 cells).
+
+	This FORTH doesn't automatically increase the size of the data segment "on demand"
+	(ie. when , (COMMA), ALLOT, CREATE, and so on are used).  Instead the programmer
+	needs to be aware of how much space a large allocation will take, check UNUSED, and
+	call MORECORE if necessary.  A simple programming exercise is to change the
+	implementation of the data segment so that MORECORE is called automatically if
+	the program needs more memory.
+)
+: BRK		( brkpoint -- )
+	SYS_BRK SYSCALL1
+;
+
+: MORECORE	( cells -- )
+	CELLS GET-BRK + BRK
+;
+
+(
+	Standard FORTH provides some simple file access primitives which we model on
+	top of Linux syscalls.
+
+	The main complication is converting FORTH strings (address & length) into C
+	strings for the Linux kernel.
+
+	Notice there is no buffering in this implementation.
+)
+
+: R/O ( -- fam ) O_RDONLY ;
+: R/W ( -- fam ) O_RDWR ;
+
+: OPEN-FILE	( addr u fam -- fd 0 (if successful) | c-addr u fam -- fd errno (if there was an error) )
+	-ROT		( fam addr u )
+	CSTRING		( fam cstring )
+	SYS_OPEN SYSCALL2 ( open (filename, flags) )
+	DUP		( fd fd )
+	DUP 0< IF	( errno? )
+		NEGATE		( fd errno )
+	ELSE
+		DROP 0		( fd 0 )
+	THEN
+;
+
+: CREATE-FILE	( addr u fam -- fd 0 (if successful) | c-addr u fam -- fd errno (if there was an error) )
+	O_CREAT OR
+	O_TRUNC OR
+	-ROT		( fam addr u )
+	CSTRING		( fam cstring )
+	420 -ROT	( 0644 fam cstring )
+	SYS_OPEN SYSCALL3 ( open (filename, flags|O_TRUNC|O_CREAT, 0644) )
+	DUP		( fd fd )
+	DUP 0< IF	( errno? )
+		NEGATE		( fd errno )
+	ELSE
+		DROP 0		( fd 0 )
+	THEN
+;
+
+: CLOSE-FILE	( fd -- 0 (if successful) | fd -- errno (if there was an error) )
+	SYS_CLOSE SYSCALL1
+	NEGATE
+;
+
+: READ-FILE	( addr u fd -- u2 0 (if successful) | addr u fd -- 0 0 (if EOF) | addr u fd -- u2 errno (if error) )
+	>R SWAP R>	( u addr fd )
+	SYS_READ SYSCALL3
+
+	DUP		( u2 u2 )
+	DUP 0< IF	( errno? )
+		NEGATE		( u2 errno )
+	ELSE
+		DROP 0		( u2 0 )
+	THEN
+;
+
+(
+	PERROR prints a message for an errno, similar to C's perror(3) but we don't have the extensive
+	list of strerror strings available, so all we can do is print the errno.
+)
+: PERROR	( errno addr u -- )
+	TELL
+	':' EMIT SPACE
+	." ERRNO="
+	. CR
+;
+
+(
+	ASSEMBLER CODE ----------------------------------------------------------------------
+
+	This is just the outline of a simple assembler, allowing you to write FORTH primitives
+	in assembly language.
+
+	Assembly primitives begin ': NAME' in the normal way, but are ended with ;CODE.  ;CODE
+	updates the header so that the codeword isn't DOCOL, but points instead to the assembled
+	code (in the DFA part of the word).
+
+	We provide a convenience macro NEXT (you guessed what it does).  However you don't need to
+	use it because ;CODE will put a NEXT at the end of your word.
+
+	The rest consists of some immediate words which expand into machine code appended to the
+	definition of the word.  Only a very tiny part of the i386 assembly space is covered, just
+	enough to write a few assembler primitives below.
+)
+
+HEX
+
+( Equivalent to the NEXT macro )
+: NEXT IMMEDIATE AD C, FF C, 20 C, ;
+
+: ;CODE IMMEDIATE
+	[COMPILE] NEXT		( end the word with NEXT macro )
+	ALIGN			( machine code is assembled in bytes so isn't necessarily aligned at the end )
+	LATEST @ DUP
+	HIDDEN			( unhide the word )
+	DUP >DFA SWAP >CFA !	( change the codeword to point to the data area )
+	[COMPILE] [		( go back to immediate mode )
+;
+
+( The i386 registers )
+: EAX IMMEDIATE 0 ;
+: ECX IMMEDIATE 1 ;
+: EDX IMMEDIATE 2 ;
+: EBX IMMEDIATE 3 ;
+: ESP IMMEDIATE 4 ;
+: EBP IMMEDIATE 5 ;
+: ESI IMMEDIATE 6 ;
+: EDI IMMEDIATE 7 ;
+
+( i386 stack instructions )
+: PUSH IMMEDIATE 50 + C, ;
+: POP IMMEDIATE 58 + C, ;
+
+( RDTSC instruction )
+: RDTSC IMMEDIATE 0F C, 31 C, ;
+
+DECIMAL
+
+(
+	RDTSC is an assembler primitive which reads the Pentium timestamp counter (a very fine-
+	grained counter which counts processor clock cycles).  Because the TSC is 64 bits wide
+	we have to push it onto the stack in two slots.
+)
+: RDTSC		( -- lsb msb )
+	RDTSC		( writes the result in %edx:%eax )
+	EAX PUSH	( push lsb )
+	EDX PUSH	( push msb )
+;CODE
+
+(
+	INLINE can be used to inline an assembler primitive into the current (assembler)
+	word.
+
+	For example:
+
+		: 2DROP INLINE DROP INLINE DROP ;CODE
+
+	will build an efficient assembler word 2DROP which contains the inline assembly code
+	for DROP followed by DROP (eg. two 'pop %eax' instructions in this case).
+
+	Another example.  Consider this ordinary FORTH definition:
+
+		: C@++ ( addr -- addr+1 byte ) DUP 1+ SWAP C@ ;
+
+	(it is equivalent to the C operation '*p++' where p is a pointer to char).  If we
+	notice that all of the words used to define C@++ are in fact assembler primitives,
+	then we can write a faster (but equivalent) definition like this:
+
+		: C@++ INLINE DUP INLINE 1+ INLINE SWAP INLINE C@ ;CODE
+
+	One interesting point to note is that this "concatenative" style of programming
+	allows you to write assembler words portably.  The above definition would work
+	for any CPU architecture.
+
+	There are several conditions that must be met for INLINE to be used successfully:
+
+	(1) You must be currently defining an assembler word (ie. : ... ;CODE).
+
+	(2) The word that you are inlining must be known to be an assembler word.  If you try
+	to inline a FORTH word, you'll get an error message.
+
+	(3) The assembler primitive must be position-independent code and must end with a
+	single NEXT macro.
+
+	Exercises for the reader: (a) Generalise INLINE so that it can inline FORTH words when
+	building FORTH words. (b) Further generalise INLINE so that it does something sensible
+	when you try to inline FORTH into assembler and vice versa.
+
+	The implementation of INLINE is pretty simple.  We find the word in the dictionary,
+	check it's an assembler word, then copy it into the current definition, byte by byte,
+	until we reach the NEXT macro (which is not copied).
+)
+HEX
+: =NEXT		( addr -- next? )
+	   DUP C@ AD <> IF DROP FALSE EXIT THEN
+	1+ DUP C@ FF <> IF DROP FALSE EXIT THEN
+	1+     C@ 20 <> IF      FALSE EXIT THEN
+	TRUE
+;
+DECIMAL
+
+( (INLINE) is the lowlevel inline function. )
+: (INLINE)	( cfa -- )
+	@			( remember codeword points to the code )
+	BEGIN			( copy bytes until we hit NEXT macro )
+		DUP =NEXT NOT
+	WHILE
+		DUP C@ C,
+		1+
+	REPEAT
+	DROP
+;
+
+: INLINE IMMEDIATE
+	WORD FIND		( find the word in the dictionary )
+	>CFA			( codeword )
+
+	DUP @ DOCOL = IF	( check codeword <> DOCOL (ie. not a FORTH word) )
+		." Cannot INLINE FORTH words" CR ABORT
+	THEN
+
+	(INLINE)
+;
+
+HIDE =NEXT
+
+(
+	NOTES ----------------------------------------------------------------------
+
+	DOES> isn't possible to implement with this FORTH because we don't have a separate
+	data pointer.
+)
+
+(
+	WELCOME MESSAGE ----------------------------------------------------------------------
+
+	Print the version and OK prompt.
+)
+
+: WELCOME
+	S" TEST-MODE" FIND NOT IF
+		." JONESFORTH VERSION " VERSION . CR
+		UNUSED . ." CELLS REMAINING" CR
+		." OK "
+	THEN
+;
+
+WELCOME
+HIDE WELCOME
diff --git a/original_jonesforth/perf_dupdrop.c b/original_jonesforth/perf_dupdrop.c
new file mode 100644
index 0000000..a1f3786
--- /dev/null
+++ b/original_jonesforth/perf_dupdrop.c
@@ -0,0 +1,33 @@
+/*	Ideal DUP DROP * 1000 assuming perfect inlining.
+	$Id: perf_dupdrop.c,v 1.1 2007-10-10 13:01:05 rich Exp $
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define DUP					\
+  asm volatile ("mov (%%esp),%%eax\n"		\
+		"\tpush %%eax"			\
+		: : : "eax")
+#define DROP					\
+  asm volatile ("pop %%eax"			\
+		: : : "eax")
+
+#define DUPDROP DUP; DROP;
+#define DUPDROP10 DUPDROP DUPDROP DUPDROP DUPDROP DUPDROP DUPDROP DUPDROP DUPDROP DUPDROP DUPDROP
+#define DUPDROP100 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10 DUPDROP10
+#define DUPDROP1000 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100 DUPDROP100
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long long start_time, end_time;
+
+  asm volatile ("rdtsc" : "=A" (start_time));
+  DUPDROP1000
+  asm volatile ("rdtsc" : "=A" (end_time));
+
+  printf ("%llu\n", end_time - start_time);
+
+  exit (0);
+}
diff --git a/original_jonesforth/perf_dupdrop.f b/original_jonesforth/perf_dupdrop.f
new file mode 100644
index 0000000..4575ba1
--- /dev/null
+++ b/original_jonesforth/perf_dupdrop.f
@@ -0,0 +1,79 @@
+( -*- text -*-
+  FORTH repeated DUP DROP * 1000 using ordinary indirect threaded code
+  and the assembler primitives.
+  $Id: perf_dupdrop.f,v 1.3 2007-10-12 01:46:26 rich Exp $ )
+
+1024 32 * MORECORE
+
+( Print the time passed. )
+: PRINT-TIME	( lsb msb lsb msb -- lsb lsb )
+	( The test is very short so likely the MSBs will be the same.  This
+	  makes calculating the time easier (because we can only do 32 bit
+	    subtraction).  So check MSBs are equal. )
+	2 PICK <> IF
+		." MSBs not equal, please repeat the test" CR
+	ELSE
+		NIP
+		SWAP - U. CR
+	THEN
+;
+
+: 4DROP DROP DROP DROP DROP ;
+
+: PERFORM-TEST	( xt -- )
+	( Get everything in the cache. )
+	DUP EXECUTE 4DROP
+	DUP EXECUTE 4DROP
+	DUP EXECUTE 4DROP
+	DUP EXECUTE 4DROP
+	DUP EXECUTE 4DROP
+	DUP EXECUTE 4DROP
+	0 0 0 0 PRINT-TIME
+	( Run the test 10 times. )
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DUP EXECUTE PRINT-TIME
+	DROP
+;
+
+( ---------------------------------------------------------------------- )
+( Make a word which builds the repeated DUP DROP sequence. )
+: MAKE-DUPDROP	( n -- )
+	BEGIN ?DUP WHILE ' DUP , ' DROP , 1- REPEAT
+;
+
+( Now the actual test routine. )
+: TEST		( -- startlsb startmsb endlsb endmsb )
+	RDTSC			( Start time )
+	[ 1000 MAKE-DUPDROP ]	( 1000 * DUP DROP )
+	RDTSC			( End time )
+;
+
+: RUN ['] TEST PERFORM-TEST ;
+RUN
+
+( ---------------------------------------------------------------------- )
+( Try the inlined alternative. )
+
+( Inline the assembler primitive (cfa) n times. )
+: *(INLINE) ( cfa n -- )
+	BEGIN ?DUP WHILE OVER (INLINE) 1- REPEAT DROP
+;
+
+: DUPDROP INLINE DUP INLINE DROP ;CODE
+
+: TEST
+	INLINE RDTSC
+	[ S" DUPDROP" FIND >CFA 1000 *(INLINE) ]
+	INLINE RDTSC
+;CODE
+
+: RUN ['] TEST PERFORM-TEST ;
+RUN
diff --git a/original_jonesforth/test_assembler.f b/original_jonesforth/test_assembler.f
new file mode 100644
index 0000000..8edba7c
--- /dev/null
+++ b/original_jonesforth/test_assembler.f
@@ -0,0 +1,19 @@
+( -*- text -*- )
+
+: 2DROP INLINE DROP INLINE DROP ;CODE
+
+: C@++ INLINE DUP INLINE 1+ INLINE SWAP INLINE C@ ;CODE
+
+: TEST
+	." 2DROP: "	1 2 3 4 2DROP . . CR
+
+	S" testing" DROP
+	C@++ EMIT CR
+	C@++ EMIT CR
+	C@++ EMIT CR
+	C@++ EMIT CR
+	C@++ EMIT CR
+	C@++ EMIT CR
+	C@++ EMIT CR
+	DROP
+;
diff --git a/original_jonesforth/test_assembler.f.out b/original_jonesforth/test_assembler.f.out
new file mode 100644
index 0000000..9a172d4
--- /dev/null
+++ b/original_jonesforth/test_assembler.f.out
@@ -0,0 +1,8 @@
+2DROP: 2 1 
+t
+e
+s
+t
+i
+n
+g
diff --git a/original_jonesforth/test_comparison.f b/original_jonesforth/test_comparison.f
new file mode 100644
index 0000000..f4908fb
--- /dev/null
+++ b/original_jonesforth/test_comparison.f
@@ -0,0 +1,73 @@
+( -*- text -*- )
+
+: TEST
+	1 0 < . CR
+	0 1 < . CR
+	1 -1 < . CR
+	-1 1 < . CR
+	-1 0 < . CR
+	0 -1 < . CR CR
+
+	1 0 > . CR
+	0 1 > . CR
+	1 -1 > . CR
+	-1 1 > . CR
+	-1 0 > . CR
+	0 -1 > . CR CR
+
+	1 1 <= . CR
+	0 0 <= . CR
+	-1 -1 <= . CR
+	1 0 <= . CR
+	0 1 <= . CR
+	1 -1 <= . CR
+	-1 1 <= . CR
+	-1 0 <= . CR
+	0 -1 <= . CR CR
+
+	1 1 >= . CR
+	0 0 >= . CR
+	-1 -1 >= . CR
+	1 0 >= . CR
+	0 1 >= . CR
+	1 -1 >= . CR
+	-1 1 >= . CR
+	-1 0 >= . CR
+	0 -1 >= . CR CR
+
+	1 1 = . CR
+	1 0 = . CR
+	0 0 = . CR
+	1 -1 = . CR
+	-1 -1 = . CR CR
+
+	1 1 <> . CR
+	1 0 <> . CR
+	0 0 <> . CR
+	1 -1 <> . CR
+	-1 -1 <> . CR CR
+
+	1 0= . CR
+	0 0= . CR
+	-1 0= . CR CR
+
+	1 0<> . CR
+	0 0<> . CR
+	-1 0<> . CR CR
+
+	1 0< . CR
+	0 0< . CR
+	-1 0< . CR CR
+
+	1 0> . CR
+	0 0> . CR
+	-1 0> . CR CR
+
+	1 0<= . CR
+	0 0<= . CR
+	-1 0<= . CR CR
+
+	1 0>= . CR
+	0 0>= . CR
+	-1 0>= . CR CR
+;
diff --git a/original_jonesforth/test_comparison.f.out b/original_jonesforth/test_comparison.f.out
new file mode 100644
index 0000000..40d6034
--- /dev/null
+++ b/original_jonesforth/test_comparison.f.out
@@ -0,0 +1,70 @@
+0 
+1 
+0 
+1 
+1 
+0 
+
+1 
+0 
+1 
+0 
+0 
+1 
+
+1 
+1 
+1 
+0 
+1 
+0 
+1 
+1 
+0 
+
+1 
+1 
+1 
+1 
+0 
+1 
+0 
+0 
+1 
+
+1 
+0 
+1 
+0 
+1 
+
+0 
+1 
+0 
+1 
+0 
+
+0 
+1 
+0 
+
+1 
+0 
+1 
+
+0 
+0 
+1 
+
+1 
+0 
+0 
+
+0 
+1 
+1 
+
+1 
+1 
+0 
+
diff --git a/original_jonesforth/test_exception.f b/original_jonesforth/test_exception.f
new file mode 100644
index 0000000..e8f57d5
--- /dev/null
+++ b/original_jonesforth/test_exception.f
@@ -0,0 +1,13 @@
+( -*- text -*- )
+
+: TEST4 PRINT-STACK-TRACE THROW ;
+
+: TEST3 0 TEST4 26 TEST4 ;
+
+: TEST2
+	['] TEST3 CATCH
+	?DUP IF ." TEST3 threw exception " . CR THEN
+	TEST3
+;
+
+: TEST TEST2 ;
diff --git a/original_jonesforth/test_exception.f.out b/original_jonesforth/test_exception.f.out
new file mode 100644
index 0000000..a62679f
--- /dev/null
+++ b/original_jonesforth/test_exception.f.out
@@ -0,0 +1,6 @@
+TEST4+0 TEST3+8 CATCH+28 CATCH (  ) TEST2+8 TEST+0 
+TEST4+0 TEST3+20 CATCH+28 CATCH (  ) TEST2+8 TEST+0 
+TEST3 threw exception 26 
+TEST4+0 TEST3+8 TEST2+68 TEST+0 
+TEST4+0 TEST3+20 TEST2+68 TEST+0 
+UNCAUGHT THROW 26 
diff --git a/original_jonesforth/test_number.f b/original_jonesforth/test_number.f
new file mode 100644
index 0000000..846347f
--- /dev/null
+++ b/original_jonesforth/test_number.f
@@ -0,0 +1,11 @@
+( -*- text -*- )
+
+: TEST
+	123                                . CR
+	[ HEX -7F ] LITERAL      DECIMAL   . CR
+	[ HEX 7FF77FF7 ] LITERAL HEX       . CR
+	[ HEX -7FF77FF7 ] LITERAL 2 BASE ! . CR
+	[ 2 BASE ! 1111111111101110111111111110111 ] LITERAL HEX . CR
+;
+
+DECIMAL ( restore immediate-mode base )
diff --git a/original_jonesforth/test_number.f.out b/original_jonesforth/test_number.f.out
new file mode 100644
index 0000000..734c750
--- /dev/null
+++ b/original_jonesforth/test_number.f.out
@@ -0,0 +1,5 @@
+123 
+-127 
+7FF77FF7 
+-1111111111101110111111111110111 
+7FF77FF7 
diff --git a/original_jonesforth/test_read_file.f b/original_jonesforth/test_read_file.f
new file mode 100644
index 0000000..3e3c847
--- /dev/null
+++ b/original_jonesforth/test_read_file.f
@@ -0,0 +1,24 @@
+( -*- text -*-
+	Test READ-FILE.
+	$Id: test_read_file.f,v 1.2 2007-10-22 18:53:13 rich Exp $
+)
+
+0 VALUE FD
+100 CELLS ALLOT CONSTANT BUFFER
+
+: TEST
+	S" test_read_file.f.out" R/O OPEN-FILE
+	?DUP IF S" test_read_file.f.out" PERROR QUIT THEN
+
+	TO FD
+
+	BEGIN
+		BUFFER 100 CELLS FD READ-FILE
+		?DUP IF S" READ-FILE" PERROR QUIT THEN
+		DUP
+		BUFFER SWAP TELL
+	0= UNTIL
+
+	FD CLOSE-FILE
+	?DUP IF S" CLOSE-FILE" PERROR QUIT THEN
+;
diff --git a/original_jonesforth/test_read_file.f.out b/original_jonesforth/test_read_file.f.out
new file mode 100644
index 0000000..1b95f7b
--- /dev/null
+++ b/original_jonesforth/test_read_file.f.out
@@ -0,0 +1,7 @@
+/dev/VolGroup00/LogVol00 /                       ext3    defaults,noatime 1 1
+LABEL=/boot             /boot                   ext3    defaults        1 2
+tmpfs                   /dev/shm                tmpfs   defaults        0 0
+devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
+sysfs                   /sys                    sysfs   defaults        0 0
+proc                    /proc                   proc    defaults        0 0
+/dev/VolGroup00/LogVol01 swap                    swap    defaults        0 0
diff --git a/original_jonesforth/test_stack.f b/original_jonesforth/test_stack.f
new file mode 100644
index 0000000..1c4563d
--- /dev/null
+++ b/original_jonesforth/test_stack.f
@@ -0,0 +1,17 @@
+( -*- text -*- )
+
+: TEST
+	DEPTH . CR
+
+	42 DUP . . CR
+	23 DROP DEPTH . CR
+	1 2 SWAP . . CR
+	1 2 OVER . . . CR
+	1 2 3 -ROT . . . CR
+	1 2 3 ROT . . . CR
+	1 2 3 4 2DROP . . CR
+	1 2 3 4 2DUP . . . . . . CR
+	1 2 3 4 2SWAP . . . . CR
+
+	DEPTH . CR
+;
diff --git a/original_jonesforth/test_stack.f.out b/original_jonesforth/test_stack.f.out
new file mode 100644
index 0000000..e6d6204
--- /dev/null
+++ b/original_jonesforth/test_stack.f.out
@@ -0,0 +1,11 @@
+0 
+42 42 
+0 
+1 2 
+1 2 1 
+2 1 3 
+1 3 2 
+2 1 
+4 3 4 3 2 1 
+2 1 4 3 
+0 
diff --git a/original_jonesforth/test_stack_trace.f b/original_jonesforth/test_stack_trace.f
new file mode 100644
index 0000000..e72f0fa
--- /dev/null
+++ b/original_jonesforth/test_stack_trace.f
@@ -0,0 +1,9 @@
+( -*- text -*- )
+
+: TEST4 PRINT-STACK-TRACE ;
+
+: TEST3 TEST4 1 2 + . CR TEST4 ;
+
+: TEST2 TEST3 TEST3 ;
+
+: TEST TEST2 ;
diff --git a/original_jonesforth/test_stack_trace.f.out b/original_jonesforth/test_stack_trace.f.out
new file mode 100644
index 0000000..3595aa2
--- /dev/null
+++ b/original_jonesforth/test_stack_trace.f.out
@@ -0,0 +1,6 @@
+TEST4+0 TEST3+0 TEST2+0 TEST+0 
+3 
+TEST4+0 TEST3+32 TEST2+0 TEST+0 
+TEST4+0 TEST3+0 TEST2+4 TEST+0 
+3 
+TEST4+0 TEST3+32 TEST2+4 TEST+0