+ EXIT], flags=F_IMMED)
+
+IMMEDIATE = defPrimWord("IMMEDIATE", () -> begin
+ lenAndFlagsAddr = mem[LATEST] + 1
+ mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_IMMED
+ return NEXT
+end, flags=F_IMMED)
+
+TICK = defWord("'",
+ [WORD, FIND, TOCFA, EXIT])
+
+BTICK = defWord("[']",
+ [FROMR, DUP, INCR, TOR, FETCH, EXIT])
+
+# CREATE and DOES>
+
+CREATE = defWord("CREATE",
+ [WORD,
+ HEADER,
+ LIT, DOVAR, COMMA, EXIT]);
+
+DODOES = defPrim(() -> begin
+ pushRS(reg.IP)
+ reg.IP = reg.W + 1
+ return NEXT
+end, name="DOCOL")
+
+defConst("DODOES", DODOES)
+
+FROMDOES_PAREN = defWord("(DOES>)",
+ [DODOES, LATEST, FETCH, TOCFA, STORE, EXIT])
+
+FROMDOES = defWord("DOES>",
+ [BTICK, FROMDOES_PAREN, COMMA, BTICK, EXIT, COMMA,
+ BTICK, LIT, COMMA, LATEST, FETCH, TODFA, COMMA], flags=F_IMMED)
+
+
+# Strings
+
+LITSTRING = defPrimWord("LITSTRING", () -> begin
+ len = mem[reg.IP]
+ reg.IP += 1
+ pushPS(reg.IP)
+ pushPS(len)
+ reg.IP += len
+
+ return NEXT
+end)
+
+TELL = defPrimWord("TELL", () -> begin
+ len = popPS()
+ addr = popPS()
+ str = getString(addr, len)
+ print(str)
+ return NEXT
+end)
+
+# Outer interpreter
+
+EXECUTE = defPrimWord("EXECUTE", () -> begin
+ reg.W = popPS()
+ return mem[reg.W]
+end)
+
+type ParseError <: Exception
+ wordName::ASCIIString
+end
+Base.showerror(io::IO, ex::ParseError) = print(io, "Parse error at word: '$(ex.wordName)'.")
+
+DEBUG, DEBUG_CFA = defNewVar("DEBUG", 0)
+
+INTERPRET = defPrimWord("INTERPRET", () -> begin
+
+ callPrim(mem[WORD])
+
+ wordName = getString(mem[reg.PSP-1], mem[reg.PSP])
+ if mem[DEBUG] != 0
+ println("... ", replace(replace(wordName, "\004", "EOF"), "\n", "\\n"), " ...")
+ end
+
+ callPrim(mem[TWODUP])
+ callPrim(mem[FIND])
+
+ wordAddr = mem[reg.PSP]
+
+ if wordAddr>0
+ # Word in dictionary
+
+ isImmediate = (mem[wordAddr+1] & F_IMMED) != 0
+ callPrim(mem[TOCFA])
+
+ callPrim(mem[NROT]) # get rid of extra copy of word string details
+ popPS()
+ popPS()
+
+ if mem[STATE] == 0 || isImmediate
+ # Execute!
+ return callPrim(mem[EXECUTE])
+ else
+ # Append CFA to dictionary
+ callPrim(mem[COMMA])
+ end
+ else
+ # Not in dictionary, assume number
+
+ popPS()
+
+ callPrim(mem[NUMBER])
+
+ if popPS() != 0
+ throw(ParseError(wordName))
+ end
+
+ if mem[STATE] == 0
+ # Number already on stack!
+ else
+ # Append literal to dictionary
+ pushPS(LIT)
+ callPrim(mem[COMMA])
+ callPrim(mem[COMMA])
+ end
+ end
+
+ return NEXT
+end)
+
+QUIT = defWord("QUIT",
+ [RSP0_CFA, RSPSTORE,
+ INTERPRET,
+ BRANCH,-2])
+
+BYE = defPrimWord("BYE", () -> begin
+ return 0
+end)
+
+PROMPT = defPrimWord("PROMPT", () -> begin
+ println(" ok")
+end)
+
+NL = defPrimWord("\n", () -> begin
+ if mem[STATE] == 0 && currentSource() == STDIN
+ callPrim(mem[PROMPT])
+ end
+ return NEXT
+end, flags=F_IMMED)
+
+INCLUDE = defPrimWord("INCLUDE", () -> begin
+ callPrim(mem[WORD])
+ wordLen = popPS()
+ wordAddr = popPS()
+ word = getString(wordAddr, wordLen)
+
+ push!(sources, open(word, "r"))
+
+ # Clear input buffer
+ mem[NUMTIB] = 0
+
+ return NEXT
+end)
+
+EOF_WORD = defPrimWord("\x04", () -> begin
+ if currentSource() != STDIN
+ close(currentSource())
+ end
+
+ pop!(sources)
+
+ if length(sources)>0
+ if currentSource() == STDIN
+ callPrim(mem[PROMPT])
+ end
+
+ return NEXT
+ else
+ return 0
+ end
+end, flags=F_IMMED)
+
+# Odds and Ends
+
+CHAR = defPrimWord("CHAR", () -> begin
+ callPrim(mem[WORD])
+ wordLen = popPS()
+ wordAddr = popPS()
+ word = getString(wordAddr, wordLen)
+ pushPS(Int64(word[1]))
+
+ return NEXT
+end)
+
+initialized = false
+initFileName = nothing
+if isfile("lib.4th")
+ initFileName = "lib.4th"
+elseif isfile(Pkg.dir("forth/src/lib.4th"))
+ initFileName = Pkg.dir("forth/src/lib.4th")
+end
+