; MINIFORTH  - Copyright 1988 by Ted Beach
;                                5112 Williamsburg Blvd.
;                                Arlington VA, 22207
;				 703-237-0295

; This is a VERY minimum version of FORTH that has several innovations -
; First, mini makes extensive use of TO variables, particularly as USER
; variables : BASE, >IN, COMPILING (STATE), S0, R0, BLK, BLOCK, etc.
; Second, there is incorporated a mechanism whereby conditionals (IF, THEN
; ELSE, BEGIN, UNTIL, etc.) can be executed directly from the keyboard with-
; out having to create a word (sometimes a dummy word) to compile them in.
; Simply key in the words as needed, then add a semicolon. The structure 
; will execute at HERE then be discarded. Should you ever make an error while
; compiling from the keyboard, your mistake will be automatically erased --
; you won't find the dictionary garbaged up with a partially compiled word.
; Source code MUST BE ASSEMBLED WITH A86 - make needed changes if you
; want to use MASM (ugh!).
; The file named MINI.MIN has certain needed structures. You will have to
; enter these from the keyboard. In order to save the extended version, run
; mini under DEBUG. Then, just before leaving mini, enter "HERE  .H"
; Note the number printed, type "BYE", then from DEBUG change CX to the number
; printed. Use DEBUG's W command to Write the program to disk.

;          ***************** NOTE ******************* 

; You are free to use this copyrighted material for your own personal
; needs. Commercial use is prohibited without the consent of the copyright
; holder. Contact the author at the address above for additional information.
; There is already available version 1.5 which adds a second (short) machine
; stack to help certain operations. Tutorial material is available on learning
; how to use miniforth. For those used to FORTH, this listing and the MINI.MIN
; file should provide adequate information on how to extend miniforth.

;         *******************************************

HEAD	MACRO
	DW LINK
	LINK=$-2
	DB #1+080
	DB #2
#EM

HEADI	MACRO
	DW LINK
	LINK=$-2
	DB #1+0C0
	DB #2
#EM

COLON	MACRO
	CALL DOCOLON
#EM
NEXT	MACRO
	LODSW
	JMP AX
#EM

VARI	MACRO
	JMP DOVAR
#EM

CONST	MACRO
	JMP DOCON
#EM

TOVAR	MACRO
	JMP DOTOVAR
#EM

VOCAB	MACRO
	JMP DOVOC
#EM

X	MACRO
	XCHG SP,BP
#EM

ORG	0100
	JMP INIT

; STORAGE LOCATIONS FOR USER VARIABLES

CHERE	DW DP
CTOIN	DW 0
CBLOCK	DW 0
CBASE	DW 10
CBLK	DW 0
CSPAN	DW 0
CCOMP	DW 0
CTDP	DW ABORT-6
CS0	DW -256
CR0	DW 0
CDBL	DW 0

TFL	DW 0
CSP	DW 0

BUF:	DB 80		; TIB FOR KEYBOARD
CNT	DB 81 DUP (0)

; HEADERLESS EXECUTION CODE GOES HERE

DOCOLON:
	X
	PUSH SI
	X
	POP SI
	NEXT
DOTOVAR:
	PUSH BX
	ADD AX,3
	MOV BX,AX
	MOV BX,[BX]
	MOV CX,TFL
	JCXZ FETCH
	OR CX,CX
	MOV W TFL,0
	JNS XSTORE
XPSTORE:
	POP AX
	ADD [BX],AX
	POP BX
	NEXT
XSTORE:
	POP AX
	MOV [BX],AX
	POP BX
	NEXT
DOCON:
	PUSH BX
	ADD AX,3
	MOV BX,AX
FETCH:
	MOV BX,[BX]
	NEXT
DOVAR:
	PUSH BX
	ADD AX,3
	MOV BX,AX
	NEXT
DOVOC:
	ADD AX,3
	MOV W CONT,AX
	NEXT
XEXEC:	MOV AX,BX
	POP BX
	JMP AX
XEXIT:
	X
	POP SI
	X
	NEXT
XTOR:	X
	PUSH BX
	X
	POP BX
	NEXT
XRFR:	PUSH BX
	X
	POP BX
	X
	NEXT
XTOR2:	POP AX
	X
	PUSH BX,AX
	X
	POP BX
	NEXT
XRFR2:	PUSH BX
	X
	POP AX,BX
	X
	PUSH AX
	NEXT
XTO:	INC W TFL
	NEXT
XPTO:	DEC W TFL
	NEXT
XDUP:	PUSH BX
	NEXT
XQDUP:	OR BX,BX
	JNZ XDUP
	NEXT
XDROP:	POP BX
	NEXT
XSWAP:	POP AX
	PUSH BX
	MOV BX,AX
	NEXT
XOVER:	POP AX
	PUSH AX,BX
	MOV BX,AX
	NEXT
XROT:	POP CX,DX
	PUSH CX,BX
	MOV BX,DX
	NEXT
XCAT:	MOV BL,[BX]
	MOV BH,0
	NEXT
XCSTORE:POP AX
	MOV [BX],AL
	POP BX
	NEXT
XDUP2:	PUSH BX
	MOV DI,SP
	PUSH [DI+2]
	NEXT
XDROP2:	POP BX,BX
	NEXT
