;-*-Midas-*-

       Title FORTH - The FORTH Language

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     Caution:  This FORTH is NOT totally standard.
;;;
;;;     When FORTH is started up, the file AUTO-LOAD.4TH is searched
;;;     for.  If it exists, it is loaded automatically.  If not, a
;;;     standard header is printed.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DECSAV

A=1     ;Used by JSYSs mostly
B=2
C=3

D=4     ;Used exclusively by colon-compiler (Addr is last word built)
E=5     ;  "       "      "  EVAL (Addr of last word evaluated)

U=6     ;# things in FORTH stack
V=7     ;Args for FORTH stack pushing/popping
L=10    ;Args for EVAL

K=11    ;Kharacter from GETCHR and such

T1=12   ;Trashy temporaries - No special purpose
T2=13
T3=14
T4=15

S=16    ;FORTH stack pointer
P=17    ;100% Pure Porpoise stack pointer


Call=PUSHJ P,
Return=POPJ P,


PRIIN==100      ;TTY input JFN
PRIOU==101      ;TTY output JFN


;;;
;;;     Macros
;;;


Define TYPE &string
       Hrroi A,[Asciz string]
       PSOUT
Termin


Define DBP ac
       Add ac,[70000,,0]
       Skipge ac
         Sub ac,[430000,,1]
Termin


;;;
;;;     Storage
;;;


       Loc 140


Popj1:  Aos (P)
CPopj:  Return

PDLen==200              ;Porpoise stack
PDList: -PDLen,,.
       Block PDLen

Deep==100.              ;FORTH stack
Stack:  -Deep,,.
       Block Deep

LogNcs: 1.0 ? 3.0 ? 5.0 ? 7.0 ? 9.0 ? 11.0 ? 13.0 ? 15.0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     Start of execute-time stuff for structures.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


DOn==10.                ;Maximum depth of DO loop nesting.
DOc:    -1              ;Loop # we're in.  -1 means not in.
DOs:    Block DOn
DOtop:  Block DOn       ;Upper limit of DO
DOind:  Block DOn       ;Loop counter, what you get with I, J, etc

IFc:    -1

UNTILn==10.
UNTILc: -1
UNTILs: Block UNTILn

WHILEn==10.
WHILEc: -1
WHILEs: Block WHILEn
WHILEe: Block WHILEn
BEGINp: 0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     Random flags, variables, constants, etc
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Level:  -1              ;Level of recursion
Trace:  0
Base:   10.             ;I/O number base
Echo:   -1              ;True if we echo input

Width:  0               ;Terminal width
Term:   0               ;Terminal-type #

FName:  Block 7         ;Filename (asciz) you're screwing with
Delim:  0               ;Delimiter for text input stuff
lsText: 0               ;Length of text read by sText
Loadp:  0               ;True when input is from a file
StoNmp: 0               ;Flag returned by StoN: Valid number?

Making: 0       ;True when we're in the middle of building a Dictionary entry
Did:    0       ;True when a DOES> was found after <BUILDS during execution.
BStart: 0       ;For run-time DOES>... the address it returns.

JCall:  JSYS


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     <# and #> formatting controls
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


FBufl==6        ;Room for 30. characters
Format: 0
FLeft:  0
FMinus: 0
FBuffr: Block FBufl
FBufBP: 0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     Instructions that are executed in the body of the two
;;;     testing routines, via XCT
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


2Tests: Camn V,(S)      ; =
       Came V,(S)      ; =_
       Camle V,(S)     ; <
       Caml V,(S)      ; <=
       Camge V,(S)     ; >
       Camg V,(S)      ; >=

1Tests: Skipn (S)       ; 0=
       Skipe (S)       ; 0=_
       Skipge (S)      ; 0<
       Skipg (S)       ; 0<=
       Skiple (S)      ; 0>
       Skipl (S)       ; 0>=


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     The ASCII strings needed to clear screen and home cursor
;;;     on assorted terminals.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Clears: 0 ? 0 ? 0 ? 0 ? 0
       Asciz //                       ;#5 - DM2500
       Asciz //                    ;#6 - I400
       Asciz / /                       ;#7 - DM1520
       0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0
       Asciz /HJ/                    ;#15 - VT52
       0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0
       Asciz /v/                      ;#24 - V200
       0
       Asciz /E/                      ;#26 - H19

Homes:  0 ? 0 ? 0 ? 0 ? 0
       Asciz //
       Asciz //
       Asciz //
       0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0
       Asciz /H/
       0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0
       Asciz //
       0
       Asciz //


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     Control needed to keep track of nested LOADs and iJFNs
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


MaxLLs: 10
LLoad:  -1
LiJFNs: Block MaxLLs
iJFN:   .PRIIN


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     All the rubbish used by the input processor
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


IBufln==40              ;Allowing for 160. character input lines
pInBuf: 0
InBuf:  Block IBufln
nIchar: 0

IStrin: Block 3
IAddr:  0
INump:  0
Inmpos: 0
NotNum: 0
IVal:   0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     The Primitive FORTH Dictionary
;;;
;;;     Entries are like:
;;;
;;;     +0: NAME 01-05
;;;     +1: NAME 06-10
;;;     +2: NAME 11-15
;;;     +3: LENGTH,,CODE
;;;     +4: STUFF1
;;;      .    .
;;;     +n: STUFFi
;;;
;;;     Where NAME's are ASCII words, LENGTH is the total length
;;;     of this entry, CODE is a pointer to a list of STUFFs that
;;;     will be executed when this word is mentioned, and a STUFF
;;;     is one of:
;;;
;;;             -1 ? CONSTANT
;;;             -1,,SUBROUTINE
;;;              0,,DICTIONARY
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DPage==10               ;Page to load Dictionary into

Foo:    Loc DPage*2000

