Implemented ABORT".
[forth.jl.git] / src / forth.jl
index 8cc7547..f10ea04 100644 (file)
@@ -13,19 +13,19 @@ mem = Array{Int64,1}(size_mem)
 primitives = Array{Function,1}()
 primNames = Array{ASCIIString,1}()
 
-# Built-in variables
+# Memory geography and built-in variables
 
 nextVarAddr = 1
-H = nextVarAddr; nextVarAddr += 1       # Next free memory address
-FORTH = nextVarAddr; nextVarAddr += 1   # LFA of latest word in system dict
-CURRENT = nextVarAddr; nextVarAddr += 1 # Current compilation dict
+H = nextVarAddr; nextVarAddr += 1              # Next free memory address
+FORTH_LATEST = nextVarAddr; nextVarAddr += 1   # FORTH dict latest
+CURRENT = nextVarAddr; nextVarAddr += 1        # Current compilation dict
 
 RSP0 = nextVarAddr                  # bottom of RS
 PSP0 = RSP0 + size_RS               # bottom of PS
 TIB = PSP0 + size_PS                # address of terminal input buffer
 mem[H] = TIB + size_TIB             # location of bottom of dictionary
-mem[FORTH] = 0                      # no previous definition
-mem[CURRENT] = FORTH                # Compile words to system dict initially
+mem[FORTH_LATEST] = 0               # zero FORTH dict latest (no previous def)
+mem[CURRENT] = FORTH_LATEST-1       # Compile words to system dict initially
 
 DICT = mem[H] # Save bottom of dictionary as constant
 
@@ -84,6 +84,8 @@ function putString(str::ASCIIString, addr::Int64)
     mem[addr:(addr+length(str)-1)] = [Int64(c) for c in str]
 end
 
+stringAsInts(str::ASCIIString) = [Int(c) for c in collect(str)]
+
 # Primitive creation and calling functions
 
 function defPrim(f::Function; name="nameless")
@@ -109,21 +111,27 @@ F_IMMED = 32
 F_HIDDEN = 64
 NFA_MARK = 128
 
+function dictWrite(ints::Array{Int64,1})
+    mem[mem[H]:(mem[H]+length(ints)-1)] = ints
+    mem[H] += length(ints)
+end
+dictWrite(int::Int64) = dictWrite([int])
+dictWriteString(string::ASCIIString) = dictWrite([Int64(c) for c in string])
+
 function createHeader(name::AbstractString, flags::Int64)
-    mem[mem[H]] = mem[mem[CURRENT]]
-    mem[mem[CURRENT]] = mem[H]
+    mem[mem[H]] = mem[mem[CURRENT]+1]
+    mem[mem[CURRENT]+1] = mem[H]
     mem[H] += 1
 
-    mem[mem[H]] = length(name) | flags | NFA_MARK; mem[H] += 1
-    putString(name, mem[H]); mem[H] += length(name)
+    dictWrite(length(name) | flags | NFA_MARK)
+    dictWriteString(name)
 end
 
 function defPrimWord(name::AbstractString, f::Function; flags::Int64=0)
     createHeader(name, flags)
 
     codeWordAddr = mem[H]
-    mem[codeWordAddr] = defPrim(f, name=name)
-    mem[H] += 1
+    dictWrite(defPrim(f, name=name))
 
     return codeWordAddr
 end