XSWAP2: POP AX,CX,DX
	PUSH AX,BX,DX
	MOV BX,CX
	NEXT
XPLUS:	POP AX
	ADD BX,AX
	NEXT
XSUBT:	POP AX
	NEG BX
	ADD BX,AX
	NEXT
XZEQ:	XOR AX,AX
	OR BX,BX
	JNZ X1
X2:	DEC AX
X1:	XCHG AX,BX
	NEXT
XZLESS:	XOR AX,AX
	OR BX,BX
	JNS X1
	JS X2
XZGRT:	XOR AX,AX
	OR BX,BX
	JZ X1
	JS X1
	JMP X2
XZNE:	MOV AX,-1
	OR BX,BX
	JZ >L0
	MOV BX,AX
L0:	NEXT
XPLOOP:	X
	POP AX,CX
	INC AX
	INC CX
	JO EXLP
L1:	PUSH CX,AX
	X
XBRAN:	MOV SI,[SI]
	NEXT
XPPLOOP:
	POP DI
	X
	POP AX,CX
	ADD AX,BX
	ADD CX,BX
	MOV BX,DI
	JNO L1
EXLP:	X
L3:	ADD SI,2
	NEXT
XZBRAN:	OR BX,BX
	POP BX
	JZ XBRAN
	JNZ L3
XI:
XRAT:	PUSH BX
	X
	POP BX
	PUSH BX
	X
	NEXT
XOF:	POP AX
	CMP AX,BX
	JZ >L1
	MOV BX,AX
	JMP XBRAN
L1:	POP BX
	ADD SI,2
	NEXT
XOVER2:	POP AX,CX,DX
	PUSH DX,CX,AX,BX,DX
	MOV BX,CX
	NEXT
XONEPL:	INC BX
	NEXT
XTWOPL:	ADD BX,2
	NEXT
XTHREEPL:
	ADD BX,3
	NEXT
XONEMI:	DEC BX
	NEXT
XTWOMI:	SUB BX,2
	NEXT
XTHREEMI:SUB BX,3
	NEXT
XTWOSLS:SAR BX,1
	NEXT
XTWOSTAR:
	SHL BX,1
	NEXT
XUMSTAR:POP AX
	MUL BX
	PUSH AX
	MOV BX,DX
	NEXT
XUMSLSM:POP DX
	XOR AX,AX
	CMP DX,BX
	JNB >L0
	POP AX
	DIV BX
	PUSH DX
L0:	MOV BX,AX
	NEXT
XDPLUS:	POP AX,CX,DX
	ADD DX,AX
	PUSH DX
	ADC BX,CX
	NEXT
XDNEGATE:POP AX
	NEG AX
	PUSH AX
	XCHG AX,BX
	MOV BX,0
	SBB BX,AX
	NEXT
XNEGATE:NEG BX
	NEXT
XAND:	POP AX
	AND BX,AX
	NEXT
XORE:	POP AX
	OR BX,AX
	NEXT
XXORX:	POP AX
	XOR BX,AX
	NEXT
XLIT:	PUSH BX
	LODSW
	MOV BX,AX
	NEXT
XULESS:	POP AX
	SUB AX,BX
	MOV BX,-1
	JB >L0
	INC BX
L0:	NEXT
XLESS:	POP AX
	SUB AX,BX
	MOV BX,-1
	JL  >L0
	INC BX
L0:	NEXT
XTWOAT:	PUSH [BX+2]
	MOV BX,[BX]
	NEXT
XTWOSTORE:POP [BX]
	POP [BX+2]
	POP BX
	NEXT
XPICK:	SHL BX,1
	ADD BX,SP
	MOV BX,[BX]
	NEXT
XEQUAL:	POP AX
	CMP BX,AX
	MOV BX,-1
	JZ >L0
	INC BX
L0:	NEXT
XCR:	MOV DL,0D
	MOV AH,2
	INT 021
	MOV DL,0A
	INT 021
	NEXT
XQKEY:	PUSH BX
	MOV AH,0B
	INT 021
	CBW
	MOV BX,AX
	NEXT
XKEY:	PUSH BX
	MOV AH,7
	INT 021
	XOR AH,AH
	MOV BX,AX
	NEXT
XEMIT:	MOV DL,BL
	MOV AH,2
	INT 021
	POP BX
	NEXT
XTYPE:	POP DX
	MOV CX,BX
	JCXZ >L0
	MOV AH,040
	MOV BX,1
	INT 021
L0:	POP BX
	NEXT

LINK=0
	; START OF MINIFORTH WITH ITS HEADERS
MINE:	DW LINK
	DB 0E4,'MINI'	; BIT 6 SET FOR IMMEDIATE, BIT 5 FOR VOCABULARY
MINI:	VOCAB   
RUTE:	DW LAST		; HOLDER FOR LAST
	DW MINE		; VOCABULARY STOPPER
LINK=$-2		; WORDS LINK INTO ROOT VOCABULARY, 'MINI'.
	HEAD 4,'EXIT'	; ( 0/0)
EXIT:	JMP XEXIT
	HEAD 1,'!'	; (2/0)
STORE:	JMP XSTORE	
	HEAD 2,'+!'	; (2/0)
PSTOR:	JMP XPSTORE
	HEAD 1,'@'	; (1/1)
