+
+BYE_CFA = defPrimWord("BYE", () -> begin
+ println("\nBye!")
+ return 0
+end)
+
+STATE, STATE_CFA = defNewVar("STATE", 0)
+
+INTERPRET_CFA = defWord("INTERPRET",
+ [LIT_CFA, 32, WORD_CFA, # Read next space-delimited word
+
+ DUP_CFA, FETCH_CFA, ZE_CFA, ZBRANCH_CFA, 3,
+ DROP_CFA, EXIT_CFA, # Exit if TIB is exhausted
+
+ STATE_CFA, FETCH_CFA, ZBRANCH_CFA, 24,
+ # Compiling
+ FIND_CFA, QDUP_CFA, ZBRANCH_CFA, 13,
+
+ # Found word.
+ LIT_CFA, -1, EQ_CFA, INVERT_CFA, ZBRANCH_CFA, 4,
+
+ # Immediate: Execute!
+ EXECUTE_CFA, BRANCH_CFA, -26,
+
+ # Not immediate: Compile!
+ COMMA_CFA, BRANCH_CFA, -29,
+
+ # No word found, parse number
+ NUMBER_CFA, BTICK_CFA, LIT_CFA, COMMA_CFA, COMMA_CFA, BRANCH_CFA, -36,
+
+ # Interpreting
+ FIND_CFA, QDUP_CFA, ZBRANCH_CFA, 5,
+
+ # Found word. Execute!
+ DROP_CFA, EXECUTE_CFA, BRANCH_CFA, -44,
+
+ # No word found, parse number and leave on stack
+ NUMBER_CFA, BRANCH_CFA, -47,
+ EXIT_CFA])
+
+PROMPT_CFA = defPrimWord("PROMPT", () -> begin
+ if (mem[STATE] == 0 && currentSource() == STDIN)
+ println(" ok")
+ end
+
+ return NEXT
+end)
+
+QUIT_CFA = defWord("QUIT",
+ [LIT_CFA, 0, STATE_CFA, STORE_CFA,
+ LIT_CFA, 0, NUMTIB_CFA, STORE_CFA,
+ RSP0_CFA, RSPSTORE_CFA,
+ QUERY_CFA,
+ INTERPRET_CFA, PROMPT_CFA,
+ BRANCH_CFA,-4])
+
+ABORT_CFA = defWord("ABORT",
+ [PSP0_CFA, PSPSTORE_CFA, QUIT_CFA])
+
+INCLUDE_CFA = defPrimWord("INCLUDE", () -> begin
+ pushPS(32)
+ callPrim(mem[WORD_CFA])
+ wordAddr = popPS()+1
+ wordLen = mem[wordAddr-1]
+ word = getString(wordAddr, wordLen)
+
+ push!(sources, open(word, "r"))
+
+ # Clear input buffer
+ mem[NUMTIB] = 0
+
+ return NEXT
+end)
+
+# Compilation
+
+HERE_CFA = defWord("HERE",
+ [H_CFA, FETCH_CFA, EXIT_CFA])
+
+HEADER_CFA = defPrimWord("HEADER", () -> begin
+ wordAddr = popPS()+1
+ wordLen = mem[wordAddr-1]
+ word = getString(wordAddr, wordLen)
+
+ createHeader(word, 0)
+
+ return NEXT
+end)
+
+CREATE_CFA = defWord("CREATE",
+ [LIT_CFA, 32, WORD_CFA, HEADER_CFA,
+ LIT_CFA, DOVAR, COMMA_CFA,
+ EXIT_CFA])
+
+DODOES = defPrim(() -> begin
+ pushRS(reg.IP)
+ reg.IP = popPS()
+ pushPS(reg.W + 1)
+ return NEXT
+end, name="DODOES")
+
+DOES_HELPER_CFA = defPrimWord("(DOES>)", () -> begin
+
+ pushPS(mem[LATEST])
+ callPrim(mem[TOCFA_CFA])
+ cfa = popPS()
+
+ runtimeAddr = popPS()
+
+ mem[cfa] = defPrim(eval(:(() -> begin
+ pushPS($(runtimeAddr))
+ return DODOES
+ end)), name="doesPrim")
+
+ return NEXT
+end, flags=F_IMMED)
+
+DOES_CFA = defWord("DOES>",
+ [BTICK_CFA, LIT_CFA, COMMA_CFA, HERE_CFA, LIT_CFA, 3, ADD_CFA, COMMA_CFA,
+ BTICK_CFA, DOES_HELPER_CFA, COMMA_CFA, BTICK_CFA, EXIT_CFA, COMMA_CFA, EXIT_CFA],
+ flags=F_IMMED)
+
+LBRAC_CFA = defPrimWord("[", () -> begin
+ mem[STATE] = 0
+ return NEXT
+end, flags=F_IMMED)
+
+RBRAC_CFA = defPrimWord("]", () -> begin
+ mem[STATE] = 1
+ return NEXT
+end, flags=F_IMMED)
+
+HIDDEN_CFA = defPrimWord("HIDDEN", () -> begin
+ lenAndFlagsAddr = mem[LATEST] + 1
+ mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_HIDDEN
+ return NEXT
+end)
+
+COLON_CFA = defWord(":",
+ [LIT_CFA, 32, WORD_CFA,
+ HEADER_CFA,
+ LIT_CFA, DOCOL, COMMA_CFA,
+ HIDDEN_CFA,
+ RBRAC_CFA,
+ EXIT_CFA])
+
+SEMICOLON_CFA = defWord(";",
+ [LIT_CFA, EXIT_CFA, COMMA_CFA,
+ HIDDEN_CFA,
+ LBRAC_CFA,
+ EXIT_CFA], flags=F_IMMED)
+
+IMMEDIATE_CFA = defPrimWord("IMMEDIATE", () -> begin
+ lenAndFlagsAddr = mem[LATEST] + 1
+ mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_IMMED
+ return NEXT
+end, flags=F_IMMED)
+
+