diff examples_forth/kernel09.4 @ 57:2088fd998865

sbc09 directry clean up
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 23 Jul 2018 16:07:12 +0900
parents
children ef64e3f4e229
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples_forth/kernel09.4	Mon Jul 23 16:07:12 2018 +0900
@@ -0,0 +1,1800 @@
+\ This is the file kernel.4, included by the cross compiler.
+\ created 1994 by L.C. Benschop.
+\ copyleft (c) 1994-2014 by the sbc09 team, see AUTHORS for more details.
+\ license: GNU General Public License version 2, see LICENSE for more details.
+
+\ It is excessively commented as it must serve as an introduction to the
+\ construction of Forth compilers.
+
+\ Lines starting with \G are comments that are included in the glossary.
+
+ALSO TRANSIENT DEFINITIONS
+FORWARD THROW
+FORWARD COLD
+FORWARD WARM
+PREVIOUS DEFINITIONS
+
+ALSO ASSEMBLER DEFINITIONS
+
+: NEXT
+\  JMP $300 \ For tracing/debugging.
+  PULU PC \ For normal use.
+;
+
+PREVIOUS DEFINITIONS
+
+ASSEMBLE HEX
+
+ORIGIN ORG
+ 7E C,  TRANSIENT COLD ASSEMBLER
+ 7E C,  TRANSIENT WARM ASSEMBLER  \ Jumps to cold and warm entry points.
+
+ENDASM
+
+DECIMAL
+CROSS-COMPILE
+
+LABEL DOCON
+ LDD 0 ,S [] \ Get constant.
+ STD 0 ,S    \ Store it on stack.
+LABEL DOVAR
+ NEXT
+
+LABEL DOCOL
+ STU ,--Y \ Save IP on return stack.
+ LDU ,S++ \ Pop IP from stack where it is left by JSR DOCOL.
+ NEXT
+
+LABEL DODEFER
+ LDX ,S++ [] \ Get jump address.
+ JMP 0 ,X
+ENDASM
+
+CODE LIT ( --- n)
+ LDD ,U++ \ Get literal from instruction stream.
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE BRANCH
+LABEL BR
+ LDU 0 ,U
+ NEXT
+END-CODE
+
+CODE ?BRANCH ( f ---)
+ LDD ,S++
+ BEQ BR     \ Bracnh if TOS is zero.
+ LEAU 2 ,U  \ Skip branch address.
+ NEXT
+END-CODE
+
+CODE EXECUTE ( a ---)
+ RTS
+END-CODE
+
+CODE EXIT
+ LDU ,Y++
+ NEXT
+END-CODE
+
+CODE UNNEST
+ LDU ,Y++
+ NEXT
+END-CODE
+
+CODE (DO) ( l s ---)
+ LDD  ,S++
+LABEL DO1
+ SUBD 0 ,S
+ EORA # $80 \ Now START-LIMIT-$8000 Initial value for counter.
+ LDX ,S++
+ STX ,--Y   \ Push limit value.
+ STD ,--Y
+ NEXT
+END-CODE
+
+CODE (?DO) ( l s ---)
+ LDD ,S++
+ CMPD 0 ,S
+ 0<> IF
+   LEAU 2 ,U \ Skip branch address.
+   BRA DO1
+ THEN
+ LEAS 2 ,S
+ BRA BR
+END-CODE
+
+CODE (LOOP)
+ LDD 0 ,Y
+ ADDD # 1
+ LABEL LOOP1
+ VC IF
+  STD 0 ,Y
+  LDU 0 ,U
+  NEXT
+ THEN
+ LEAY 4 ,Y \ Discard parameters from return stack.
+ LEAU 2 ,U \ Skip branch address.
+ NEXT
+END-CODE
+
+CODE (+LOOP) ( n ---)
+ LDD 0 ,Y
+ ADDD ,S++
+ BRA LOOP1
+END-CODE
+
+CODE (LEAVE)
+LABEL LEAV1
+ LDU 0 ,U
+ LEAY 4 ,Y
+ NEXT
+END-CODE
+
+CODE (?LEAVE) ( f ---)
+ LDD ,S++
+ BEQ LEAV1
+ LEAU 2 ,U
+ NEXT
+END-CODE
+
+CODE I ( --- n)
+ LDD 0 ,Y
+ EORA # $80
+ ADDD 2 ,Y
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE I' ( ---n)
+ LDD 2 ,Y
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE J ( ---n)
+ LDD 4 ,Y
+ EORA # $80
+ ADDD 6 ,Y
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE UNLOOP
+ LEAY 4 ,Y
+ NEXT
+END-CODE
+
+CODE R@ ( --- n)
+ LDD 0 ,Y
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE >R ( n ---)
+ LDD ,S++
+ STD ,--Y
+ NEXT
+END-CODE
+
+CODE R> ( --- n)
+ LDD ,Y++
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE RP@ ( --- addr)
+ PSHS Y
+ NEXT
+END-CODE
+
+CODE RP! ( addr --- )
+ PULS Y
+ NEXT
+END-CODE
+
+CODE SP@ ( --- addr)
+ TFR S, D
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE SP! ( addr ---)
+ LDD ,S++
+ TFR D, S
+ NEXT
+END-CODE
+
+CODE UM* ( u1 u2 --- ud)
+ LEAS -4 ,S \ Create room for result.
+ LDA 7 ,S
+ LDB 5 ,S
+ MUL        \ Multiply least significant bytes.
+ STD 2 ,S
+ LDA 7 ,S
+ LDB 4 ,S
+ MUL        \ Multiply LSB of n1 and MSB of n2.
+ ADDB 2 ,S
+ ADCA # 0
+ STD 1 ,S
+ LDA 6 ,S
+ LDB 5 ,S
+ MUL        \ Multiply LSB of n2 and MSB of n1.
+ ADDD 1 ,S
+ STD 1 ,S
+ LDA # 0
+ ADCA # 0
+ STA 0 ,S
+ LDA 6 ,S
+ LDB 4 ,S
+ MUL        \ Multiply most significant bytes.
+ ADDD 0 ,S
+ STD 4 ,S
+ LDD 2 ,S
+ STD 6 ,S    \ Move result to position of numbers.
+ LEAS 4 ,S   \ Reclaim extra space for result.
+ NEXT
+END-CODE
+
+CODE UM/MOD  ( ud u --- rem quot)
+ LEAS -1 ,S \ Create room for iteration counter.
+ LDA # 16
+ STA 0 ,S
+ BEGIN
+  ASL 6 ,S
+  ROL 5 ,S
+  ROL 4 ,S
+  ROL 3 ,S
+  LDD 3 ,S
+  U< IF     \ Account for extra bit shifted out, perform subtraction anyway.
+   SUBD 1 ,S
+   STD 3 ,S
+   INC 6 ,S
+  ELSE
+   SUBD 1 ,S  \ Perform trial subtraction.
+   U>= IF
+    STD 3 ,S
+    INC 6 ,S  \ Add 1-bit to quotient.
+   THEN
+  THEN
+  DEC 0 ,S
+  0= UNTIL
+  LEAS 3 ,S
+  LDD 2 ,S
+  LDX 0 ,S
+  STX 2 ,S
+  STD 0 ,S
+  NEXT
+END-CODE
+
+CODE + ( n1 n2 ---n3)
+ LDD  ,S++
+ ADDD 0 ,S
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE - ( n1 n2 ---n3)
+ LDD 2 ,S
+ SUBD ,S++
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE NEGATE ( n1 --- n2)
+ CLRA
+ CLRB
+ SUBD 0 ,S
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE AND ( n1 n2 ---n3)
+ LDD 2 ,S
+ ANDA ,S+
+ ANDB ,S+
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE OR ( n1 n2 ---n3)
+ LDD 2 ,S
+ ORA ,S+
+ ORB ,S+
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE XOR ( n1 n2 ---n3)
+ LDD 2 ,S
+ EORA ,S+
+ EORB ,S+
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE 1+ ( n1 --- n2)
+ INC 1 ,S
+ 0= IF INC 0 ,S THEN
+ NEXT
+END-CODE
+
+CODE 1- ( n1 --- n2)
+ LDD 0 ,S
+ SUBD # 1
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE 2+ ( n1 --- n2)
+ LDD 0 ,S
+ ADDD # 2
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE 2- ( n1 --- n2)
+ LDD 0 ,S
+ SUBD # 2
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE 2* ( n1 --- n2)
+ LDD 0 ,S
+ ASLB
+ ROLA
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE 2/ ( n1 --- n2)
+ LDD 0 ,S
+ ASRA
+ RORB
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE D+ ( d1 d2 --- d3)
+ LDD 6 ,S
+ ADDD 2 ,S
+ STD 6 ,S
+ LDD 4 ,S
+ ADCB 1 ,S
+ ADCA 0 ,S
+ STD 4 ,S
+ LEAS 4 ,S
+ NEXT
+END-CODE
+
+CODE DNEGATE ( d1 --- d2)
+ CLRA
+ CLRB
+ SUBD 2 ,S
+ STD 2 ,S
+ LDD # 0
+ SBCB 1 ,S
+ SBCA 0 ,S
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE LSHIFT ( u1 n1 --- u2)
+ PULS D
+ TSTB
+ 0<> IF
+  BEGIN
+   ASL 1 ,S
+   ROL 0 ,S
+   DECB
+  0= UNTIL
+ THEN
+ NEXT
+END-CODE
+
+CODE RSHIFT ( u1 n1 --- u2)
+ PULS D
+ TSTB
+ 0<> IF
+  BEGIN
+   LSR 0 ,S
+   ROR 1 ,S
+   DECB
+  0= UNTIL
+ THEN
+ NEXT
+END-CODE
+
+CODE DROP ( n --- )
+ LEAS 2 ,S
+ NEXT
+END-CODE
+
+CODE DUP   ( n --- n n )
+ LDD 0 ,S
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE SWAP  ( n1 n2 --- n2 n1)
+ LDD 0 ,S
+ LDX 2 ,S
+ STX 0 ,S
+ STD 2 ,S
+ NEXT
+END-CODE
+
+CODE OVER  ( n1 n2 --- n1 n2 n1)
+ LDD 2 ,S
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE ROT ( n1 n2 n3 --- n2 n3 n1)
+ LDD 4 ,S
+ LDX 0 ,S
+ STD 0 ,S
+ LDD 2 ,S
+ STX 2 ,S
+ STD 4 ,S
+ NEXT
+END-CODE
+
+CODE -ROT ( n1 n2 n3 --- n3 n1 n2)
+ LDD 4 ,S
+ LDX 2 ,S
+ STD 2 ,S
+ LDD 0 ,S
+ STX 0 ,S
+ STD 4 ,S
+ NEXT
+END-CODE
+
+CODE 2DROP ( d ---)
+ LEAS 4 ,S
+ NEXT
+END-CODE
+
+CODE 2DUP ( d --- d d )
+ LDX 2 ,S
+ LDD 0 ,S
+ PSHS X, D
+ NEXT
+END-CODE
+
+CODE 2SWAP ( d1 d2 --- d2 d1)
+ LDD 6 ,S
+ LDX 2 ,S
+ STD 2 ,S
+ STX 6 ,S
+ LDD 4 ,S
+ LDX 0 ,S
+ STD 0 ,S
+ STX 4 ,S
+ NEXT
+END-CODE
+
+CODE 2OVER ( d1 d2 --- d1 d2 d1)
+ LDX 6 ,S
+ LDD 4 ,S
+ PSHS X, D
+ NEXT
+END-CODE
+
+CODE PICK ( n1 --- n2)
+ LDD 0 ,S
+ ADDD ,S++
+ LDD D,S
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE ROLL ( n1 ---)
+ LDD 0 ,S
+ LEAS -2 ,S \ Make room to store counter.
+ ADDD # 1
+ STD 0 ,S   \ Store 1 plus the counter.
+ ADDD 2 ,S  \ Double counter.
+ ADDD # 3
+ LEAX D,S   \ Point past last elemtn to roll on stack.
+ LEAX 2 ,X
+ LDD D,S
+ STD 2 ,S   \ Store element  picked.
+ INC 0 ,S
+ BEGIN
+  BEGIN
+   LDD -4 ,X
+   STD ,--X
+   DEC 1 ,S
+  0= UNTIL
+  DEC 0 ,S
+ 0= UNTIL
+ LEAS 4 ,S
+ NEXT
+END-CODE
+
+CODE C@ ( addr --- c)
+ LDB 0 ,S []
+ CLRA
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE @ ( addr --- n)
+ LDD 0 ,S []
+ STD 0 ,S
+ NEXT
+END-CODE
+
+CODE C! ( c addr ---)
+ LDB 3 ,S
+ STB 0 ,S []
+ LEAS 4 ,S
+ NEXT
+END-CODE
+
+CODE ! ( n addr ---)
+ LDD 2 ,S
+ STD 0 ,S []
+ LEAS 4 ,S
+ NEXT
+END-CODE
+
+CODE +! ( n addr ---)
+ PULS X
+ PULS D
+ ADDD 0 ,X
+ STD 0 ,X
+ NEXT
+END-CODE
+
+CODE 2@ ( addr --- d)
+ LDX 0 ,S
+ LDD 0 ,X
+ LDX 2 ,X
+ STX 0 ,S
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE 2! ( d addr ---)
+ LDX 0 ,S
+ LDD 2 ,S
+ STD 0 ,X
+ LDD 4 ,S
+ STD 2 ,X
+ LEAS 6 ,S
+ NEXT
+END-CODE
+
+LABEL YES       \ Store a true flag on stack.
+ LEAX -1 ,X
+ STX 0 ,S
+ NEXT
+ENDASM
+
+CODE 0= ( n --- f)
+ LDX # 0
+ LDD 0 ,S
+ BEQ YES
+ STX 0 ,S
+ NEXT
+END-CODE
+
+CODE 0< ( n --- f)
+ LDX # 0
+ LDD 0 ,S
+ BMI YES
+ STX 0 ,S
+ NEXT
+END-CODE
+
+CODE < ( n1 n2 --- f)
+ LDX # 0
+ LDD 2 ,S
+ SUBD ,S++
+ BLT YES
+ STX 0 ,S
+ NEXT
+END-CODE
+
+CODE U< ( n1 n2 --- f)
+ LDX # 0
+ LDD 2 ,S
+ SUBD ,S++
+ BLO YES
+ STX 0 ,S
+ NEXT
+END-CODE
+
+CODE CMOVE ( addr1 addr2 n ---)
+ LDX 4 ,S
+ STY 4 ,S
+ LDY 2 ,S
+ LDD 0 ,S
+ 0<> IF
+  INC 0 ,S
+  BEGIN
+   BEGIN
+    LDA ,X+
+    STA ,Y+
+    DECB
+   0= UNTIL
+   DEC 0 ,S
+  0= UNTIL
+ THEN
+ LDY 4 ,S
+ LEAS 6 ,S
+ NEXT
+END-CODE
+
+CODE CMOVE> ( addr1 addr2 n ---)
+ LDX 4 ,S
+ STY 4 ,S
+ LDY 2 ,S
+ LDD 0 ,S
+ LEAX D,X
+ LEAY D,Y
+ LDD 0 ,S
+ 0<> IF
+  INC 0 ,S
+  BEGIN
+   BEGIN
+    LDA ,-X
+    STA ,-Y
+    DECB
+   0= UNTIL
+   DEC 0 ,S
+  0= UNTIL
+ THEN
+ LDY 4 ,S
+ LEAS 6 ,S
+ NEXT
+END-CODE
+
+CODE FILL ( addr n c ---)
+ LDX 4 ,S
+ LDD 2 ,S
+ 0<> IF
+  INC 2 ,S
+  LDA 1 ,S
+  BEGIN
+   BEGIN
+    STA ,X+
+    DECB
+   0= UNTIL
+   DEC 2 ,S
+  0= UNTIL
+ THEN
+ LEAS 6 ,S
+ NEXT
+END-CODE
+
+CODE (FIND) ( word firstnfa  --- cfa/word f )
+ LDX 0 ,S
+ 0<> IF
+  STU 0 ,S
+  LDU 2 ,S
+  STY 2 ,S
+  PSHS U
+  BEGIN
+   TFR X, Y
+   LDA ,X+
+   ANDA # $1F
+   CMPA ,U+         \ Compare count bytes.
+   0= IF            \ Do count bytes match?
+    BEGIN
+     DECA
+     LDB ,X+
+     CMPB ,U+
+    0<> UNTIL       \ Compare strings until difference encountered.
+    INCA
+    0= IF
+     LEAS 2 ,S      \ Yes, then word is found.
+     TFR Y, X
+     LDY 2 ,S
+     LDU 0 ,S
+     LDA 0 ,X
+     ANDA # $40
+     0= IF
+      LDD # -1
+     ELSE
+      LDD # 1       \ Make flag that indicates immediate bit.
+     THEN
+     STD 0 ,S
+     LDB ,X+
+     ANDB # $1F
+     ABX            \ Compute CFA
+     STX 2 ,S
+     NEXT
+    THEN
+   THEN
+   LDU 0 ,S
+   LDX -2 ,Y       \ Point to next word in linked list.
+  0= UNTIL
+  LEAS 2 ,S
+  LDY 2 ,S
+  STU 2 ,S
+  LDU 0 ,S
+  STX 0 ,S
+ THEN
+ NEXT
+END-CODE
+
+CODE SKIP ( addr1 len1 c --- addr2 len2 )
+ STU ,--Y
+ PULS D
+ PULS X
+ PULS U
+ LEAX 0 ,X
+ 0<> IF
+ BEGIN
+  CMPB ,U+
+  0<> IF
+   LEAU -1 ,U
+   PSHS U
+   PSHS X
+   LDU ,Y++
+   NEXT
+  THEN
+  LEAX -1 ,X
+ 0= UNTIL
+ THEN
+ PSHS U
+ PSHS X
+ LDU ,Y++
+ NEXT
+END-CODE
+
+CODE SCAN ( addr1 len1 c --- addr2 len2 )
+ STU ,--Y
+ PULS D
+ PULS X
+ PULS U
+ LEAX 0 ,X
+ 0<> IF
+ BEGIN
+  CMPB ,U+
+  0= IF
+   LEAU -1 ,U
+   PSHS U
+   PSHS X
+   LDU ,Y++
+   NEXT
+  THEN
+  LEAX -1 ,X
+ 0= UNTIL
+ THEN
+ PSHS U
+ PSHS X
+ LDU ,Y++
+ NEXT
+END-CODE
+
+CODE KEY ( --- c)
+ JSR 0
+ CLRA
+ STD ,--S
+ NEXT
+END-CODE
+
+CODE EMIT ( c ---)
+ LDD ,S++
+ JSR 3
+ NEXT
+END-CODE
+
+CODE KEY? ( --- f)
+ JSR 15
+ SEX
+ PSHS D
+ NEXT
+END-CODE
+
+CODE BYE
+ JMP $E400
+ NEXT
+END-CODE
+
+CODE CR
+ JSR 12
+ NEXT
+END-CODE
+
+CODE XOPENIN
+ JSR 18
+ NEXT
+END-CODE
+
+CODE XABORTIN
+ PSHS Y, U
+ JSR 24
+ PULS Y, U
+ NEXT
+END-CODE
+
+: NOOP ;
+
+00 CONSTANT 0
+01 CONSTANT 1
+02 CONSTANT 2
+-1 CONSTANT -1
+
+\ PART 3: SIMPLE DEFINITIONS
+
+\ This is a large class of words, which would be written in machine code
+\ on most non-native code systems. Many contain just a few words, so they
+\ are implemented as macros.
+
+\ This category contains simple arithmetic and compare words, the runtime
+\ parts of DO LOOP  and string related words etc, many on which are
+\ dependent on each other, so they are in a less than logical order to
+\ avoid large numbers of forward references.
+
+: =    ( x1 x2 --- f)
+\G f is true if and only if x1 is equal to x2.
+  - 0= ;
+
+: <>   ( x1 x2 --- f)
+\G f is true if and only if x1 is not equal to x2.
+  = 0= ;
+
+: >    ( n1 n2 --- f)
+\G f is true if and only if the signed number n1 is less than n2.
+  SWAP < ;
+
+: 0>  ( n --- f)
+\G f is true if and only if n is greater than 0.
+  0 > ;
+
+: U>  ( u1 u2 --- f)
+\G f is true if and only if the unsigned number u1 is greater than u2.
+  SWAP U< ;
+
+VARIABLE S0 ( --- a-addr)
+\G Variable that holds the bottom address of the stack.
+ -2 ALLOT-T
+LABEL S0ADDR ENDASM
+ 02 ALLOT-T
+
+VARIABLE R0 ( --- a-addr)
+\G Variable that holds the bottom address of the return stack.
+ -2 ALLOT-T
+LABEL R0ADDR ENDASM
+ 02 ALLOT-T
+
+: DEPTH ( --- n )
+\G n is the number of cells on the stack (before DEPTH was executed).
+  SP@ S0 @ SWAP - 2/ ;
+
+: COUNT  ( c-addr1 --- c-addr2 c)
+\G c-addr2 is the next address after c-addr1 and c is the character
+\G stored at c-addr1.
+\G This word is intended to be used with 'counted strings' where the
+\G first character indicates the length of the string.
+   DUP 1 + SWAP C@ ;
+
+: TYPE ( c-addr1 u --- )
+\G Output the string starting at c-addr and length u to the terminal.
+  DUP IF 0 DO DUP I + C@ EMIT LOOP DROP ELSE DROP DROP THEN ;
+
+: ALIGNED ( c-addr --- a-addr )
+\G a-addr is the first aligned address after c-addr.
+   ;
+
+: (.") ( --- )
+\G Runtime part of ."
+\ This expects an in-line counted string.
+  R> COUNT OVER OVER TYPE + ALIGNED >R ;
+: (S")  ( --- c-addr u )
+\G Runtime part of S"
+\ It returns address and length of an in-line counted string.
+  R> COUNT OVER OVER + ALIGNED >R ;
+
+
+00
+CONSTANT FALSE ( --- 0)
+\G Constant 0, indicates FALSE
+
+-01
+CONSTANT TRUE ( --- -1)
+\G Constant -1, indicates TRUE
+
+32
+CONSTANT BL ( --- 32 )
+\G Constant 32, the blank character
+
+: OFF ( a-addr ---)
+\G Store FALSE at a-addr.
+   0 SWAP ! ;
+
+: ON ( a-addr ---)
+\G Store TRUE at a-addr.
+   -1 SWAP ! ;
+
+: INVERT ( x1 --- x2)
+\G Invert all the bits of x1 (one's complement)
+   -1 XOR ;
+
+
+\ The next few words manipulate addresses in a system-independent way.
+\ Use CHAR+ instead of 1+ and it will be portable to systems where you
+\ have to add something different from 1.
+
+: CHAR+ ( c-addr1 --- c-addr2)
+\G c-addr2 is the next character address after c-addr1.
+   1+ ;
+
+: CHARS ( n1 --- n2)
+\G n2 is the number of address units occupied by n1 characters.
+; \ A no-op.
+
+: CHAR-  ( c-addr1 --- c-addr2)
+\G c-addr2 is the previous character address before c-addr1.
+   1- ;
+
+: CELL+ ( a-addr1 --- a-addr2)
+\G a-addr2 is the address of the next cell after a-addr2.
+    2+ ;
+
+: CELLS ( n2 --- n1)
+\G n2 is the number of address units occupied by n1 cells.
+   1 LSHIFT ;
+
+: CELL- ( a-addr1 --- a-addr2)
+\G a-addr2 is the address of the previous cell before a-addr1.
+   2- ;
+
+: ?DUP ( n --- 0 | n n)
+\G Duplicate the top cell on the stack, but only if it is nonzero.
+   DUP IF DUP THEN ;
+
+: MIN ( n1 n2 --- n3)
+\G n3 is the minimum of n1 and n2.
+   OVER OVER > IF SWAP THEN DROP ;
+
+: MAX ( n1 n2 --- n3)
+\G n3 is the maximum of n1 and n2.
+   OVER OVER < IF SWAP THEN DROP ;
+
+: ABS ( n --- u)
+\G u is the absolute value of n.
+   DUP 0< IF NEGATE THEN ;
+
+: DABS ( d --- ud)
+\G ud is the absolute value of d.
+   DUP 0< IF DNEGATE THEN ;
+
+: SM/REM ( d n1 --- nrem nquot )
+\G Divide signed double number d by single number n1, giving quotient and
+\G remainder. Round towards zero, remainder has same sign as dividend.
+  2DUP XOR >R OVER >R \ Push signs of quot and rem.
+  ABS >R DABS R>
+  UM/MOD
+  SWAP R> 0< IF NEGATE THEN SWAP
+  R> 0< IF NEGATE THEN ;
+
+: FM/MOD ( d n1 --- nrem nquot )
+\G Divide signed double number d by single number n1, giving quotient and
+\G remainder. Round always down (floored division),
+\G remainder has same sign as divisor.
+  DUP >R OVER OVER XOR >R
+  SM/REM
+  OVER R> 0< AND IF SWAP R@ + SWAP 1 - THEN R> DROP ;
+
+: M* ( n1 n2 --- d )
+\G Multiply the signed numbers n1 and n2, giving the signed double number d.
+  2DUP XOR >R ABS SWAP ABS UM* R> 0< IF DNEGATE THEN ;
+
+: * ( w1 w2 --- w3)
+\G Multiply single numbers, signed or unsigned give the same result.
+  UM* DROP ;
+
+: */MOD ( n1 n2 n3 --- nrem nquot)
+\G Multiply signed numbers n1 by n2 and divide by n3, giving quotient and
+\G remainder. Intermediate result is double.
+  >R M* R> FM/MOD ;
+
+: */    ( n1 n2 n3 --- n4 )
+\G Multiply signed numbers n1 by n2 and divide by n3, giving quotient n4.
+\G Intermediate result is double.
+  */MOD SWAP DROP ;
+
+: S>D  ( n --- d)
+\G Convert single number to double number.
+   DUP 0< ;
+
+: /MOD  ( n1 n2 --- nrem nquot)
+\G Divide signed number n1 by n2, giving quotient and remainder.
+   SWAP S>D ROT FM/MOD ;
+
+: / ( n1 n2 --- n3)
+\G n3 is n1 divided by n2.
+ /MOD SWAP DROP ;
+
+: MOD ( n1 n2 --- n3)
+\G n3 is the remainder of n1 and n2.
+  /MOD DROP ;
+
+: ?THROW ( f n --- )
+\G Perform n THROW if f is nonzero.
+  SWAP IF THROW ELSE DROP THEN ;
+
+\ PART 4: NUMERIC OUTPUT WORDS.
+
+VARIABLE BASE ( --- a-addr)
+\G Variable that contains the numerical conversion base.
+
+VARIABLE DP   ( --- a-addr)
+\G Variable that contains the dictionary pointer. New space is allocated
+\G from the address in DP
+
+VARIABLE HLD ( --- a-addr)
+\G Variable that holds the address of the numerical output conversion
+\G character.
+
+VARIABLE DPL ( --- a-addr)
+\G Variable that holds the decimal point location for numerical conversion.
+
+: DECIMAL ( --- )
+\G Set numerical conversion to decimal.
+  10 BASE ! ;
+
+: HEX     ( --- )
+\G Set numerical conversion to hexadecimal.
+  16 BASE ! ;
+
+: SPACE  ( ---)
+\G Output a space to the terminal.
+  32 EMIT ;
+
+: SPACES ( u --- )
+\G Output u spaces to the terminal.
+  ?DUP IF 0 DO SPACE LOOP THEN ;
+
+: HERE ( --- c-addr )
+\G The address of the dictionary pointer. New space is allocated here.
+  DP @ ;
+
+: PAD ( --- c-addr )
+\G The address of a scratch pad area. Right below this address there is
+\G the numerical conversion buffer.
+  DP @ 84 + ;
+
+: MU/MOD ( ud u --- urem udquot )
+\G Divide unsigned double number ud by u and return a double quotient and
+\G a single remainder.
+  >R 0 R@ UM/MOD R> SWAP >R UM/MOD R> ;
+
+\ The numerical conversion buffer starts right below PAD and grows down.
+\ Characters are added to it from right to left, as as the div/mod algorithm
+\ to convert numbers to an arbitrary base produces the digits from right to
+\ left.
+
+: HOLD ( c ---)
+\G Insert character c into the numerical conversion buffer.
+  1 NEGATE HLD +! HLD @ C! ;
+
+: # ( ud1 --- ud2)
+\G Extract the rightmost digit of ud1 and put it into the numerical
+\G conversion buffer.
+  BASE @ MU/MOD ROT DUP 9 > IF 7 + THEN 48 + HOLD ;
+
+: #S ( ud --- 0 0 )
+\G Convert ud by repeated use of # until ud is zero.
+  BEGIN # OVER OVER OR 0= UNTIL ;
+
+: SIGN ( n ---)
+\G Insert a - sign in the numerical conversion buffer if n is negative.
+  0< IF 45 HOLD THEN ;
+
+: <# ( --- )
+\G Reset the numerical conversion buffer.
+  PAD HLD ! ;
+
+: #> ( ud --- addr u )
+\G Discard ud and give the address and length of the numerical conversion
+\G buffer.
+  DROP DROP HLD @ PAD OVER - ;
+
+: D. ( d --- )
+\G Type the double number d to the terminal.
+  SWAP OVER DABS <# #S ROT SIGN #> TYPE SPACE ;
+
+: U. ( u ---)
+\G Type the unsigned number u to the terminal.
+  0 D. ;
+
+: . ( n ---)
+\G Type the signed number n to the terminal.
+  S>D D. ;
+
+: MOVE ( c-addr1 c-addr2 u --- )
+\G Copy a block of u bytes starting at c-addr1 to c-addr2. Order is such
+\G that partially overlapping blocks are copied intact.
+  >R OVER OVER U< IF R> CMOVE> ELSE R> CMOVE THEN ;
+
+
+CODE ACCEPT ( c-addr n1 --- n2 )
+\G Read a line from the terminal to a buffer starting at c-addr with
+\G length n1. n2 is the number of characters read,
+PULS X, D
+JSR 6
+CLRA
+PSHS D
+NEXT
+END-CODE
+
+
+$200 CONSTANT TIB ( --- addr)
+\G is the standard terminal input buffer.
+
+VARIABLE SPAN ( --- addr)
+\G This variable holds the number of characters read by EXPECT.
+
+VARIABLE #TIB ( --- addr)
+\G This variable holds the number of characters in the terminal input buffer.
+
+VARIABLE >IN  ( --- addr)
+\G This variable holds an index in the current input source where the next word
+\G will be parsed.
+
+VARIABLE SID  ( --- addr)
+\G This variable holds the source i.d. returned by SOURCE-ID.
+
+VARIABLE SRC  ( --- addr)
+\G This variable holds the address of the current input source.
+
+VARIABLE #SRC ( --- addr)
+\G This variable holds the length of the current input source.
+
+VARIABLE LOADLINE ( --- addr)
+\G This variable holds the line number in the file being included.
+
+
+: EXPECT ( c-addr u --- )
+\G Read a line from the terminal to a buffer at c-addr with length u.
+\G Store the length of the line in SPAN.
+  ACCEPT SPAN ! ;
+
+: QUERY ( --- )
+\G Read a line from the terminal into the terminal input buffer.
+  TIB 128 ACCEPT #TIB ! ;
+
+: SOURCE ( --- addr len)
+\G Return the address and length of the current input source.
+   SRC @ #SRC @ ;
+
+: SOURCE-ID ( --- sid)
+\G Return the i.d. of the current source i.d., 0 for terminal, -1
+\G for EVALUATE and positive number for INCLUDE file.
+   SID @ ;
+
+: REFILL ( --- f)
+\G Refill the current input source when it is exhausted. f is
+\G true if it was successfully refilled.
+  SOURCE-ID -1 = IF
+   0 \ Not refillable for EVALUATE
+  ELSE
+    QUERY #TIB @ #SRC ! 0 >IN ! -1 \ Always successful from terminal.
+    1 LOADLINE +!
+  THEN
+;
+
+: PARSE ( c --- addr len )
+\G Find a character sequence in the current source that is delimited by
+\G character c. Adjust >IN to 1 past the end delimiter character.
+  >R SOURCE >IN @ - SWAP >IN @ + R> OVER >R >R SWAP
+  R@ SKIP OVER R> SWAP >R SCAN IF 1 >IN +! THEN
+  DUP R@ - R> SWAP
+  ROT R> - >IN +! ;
+
+: PLACE ( addr len c-addr --- )
+\G Place the string starting at addr with length len at c-addr as
+\G a counted string.
+  OVER OVER C!
+  1+ SWAP CMOVE ;
+
+: WORD ( c --- addr )
+\G Parse a character sequence delimited by character c and return the
+\G address of a counted string that is a copy of it. The counted
+\G string is actually placed at HERE. The character after the counted
+\G string is set to a space.
+  PARSE HERE PLACE HERE BL HERE COUNT + C! ;
+
+VARIABLE CAPS ( --- a-addr)
+\G This variable contains a nonzero number if input is case insensitive.
+
+: UPPERCASE? ( --- )
+\G Convert the parsed word to uppercase is CAPS is true.
+   CAPS @ HERE C@ AND IF
+   HERE COUNT 0 DO
+    DUP I + C@ DUP 96 > SWAP 123 < AND IF DUP I + DUP C@ 32 - SWAP C! THEN
+   LOOP DROP
+  THEN
+;
+
+
+\ PART 8: INTERPRETER HELPER WORDS
+
+\ First we need FIND and related words.
+
+\ Each word list consists of a number of linked list of definitions (number
+\ is a power of 2). Hashing
+\ is used to speed up dictionary search. All names in the dictionary
+\ are at aligned addresses and FIND is optimized to compare one 4-byte
+\ cell at a time.
+
+\ Dictionary definitions are built as follows:
+\
+\ LINK field: 1 cell, aligned, contains name field of previous word in thread.
+\ NAME field: counted string of at most 31 characters.
+\             bits 5-7 of length byte have special meaning.
+\                   7 is always set to mark start of name ( for >NAME)
+\                   6 is set if the word is immediate.
+\ CODE field: first aligned address after name, is execution token for word.
+\             here the executable code for the word starts. (is 3 bytes for
+\             variables etc.)
+\ PARAMETER field: (body) Contains the data of constants and variables etc.
+
+VARIABLE NAMEBUF ( --- a-addr)
+\G An aligned buffer that holds a copy of the name that is searched.
+30 ALLOT-T
+
+VARIABLE FORTH-WORDLIST ( --- addr)
+4 CELLS-T ALLOT-T
+\G This array holds pointers to the last definition of each thread in the Forth
+\G word list.
+
+VARIABLE LAST ( --- addr)
+\G This variable holds a pointer to the last definition created.
+
+VARIABLE CONTEXT 28 ALLOT-T ( --- a-addr)
+\G This variable holds the addresses of up to 8 word lists that are
+\G in the search order.
+
+VARIABLE #ORDER ( --- addr)
+\G This variable holds the number of word list that are in the search order.
+
+VARIABLE CURRENT ( --- addr)
+\G This variable holds the address of the word list to which new definitions
+\G are added.
+
+: HASH ( c-addr u #threads --- n)
+\G Compute the hash function for the name c-addr u with the indicated number
+\G of threads.
+  >R OVER C@ 1 LSHIFT OVER 1 > IF ROT CHAR+ C@ 2 LSHIFT XOR ELSE ROT DROP
+   THEN XOR
+  R> 1- AND
+;
+
+: NAME>BUF ( c-addr u ---)
+\G Move the name c-addr u to the aligned buffer NAMEBUF.
+  NAMEBUF 32 0 FILL 32 MIN NAMEBUF PLACE ;
+
+
+: SEARCH-WORDLIST ( c-addr u wid --- 0 | xt 1 xt -1)
+\G Search the wordlist with address wid for the name c-addr u.
+\G Return 0 if not found, the execution token xt and -1 for non-immediate
+\G words and xt and 1 for immediate words.
+  ROT ROT
+  NAME>BUF
+  NAMEBUF COUNT 2 PICK @ HASH 1+ CELLS SWAP + @ \ Get the right thread.
+  DUP IF
+   NAMEBUF SWAP (FIND) DUP 0= IF DROP DROP 0 THEN EXIT
+  THEN
+  DROP 0 \ Not found.
+;
+
+: FIND ( c-addr --- c-addr 0| xt 1|xt -1 )
+\G Search all word lists in the search order for the name in the
+\G counted string at c-addr. If not found return the name address and 0.
+\G If found return the execution token xt and -1 if the word is non-immediate
+\G and 1 if the word is immediate.
+  #ORDER @ DUP 1 > IF
+   CONTEXT #ORDER @ 1- CELLS + DUP @ SWAP CELL- @ =
+  ELSE 0 THEN
+  IF 1- THEN \ If last wordlist is double, don't search it twice.
+  BEGIN
+   DUP
+  WHILE
+   1- >R
+   DUP COUNT
+   R@ CELLS CONTEXT + @ SEARCH-WORDLIST
+   DUP
+   IF
+    R> DROP ROT DROP EXIT \ Exit if found.
+   THEN
+   DROP R>
+  REPEAT
+;
+
+\ The following words are related to numeric input.
+
+: DIGIT? ( c -- 0| c--- n -1)
+\G Convert character c to its digit value n and return true if c is a
+\G digit in the current base. Otherwise return false.
+  48 - DUP 0< IF DROP 0 EXIT THEN
+  DUP 9 > OVER 17 < AND IF DROP 0 EXIT THEN
+  DUP 9 > IF 7 - THEN
+  DUP BASE @ < 0= IF DROP 0 EXIT THEN
+  -1
+;
+
+: >NUMBER ( ud1 c-addr1 u1 --- ud2 c-addr2 u2 )
+\G Convert the string at c-addr with length u1 to binary, multiplying ud1
+\G by the number in BASE and adding the digit value to it for each digit.
+\G c-addr2 u2 is the remainder of the string starting at the first character
+\G that is no digit.
+  BEGIN
+   DUP
+  WHILE
+   1 - >R
+   COUNT DIGIT? 0=
+   IF
+    R> 1+ SWAP 1 - SWAP  EXIT
+   THEN
+   SWAP >R
+   >R
+   SWAP BASE @ UM* ROT BASE @ * 0 SWAP D+ \ Multiply ud by base.
+   R> 0 D+                                \ Add new digit.
+   R> R>
+  REPEAT
+;
+
+: CONVERT ( ud1 c-addr1 --- ud2 c-addr2)
+\G Convert the string starting at c-addr1 + 1 to binary. c-addr2 is the
+\G address of the first non-digit. Digits are added into ud1 as in >NUMBER
+  1 - -1 >NUMBER DROP ;
+
+: NUMBER? ( c-addr ---- d f)
+\G Convert the counted string at c-addr to a double binary number.
+\G f is true if and only if the conversion was successful. DPL contains
+\G -1 if there was no point in the number, else the position of the point
+\G from the right. Special prefixes: # means decimal, $ means hex.
+  -1 DPL !
+  BASE @ >R
+  COUNT
+  OVER C@ 45 = DUP >R IF 1 - SWAP 1 + SWAP THEN \ Get any - sign
+  OVER C@ 36 = IF 16 BASE ! 1 - SWAP 1 + SWAP THEN   \ $ sign for hex.
+  OVER C@ 35 = IF 10 BASE ! 1 - SWAP 1 + SWAP THEN   \ # sign for decimal
+  DUP  0 > 0= IF  R> DROP R> BASE ! 0 EXIT THEN   \ Length 0 or less?
+  >R >R 0 0 R> R>
+  BEGIN
+   >NUMBER
+   DUP IF OVER C@ 46 = IF 1 - DUP DPL ! SWAP 1 + SWAP ELSE \ handle point.
+         R> DROP R> BASE ! 0 EXIT THEN   \ Error if anything but point
+       THEN
+  DUP 0= UNTIL DROP DROP R> IF DNEGATE THEN
+  R> BASE ! -1
+;
+
+\ PART 9: THE COMPILER
+
+VARIABLE ERROR$ ( --- a-addr )
+\G Variable containing string address of ABORT" message.
+
+VARIABLE HANDLER ( --- a-addr )
+\G Variable containing return stack address where THROW should return.
+
+: (ABORT") ( f -- - )
+\G Runtime part of ABORT"
+           IF R>  ERROR$ ! -2 THROW
+           ELSE R> COUNT + ALIGNED >R THEN ;
+
+: THROW ( n --- )
+\G If n is nonzero, cause the corresponding CATCH to return with n.
+DUP IF
+ HANDLER @ IF
+  HANDLER @ RP!
+  RP@ 4 + @ HANDLER ! \ point to previous exception frame.
+  R>                  \ get old stack pointer.
+  SWAP >R SP! DROP R> \ save throw code temp. on ret. stack set old sp.
+  R> DROP             \ remove address of handler.
+                      \ return stack points to return address of CATCH.
+ ELSE
+  WARM \ Warm start if no exception frame on stack.
+ THEN
+ELSE
+ DROP \ continue if zero.
+THEN
+;
+
+: CATCH ( xt --- n )
+\G Execute the word with execution token xt. If it returns normally, return
+\G 0. If it executes a THROW, return the throw parameter.
+ HANDLER @ >R  \ push handler on ret stack.
+ SP@ >R        \ push stack pointer on ret stack,
+ RP@ HANDLER !
+ EXECUTE
+ RP@ 4 + @ HANDLER ! \ set handler to previous exception frame.
+ R> DROP R> DROP \ remove exception frame.
+ 0 \ return 0
+;
+
+: ALLOT ( n --- )
+\G Allot n extra bytes of memory, starting at HERE to the dictionary.
+  DP +! ;
+
+: , ( x --- )
+\G Append cell x to the dictionary at HERE.
+  HERE ! 1 CELLS ALLOT ;
+
+: C, ( n --- )
+\G Append character c to the dictionary at HERE.
+  HERE C! 1 ALLOT ;
+
+: ALIGN ( --- )
+\G Add as many bytes to the dictionary as needed to align dictionary pointer.
+  ;
+
+: >NAME ( addr1 --- addr2 )
+\G Convert execution token addr1 (address of code) to address of name.
+  BEGIN 1- DUP C@ 128 AND UNTIL ;
+
+: NAME> ( addr1 --- addr2 )
+\G Convert address of name to address of code.
+  COUNT 31 AND + ALIGNED ;
+
+: HEADER ( --- )
+\G Create a header for a new definition without a code field.
+  ALIGN 0 , \ Create link field.
+  HERE LAST !         \ Set LAST so definition can be linked by REVEAL
+  32 WORD UPPERCASE?
+           DUP FIND IF ." Redefining: " HERE COUNT TYPE CR THEN DROP
+                       \ Give warning if existing word redefined.
+  DUP COUNT CURRENT @ @ HASH 1+ CELLS CURRENT @ + @ HERE CELL- !
+                       \ Set link field to point to the right thread
+  C@ 1+ HERE C@ 128 + HERE C! ALLOT ALIGN
+                       \ Allot the name and set bit 7 in length byte.
+;
+
+: JSR, $BD C, ;
+
+: REVEAL ( --- )
+\G Add the last created definition to the CURRENT wordlist.
+  LAST @ DUP COUNT 31 AND \ Get address and length of name
+  CURRENT @ @ HASH        \ compute hash code.
+  1+ CELLS CURRENT @ + ! ;
+
+: CREATE ( "ccc" --- )
+\G Create a definition that returns its parameter field address when
+\G executed. Storage can be added to it with ALLOT.
+  HEADER REVEAL JSR, LIT DOVAR , ;
+
+: VARIABLE ( "ccc" --- )
+\G Create a variable where 1 cell can be stored. When executed it
+\G returns the address.
+  CREATE 0 , ;
+
+: CONSTANT ( x "ccc" ---)
+\G Create a definition that returns x when executed.
+\ Definition contains lit & return in its code field.
+  HEADER REVEAL JSR, LIT DOCON , , ;
+
+
+VARIABLE STATE ( --- a-addr)
+\G Variable that holds the compiler state, 0 is interpreting 1 is compiling.
+
+: ]  ( --- )
+\G Start compilation mode.
+  1 STATE ! ;
+
+: [  ( --- )
+\G Leave compilation mode.
+  0 STATE ! ; IMMEDIATE
+
+: LITERAL ( n --- )
+\G Add a literal to the current definition.
+ POSTPONE LIT , ; IMMEDIATE
+
+: COMPILE, ( xt --- )
+\G Add the execution semantics of the definition xt to the current definition.
+ ,
+;
+
+VARIABLE CSP ( --- a-addr )
+\G This variable is used for stack checking between : and ;
+
+VARIABLE 'LEAVE ( --- a-addr)
+\ This variable is used for LEAVE address resolution.
+
+: !CSP ( --- )
+\G Store current stack pointer in CSP.
+   SP@ CSP ! ;
+
+: ?CSP ( --- )
+\G Check that stack pointer is equal to value contained in CSP.
+   SP@ CSP @ - -22 ?THROW ;
+
+: ; ( --- )
+\G Finish the current definition by adding a return to it, make it
+\G visible and leave compilation mode.
+    POSTPONE UNNEST [
+    ?CSP REVEAL
+; IMMEDIATE
+
+: (POSTPONE) ( --- )
+\G Runtime for POSTPONE.
+\ has inline argument.
+  R> DUP @ SWAP CELL+ >R
+  DUP >NAME C@ 64 AND IF EXECUTE ELSE COMPILE, THEN
+;
+
+: : ( "ccc" --- )
+\G Start a new definition, enter compilation mode.
+  !CSP HEADER JSR, LIT DOCOL , ] ;
+
+: BEGIN ( --- x )
+\G Start a BEGIN UNTIL or BEGIN WHILE REPEAT loop.
+  HERE ; IMMEDIATE
+
+: UNTIL ( x --- )
+\G Form a loop with matching BEGIN.
+\G Runtime: A flag is take from the stack
+\G each time UNTIL is encountered and the loop iterates until it is nonzero.
+  POSTPONE ?BRANCH , ; IMMEDIATE
+
+: IF    ( --- x)
+\G Start an IF THEN or IF ELSE THEN construction.
+\G Runtime: At IF a flag is taken from
+\G the stack and if it is true the part between IF and ELSE is executed,
+\G otherwise the part between ELSE and THEN. If there is no ELSE, the part
+\G between IF and THEN is executed only if flag is true.
+   POSTPONE ?BRANCH HERE 1 CELLS ALLOT ; IMMEDIATE
+
+: THEN ( x ---)
+\G End an IF THEN or IF ELSE THEN construction.
+   HERE SWAP ! ; IMMEDIATE
+
+: ELSE ( x1 --- x2)
+\G part of IF ELSE THEN construction.
+   POSTPONE BRANCH HERE 1 CELLS ALLOT SWAP POSTPONE THEN ; IMMEDIATE
+
+: WHILE  ( x1 --- x2 x1 )
+\G part of BEGIN WHILE REPEAT construction.
+\G Runtime: At WHILE a flag is taken from the stack. If it is false,
+\G  the program jumps out of the loop, otherwise the part between WHILE
+\G  and REPEAT is executed and the loop iterates to BEGIN.
+  POSTPONE IF SWAP ; IMMEDIATE
+
+: REPEAT ( x1 x2 --- )
+\G part of BEGIN WHILE REPEAT construction.
+  POSTPONE BRANCH , POSTPONE THEN ; IMMEDIATE
+
+VARIABLE POCKET ( --- a-addr )
+\G Buffer for S" strings that are interpreted.
+  252 ALLOT-T
+
+: '  ( "ccc" --- xt)
+\G Find the word with name ccc and return its execution token.
+  32 WORD UPPERCASE? FIND 0= -13 ?THROW ;
+
+: ['] ( "ccc" ---)
+\G Copile the execution token of the word with name ccc as a literal.
+  ' LITERAL ; IMMEDIATE
+
+: CHAR ( "ccc" --- c)
+\G Return the first character of "ccc".
+  BL WORD 1 + C@ ;
+
+: [CHAR] ( "ccc" --- )
+\G Compile the first character of "ccc" as a literal.
+  CHAR LITERAL ; IMMEDIATE
+
+: DO ( --- x)
+\G Start a DO LOOP.
+\G Runtime: ( n1 n2 --- ) start a loop with initial count n2 and
+\G limit n1.
+  POSTPONE (DO) 'LEAVE @ HERE 0 'LEAVE ! ; IMMEDIATE
+
+: ?DO ( --- x )
+\G Start a ?DO LOOP.
+\G Runtime: ( n1 n2 --- ) start a loop with initial count n2 and
+\G limit n1. Exit immediately if n1 = n2.
+  POSTPONE (?DO) 'LEAVE @ HERE 'LEAVE ! 0 , HERE ; IMMEDIATE
+
+: LEAVE ( --- )
+\G Runtime: leave the matching DO LOOP immediately.
+\ All places where a leave address for the loop is needed are in a linked
+\ list, starting with 'LEAVE variable, the other links in the cells where
+\ the leave addresses will come.
+  POSTPONE (LEAVE) HERE 'LEAVE @ , 'LEAVE ! ; IMMEDIATE
+
+: RESOLVE-LEAVE
+\G Resolve the references to the leave addresses of the loop.
+          'LEAVE @
+          BEGIN DUP WHILE DUP @ HERE ROT ! REPEAT DROP ;
+
+: LOOP  ( x --- )
+\G End a DO LOOP.
+\G Runtime: Add 1 to the count and if it is equal to the limit leave the loop.
+  POSTPONE (LOOP) , RESOLVE-LEAVE 'LEAVE ! ; IMMEDIATE
+
+: +LOOP ( x --- )
+\G End a DO +LOOP
+\G Runtime: ( n ---) Add n to the count and exit if this crosses the
+\G boundary between limit-1 and limit.
+  POSTPONE (+LOOP) , RESOLVE-LEAVE 'LEAVE ! ; IMMEDIATE
+
+: RECURSE ( --- )
+\G Compile a call to the current (not yet finished) definition.
+  LAST @ NAME> COMPILE, ; IMMEDIATE
+
+: ."  ( "ccc<quote>" --- )
+\G Parse a string delimited by " and compile the following runtime semantics.
+\G Runtime: type that string.
+   POSTPONE (.") 34 WORD C@ 1+ ALLOT ALIGN ; IMMEDIATE
+
+
+: S"  ( "ccc<quote>" --- )
+\G Parse a string delimited by " and compile the following runtime semantics.
+\G Runtime: ( --- c-addr u) Return start address and length of that string.
+  STATE @ IF POSTPONE (S") 34 WORD C@ 1+ ALLOT ALIGN
+             ELSE 34 WORD COUNT POCKET PLACE POCKET COUNT THEN ; IMMEDIATE
+
+: ABORT"  ( "ccc<quote>" --- )
+\G Parse a string delimited by " and compile the following runtime semantics.
+\G Runtime: ( f --- ) if f is nonzero, print the string and abort program.
+  POSTPONE (ABORT") 34 WORD C@ 1+ ALLOT ALIGN ; IMMEDIATE
+
+: ABORT ( --- )
+\G Abort unconditionally without a message.
+ -1 THROW ;
+
+: POSTPONE ( "ccc" --- )
+\G Parse the next word delimited by spaces and compile the following runtime.
+\G Runtime: depending on immediateness EXECUTE or compile the execution
+\G semantics of the parsed word.
+  POSTPONE (POSTPONE) ' , ; IMMEDIATE
+
+: IMMEDIATE ( --- )
+\G Make last definition immediate, so that it will be executed even in
+\G compilation mode.
+  LAST @ DUP C@ 64 OR SWAP C! ;
+
+: ( ( "ccc<rparen>" --- )
+\G Comment till next ).
+  41 PARSE DROP DROP ; IMMEDIATE
+
+: \
+\G Comment till end of line.
+  SOURCE >IN ! DROP ; IMMEDIATE
+
+: >BODY ( xt --- a-addr)
+\G Convert execution token to parameter field address.
+  3 + ;
+
+: (;CODE) ( --- )
+\G Runtime for DOES>, exit calling definition and make last defined word
+\G execute the calling definition after (;CODE)
+  R> LAST @ NAME> 1+ ! ;
+
+: DOES>  ( --- )
+\G Word that contains DOES> will change the behavior of the last created
+\G word such that it pushes its parameter field address onto the stack
+\G and then executes whatever comes after DOES>
+  POSTPONE (;CODE)
+  JSR, LIT DOCOL ,
+; IMMEDIATE
+
+\ PART 10: TOP LEVEL OF INTERPRETER
+
+: ?STACK ( ---)
+\G Check for stack over/underflow and abort with an error if needed.
+  DEPTH DUP 0< -4 ?THROW 10000 > -3 ?THROW ;
+
+: INTERPRET ( ---)
+\G Interpret words from the current source until the input source is exhausted.
+  BEGIN
+   32 WORD UPPERCASE?  DUP C@
+  WHILE
+   FIND DUP
+   IF
+    -1 = STATE @ AND
+    IF
+     COMPILE,
+    ELSE
+     EXECUTE
+    THEN
+   ELSE DROP
+    NUMBER? 0= -13 ?THROW
+    DPL @ 1+ IF
+     STATE @ IF SWAP LITERAL LITERAL THEN
+    ELSE
+     DROP STATE @ IF LITERAL THEN
+    THEN
+   THEN  ?STACK
+  REPEAT   DROP
+;
+
+: EVALUATE ( c-addr u --- )
+\G Evaluate the string c-addr u as if it were typed on the terminal.
+  SID @ >R SRC @ >R #SRC @ >R  >IN @ >R
+  #SRC ! SRC ! 0 >IN ! -1 SID ! INTERPRET
+  R> >IN ! R> #SRC ! R> SRC ! R> SID ! ;
+
+VARIABLE ERRORS ( --- a-addr)
+\G This variable contains the head of a linked list of error messages.
+
+: ERROR-SOURCE ( --- )
+\G Print location of error source.
+     SID @ 0 > IF
+      ." in line " LOADLINE @ .
+     THEN
+     HERE COUNT TYPE CR WARM
+;
+
+: QUIT ( --- )
+\G This word resets the return stack, resets the compiler state, the include
+\G buffer and then it reads and interprets terminal input.
+  R0 @ RP! [
+  TIB SRC ! 0 SID !
+  BEGIN
+   REFILL DROP ['] INTERPRET CATCH DUP 0= IF
+         DROP STATE @ 0= IF ." OK" THEN CR
+   ELSE \ throw occured.
+     XABORTIN
+     DUP -2 = IF
+      ERROR$ @ COUNT TYPE SPACE
+     ELSE
+      ERRORS @
+      BEGIN DUP WHILE
+       OVER OVER @ = IF 4 + COUNT TYPE SPACE ERROR-SOURCE THEN CELL+ @
+      REPEAT DROP
+      ." Error " .
+     THEN ERROR-SOURCE
+   THEN
+  0 UNTIL
+;
+
+: XLOAD
+  XOPENIN 1 SID ! 0 LOADLINE ! ;
+
+:  WARM ( ---)
+\G This word is called when an error occurs. Clears the stacks, sets
+\G BASE to decimal, closes the files and resets the search order.
+  R0 @ RP! S0 @ SP! DECIMAL
+  2 #ORDER !
+  FORTH-WORDLIST CONTEXT !
+  FORTH-WORDLIST CONTEXT CELL+ !
+  FORTH-WORDLIST CURRENT !
+  0 HANDLER !
+  ." Welcome to Forth" CR
+  QUIT ;
+
+CODE COLD ( --- )
+\G The first word that is called at the start of Forth.
+  LDY # $8000
+  STY R0ADDR
+  LDS # $7C00
+  STS S0ADDR A;
+  $7E C, WARM
+END-CODE
+
+
+END-CROSS
+
+\ PART 10: FINISHING AND SAVING THE TARGET IMAGE.
+
+\ Resolve the forward references created by the cross compiler.
+RESOLVE DOCOL RESOLVE DOCON RESOLVE LIT RESOLVE BRANCH RESOLVE ?BRANCH
+RESOLVE (DO) RESOLVE DOVAR RESOLVE UNNEST
+RESOLVE (LOOP) RESOLVE (.")
+RESOLVE COLD   RESOLVE WARM
+RESOLVE THROW
+RESOLVE (POSTPONE)
+
+\ Store appropriate values into some of the new Forth's variables.
+: CELLS>TARGET
+  0 DO OVER I CELLS + @ OVER I CELLS-T + !-T LOOP 2DROP ;
+
+#THREADS T' FORTH-WORDLIST >BODY-T !-T
+TLINKS T' FORTH-WORDLIST >BODY-T 2 + #THREADS CELLS>TARGET
+THERE   T' DP             >BODY-T !-T
+
+: TELLMEHOW BASE @ HEX
+ ." Type  SO" ORIGIN . ." ,then SS" IMAGE . ." ," THERE ORIGIN - .
+ BYE ;