ATT:	JMP FETCH
	HEAD 2,'>R'	; (1/0)
TOR:	JMP XTOR
	HEAD 2,'R>'	; (0/1)
RFR:	JMP XRFR
	HEAD 3,'2>R'	; (2/0)
TOR2:	JMP XTOR2
	HEAD 3,'2R>'	; (0/2)
RFR2:	JMP XRFR2
	HEAD 2,'to'	; (1/0)
TO:	JMP XTO
	HEAD 3,'+to'	; (1/0)
PTO:	JMP XPTO
	HEAD 3,'DUP'	; (1/2)
DUPE:	JMP XDUP
	HEAD 4,'?DUP'	; (1/2/0)
QDUP:	JMP XQDUP
	HEAD 4,'DROP'	; (1/0)
DROP:	JMP XDROP
	HEAD 4,'SWAP'	; (2/2)
SWAP:	JMP XSWAP
	HEAD 4,'OVER'	; (2/3)
OVER:	JMP XOVER
	HEAD 3,'ROT'	; (3/3)
ROT:	JMP XROT
	HEAD 2,'C@'	; (1/1)
CAT:	JMP XCAT
	HEAD 2,'C!'	; (2/0)
CSTORE:	JMP XCSTORE
	HEAD 4,'2DUP'	; (2/4)
DUP2:	JMP XDUP2
	HEAD 5,'2DROP'	; (2/0)
DROP2:	JMP XDROP2
	HEAD 5,'2SWAP'	; (4/4)
SWAP2:	JMP XSWAP2
	HEAD 5,'2OVER'	; (4/6)
OVER2:	JMP XOVER2
	HEAD 1,'+'	; (2/1)
PLUS:	JMP XPLUS
	HEAD 1,'-'	; (2/1)
SUBT:	JMP XSUBT
	HEAD 2,'0='	; (1/1)
ZEQ:	JMP XZEQ
	HEAD 2,'0<'	; (1/1)
ZLESS:	JMP XZLESS
	HEAD 2,'0>'	; (1/1)
ZGRT:	JMP XZGRT
	HEAD 3,'0<>'	; (1/1)
ZNE:	JMP XZNE
	HEAD 1,'='	; (2/1)
EQUAL:	JMP XEQUAL
	HEAD 3,'0br'	; (1/0)
ZBRAN:	JMP XZBRAN
	HEAD 2,'br'	; (0/0)
BRAN:	JMP XBRAN
	HEAD 2,'lp'	; (0/0)
PLOOP:	JMP XPLOOP
	HEAD 3,'+lp'	; (1/0)
PPLOOP: JMP XPPLOOP
	HEAD 1,'I'	; (0/1)
I:	JMP XI
	HEAD 2,'R@'	; (0/1)
RAT:	JMP XRAT
	HEAD 2,'of'	; (2/0/1)
OF:	JMP XOF
	HEAD 2,'1+'	; (1/1)
ONEPL:	JMP XONEPL
	HEAD 2,'2+'	; (1/1)
TWOPL:	JMP XTWOPL
	HEAD 2,'3+'	; (1/1)
THREEPL:JMP XTHREEPL
	HEAD 2,'1-'	; (1/1)
ONEMI:	JMP XONEMI
	HEAD 2,'2-'	; (1/1)
TWOMI:	JMP XTWOMI
	HEAD 2,'3-'	; (1/1)
THREEMI:JMP XTHREEMI
	HEAD 2,'2/'	; (1/1)
TWOSLS:	JMP XTWOSLS
	HEAD 2,'2*'	; (1/1)
TWOSTAR:JMP XTWOSTAR
	HEAD 3,'UM*'	; (2/2)
UMSTAR:	JMP XUMSTAR
	HEAD 6,'UM/MOD'	; (3/2)
UMSLSM:	JMP XUMSLSM
	HEAD 2,'D+'	; (4/2)
DPLUS:	JMP XDPLUS
	HEAD 7,'DNEGATE'; (2/2)
DNEGATE:JMP XDNEGATE
	HEAD 6,'NEGATE'	; (1/1)
NEGATE:	JMP XNEGATE
	HEAD 3,'AND'	; (2/1)
ANDD:	JMP XAND
	HEAD 2,'OR'	; (2/1)
ORE:	JMP XORE
	HEAD 3,'XOR'	; (2/1)
XORX:	JMP XXORX
	HEAD 3,'LIT'	; (1/0)
LIT:	JMP XLIT
	HEAD 2,'U<'	; (2/1)
ULESS:	JMP XULESS
	HEAD 1,'<'	; (2/1)
LESS:	JMP XLESS
	HEAD 2,'2@'	; (1/2)
TWOAT:	JMP XTWOAT
	HEAD 2,'2!'	; (3/0)
TWOSTORE:JMP XTWOSTORE
	HEAD 4,'PICK'	; (1/1)
PICK:	JMP XPICK
	HEAD 2,'CR'	; (0/0)
CR:	JMP XCR
	HEAD 4,'?KEY'	; (0/1)
QKEY:	JMP XQKEY
	HEAD 3,'KEY'	; (0/1)
KEY:	JMP XKEY
	HEAD 4,'EMIT'	; (1/0)
EMIT:	JMP XEMIT
	HEAD 4,'TYPE'	; (2/0)