Dict:   Ascii /DUP/ ? 0 ? 0 ?           5,,0 ? -1,,Dup
       Ascii /SWAP/ ? 0 ? 0 ?          5,,0 ? -1,,Swap
       Ascii /ROLL/ ? 0 ? 0 ?          5,,0 ? -1,,Roll
       Ascii /PICK/ ? 0 ? 0 ?          5,,0 ? -1,,Pick
       Ascii /DROP/ ? 0 ? 0 ?          5,,0 ? -1,,Drop
       Ascii /OVER/ ? 0 ? 0 ?          5,,0 ? -1,,Over
       Ascii /ROT/ ? 0 ? 0 ?           5,,0 ? -1,,Rotate
       Ascii /-DUP/ ? 0 ? 0 ?          5,,0 ? -1,,NZDup
       Ascii /?DUP/ ? 0 ? 0 ?          5,,0 ? -1,,NZDup
       Ascii /LEVEL/ ? 0 ? 0 ?         5,,0 ? -1,,PLevel
       Ascii /DEPTH/ ? 0 ? 0 ?         5,,0 ? -1,,Depth
       Ascii /FLOAT/ ? 0 ? 0 ?         5,,0 ? -1,,ItoF
       Ascii /+/ ? 0 ? 0 ?             5,,0 ? -1,,Plus
       Ascii /-/ ? 0 ? 0 ?             5,,0 ? -1,,Minus
       Ascii /*/ ? 0 ? 0 ?             5,,0 ? -1,,Times
       Ascii "/" ? 0 ? 0 ?             5,,0 ? -1,,Divide
       Ascii /^/ ? 0 ? 0 ?             5,,0 ? -1,,Power
       Ascii /F+/ ? 0 ? 0 ?            5,,0 ? -1,,FPlus
       Ascii /F-/ ? 0 ? 0 ?            5,,0 ? -1,,FMin
       Ascii /F*/ ? 0 ? 0 ?            5,,0 ? -1,,FTimes
       Ascii "F/" ? 0 ? 0 ?            5,,0 ? -1,,FDiv
       Ascii /FIX/ ? 0 ? 0 ?           5,,0 ? -1,,FtoI
       Ascii /MOD/ ? 0 ? 0 ?           5,,0 ? -1,,Mod
       Ascii "/MOD" ? 0 ? 0 ?          5,,0 ? -1,,DivMod
       Ascii /0=/ ? 0 ? 0 ?            5,,0 ? -1,,EqualZ
       Ascii /0=_/ ? 0 ? 0 ?           5,,0 ? -1,,NotEq0
       Ascii /0</ ? 0 ? 0 ?            5,,0 ? -1,,LessZ
       Ascii /0<=/ ? 0 ? 0 ?           5,,0 ? -1,,LesEq0
       Ascii /0>/ ? 0 ? 0 ?            5,,0 ? -1,,GreatZ
       Ascii /0>=/ ? 0 ? 0 ?           5,,0 ? -1,,GrEq0
       Ascii /EXCHANGE/ ? 0 ?          5,,0 ? -1,,XChanj
       Ascii /JSYS/ ? 0 ? 0 ?          5,,0 ? -1,,JSys0
       Ascii /=/ ? 0 ? 0 ?             5,,0 ? -1,,Equal
       Ascii /=_/ ? 0 ? 0 ?            5,,0 ? -1,,NotEqu
       Ascii /</ ? 0 ? 0 ?             5,,0 ? -1,,Less
       Ascii /<=/ ? 0 ? 0 ?            5,,0 ? -1,,LessEq
       Ascii />/ ? 0 ? 0 ?             5,,0 ? -1,,Greatr
       Ascii />=/ ? 0 ? 0 ?            5,,0 ? -1,,GretEq
       Ascii /FLUSH/ ? 0 ? 0 ?         5,,0 ? -1,,Flush
       Ascii /TRACE/ ? 0 ? 0 ?         5,,0 ? -1,,CTrace
       Ascii /@/ ? 0 ? 0 ?             5,,0 ? -1,,Fetch
       Ascii /!/ ? 0 ? 0 ?             5,,0 ? -1,,Store
       Ascii /+!/ ? 0 ? 0 ?            5,,0 ? -1,,Storep
       Ascii /-!/ ? 0 ? 0 ?            5,,0 ? -1,,Storem
       Ascii /FILL/ ? 0 ? 0 ?          5,,0 ? -1,,Fill
       Ascii /'/ ? 0 ? 0 ?             5,,0 ? -1,,Tic
       Ascii /'#/ ? 0 ? 0 ?            5,,0 ? -1,,Ticnum
       Ascii "]" ? 0 ? 0 ?             5,,0 ? -1,,Ticome
       Ascii /QUIT/ ? 0 ? 0 ?          5,,0 ? -1,,Exit
       Ascii "<#" ? 0 ? 0 ?            5,,0 ? -1,,SOutF
       Ascii "#" ? 0 ? 0 ?             5,,0 ? -1,,FDigit
       Ascii /HOLD/ ? 0 ? 0 ?          5,,0 ? -1,,FHold
       Ascii "#N" ? 0 ? 0 ?            5,,0 ? -1,,FNDigs
       Ascii /SIGN/ ? 0 ? 0 ?          5,,0 ? -1,,FSign
       Ascii "#S" ? 0 ? 0 ?            5,,0 ? -1,,FDigs
       Ascii "#>" ? 0 ? 0 ?            5,,0 ? -1,,EOutF
       Ascii /HOME/ ? 0 ? 0 ?          5,,0 ? -1,,Home
       Ascii /CR/ ? 0 ? 0 ?            5,,0 ? -1,,Terpri
       Ascii /CLEAR/ ? 0 ? 0 ?         5,,0 ? -1,,CLS
       Ascii /SPACE/ ? 0 ? 0 ?         5,,0 ? -1,,Space
       Ascii /SPACES/ ? 0 ?            5,,0 ? -1,,Spaces
       Ascii /EMIT/ ? 0 ? 0 ?          5,,0 ? -1,,Emit
       Ascii /TYPE/ ? 0 ? 0 ?          5,,0 ? -1,,7TypeN
       Ascii "[TYPE]" ? 0 ?            5,,0 ? -1,,7Type
       Ascii /KEY/ ? 0 ? 0 ?           5,,0 ? -1,,Key
       Ascii /?TERMINAL/ ? 0 ?         5,,0 ? -1,,Inputp
       Ascii /EXPECT/ ? 0 ?            5,,0 ? -1,,ExpecN
       Ascii "[EXPECT]" ? 0 ?          5,,0 ? -1,,Expect
       Ascii /C@/ ? 0 ? 0 ?            5,,0 ? -1,,CFetch
       Ascii /C!/ ? 0 ? 0 ?            5,,0 ? -1,,CStore
       Ascii /C>/ ? 0 ? 0 ?            5,,0 ? -1,,CPlus
       Ascii /C</ ? 0 ? 0 ?            5,,0 ? -1,,CMinus
       Ascii /./ ? 0 ? 0 ?             5,,0 ? -1,,Dot
       Ascii /.R/ ? 0 ? 0 ?            5,,0 ? -1,,DotR
       Ascii /F./ ? 0 ? 0 ?            5,,0 ? -1,,FDot