@@ -132,13 +140,9 @@ function defWord(name::AbstractString, wordAddrs::Array{Int64,1}; flags::Int64=0
     createHeader(name, flags)
 
     addr = mem[H]
-    mem[mem[H]] = DOCOL
-    mem[H] += 1
+    dictWrite(DOCOL)
 
-    for wordAddr in wordAddrs
-        mem[mem[H]] = wordAddr
-        mem[H] += 1
-    end
+    dictWrite(wordAddrs)
 
     return addr
 end
@@ -159,8 +163,8 @@ function defNewVar(name::AbstractString, initial::Array{Int64,1}; flags::Int64=0
     codeWordAddr = mem[H]
     varAddr = mem[H] + 1
 
-    mem[mem[H]] = DOVAR; mem[H] += 1
-    mem[mem[H]:(mem[H]+length(initial)-1)] = initial; mem[H] += length(initial)
+    dictWrite(DOVAR)
+    dictWrite(initial)
 
     return varAddr, codeWordAddr
 end
@@ -173,8 +177,8 @@ function defConst(name::AbstractString, val::Int64; flags::Int64=0)
 
     codeWordAddr = mem[H]
 
-    mem[mem[H]] = DOCON; mem[H] += 1
-    mem[mem[H]] = val; mem[H] += 1
+    dictWrite(DOCON)
+    dictWrite(val)
 
     return codeWordAddr
 end
@@ -211,8 +215,6 @@ end)
 # Dictionary entries for core built-in variables, constants
 
 H_CFA = defExistingVar("H", H)
-FORTH_CFA = defExistingVar("FORTH", FORTH)
-CURRENT_CFA = defExistingVar("CURRENT", CURRENT)
 
 PSP0_CFA = defConst("PSP0", PSP0)
 RSP0_CFA = defConst("RSP0", RSP0)
@@ -696,7 +698,7 @@ end)
 
 # Dictionary searches
 