TYPEE:	JMP XTYPE
	HEAD 2,'<>'	; (2/1)
NEQ:	COLON
	DW EQUAL,ZEQ,EXIT

	HEAD 5,'CMOVE'
CMOVE:	JMP LONG CM1	; (3/0)
	DW CM2
CM1:	POP DI,AX
	PUSH SI
	MOV SI,AX
	MOV CX,BX
	JCXZ >L0
	REP MOVSB
L0:	POP SI,BX
	NEXT
CM2=$-CM1
 
	HEAD 1,'0'
ZERO:	CONST		; (0/1)
	DW 0
	HEAD 1,'1'
ONE:	CONST		; (0/1)
	DW 1
	HEAD 1,'2'
TWO:	CONST		; (0/1)
	DW 2
	HEAD 2,'-1'
MIONE:	CONST		; (0/1)
	DW -1
	HEAD 3,'$40'
H40:	CONST		; (0/1)
	DW 040
	HEAD 3,'$80'
H80:	CONST		; (0/1)
	DW 080
	HEAD 2,'1F'
ONEF:	CONST		; (0/1)
	DW 01F
	HEAD 2,'7F'
SEVENF:	CONST		; (0/1)
	DW 07F
	HEAD 2,'BL'
BLANK:	CONST		; (0/1)
	DW 020
	HEAD 4,'ROOT'
ROOT:	CONST 		; (0/1)
	DW RUTE
	HEAD 7,'CURRENT'
CURRENT:VARI		; (0/1)
	DW RUTE
	HEAD 7,'CONTEXT'
CONTEXT:VARI		; (0/1)
CONT	DW RUTE

;    : LATEST CURRENT @ @ ;   (0/1)

	HEAD 6,'LATEST'
LATEST:	COLON
	DW CURRENT,ATT,ATT,EXIT

;     : CLATEST CONTEXT @ @ ; (0/1)

	HEAD 7,'CLATEST'
CLATEST:COLON
	DW CONTEXT,ATT,ATT,EXIT

;    : PATCH  1+ DUP >R 2+ - R> ! ;  (2/0)

	HEAD 5,'PATCH'
PATCH:	COLON
	DW ONEPL,DUPE,TOR,TWOPL,SUBT,RFR,STORE,EXIT

	HEAD 3,'>IN'
TOIN:	TOVAR		; (0/1)
	DW OFFSET CTOIN
	HEAD 4,'HERE'
HERE:	TOVAR		; (0/1)
	DW OFFSET CHERE
	HEAD 4,'SPAN'
SPAN:	TOVAR		; (0/1)
	DW OFFSET CSPAN
	HEAD 3,'BLK'
BLK:	TOVAR		; (0/1)
	DW OFFSET CBLK
	HEAD 5,'BLOCK'
BLOCK:	TOVAR		; (0/1)
	DW OFFSET CBLOCK
	HEAD 4,'BASE'
BASE:	TOVAR		; (0/1)
	DW OFFSET CBASE
	HEAD 9,'COMPILING'
COMP:	TOVAR		; (0/1)
	DW OFFSET CCOMP
	HEAD 3,'TDP'
TDP:	TOVAR		; (0/1)
	DW OFFSET CTDP
	HEAD 2,'R0'
R0:	TOVAR		; (0/1)
	DW OFFSET CR0
	HEAD 2,'S0'
S0:	TOVAR		; (0/1)
	DW OFFSET CS0
	HEAD 3,'DBL'
DBL:	TOVAR		; (0/1)
	DW OFFSET CDBL


	HEADI 1,'['	; : [  0 TO COMPILING ; (0/0)
LBRAK:	COLON
	DW ZERO,TO,COMP,EXIT
	HEAD 1,']'
RBRAK:	COLON
	DW MIONE,TO,COMP,EXIT
	HEAD 5,'SPACE'	; : BL EMIT ; (0/0)
SPACE:	COLON
	DW BLANK,EMIT,EXIT

	HEAD 5,'COUNT'	; (1/2)
COUNT:	JMP LONG COUNT1
	DW COUNT2
COUNT1:	MOV AX,BX
	INC AX
	PUSH AX
	MOV BL,[BX]
	MOV BH,0
	NEXT
COUNT2=$-COUNT1

;    : .W   HERE COUNT 1F AND TYPE SPACE ; (0/0)

	HEAD 2,'.W'
DOTW:	COLON
	DW HERE,COUNT,ONEF,ANDD,TYPEE,SPACE,EXIT

;    : LL  TDP 2- ;  (0/1)

	HEAD 2,'LL'
LL:	COLON
	DW TDP,TWOMI,EXIT

;    : ?EX  LL @ = ;  (1/1)

	HEAD 3,'?EX'
QEX:	COLON
	DW LL,ATT,EQUAL,EXIT

;     : ILT  R> COUNT 2DUP + >R TYPE ; (0/0)

	HEAD 3,'ILT'
ILT:	COLON
	DW RFR,COUNT,DUP2,PLUS,TOR,TYPEE,EXIT
	HEAD 5,'ALLOT' ; : ALLOT +TO HERE ; (1/0)
ALLOT:	COLON
	DW PTO,HERE,EXIT
	HEAD 1,','	; : , HERE ! 2 ALLOT ;  (1/0)
COMMA:	COLON
	DW HERE,STORE,TWO,ALLOT,EXIT
	HEAD 2,'C,'	; : C, HERE C! 1 ALLOT ; (1/0)
CCOMMA:	COLON
	DW HERE,CSTORE,ONE,ALLOT,EXIT
	HEAD 4,'!CSP'	; (0/0)
STCSP:	JMP LONG STCSP1
	DW STCSP2
STCSP1:	MOV AX,SP
	MOV CSP,AX
	NEXT
STCSP2=$-STCSP1
	HEAD 4,'CSP?'	; RETURNS 'TRUE' IF CSP <> SP
CSPQ:	JMP LONG CSPQ1	; (0/1)
	DW CSPQ2
CSPQ1:	MOV AX,SP
	PUSH BX
	XOR BX,BX
	CMP AX,CSP
	JZ >L0
	DEC BX
L0:	NEXT
CSPQ2=$-CSPQ1

;  : ?CSP  CSP? ABORT" Unbalanced" ;  (0/0)

	HEAD 4,'?CSP'
QCSP:	COLON
	DW CSPQ,QER,
	DB 11,' Unbalanced'
	DW EXIT

;      : :,  $E8 C, LIT DOCOLON HERE 2+ - , ; (0/0)

	HEAD 2,':,'
COLCOM: COLON
	DW LIT,0E8,CCOMMA,LIT,DOCOLON,HERE,TWOPL,SUBT,COMMA,EXIT

;     : ?C  COMPILING 0=      (0/0)
;		IF 1 , HERE TO TDP :, !CSP ] THEN ;

	HEAD 2,'?C'