DOTQa=.
       Ascii /."/ ? 0 ? 0 ?            5,,0 ? -1,,Dotext
       Ascii /:"/ ? 0 ? 0 ?            5,,0 ? -1,,ColTex
       Ascii /(")/ ? 0 ? 0 ?           5,,0 ? -1,,SaveTd
       Ascii /["]/ ? 0 ? 0 ?           5,,0 ? -1,,SaveTs
       Ascii /VLIST/ ? 0 ? 0 ?         5,,0 ? -1,,Vlist
PARENa=.
       Ascii "(" ? 0 ? 0 ?             5,,0 ? -1,,Remark
       Ascii /ABS/ ? 0 ? 0 ?           5,,0 ? -1,,Abs
       Ascii /MINUS/ ? 0 ? 0 ?         5,,0 ? -1,,Negate
       Ascii /+-/ ? 0 ? 0 ?            5,,0 ? -1,,ApSign
       Ascii /1+/ ? 0 ? 0 ?            5,,0 ? -1,,Plus1
       Ascii /1-/ ? 0 ? 0 ?            5,,0 ? -1,,Minus1
       Ascii /MAX/ ? 0 ? 0 ?           5,,0 ? -1,,Max
       Ascii /MIN/ ? 0 ? 0 ?           5,,0 ? -1,,Min
       Ascii /SINE/ ? 0 ? 0 ?          5,,0 ? -1,,Sine
       Ascii /COSINE/ ? 0 ?            5,,0 ? -1,,Cosine
       Ascii /ROOT/ ? 0 ? 0 ?          5,,0 ? -1,,Root
       Ascii /LN/ ? 0 ? 0 ?            5,,0 ? -1,,LogN
       Ascii /<-,,/ ? 0 ? 0 ?          5,,0 ? -1,,LHalf
       Ascii /SW,,AP/ ? 0 ?            5,,0 ? -1,,SHalfs
       Ascii /,,->/ ? 0 ? 0 ?          5,,0 ? -1,,RHalf
       Ascii /AND/ ? 0 ? 0 ?           5,,0 ? -1,,LogAND
       Ascii /OR/ ? 0 ? 0 ?            5,,0 ? -1,,LogOR
       Ascii /NOT/ ? 0 ? 0 ?           5,,0 ? -1,,LogNOT
       Ascii /XOR/ ? 0 ? 0 ?           5,,0 ? -1,,LogXOR
       Ascii /EXECUTE/ ? 0 ?           5,,0 ? -1,,Execut
       Ascii /FORGET/ ? 0 ?            5,,0 ? -1,,Forget
       Ascii /:/ ? 0 ? 0 ?             5,,0 ? -1,,Colon
SEMIa=.
       Ascii /;/ ? 0 ? 0 ?             5,,0 ? -1,,Buierr
       Ascii /<BUILDS/ ? 0 ?           5,,0 ? -1,,Builds
DOESa=.
       Ascii /DOES>/ ? 0 ? 0 ?         5,,0 ? -1,,Does
       Ascii /,/ ? 0 ? 0 ?             5,,0 ? -1,,Comma
       Ascii /ALLOT/ ? 0 ? 0 ?         5,,0 ? -1,,Allot
LOADa=.
       Ascii /LOAD/ ? 0 ? 0 ?          5,,0 ? -1,,Load
       Ascii "[LOAD]" ? 0 ?            5,,0 ? -1,,Loads
       Ascii /UNLOAD/ ? 0 ?            5,,0 ? -1,,Unload
       Ascii /DECIMAL/ ? 0 ?           5,,0 ? -1,,Base10
       Ascii /OCTAL/ ? 0 ? 0 ?         5,,0 ? -1,,Base8
       Ascii /BINARY/ ? 0 ?            5,,0 ? -1,,Base2

IFa=.
       Ascii /IF/ ? 0 ? 0 ?            5,,-1 ? -1,,If
ELSEa=.
       Ascii /ELSE/ ? 0 ? 0 ?          5,,-1 ? -1,,Else
THENa=.
       Ascii /THEN/ ? 0 ? 0 ?          5,,-1 ? -1,,Then

DOa=.
       Ascii /DO/ ? 0 ? 0 ?            5,,-1 ? -1,,DoLoop
LOOPa=.
       Ascii /LOOP/ ? 0 ? 0 ?          5,,-1 ? -1,,Loop
LOOPPa=.
       Ascii /+LOOP/ ? 0 ? 0 ?         5,,-1 ? -1,,Loopp

       Ascii /I/ ? 0 ? 0 ?             5,,0 ? -1,,Aye
       Ascii /J/ ? 0 ? 0 ?             5,,0 ? -1,,Jay
       Ascii /IJ..N/ ? 0 ? 0 ?         5,,0 ? -1,,En
       Ascii /RUNT/ ? 0 ? 0 ?          5,,0 ? -1,,Runt

REPTa=.
       Ascii /REPEAT/ ? 0 ?            5,,-1 ? -1,,Rept
UNTILa=.
       Ascii /UNTIL/ ? 0 ? 0 ?         5,,-1 ? -1,,Until

       Ascii /CMOVE/ ? 0 ? 0 ?         5,,0 ? -1,,CMoveN
       Ascii "[CMOVE]" ? 0 ?           5,,0 ? -1,,CMoves
       Ascii /HERE/ ? 0 ? 0 ?          5,,0 ? -1,,Here
       Ascii /LEAVE/ ? 0 ? 0 ?         5,,0 ? -1,,Leave
       Ascii /ERROR/ ? 0 ? 0 ?         5,,0 ? -1,,Erret
       Ascii "[NUMBER]" ? 0 ?          5,,0 ? -1,,Number

WHILEa=.
       Ascii /WHILE/ ? 0 ? 0 ?         5,,-1 ? -1,,While
BEGINa=.
       Ascii /BEGIN/ ? 0 ? 0 ?         5,,-1 ? -1,,Begin
ENDa=.
       Ascii /END/ ? 0 ? 0 ?           5,,-1 ? -1,,FEnd

Bottom: 0

       Loc Foo

Dicte:  D,,Bottom

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;               Start of Executable Part of FORTH                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Start:  Move P,PDList
       Move S,Stack
       Movei A,.PRIOU
       GTTYP
       Movem B,Term
       Movei A,.PRIIN
       RFMOD
       Trz B,TT%DAM
       Tlz B,TT%ECO
       SFMOD
       Movei B,.MORLW
       MTOPR
       Movem C,Width

Initp:  Movsi A,(GJ%SHT\GJ%OLD)
       Hrroi B,[Asciz /AUTO-LOAD.4TH/]
       GTJFN
         Jrst Greet
       Move B,[070000,,OF%RD]
       OPENF
         Jrst Greet
       Call LSave
       Jrst PRun

Greet:  Type "FORTH-10   Type QUIT to exit."
       Call Terpri

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                       Top Level of FORTH                       ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PPPRun: Skipn Echo
         Jrst PRun
       Type " Ok"
PPRun:  Call Terpri
PRun:   Call FillIB
Run:    Call Getwrd
         Jrst PPPRun
       Skipe INump
         Jrst [Move V,IVal     ;Constants are pushed,
               Call 4SAVE
               Jrst Run]
       Skipn IAddr
         Jrst NamErr
       Move L,IAddr
       Hrre A,3(L)
       Skipg A                 ;Subroutines executed,
         Move L,4(L)
       Call Eval               ;Words evaluated.
       Jrst Run

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                           Primitives                           ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;
;;;     Stack operations
;;;

Dup:    Jumpe U,UFlow                   ; DUP
       Move V,(S)
       Call 4SAVE
       Return

Drop:   Call 4REST                      ; DROP
       Return

Over:   Caige U,2                       ; OVER
         Jrst UFlow
       Move V,-1(S)
       Call 4SAVE
       Return

Rotate: Caige U,3                       ; ROT
         Jrst UFlow
       Move T1,(S)
       Exch T1,-1(S)
       Exch T1,-2(S)
       Movem T1,(S)
       Return

Swap:   Caige U,2                       ; SWAP
         Jrst UFlow
       Move T1,(S)
       Exch T1,-1(S)
       Movem T1,(S)
       Return

Roll:   Call 4REST                      ; ROLL
       Camle V,U
         Jrst UFlow
       Hrrz T1,S
       Sub T1,V
       Move T2,1(T1)
       Movei T3,1(T1)
       Hrli T3,2(T1)
       BLT T3,-1(S)
       Movem T2,(S)
       Return

Pick:   Call 4REST                      ; PICK
       Camle V,U
         Jrst UFlow
       Hrrz T1,S
       Sub T1,V
       Move V,1(T1)
       Call 4SAVE
       Return

NZDup:  Jumpe U,UFlow                   ; -DUP and ?DUP
       Skipn (S)
         Return
       Move V,(S)
       Call 4SAVE
       Return

;;;
;;;     Numeric changes
;;;

Negate: Jumpe U,UFlow                   ; MINUS
       Movns (S)
       Return

RHalf:  Jumpe U,UFlow                   ; ,,->
       Hrre A,(S)
       Movem A,(S)
       Return

LHalf:  Jumpe U,UFlow                   ; <-,,
       Hlre A,(S)
       Movem A,(S)
       Return

SHalfs: Jumpe U,UFlow                   ; SW,,AP
       Movss (S)
       Return

ApSign: Call 4REST                      ; +-
       Jumpe U,UFlow
       Skipge V
         Movns (S)
       Return

Min:    Caige U,2                       ; MIN
         Jrst UFlow
       Call 4REST
       Camge V,(S)
         Movem V,(S)
       Return

Max:    Caige U,2                       ; MAX
         Jrst UFlow
       Call 4REST
       Camle V,(S)
         Movem V,(S)
       Return

Abs:    Jumpe U,UFlow                   ; ABS
       Movms (S)
       Return

Plus1:  Jumpe U,UFlow                   ; 1+
       Aos (S)
       Return

Minus1: Jumpe U,UFlow                   ; 1-
       Sos (S)
       Return

;;;
;;;     Floating-point functions
;;;

Cosine: Call 4REST                      ; COSINE
       FADR V,[1.57079632679]
       Skipa
Sine:   Call 4REST                      ; SINE
       Move A,V
       Call SorC
       Move V,A
       Call 4SAVE
       Return

SorC:   Movm B,A
       Camg B,[.0001761]
         Return
       FDVRI A,(+9.0)
       Call SorC
       Call .+1
       FMPR B,B
       FSC B,2
       FADRI B,(-3.0)
       FMPRB A,B
       Return

Root:   Call 4REST                      ; ROOT
       Jumple V,[Setz V,
                 Call 4SAVE
                 Return]
       Move T1,V
       FADRI T1,(+1.0)
       FDVRI T1,(+2.0)
Root1:  Move T2,V
       FDVR T2,T1
       FADR T2,T1
       FDVRI T2,(+2.0)
       Move T3,T2
       FSBR T3,T1
       Movms T3
       Camg T3,[.0000001]
         Jrst Root2
       Move T1,T2
       Jrst Root1
Root2:  Move V,T1
       Call 4SAVE
       Return

LogN:   Call 4REST                      ; LN
       Jumple V,[Setz V,
                 Call 4SAVE
                 Return]
       Move T1,V
       FSBRI T1,(+1.0)
       Move T2,V
       FADRI T2,(+1.0)
       FDVR T1,T2
       Move T2,T1
       Move A,T1
       Setzb C,B

LogN1:  FMPR T2,T1
       FMPR T2,T1
       Move T3,T2
       FDVR T3,LogNcs(C)
       FADR A,T3
       FSBR B,A
       Movms B
       Camg B,[.0000001]
         Jrst LogN2
       Move B,A
       Aoja C,LogN1
LogN2:  FMPRI A,(+2.0)
       Move V,A
       Call 4SAVE
       Return

;;;
;;;     System constants and toggles and stuff
;;;

Depth:  Move V,U                        ; DEPTH
       Call 4SAVE
       Return

CTrace: Setcmm Trace                    ; TRACE
       Return

Inputp: Setz V,                         ; ?TERMINAL
       Movei A,.PRIIN
       SIBE
         Seto V,
       Call 4SAVE
       Return

PLevel: Move V,Level                    ; LEVEL
       Call 4SAVE
       Return

Runt:   Movei A,.FHSLF                  ; RUNT
       RUNTM
       Move V,A
       Call 4SAVE
       Return

Base10: Movei A,10.                     ; DECIMAL
       Movem A,Base
       Return

Base8:  Movei A,8.                      ; OCTAL
       Movem A,Base
       Return

Base2:  Movei A,2                       ; BINARY
       Movem A,Base
       Return

Aye:    Skipge DOc                      ; I
         Jrst DOerr
       Move T1,DOc
       Move V,DOind(T1)
       Call 4SAVE
       Return

Jay:    Skipg DOc                       ; J
         Jrst DOerr
       Move T1,DOc
       Soj T1,
       Move V,DOind(T1)
       Call 4SAVE
       Return

En:     Call 4REST                      ; IJ..N
       Jumple V,[Type " ?Loop # <1"
                 Jrst Erret]
       Soj V,
       Camle V,DOc
         Jrst DOerr
       Move T1,DOc
       Sub T1,V
       Move V,DOind(T1)
       Call 4SAVE
       Return

VLIST:  Movei T1,Dict
       Setz T2,
       Call Terpri
VL2:    Skipn (T1)
         Return
       Move T3,[440700,,(T1)]
       Setz T4,
VL3:    Ildb A,T3
       Skipe A
       Aoja T4,VL3
       Add T2,T4
       Addi T2,2
       Caml T2,Width
         Jrst [Call Terpri
               Move T2,T4
               Addi T2,2
               Jrst .+1]
       Movei A,40
       PBOUT
       PBOUT
       Move T3,[440700,,(T1)]
VL4:    Ildb A,T3
       PBOUT
       Sojn T4,VL4

VL5:    Hlrz T3,3(T1)
       Add T1,T3
       Jrst VL2

;;;
;;;     Formatted number output stuff
;;;

SOutF:  Skipe Format                            ; <#
         Jrst [Type " ?Already formatting"
               Jrst Erret]
       Jumpe U,UFlow
       Move V,(S)
       Setom Format
       Jumpge V,SOutFs
       Movns V
       Setom FMinus
SOutFs: Movem V,(S)
       Move A,[010700,,FBufBP-1]
       Movem A,FBufBP
       Movei B,5*FBufl-1
       Movem B,FLeft
       Return

FSign:  Skipn Format                            ; SIGN
         Jrst NForm
       Skipn FMinus
         Return
       Movei K,"-
       Call FSave
       Return

FDigit: Skipn Format                            ; #
         Jrst NForm
       Jumpe U,Unform
       Move T1,(S)
       Idiv T1,Base
       Move K,T2
       Addi K,60
       Call FSave
       Movem T1,(S)
       Return

FNDigs: Skipn Format                            ; #N
         Jrst NForm
       Call 4REST
       Skipg V
         Return
       Jumpe U,Unform
       Move T1,(S)
FNDlop: Idiv T1,Base
       Move K,T2
       Addi K,60
       Call FSave
       Sojn V,FNDlop
       Movem T1,(S)
       Return

FHold:  Skipn Format                            ; HOLD
         Jrst NForm
       Call 4REST
       Move K,V
       Call FSave
       Return

FDigs:  Skipn Format                            ; #S
         Jrst NForm
       Jumpe U,Unform
       Move T1,(S)
FDigsl: Jumpe T1,FDigse
       Idiv T1,Base
       Move K,T2
       Addi K,60
       Call FSave
       Jrst FDigsl
FDigse: Setzm (S)
       Return

EOutF:  Skipn Format                            ; #>
         Jrst NForm
       Call 4REST
       Move V,FBufBP
       Call 4SAVE
       Movei V,5*FBufl-1
       Sub V,FLeft
       Call 4SAVE
       Setzm Format
       Return

FSave:  Skipn FLeft
         Jrst [Type " ?Formatting buffer full"
               Jrst Erret]
       Move A,FBufBP
       DBP A
       Movem A,FBufBP
       Dpb K,FBufBP
       Sos FLeft
       Return

;;;
;;;     Display hacking
;;;

Home:   Skipn Term                      ; HOME
         Return
       Move T1,Term
       Move A,[440700,,Homes(T1)]
       PSOUT
       Return

CLS:    Skipn Term                      ; CLEAR
         Return
       Move T1,Term
       Move A,[440700,,Clears(T1)]
       PSOUT
       Return

;;;
;;;     Outputting words
;;;

Space:  Movei A,40                      ; SPACE
       PBOUT
       Return

Spaces: Call 4REST                      ; SPACES
       Skipg V
         Return
       Movei A,40
       PBOUT
       Sojn V,.-1
       Return

Terpri: Movei A,^M                      ; CR
       PBOUT
       Movei A,^J
       PBOUT
       Return

Emit:   Call 4REST                              ; EMIT
       Move A,V
       PBOUT
       Return

7TypeN: Call 4REST      ;# Characters             TYPE
       Move T1,V
       Call 4REST      ;BP
7TNlop: Ldb A,V
       PBOUT
       Ibp V
       Sojn T1,7TNlop
       Return

7Type:  Call 4REST      ;BP                       [TYPE]
7TLoop: Ldb A,V
       Skipn A
         Return
       PBOUT
       Ibp V
       Jrst 7TLoop

Dotext: Skiple Level                    ; ."
         Jrst Dotsav
Dotxt2: Call Getchr
         Call Refill
       Movem K,Delim
Dotxt3: Call Getchr
         Call Refill
       Camn K,Delim
         Return
       Move A,K
       PBOUT
       Caie A,^M
         Jrst Dotxt3
       Movei A,^J
       PBOUT
       Jrst Dotxt3

Dotsav: Move T1,E
       Hrli T1,440700
       Aoj T1,
       Setz T2,

Dots2:  Ildb A,T1
       Jumpe A,Dots3
       PBOUT
       Caie A,^M
         Aoja T2,Dots2
       Movei A,^J
       PBOUT
       Aoja T2,Dots2

Dots3:  Idivi T2,5      ;Return # of text words to skip
       Aoj T2,
       Add E,T2
       Return

;;;
;;;     Character operations
;;;

CFetch: Jumpe U,UFlow                   ; C@
       Ldb A,(S)
       Movem A,(S)
       Return

CStore: Call 4REST      ;BP               C!
       Move T1,V
       Call 4REST      ;Byte
       Dpb V,(T1)
       Return

CPlus:  Call 4REST      ;Number           C+
       Move T1,V
       Call 4REST      ;BP
       Idivi T1,5
       Add V,T1
       Jumpe T2,CPlusb
       Ibp V
       Sojn T2,.-1
CPlusb: Call 4SAVE
       Return

CMinus: Call 4REST      ;Number           C-
       Move T1,V
       Call 4REST      ;BP
       IDivi T1,5
       Sub V,T1
       Jumpe T2,CMin2
CMin1:  Dbp V
       Sojn T2,CMin1
CMin2:  Call 4SAVE
       Return

CMoveN: Call 4REST      ;Number                 CMOVE
       Move T1,V
       Call 4REST      ;BP-to
       Move T2,V
       Call 4REST      ;BP-from
CMNlop: Ldb A,V
       Dpb A,T2
       Ibp V
       Ibp T2
       Sojn T1,CMNlop
       Return

CMoves: Call 4REST      ;BP-to          [CMOVE]         Returns #chars
       Move T1,V
       Call 4REST      ;BP-from
       Setz T2,
CMSlop: Ldb A,V
       Jumpe A,CMSdun
       Dpb A,T1
       Ibp V
       Ibp T1
       Aoja T2,CMSlop
CMSdun: Call 4SAVE
       Return

;;;
;;;     Inputting words
;;;

Key:    PBIN                            ; KEY
       Andi A,177
       Move V,A
       Call 4SAVE
       Return

Number: Jumpe U,UFlow                   ; caddr [NUMBER] --> caddr n -1
       Move T1,(S)     ;BP-from        ;                --> caddr 0
       Call StoN
         Jrst [Movem T1,(S)
               Setz V,
               Call 4SAVE
               Return]
       Movem T1,(S)
       Move V,T2
       Call 4SAVE
       Seto V,
       Call 4SAVE
       Return

ExpecN: Call 4REST      ;Number                 EXPECT
       Move T1,V
       Call 4REST      ;BP-to
ENLoop: PBIN
       Dpb A,V
       Skipe Echo
         PBOUT
       Ibp V
       Sojn T1,ENLoop
       Return

Expect: Call 4REST      ;BP             [EXPECT]
       Setz T3,
ELoop:  PBIN
       Cain A,^M
         Jrst ESave
       Dpb A,V
       Skipe Echo
         PBOUT
       Ibp V
       Aoja T3,ELoop
ESave:  Dpb V           ;Make it asciz
       Move V,T3
       Call 4SAVE
       Return

;;;
;;;     Numberic output
;;;

DotR:   Call 4REST                      ; .R
       Move T4,V
       Skipa
Dot:    Call 4REST                      ; .
Dota:   Setz T4,
       Movm T1,V
       Setz T3,
Dot1:   IDiv T1,Base
       Push P,T2
       Aoj T3,
       Jumpn T1,Dot1
Dot2:   Move T1,T3
       Skipge V
         Aoj T1,
       Camg T4,T1
         Jrst DotS
       Sub T4,T1
DotF:   Movei A,40
       PBOUT
       Sojn T4,DotF
DotS:   Jumpge V,Dot3
       Movei A,"-
       PBOUT
Dot3:   Pop P,A
       Addi A,60
       PBOUT
       Sojn T3,Dot3
Dot4:   Movei A,40
       PBOUT
       Return

FDot:   Call 4REST                      ; F.
       Movei A,.PRIOU
       Move B,V
       Movei C,FL%ONE\FL%PNT
       FLOUT
         Jfcl
       Return

;;;
;;;     Text building (Dictionary)
;;;

SaveTs: Call 4REST                      ; ["]
       Move T1,V
       Movei A,^M
       Movem A,Delim
       Call sTextd
       Move V,T2
       Call 4SAVE
       Return

SaveTd: Call 4REST                      ; (")
       Move T1,V
       Call sText
       Move V,T2
       Call 4SAVE
       Return

ColTex: Call BText
       Move V,lsText
       Call 4SAVE
       Return

;;;
;;;     Miscellaneous
;;;

Exit:   Call Terpri
       Type "Exiting FORTH"
       Call Terpri
       Jrst Die

Remark: Call Getchr                     ; (
         Call Refill
       Caie K,")
         Jrst Remark
       Return

Here:   Skipn Making                    ; HERE
         Jrst Buierr
       Move V,Dicte
       Add V,D
       Call 4SAVE
       Return

Execut: Call 4REST                      ; EXECUTE
       Move L,V
       Call Eval
       Return

Leave:  Skipge DOc
         Jrst DOerr
       Move T1,DOc
       Move T2,DOtop(T1)
       Movem T2,DOind(T1)
       Return

Jsys0:  Call 4REST      ;JSys#            JSYS
       Hrr V,JCall
       Xct JCall
       Return

Flush:  Move S,Stack                    ; FLUSH
       Setz U,
       Return

;;;
;;;     Stack/Memory operations
;;;

Store:  Call 4REST                      ; !
       Move T1,V
       Call 4REST
       Movem V,(T1)
       Return

Storep: Call 4REST                      ; +!
       Move T1,V
       Call 4REST
       Addm V,(T1)
       Return

Storem: Call 4REST                      ; -!
       Move T1,V
       Call 4REST
       Exch V,(T1)
       Subm V,(T1)
       Return

Fill:   Call 4REST      ;Value                  FILL
       Move T1,V
       Call 4REST      ;Number
       Move T2,V
       Call 4REST      ;Address
       Add T2,V
       Movem T1,V
       Hrl V,V
       Aoj V,
       BLT V,-1(T2)
       Return

XChanj: Call 4REST                              ; EXCHANGE
       Move T1,V
       Call 4REST
       Move T2,(V)
       Exch T2,(T1)
       Movem T2,(V)
       Return

Fetch:  Jumpe U,UFlow                           ; @
       Move T1,(S)
       Move T2,(T1)
       Movem T2,(S)
       Return

;;;
;;;     Random Dictionary stuff
;;;

Tic:    Call Getwrd                             ; '
         Call Refill
       Skipn IAddr
         Jrst NamErr
       Move V,IAddr
       Call 4SAVE
       Return

Ticnum: Call Getwrd                             ; '#
         Call Refill
       Skipn INump
         Jrst NamErr
       Move V,IVal
       Call 4SAVE
       Return

Forget: Call Getwrd                             ; FORGET
         Call Refill
       Skipn IAddr
         Jrst NamErr
       Move T1,IAddr
       Setzm (T1)
       Hrl T1,T1
       Aoj T1,
       BLT T1,Dicte
       Move A,IAddr
       Hrrm A,Dicte
       Return

;;;
;;;     Logical operations
;;;

LogAND: Caige U,2                       ; AND
         Jrst UFlow
       Call 4REST
       Andm V,(S)
       Return

LogOR:  Caige U,2                       ; OR
         Jrst UFlow
       Call 4REST
       IOrm V,(S)
       Return

LogNOT: Jumpe U,UFlow                   ; NOT
       Setcmm (S)
       Return

LogXOR: Caige U,2                       ; XOR
         Jrst UFlow
       Call 4REST
       XOrm V,(S)
       Return

;;;
;;;     Arithmetic operations
;;;

Plus:   Caige U,2                       ; +
         Jrst UFlow
       Call 4REST
       Addm V,(S)
       Return

FPlus:  Caige U,2                       ; F+
         Jrst UFlow
       Call 4REST
       FADM V,(S)
       Return

Minus:  Call 4REST                      ; -
       Jumpe U,UFlow
       Exch V,(S)
       Subm V,(S)
       Return

FMin:   Call 4REST                      ; F-
       Jumpe U,UFlow
       Exch V,(S)
       FSBM V,(S)
       Return

Times:  Caige U,2                       ; *
         Jrst UFlow
       Call 4REST
       IMulm V,(S)
       Return

FTimes: Caige U,2                       ; F*
         Jrst UFlow
       Call 4REST
       FMPM V,(S)
       Return

Divide: Call 4REST                      ; /
       Jumpe U,UFlow
       Exch V,(S)
       IDivm V,(S)
       Return

FDiv:   Call 4REST                      ; F/
       Jumpe U,UFlow
       Exch V,(S)
       FDVM V,(S)
       Return

Power:  Call 4REST                      ; ^
       Move T1,V
       Call 4REST
       Movei T2,1
P2:     Jumple T1,P3
       Imul T2,V
       Soja T1,P2
P3:     Move V,T2
       Call 4SAVE
       Return

Mod:    Call 4REST                      ; MOD
       Move T1,V
       Call 4REST
       Move T2,V
       IDiv T2,T1
       Move V,T3
       Call 4SAVE
       Return

DivMod: Call 4REST                      ; /MOD
       Move T1,V
       Call 4REST
       Move T2,V
       IDiv T2,T1
       Move V,T3
       Call 4SAVE
       Move V,T2
       Call 4SAVE
       Return

;;;
;;;     Conversions
;;;

ItoF:   Jumpe U,UFlow                   ; FLOAT
       FLTR T1,(S)
       Movem T1,(S)
       Return

FtoI:   Jumpe U,UFlow                   ; FIX
       FIXR T1,(S)
       Movem T1,(S)
       Return

;;;
;;;     Single operator tests
;;;

EqualZ: Setz A,                 ; 0=
       Jrst 1Test
NotEq0: Movei A,1               ; 0=_
       Jrst 1Test
LessZ:  Movei A,2               ; 0<
       Jrst 1Test
LesEq0: Movei A,3               ; 0<=
       Jrst 1Test
GreatZ: Movei A,4               ; 0>
       Jrst 1Test
GrEq0:  Movei A,5               ; 0>=

1Test:  Jumpe U,UFlow
       Setz T1,
       Xct 1Tests(A)
         Seto T1,
       Movem T1,(S)
       Return

;;;
;;;     Two operator tests
;;;

Equal:  Setz A,                 ; =
       Jrst 2Test
NotEqu: Movei A,1               ; =_
       Jrst 2Test
Less:   Movei A,2               ; <
       Jrst 2Test
LessEq: Movei A,3               ; <=
       Jrst 2Test
Greatr: Movei A,4               ; >
       Jrst 2Test
GretEq: Movei A,5               ; >=

2Test:  Call 4REST
       Jumpe U,UFlow
       Setz T1,
       Xct 2Tests(A)
         Seto T1,
       Movem T1,(S)
       Return

;;;
;;;     File-loading things
;;;

Load:   Move T3,LLoad                           ; LOAD
       Cail T3,MaxLLs
         Jrst [Type " ?Can't load deeper"
               Jrst Erret]
       Skipg Level
         Jrst L2
       Movsi A,(GJ%SHT\GJ%OLD)
       Hrro B,E
       Aoj B,
       GTJFN
         Jrst NoFile
       Hrrz T1,B
       Sub T1,E
       Move B,[070000,,OF%RD]
       OPENF
         Jrst NoFile
       Add E,T1
       Jrst LSave

L2:     Call Getchr
         Call Refill
       Movem K,Delim
       Move T1,[440700,,FName]
L3:     Call Getchr
         Call Refill
       Camn K,Delim
         Jrst L4
       Idpb K,T1
       Jrst L3
L4:     Idpb T1         ;Make asciz
       Hrroi B,FName
L5:     Movsi A,(GJ%SHT\GJ%OLD)
       GTJFN
         Jrst NoFile
       Move B,[070000,,OF%RD]
       OPENF
         Jrst NoFile

LSave:  Move T1,iJFN
       Aos T2,LLoad
       Movem T1,LiJFNs(T2)
       Movem A,iJFN
       Setom Loadp
       Setzm Echo
       Return

Loads:  Call 4REST                              ; [LOAD]
       Hrro B,V
       Jrst L5

Unload: Skipge LLoad                    ; UNLOAD
         Jrst [Type " ?Not loading"
               Jrst Erret]
       Move A,iJFN
       CLOSF
         Jrst [Type " %Can't close file"
               Jrst .+1]
       Move T1,LLoad
       Move A,LiJFNs(T1)
       Movem A,iJFN
       Sos LLoad
       Skipl LLoad
         Return
       Setom Echo
       Setzm Loadp
       Return

;;;
;;;     The infamous IF/ELSE/THEN structure
;;;

IF:     Call 4REST
       Skipe V
         Return
IFskip: Aoj E,
       Move T1,(E)
       Came T1,[-1,,Then]
         Camn T1,[-1,,Else]
           Return
       Jrst IFskip

Else:   Aoj E,
       Move T1,(E)
       Came T1,[-1,,Then]
         Jrst Else
       Return

Then:   Return

;;;
;;;     The REPEAT/UNTIL loop
;;;

Rept:   Aos T1,UNTILc
       Movem E,UNTILs(T1)      ;Start of REPEAT code
       Return

Until:  Call 4REST
       Jumpe V,[Move T1,UNTILc
                Move E,UNTILs(T1)
                Return]
       Sos UNTILc
       Return

;;;
;;;     The leading test WHILE/BEGIN/END loop
;;;

While:  Aos T1,WHILEc
       Movem E,WHILEs(T1)
       Setzm WHILEe(T1)
       Return

Begin:  Call 4REST
       Skipe V
         Return
       Move T1,WHILEc
       Skipe WHILEe(T1)
         Jrst [Move E,WHILEe(T1)
               Return]
Begin2: Aoj E,
       Move T1,(E)
       Came T1,[-1,,FEnd]
         Aoja E,Begin2
       Sos WHILEc
       Return

FEnd:   Move T1,WHILEc
       Movem E,WHILEe(T1)
       Move E,WHILEs(T1)
       Return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;     The obligatory DO/LOOP[+] structure.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DoLoop: Aos T1,DOc
       Movem E,DOs(T1)
       Call 4REST
       Movem V,DOind(T1)       ;Initial value
       Call 4REST
       Movem V,DOtop(T1)       ;Upper limit
       Return

Loop:   Move T1,DOc
       Aos V,DOind(T1)
       Jrst Loopt

Loopp:  Move T1,DOc
       Call 4REST
       Jumpl V,Looppm
       Addb V,DOind(T1)

Loopt:  Camge V,DOtop(T1)
         Move E,DOs(T1)
       Caml V,DOtop(T1)
         Sos DOc
       Return

Looppm: Addb V,DOtop(T1)
       Camle V,DOtop(T1)
         Move E,DOs(T1)
       Camg V,DOtop(t1)
         Sos DOc
       Return

;;;
;;;     The Colon (:) Compiler (Quite Hirsute)
;;;

Colon:  Skipe Making
         Jrst [Type " ?Can't compile :'s"
               Jrst Erret]
       Setom Making
       Call MHead

Colon1: Call Getwrd
         Call Refill
       Skipe INump
         Jrst [Aoj D,
               Setom @Dicte
               Aoj D,
               Move T1,IVal
               Movem T1,@Dicte
               Jrst Colon1]
       Skipn IAddr
         Jrst [Type " ?Undefined"
               Jrst Erret]
       Move T1,IAddr
       Cain T1,SEMIa
         Jrst Coldun
       Caie T1,PARENa  ;Don't compile comments
         Jrst Colon2
Colsr:  Call Getchr
         Call Refill
       Caie K,")
         Jrst Colsr

Colon2: Hrre A,3(T1)
       Jumpg A,[Aoj D,
                Movem T1,@Dicte
                Jrst Colon1]
       Caie T1,ELSEa
         Jrst Colon3
       Skipge IFc
         Jrst [Type " ?ELSE without IF"
               Jrst Erret]
       Jrst Colis

Colon3: Caie T1,THENa
         Jrst Colon4
       Skipge IFc
         Jrst [Type " ?THEN without IF"
               Jrst Erret]
       Sos IFc
       Jrst Colis

Colon4: Caie T1,BEGINa
         Jrst Colon5
       Skipge WHILEc
         Jrst [Type " ?BEGIN without WHILE"
               Jrst Erret]
       Setom BEGINp
       Jrst Colis

Colon5: Caie T1,ENDa
         Jrst Colis
       Skipge WHILEc
         Jrst [Type " ?END without WHILE"
               Jrst Erret]
       Skipn BEGINp
         Jrst [Type " ?END without BEGIN"
               Jrst Erret]
       Pop P,BEGINp
       Sos WHILEc

Colis:  Move T4,4(T1)
       Aoj D,
       Movem T4,@Dicte

CLoad:  Caie T1,DOTQa
         Cain T1,LOADa
           Jrst [Call BText
                 Jrst Colon1]

Colis1: Caie T1,UNTILa
         Jrst Colis2
       Skipge UNTILc
         Jrst [Type " ?UNTIL without REPEAT"
               Jrst Erret]
       Sos UNTILc
       Jrst Colon1

Colis2: Caie T1,LOOPa
         Cain T1,LOOPPa
           Skipa
       Jrst Colis3
       Skipge DOc
         Jrst [Type " ?LOOP without DO"
               Jrst Erret]
       Sos DOc
       Jrst Colon1

Colis3: Caie T1,IFa
         Jrst Colis4
       Aos IFc
       Jrst Colon1

Colis4: Caie T1,DOa
         Jrst Colis5
       Move A,DOc
       Cail A,DOn-1
         Jrst [Type " ?DOs nested too deeply"
               Jrst Erret]
       Aos DOc
       Jrst Colon1

Colis5: Caie T1,REPTa
         Jrst Colis6
       Move A,UNTILc
       Cail A,UNTILn-1
         Jrst [Type " ?REPEATs nested too deeply"
               Jrst Erret]
       Aos UNTILc
       Jrst Colon1

Colis6: Caie T1,WHILEa
         Jrst Colon1
       Move A,WHILEc
       Cail A,WHILEn-1
         Jrst [Type " ?WHILEs nested too deeply"
               Jrst Erret]
       Aos WHILEc
       Push P,BEGINp
       Setzm BEGINp
       Jrst Colon1

Coldun: Skipl IFc
         Jrst [Type " ?Unfinished IF"
               Jrst Erret]
       Skipl DOc
         Jrst [Type " ?Unfinished DO"
               Jrst Erret]
       Skipl UNTILc
         Jrst [Type " ?Unfinished REPEAT"
               Jrst Erret]
       Skipl WHILEc
         Jrst [Type " ?Unfinished WHILE"
               Jrst Erret]
       Hrrz T1,Dicte
       Addi T1,4       ;Address of executable part
       Addi D,2
       Hrl T1,D
       Movem T1,-1(T1) ;Length,,Address
       Addm D,Dicte
       Setzm Making
       Return

;;;
;;;     Dictionary building words
;;;

Builds: Skipe Making                            ; <BUILDS
         Jrst [Type " ?Already building"
               Jrst Erret]
       Call MHead
       Setom Making
       Return

Does:   Skipn Making                            ; DOES>
         Jrst [Move V,BStart
               Call 4SAVE
               Return]
       Move T1,Dicte
       Move T2,E
       Aoj D,
       Hrl T2,D
       Movem T2,3(T1)
       Addm D,Dicte
       Setzm Making
       Setom Did
       Return

Comma:  Skipn Making                    ; ,
         Jrst Buierr
       Call 4REST
       Aoj D,
       Movem V,@Dicte
       Return

Allot:  Skipn Making                    ; ALLOT
         Jrst Buierr
       Call 4REST
       Skiple V
         Add D,V
       Return

Ticome: Skipn Making                    ; ] --> n
         Jrst Buierr
       Setz V,
Ticom2: Call Getwrd
         Call Refill
       Skipe INump
         Jrst Numer
       Skipn IAddr
         Jrst UDef
       Move A,IAddr
       Cain A,SEMIa
         Jrst [Call 4SAVE
               Return]
       Aoj D,
       Movem A,@Dicte
       Aoja V,Ticom2

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                  Error Messages and Handling                   ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NoFile: Type " ?Can't access file"
       Jrst Rerun

UFlow:  Type " ?Stack underflow"
       Jrst Erret

OFlow:  Type " ?Stack overflow"
       Jrst Erret

Buierr: Type " ?Not building"
       Jrst Erret

DOerr:  Type " ?Loops too shallow"
       Jrst Erret

NForm:  Type " ?Not formatting"
       Jrst Erret

Unform: Type " ?Formatting # gone"
       Setzm Format
       Jrst Erret

UDef:   Type " ?Undefined word"
       Jrst Erret

Numer:  Type " ?Numeric word"
       Jrst Erret

WMode:  Type " ?Immediate use disallowed"

Erret:  Call Terpri
       Move T1,[440700,,InBuf]
       Move T2,nIchar
       Soj T2,
Erret2: Ildb A,T1
       PBOUT
       Sojg T2,Erret2
Erret3: Type "<--"

UnMake: Skipn Making
         Jrst ReRun
       Call Terpri
       Type "%Unbuilding"
       Setzm @Dicte
       Sojge D,.-1
       Setzm Making

ReRun:  Setzm nIchar
       Setom Level
       Setom DOc
       Setom IFc
       Setom WHILEc
       Setom UNTILc
       Move P,PDList
       Skipn Loadp
         Jrst PPRun
       Call Terpri
       Type "%Aborting load"
       Call Unload
       Jrst PPRun

NamErr: Movei A,40
       PBOUT
       Hrroi A,IStrin
       PSOUT
       Movei A,"?
       PBOUT
       Movei A,40
       PBOUT
       Jrst ReRun

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                          Subroutines                           ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;                                                                ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

4SAVE:  Cail U,Deep
         Jrst OFlow
       Aoj U,
       Push S,V
       Return

4REST:  Jumpe U,UFlow
       Soj U,
       Pop S,V
       Return

Getchr: Ildb K,pInBuf           ;Returns one character in K.  Skips
       Skipn K                 ;if there's something to get.
         Return
       Aos nIchar
       Jrst Popj1

Refill: Skipe Echo              ;Does a fill-input-buffer and returns
         Call Terpri           ;to the instruction BEFORE the call.
       Call FillIB
       Sos (P)
       Sos (P)
       Return

FillIB: Setzb T2,nIchar         ;Gets a line of input from the input
       Move T4,[440700,,InBuf] ;source, with rubout handling, and
GL2:    Move A,iJFN             ;stores it in InBuf - Appropriate BPs
GL2a:   BIN                     ;and character counts are reset.
       Erjmp [Call Unload
              Jrst GLF]
       Andi B,177
       Cain B,^M
         Jrst GL4
       Cain B,^E
         Jrst [Setcmm Echo
               Jrst GL2a]
       Caige B,40
         Jrst GL2
       Cain B,177
         Jrst [Jumpe T2,GL2
               DBP T4
               Movei A,^H
               PBOUT
               Movei A,40
               PBOUT
               Movei A,^H
               PBOUT
               Soja T2,GL2]
GL3:    Move A,B
       Skipe Echo
         PBOUT
GL4:    Cail T2,IBufln*5
         Jrst GL2
       Idpb B,T4
       Aoj T2,
       Caie B,^M
         Jrst GL2

GLnulp: Caie T2,1       ;Ignore blank lines.
         Jrst GLF
       Skipe Echo
         Call Terpri
       Jrst FillIB

GLF:    Idpb T4         ;Store the final 0 to make string ASCIZ
       Move B,[440700,,InBuf]
       Movem B,pInbuf
       Return

Getwrd: Setzm IStrin                    ;Reads one word (terminated by
       Move A,[IStrin,,IStrin+1]       ;a blank, tab, or CR), parses
       BLT A,IVal                      ;it, and sets flags.  If INUMp
       Setz T2,                        ;is true, it's a number, whose
       Move T4,[440700,,IStrin]        ;value is in IVAL.  If IADDR is
GWskip: Call Getchr                     ;nonzero, then it is the address
         Return                        ;in the Dictionary of the word.
       Caie K,40
         Cain K,^I
           Jrst GWskip
       Jrst GW3
GW2:    Call Getchr
         Jrst Check
GW3:    Caie K,40
         Cain K,^I
           Jrst Check
       Cain K,^M
         Jrst Check
       Cail T3,5*3     ;Only 15 characters are significant
         Jrst GW2
       Cail K,140
         Trz K,40
       Cail K,"0       ;if 0-9, or - in 1st place, or a ".", then ok.
         Caile K,"9
           Skipa
       Jrst GW4
       Cain K,"-
         Skipe T2
           Skipa
       Jrst GW4
       Caie K,".
         Setom NotNum
GW4:    Idpb K,T4       ;Store UPPERCASE
       Aoja T2,GW2

Check:  Skipn T2
         Return
       Move T1,[350700,,IStrin]
       Call StoN
         Jrst FCheck
       Movem T2,IVal
       Setom INump
       Jrst Popj1

FCheck: Skipe NotNum
         Jrst Search
       Move A,[440700,,IStrin]
       FLIN
         Jrst Search
       Movem B,IVal
       Setom INump
       Jrst Popj1

Search: Movei T1,Dict
S1:     Move T4,IStrin
       Came T4,(T1)
         Jrst NFound
       Move T4,IStrin+1
       Came T4,1(T1)
         Jrst NFound
       Move T4,IStrin+2
       Came T4,2(T1)
         Jrst NFound
       Hrrzm T1,IAddr
       Jrst Popj1

NFound: Hlrz T2,3(T1)
       Skipn T2
         Jrst Popj1
       Add T1,T2
       Jrst S1

Eval:   Aos Level       ;The heart of FORTH.  EVAL is the creature that
       Skipn Trace     ;evaluates *things* - It either pushes constants,
         Jrst Eval1    ;calls subroutines (FORTH primitives), or EVALs
       Call Terpri     ;the body of a FORTH word.  Note than that EVAL
       Move C,Level    ;is, by nature, recursive.
       Jumpe C,ET1
       IMuli C,2
       Movei A,"=
       PBOUT
       Sojn C,.-1
ET1:    Movei A,">
       PBOUT

Eval1:  Came L,[-1]
         Jrst Eval2
       Move V,1(E)
       Call 4SAVE
       Skipn Trace
         Aoja E,EExit
       Type " Constant"
       Call SDump
       Aoja E,EExit

Eval2:  Skipl L
         Jrst Eval3
       Skipe Trace
         Jrst [Movei A,40
               PBOUT
               Call PFind
               Hrli V,350700
               Call 7TLoop
               Jrst .+1]
       Call (L)                ; -1,,Subroutine
       Skipe Trace
         Call SDump
       Jrst EExit

Eval3:  Hrrz T1,L       ;T1 = Dict Addr
       Push P,E
       Hrrz E,3(T1)    ;Code field
       Movei B,4(T1)
       Movem B,BStart
       Skipn Trace
         Jrst Eval5
       Movei A,40
       PBOUT
       Move V,T1
       Hrli V,350700
       Call 7TLoop
       Call SDump

Eval5:  Skipe Did
         Jrst EExitd
       Move L,(E)
       Jumpe L,EExit1
       Call Eval               ;Recurse!
       Aoja E,Eval5

EExitd: Setzm Did
EExit1: Pop P,E
EExit:  Sos Level
       Return


MHead:  Call Getwrd             ;This starts a Dictionary entry by filling
         Call Refill           ;in the name field, and reserving 1 more.
       Skipe INump
         Jrst [Type " ?Numeric name field"
               Jrst Erret]
       Skipe IAddr
         Jrst [Type " ?Already defined"
               Jrst Erret]
       Movei D,2
MH2:    Move T2,IStrin(D)
       Movem T2,@Dicte
       Sojge D,MH2
       Movei D,3
       Movei A,1
       Movem A,@Dicte
       Return

sText:  Call Getchr             ;This reads text from the input buffer
         Call Refill           ;(delimited by 1st character) and stores
       Movem K,Delim           ;them using T1 as the BP.  It saves the
sTextd: Hrli T1,440700          ;# of chars read in LSTEXT
       Setzm lsText
BTLoop: Call Getchr
         Call Refill
       Camn K,Delim
         Jrst BTdone
       Idpb K,T1
       Aos lsText
       Jrst BTLoop
BTdone: Idpb T1         ;Make asciz
       Return

BText:  Skipn Making            ;Used for ." and so on while building
         Jrst Buierr           ;to save the text in the Dictionary entry.
       Move T1,Dicte
       Aoj D,
       Add T1,D
       Call sText
       Move T2,lsText
       Idivi T2,5
       Add D,T2
       Return

PFind:  Movei V,Dict+3          ;This finds the address of the primitive
PFind1: Hrre A,(V)              ;whose machine address we know (L)
       Jumpg A,[Setz V,
                Return]
       Came L,1(V)
         Jrst [Hlrz B,(V)
               Add V,B
               Jrst PFind1]
       Subi V,3
       Return

SDump:  Call Terpri                     ;This dumps the top 10. numbers
       Type "[ "                       ;on the stack for TRACEing.  TOS
       Jumpe U,[Type "Nil ] "          ;is to the right.
               Return]
       Move C,U
       Soj C,
       Caig C,10.
         Jrst SDump1
       Type "... "
       Movei C,10.
SDump1: Move V,S
       Sub V,C
       Move V,(V)
       Call Dota
       Sojge C,SDump1
       Type "] "
       Return

StoN:   Setzb A,B               ;This is the String-to-Number routine.  It
       Setzb T3,StoNmp         ;expects a BP to the text in T1, and returns
SN1:    Ldb K,T1                ;(skipping) with T2 as the number, and T3
       Caie K,40               ;the number of character read.
         Cain K,^I
           Aoja T3,SN1
       Skipa
SN2:    Ldb K,T1
       Aoj A,
       Caie K,40       ;String ends on "," or <space> or <cr>
         Cain K,^M     ;or a 0-byte
           Jrst SNtest
       Caie K,",
         Skipn K
           Jrst SNtest
       Cain K,"-
         Caie A,1
           Jrst SN3
       Setom StoNmp
       Ibp T1
       Jrst SN2
SN3:    Subi K,60
       Skipge K
         Jrst SNbad
       Caml K,Base
         Jrst SNbad
       Push P,K
       Ibp T1
       Aoja B,SN2

SNtest: Jumpe B,SNbad
       Setz T2,
       Movei T4,1
SNgood: Pop P,K
       Imul K,T4
       Imul T4,Base
       Add T2,K
       Sojn B,SNgood
SNg2:   Skipe StoNmp
         Movns T2
       Add T3,A
       Jrst Popj1

SNbad:  Skipn B
         Return
       Pop P,K
       Soja B,SNbad

Lose:   Type "--Severe lossage--Dying--"
Die:    HALTF
       Jrst .-1

;;;
;;;     The End
;;;

Variables
Constants

       END Start