-LFATOCFA_CFA = defPrimWord("LFA>CFA", () -> begin
+FROMLINK_CFA = defPrimWord("LINK>", () -> begin
 
     addr = popPS()
     lenAndFlags = mem[addr+1]
@@ -707,53 +709,56 @@ LFATOCFA_CFA = defPrimWord("LFA>CFA", () -> begin
     return NEXT
 end)
 
-TOBODY_CFA = defWord(">BODY", [INCR_CFA, EXIT_CFA])
-
-CONTEXT, CONTEXT_CFA = defNewVar("CONTEXT", zeros(Int64, 100))
-mem[CONTEXT] = FORTH_CFA
 NUMCONTEXT, NUMCONTEXT_CFA = defNewVar("#CONTEXT", 1)
 
-FIND_CFA = defPrimWord("FIND", () -> begin
+createHeader("FORTH", 0)
+FORTH_CFA = mem[H]
+dictWrite(defPrim(() -> begin
+    mem[CONTEXT + mem[NUMCONTEXT] - 1] = reg.W
+    return NEXT
+end, name="FORTH"))
+dictWrite(0) # cell for latest
 
+CURRENT_CFA = defExistingVar("CURRENT", CURRENT)
+
+# Switch to new FORTH vocabulary cfa
+mem[FORTH_CFA+1] = mem[mem[CURRENT]+1]
+mem[CURRENT] = FORTH_CFA
+
+CONTEXT, CONTEXT_CFA = defNewVar("CONTEXT", zeros(Int64, 10))
+mem[CONTEXT] = FORTH_CFA
+
+FINDVOCAB_CFA = defPrimWord("FINDVOCAB", () -> begin
+    vocabCFA = popPS()
     countedAddr = popPS()
+
     wordAddr = countedAddr + 1
     wordLen = mem[countedAddr]
     word = lowercase(getString(wordAddr, wordLen))
 
-    context = mem[CONTEXT:(CONTEXT+mem[NUMCONTEXT]-1)]
-
+    lfa = vocabCFA+1
     lenAndFlags = 0
-    lfa = 0
-
-    for vocabCFA in reverse(context)
-        callPrim(mem[vocabCFA])
-        lfa = popPS()
-
-        while (lfa = mem[lfa]) > 0
-
-            lenAndFlags = mem[lfa+1]
-            len = lenAndFlags & F_LENMASK
-            hidden = (lenAndFlags & F_HIDDEN) == F_HIDDEN
 
-            if hidden || len != wordLen
-                continue
-            end
+    while (lfa = mem[lfa]) > 0
 
-            thisWord = lowercase(getString(lfa+2, len))
+        lenAndFlags = mem[lfa+1]
+        len = lenAndFlags & F_LENMASK
+        hidden = (lenAndFlags & F_HIDDEN) == F_HIDDEN
 
-            if thisWord == word
-                break
-            end
+        if hidden || len != wordLen
+            continue
         end
 
-        if lfa>0
+        thisWord = lowercase(getString(lfa+2, len))
+
+        if thisWord == word
             break
         end
     end
 
     if lfa > 0
         pushPS(lfa)
-        callPrim(mem[LFATOCFA_CFA])
+        callPrim(mem[FROMLINK_CFA])
         if (lenAndFlags & F_IMMED) == F_IMMED
             pushPS(1)
         else
@@ -767,6 +772,31 @@ FIND_CFA = defPrimWord("FIND", () -> begin
     return NEXT
 end)
 
+FIND_CFA = defPrimWord("FIND", () -> begin
+
+    countedAddr = popPS()
+    context = mem[CONTEXT:(CONTEXT+mem[NUMCONTEXT]-1)]
+
+    for vocabCFA in reverse(context)
+        pushPS(countedAddr)
+        pushPS(vocabCFA)
+        callPrim(mem[FINDVOCAB_CFA])
+
+        callPrim(mem[DUP_CFA])
+        if popPS() != 0
+            return NEXT
+        else
+            popPS()
+            popPS()
+        end
+    end
+
+    pushPS(countedAddr)
+    pushPS(0)
+
+    return NEXT
+end)
+
 
 # Branching
 
@@ -887,8 +917,8 @@ end, name="DODOES")
 
 DOES_HELPER_CFA = defPrimWord("(DOES>)", () -> begin
 
-    pushPS(mem[mem[CURRENT]])
-    callPrim(mem[LFATOCFA_CFA])
+    pushPS(mem[mem[CURRENT]+1])
+    callPrim(mem[FROMLINK_CFA])
     cfa = popPS()
 
     runtimeAddr = popPS()
@@ -899,7 +929,7 @@ DOES_HELPER_CFA = defPrimWord("(DOES>)", () -> begin
     end)), name="doesPrim")
 
     return NEXT
-end, flags=F_IMMED)
+end, flags=F_IMMED | F_HIDDEN)
 
 DOES_CFA = defWord("DOES>",
     [LIT_CFA, LIT_CFA, COMMA_CFA, HERE_CFA, LIT_CFA, 3, ADD_CFA, COMMA_CFA,
@@ -917,7 +947,7 @@ RBRAC_CFA = defPrimWord("]", () -> begin
 end, flags=F_IMMED)
 
 HIDDEN_CFA = defPrimWord("HIDDEN", () -> begin
-    lenAndFlagsAddr = mem[mem[CURRENT]] + 1
+    lenAndFlagsAddr = mem[mem[CURRENT]+1] + 1
     mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_HIDDEN
     return NEXT
 end)
@@ -937,7 +967,7 @@ SEMICOLON_CFA = defWord(";",
     EXIT_CFA], flags=F_IMMED)
 
 IMMEDIATE_CFA = defPrimWord("IMMEDIATE", () -> begin
-    lenAndFlagsAddr = mem[mem[CURRENT]] + 1
+    lenAndFlagsAddr = mem[mem[CURRENT]+1] + 1
     mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_IMMED
     return NEXT
 end, flags=F_IMMED)
@@ -982,8 +1012,11 @@ INTERPRET_CFA = defWord("INTERPRET",
     EXIT_CFA])
 
 PROMPT_CFA = defPrimWord("PROMPT", () -> begin
-    if (mem[STATE] == 0 && currentSource() == STDIN)
-        println(" ok")
+    if currentSource() == STDIN
+        if mem[STATE] == 0
+            print(" ok")
+        end
+        println()
     end
 
     return NEXT