QC:	COLON
	DW COMP,ZEQ,ZBRAN,QC1,ONE,COMMA,HERE,TO,TDP,COLCOM,STCSP,RBRAK
QC1:	DW EXIT

;    : COMPILE  ?C R> DUP @ , 2+ >R ; (0/0)

	HEAD 7,'COMPILE'
COMPILE:COLON
	DW QC,RFR,DUPE,ATT,COMMA,TWOPL,TOR,EXIT

	HEAD 3,'CXR'	; XOR CHAR AT ADDR WITH BYTE: (ADDR BYTE... )
CXR:	JMP LONG CXR1	; (2/0)
	DW CXR2
CXR1:	POP DI
	XOR [DI],BL
	POP BX
	NEXT
CXR2=$-CXR1
	HEAD 3,'SP!'	; (1/0)
SPST:	JMP LONG SPST1
	DW SPST2
SPST1:  POP AX
	MOV SP,BX
	MOV BX,AX
	NEXT
SPST2=$-SPST1
	HEAD 3,'RP!'	; (1/0)
RPST:	JMP LONG RPST1
	DW RPST2
RPST1:	MOV BP,BX
	POP BX
	NEXT
RPST2=$-RPST1
	HEAD 3,'CLR'
CLR:	COLON		;  : CLR  S0 SP! ; (0/0)
	DW S0,SPST,EXIT
	HEAD 7,'EXECUTE'
EXECUTE:JMP XEXEC

	HEAD 5,'ERROR'
ERROR:	DB 0E9		; VECTORED ERROR HANDLER - PRESENTLY CLEARS STACK
	DW CLR-($+2)
;     : HEX  16 TO BASE ;   (0/0)

	HEAD 3,'HEX'
HEXX:	COLON
	DW LIT,16,TO,BASE,EXIT

;       : DECIMAL  10 TO BASE ;  (0/0)

	HEAD 7,'DECIMAL'
DECIM:	COLON
	DW LIT,10,TO,BASE,EXIT


;     : LITERAL  COMPILING 		(1/0 COMPILING)
;	IF COMPILE LIT , THEN ;		(0/0 NON-COMPILING)

	HEADI 7,'LITERAL'
LITERAL:COLON
	DW COMP,ZBRAN,LI1,COMPILE,LIT,COMMA
LI1:	DW EXIT

;      : LINK LL CURRENT @ ! ;		(0/0)

	HEAD 4,'LINK'
LYNK:	COLON
	DW LL,CURRENT,ATT,STORE,EXIT

;     : RID  LL TO HERE ;		(0/0)

	HEAD 3,'RID'
RID:	COLON
	DW LL,TO,HERE,EXIT

	HEAD 3,'0TO'	;  RESET THE 'TO' FLAG TO ZERO (0/0)
ZEROTO:	JMP LONG ZT1
	DW ZT2
ZT1:	MOV W TFL,0
	NEXT
ZT2=$-ZT1


	HEAD 4,'find'		;    (2/2)
FINDE:	JMP LONG FIND1
	DW FIND2
FIND1:	POP DX			; ADDRESS OF 'HERE'
	PUSH SI			; SAVE IP FOR LATER
L0:	MOV BX,[BX]		; START OF SEARCH
	OR BX,BX		; DONE IF LINK = 0
	JZ >L2
	MOV DI,DX		; ADDR TO DI
	MOV SI,BX		; AND SI
	ADD SI,2		; STEP TO NAME FIELD
	MOV CL,[SI]		; NAME LENGTH
	AND CX,01F		; REDUCED TO 31 MAX BYTES
	CMP CL,[DI]		; LENGTHS MATCH?
	JNZ L0			; NO, GET NEXT NAME
	INC SI			; YES, STEP TO FIRST CHAR IN NAME
	INC DI
	REPZ CMPSB		; COMPARE THEM
	JNZ L0			; NO MATCH - GO GET NEXT
	POP CX			; NAMES HIT! RESTORE SI
	PUSH SI			; SI = CODE ADDRESS OF WORD
	MOV SI,CX		; IP ONCE AGAIN = SI
	TEST B[BX+2],040	; CHACK FOR IMMEDIATE WORD
	MOV BX,-1		; TRUE FLAG BUT -1
	JZ >L1
	NEG BX			; TRUE FLAG BUT +1 IF IMMEDIATE
L1:	NEXT			; ALL DONE
L2:	POP SI			; DID NOT FIND WORD SO RECOVER IP
	PUSH DX			; BX = 0 FOR FALSE FLAG, DX = 'HERE'
	NEXT			; AND WE'RE DONE
FIND2=$-FIND1

	HEAD 2,'.H'	; PRINT 4 DIGIT UNSIGNED HEX NUMBER AND SPACE
DOTH:	MOV CX,4	;  (1/0)
	CALL PRH
	POP BX
	NEXT
	HEAD 3,'.HC'	; PRINT 2 DIGIT UNSGNED HEX NUMBER AND SPACE
DOTHC:	MOV CX,2	;  (1/0)
	CALL PRH
	POP BX
	NEXT
PRH:	MOV DI,CX
	MOV AX,BX
	MOV BX,16
L0:	XOR DX,DX
	DIV BX
	XCHG AX,DX
	ADD AL,090
	DAA
	ADC AL,040
	DAA
	PUSH AX
	XCHG AX,DX
	LOOP L0
	MOV CX,DI
	MOV AH,2
L1:	POP DX
	INT 021
	LOOP L1
	MOV DL,' '
	INT 021
	RET

	HEAD 5,'DEPTH'	; RETURN STACK DEPTH   (0/1)
DEPTH:	JMP LONG D1
	DW D2
D1:	PUSH BX
	MOV BX,CS0
	SUB BX,SP
	SAR BX,1
	DEC BX		; ACCOUNT FOR NUMBER JUST PUSHED
	NEXT
D2=$-D1

	HEAD 4,'BDOS'	; RUN DOS SERVICE $21
BDOS:	JMP LONG BDOS1	; ENTER WITH BX,CX,DX AND # ON STACK (4/1)
	DW BDOS2	; RETURNS FALSE IF NO ERROR - AX,BX,CX,DX
BDOS1:	MOV AX,BX	; FUNCTION IN AH
	POP BX,CX,DX
	INT 021
	PUSH DX,CX,BX,AX
	MOV BX,0
	JNC >L0
	DEC BX
L0:	NEXT
BDOS2=$-BDOS1

	HEAD 2,'DU'	; CONVERT STRING AT ADDRESS TO AN (1/3)
DU:	JMP LONG DU1	; UNSIGNED DOUBLE NUMBER PLUS FLAG
	DW DU2		; TRUE IF SUCCESSFUL CONVERSION
DU1:	MOV DI,BX
	XOR AX,AX
	MOV DX,AX	; CLEAR DOUBLE ACCUMULATOR
	MOV CDBL,AX	; CLEAR DOUBLE PRECISION FLAG
	MOV CX,CBASE	; CX = NUMBER BASE
L0:	MOV BL,[DI]	; ASCII CHARACTER TO CONVERT
	MOV BH,0
	SUB BX,030	; REMOVE ASCII BIAS
	JB EX		; DONE IF <0
	CMP BX,10
	JB >L1
	SUB BX,7	; -7 IF >= 10
	CMP BX,10
	JB EX		; DONE IF < 10
L1:	CMP BX,CX
	JNB EX		; DONE IF >= BASE
	PUSH BX		; SAVE NUMBER
	PUSH DX		; AND MSH OF PRODUCT
	MUL CX
	MOV BX,AX	; SAVE LSH OF PRODUCT
	POP AX		; RECOVER MSH OF PRODUCT
	PUSH DX		; SAVE OVERFLOW
	MUL CX
	POP DX
	ADD DX,AX	; ADD OVERFLOW TO MSH
	MOV AX,BX	; RECOVER LSH
	POP BX		; AND NUMBER
	ADD AX,BX	; ADD IT IN  16-BIT TO 32-BIT ADD
	ADC DX,0
	INC DI
	JMP L0
EX:	PUSH AX,DX	; SAVE DOUBLE NUMBER
	MOV BX,-1	; TRUE FLAG
	CMP B[DI],'.'
	JNZ >L2
	MOV CDBL,BX	; DOUBLE PRECISION IF DELIMITER IS A PERIOD
	INC DI
L2:	CMP B[DI],' '	; MUST BE A SPACE FOR VALID NUMBER
	JZ >L3		; OK
	INC BX		; FALSE FLAG
L3:	NEXT
DU2=$-DU1

;    : DS COUNT ASCII - = DUP >R 0= + DU	( 1/3)
;	IF R>  IF DENEGATE -1 THEN
;	ELSE R> DROP 0
;	THEN ;

	HEAD 2,'DS'
DS0:	COLON
	DW COUNT,LIT,02D,EQUAL,DUPE,TOR,ZEQ,PLUS,DU,ZBRAN,DS1
	DW RFR,ZBRAN,DS2,DNEGATE
DS2:	DW MIONE,BRAN,DS3
DS1:	DW RFR,DROP,ZERO
DS3:	DW EXIT

;     : $DS BASE >R COUNT ASCII $ = DUP		( 1/3)
;	IF HEX THEN 0= + DS R> TO BASE ;

	HEAD 3,'$DS'
HDS:	COLON
	DW BASE,TOR,COUNT,LIT,024,EQUAL,DUPE,ZBRAN,HDS1,HEXX
HDS1:	DW ZEQ,PLUS,DS0,RFR,TO,BASE,EXIT

	HEAD 2,'NU'	; VECTORED WORD FOR 'NUMBER' INITIALIZED 
NU:	DB 0E9
	DW HDS-($+2)	; TO POINT TO '$DS' FOR HEX ENTRY
	HEAD 2,'??'
QQ:	COLON		;    : ??  0= IF .W  -1  ABORT" ?" ;  ( 1/0)
	DW ZEQ,ZBRAN,QQ1,DOTW,MIONE,QER
	DB 2,' ?'
QQ1:	DW EXIT

;    : ?NU   NU  ?? ;		( 1/3/0)

	HEAD 3,'?NU'
QNU:	COLON
	DW NU,QQ,EXIT

 	HEAD 3,'KBD'	; ACCEPT UP TO 80 CHARACTERS FROM THE KEYBOARD
KBD:	JMP LONG KBD1	; SPAN HOLDS THE ACTUAL COUNT OF KEYSTROKES
	DW KBD2		;  ( 0/0)
KBD1:	MOV DX,BUF
	MOV AH,10
	INT 021
	MOV AL,CNT B
	CBW
	MOV CSPAN,AX
	NEXT
KBD2=$-KBD1

;     : RF ROOT find ;	 ( 1/2)

	HEAD 2,'RF'
RF:	COLON
	DW ROOT,FINDE,EXIT
	HEAD 4,'FIND'
FIND:	DB 0E9		; 'FIND' VECTORED TO 'RF' INITIALLY
	DW RF-($+2)

;     (1/1) FOR WORD

	HEAD 4,'WORD'	; GET NEXT WORD FROM INPUT TO 'HERE'. LEAVE
XWORD:	JMP LONG WORD1	; 'HERE' ON STACK. ALSO ACCEPTS TAB, CR, AND LF
	DW WORD2	; AS ABSOLUTE DELIMITERS IN ADDITION TO CHAR ON STK
WORD1:	MOV AH,9	; TAB CHARACTER
	MOV DX,0D0A	; CR AND LF CHARACTERS
	MOV AL,BL	; SCAN CHARACTER
	MOV BX,BUF+2	; START OF KEYBOARD BUFFER
	MOV CX,CBLK W	; 0 IF KEYBOARD
	JCXZ >L0
	MOV BX,CBLOCK	; ELSE GET BLOCK ADDRESS
	XOR CX,CX	; AND SET CX COUNT TO 0
L0:	ADD BX,CTOIN	; OFFSET INTO BUFFER
	JMP >L1
L2:	INC CX
	INC BX
L1:	CMP [BX],AL
	JZ L2
	CMP [BX],AH
	JZ L2
	CMP [BX],DL
	JZ L2
	CMP [BX],DH
	JZ L2		; SKIP BUT COUNT LEADING CHARS
	PUSH SI		; SAVE THE IP
	MOV SI,BX	; SI -> FIRST CHAR OF WORD
	JMP >L0
L1:	INC CX
	INC BX
L0:	CMP [BX],AH
	JZ >L3
	CMP [BX],DL
	JZ >L3
	CMP [BX],DH
	JZ >L3
	CMP [BX],AL
	JNZ L1		; SCAN FOR DELIMITER
L3:	INC CX		; STEP PAST DELIMITER
	ADD CTOIN,CX	; ADVANCE >IN BY CX
	SUB BX,SI	; ACTUAL COUNT OF WORD
	MOV CX,BX	; INTO CX
	MOV DI,CHERE	; MOVE TO HERE
	MOV BX,DI	; TOS ALSO = HERE ON EXIT
	MOV AL,CL	; WORD LENGTH
	STOSB
	REP MOVSB	; AND STRING MOVED TO HERE
	MOV AL,' '	; FOLLOWED BY A SPACE
	STOSB
	POP SI		; RESTORE THE IP
	NEXT
WORD2=$-WORD1

;	: W,  WORD C@ 1+ ALLOT ;  (1/0)

	HEAD 2,'W,'
WCOMMA:	COLON
	DW XWORD,CAT,ONEPL,ALLOT,EXIT

;    : HEAD  LATEST , HERE TO TDP BL W, TDP $80 CXR ; (0/0)

	HEAD 4,'HEAD'
HED:	COLON
	DW LATEST,COMMA,HERE,TO,TDP,BLANK,WCOMMA
	DW TDP,H80,CXR,EXIT

;      : CREATE  HEAD $E9 C, LIT DOVAR HERE 2+ - , ; (0/0)

	HEAD 6,'CREATE'
VCREATE:COLON
	DW HED,LIT,0E9,CCOMMA,LIT,DOVAR,HERE,TWOPL,SUBT,COMMA,EXIT


;     :  :  HEAD :, !CSP ] ;  (0/0)

	HEAD 1,':'
COLN:	COLON
	DW HED,COLCOM,STCSP,RBRAK,EXIT

;   :  ;  IMMEDIATE ?CSP COMPILE EXIT 1 ?EX  (0/0)
;		IF 2 LL !
;		ELSE LINK
;		THEN [ ;

	HEADI 1,';'
SEMI:	COLON
	DW QCSP,COMPILE,EXIT,ONE,QEX,ZBRAN,SE1,TWO,LL,STORE,BRAN,SE2
SE1:	DW LYNK
SE2:	DW LBRAK,EXIT

;   : LOCATE  BL WORD FIND ;   (0/2)

	HEAD 6,'LOCATE'
LOCATE:	COLON
	DW BLANK,XWORD,FIND,EXIT

;    : NUMBER  1+ ?NU COMPILING		( 1/0 COMPILING)
;	IF DBL	IF SWAP LITERAL LITERAL ( 1/1 NON-COMPILING)
;		ELSE DROP LITERAL
;		THEN
;	ELSE DBL 0= IF DROP THEN
;	THEN ;

	HEAD 6,'NUMBER'
NUMB:	COLON
	DW ONEPL,QNU,COMP,ZBRAN,NN1,DBL,ZBRAN,NN2,SWAP
	DW LITERAL,LITERAL,BRAN,NN4
NN2:	DW DROP,LITERAL,BRAN,NN4
NN1:	DW DBL,ZEQ,ZBRAN,NN4,DROP
NN4:	DW EXIT

;      : BYE   0 EXECUTE ; (0/0)

	HEAD 3,'BYE'
BYE:	COLON
	DW ZERO,EXECUTE,EXIT

;   : INTERPRET COMPILING	(1/0)
;	IF 1+ 	IF EXECUTE
;		ELSE ,
;		THEN
;	ELSE DROP EXECUTE
;	THEN ;

	HEAD 9,'INTERPRET'
INTERP:	COLON
	DW COMP,ZBRAN,IN1,ONEPL,ZBRAN,IN2,EXECUTE,BRAN,IN3
IN2:	DW COMMA
IN3:	DW BRAN,IN4
IN1:	DW DROP,EXECUTE
IN4:	DW EXIT

;	: RUN 	CR BEGIN >IN SPAN <	( 0/0)
;		   WHILE 0TO LOCATE ?DUP
;			IF INTERPRET
;			ELSE NUMBER
;			THEN DEPTH 0< $80 DEPTH < OR ABORT" Stack?"
;		   REPEAT    
;		   2 ?EX 	IF TDP EXECUTE RID [ THEN ;

	HEAD 3,'RUN'
RUN:	COLON
	DW CR
RU1:	DW TOIN,SPAN,LESS,ZBRAN,RU4,ZEROTO,LOCATE,QDUP,ZBRAN,RU3
	DW INTERP,BRAN,RU2
RU3:	DW NUMB
RU2:	DW DEPTH,ZLESS,H80,DEPTH,LESS,ORE,QER
	DB 7,' Stack?'
	DW BRAN,RU1
RU4:	DW TWO,QEX,ZBRAN,RU5,TDP,EXECUTE,RID,LBRAK
RU5:	DW EXIT

;	: QUIT R0 RP! [			( 0/0)
;	BEGIN CR 0 TO BLK KBD 0 TO >IN RUN
;	   COMPILING 0= IF ." ok" THEN
;	AGAIN ;

	HEAD 4,'QUIT'
QUIT:	COLON
	DW R0,RPST,LBRAK
QUI:	DW CR,ZERO,TO,BLK,KBD,ZERO,TO,TOIN,RUN,COMP,ZEQ
	DW ZBRAN,QU1,ILT
	DB 3,' ok'
QU1:	DW BRAN,QUI,EXIT

;   : ?ER 0TO			(1/0)
;	IF COMPILING IF RID THEN
;	  R> COUNT TYPE ERROR QUIT
;	ELSE R> COUNT + >R
;	THEN ;

	HEAD 3,'?ER'
QER:	COLON
	DW ZEROTO,ZBRAN,QER3,COMP,ZBRAN,QER2,RID
QER2:	DW RFR,COUNT,TYPEE,ERROR,QUIT,BRAN,QER1
QER3:	DW RFR,COUNT,PLUS,TOR
QER1:	DW EXIT

;    : ABORT  [ -1 ABORT" MINIFORTH V1.0 - 8/8/88" ; (0/0)

LAST:	HEAD 5,'ABORT'
ABORT:	COLON
	DW LBRAK,MIONE,QER
	DB CT
CT1:	DB 'MINIFORTH V1.0 - 8/8/88'
CT=$-CT1
	DW EXIT


INIT:	CLD
	XOR AX,AX
	MOV BX,AX
	MOV CR0,AX
	MOV BP,AX
	SUB AX,256
	MOV CS0,AX
	MOV SP,AX
	MOV AX,10
	MOV CBASE,AX
	MOV CCOMP,BX
	MOV SI,ABORT+3
	NEXT
DP=$
