Updated run() to call new INCLUDED word.
[forth.jl.git] / src / forth.jl
index 628f379..37c41ec 100644 (file)
@@ -99,6 +99,10 @@ end
 
 getString(addr::Int64, len::Int64) = AbstractString([Char(c) for c in mem[addr:(addr+len-1)]])
 
+function putString(str::AbstractString, addr::Int64)
+    mem[addr:(addr+length(str)-1)] = [Int64(c) for c in str]
+end
+
 function putString(str::AbstractString, addr::Int64, maxLen::Int64)
     len = min(length(str), maxLen)
     mem[addr:(addr+len-1)] = [Int64(c) for c in str]
@@ -604,7 +608,6 @@ end)
 
 openFiles = Dict{Int64,IOStream}()
 nextFileID = 1
-SOURCE_ID, SOURCE_ID_CFA = defNewVar("SOURCE-ID", 0)
 
 
 ## File access modes
@@ -666,6 +669,22 @@ CLOSE_FILES_CFA = defPrimWord("CLOSE-FILES", () -> begin
 end)
 
 READ_LINE_CFA = defPrimWord("READ-LINE", () -> begin
+    fid = popPS()
+    maxSize = popPS()
+    addr = popPS()
+
+    fh = openFiles[fid]
+    line = readline(fh)
+
+    eofFlag = endswith(line, '\n') ? 0 : -1
+    line = chomp(line)
+
+    putString(line, addr, maxSize)
+
+    pushPS(length(line))
+    pushPS(eofFlag)
+    pushPS(0)
+
     return NEXT
 end)
 
@@ -945,12 +964,27 @@ NUMFIB, NUMFIB_CFA = defNewVar("#FIB", 0)
 
 TOIN, TOIN_CFA = defNewVar(">IN", 0)
 
+SOURCE_ID, SOURCE_ID_CFA = defNewVar("SOURCE-ID", 0)
+
+SOURCE_CFA = defPrimWord("SOURCE", () -> begin
+    if mem[SOURCE_ID] == 0
+        pushPS(TIB)
+        pushPS(NUMTIB)
+    else
+        pushPS(FIB)
+        pushPS(NUMFIB)
+    end
+    return NEXT
+end)
+
 QUERY_CFA = defWord("QUERY",
     [TIB_CFA, LIT_CFA, 160, EXPECT_CFA,
     SPAN_CFA, FETCH_CFA, NUMTIB_CFA, STORE_CFA,
     LIT_CFA, 0, TOIN_CFA, STORE_CFA,
     EXIT_CFA])
 
+# ( fid -- flag )
+# Flag is false when EOF is reached.
 QUERY_FILE_CFA = defWord("QUERY-FILE",
     [FIB_CFA, LIT_CFA, 160, ROT_CFA, READ_LINE_CFA,
     DROP_CFA, SWAP_CFA,
@@ -960,13 +994,9 @@ QUERY_FILE_CFA = defWord("QUERY-FILE",
 WORD_CFA = defPrimWord("WORD", () -> begin
     delim = popPS()
 
-    if mem[SOURCE_ID] == 0
-        bufferAddr = TIB
-        sizeAddr = NUMTIB
-    else
-        bufferAddr = FIB
-        sizeAddr = NUMFIB
-    end
+    callPrim(mem[SOURCE_CFA])
+    sizeAddr = popPS()
+    bufferAddr = popPS()
 
     # Chew up initial occurrences of delim
     while (mem[TOIN]<mem[sizeAddr] && mem[bufferAddr+mem[TOIN]] == delim)
@@ -1140,7 +1170,7 @@ 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
+        DROP_CFA, EXIT_CFA, # Exit if input buffer is exhausted
 
     STATE_CFA, FETCH_CFA, ZBRANCH_CFA, 24,
         # Compiling
@@ -1185,6 +1215,18 @@ QUIT_CFA = defWord("QUIT",
     INTERPRET_CFA, PROMPT_CFA,
     BRANCH_CFA,-4])
 
+INCLUDED_CFA = defWord("INCLUDED",
+    [SOURCE_ID_CFA, FETCH_CFA, TOR_CFA, # Store current source on return stack
+    FAM_RO_CFA, OPEN_FILE_CFA, DROP_CFA, # Open the file named by this word.
+    DUP_CFA, SOURCE_ID_CFA, STORE_CFA, # Mark this as the current source
+    DUP_CFA, QUERY_FILE_CFA, # Read line from file
+    INTERPRET_CFA,
+    INVERT_CFA, ZBRANCH_CFA, -5,
+    DROP_CFA, EXIT_CFA])
+
+INCLUDE_CFA = defWord("INCLUDE", [LIT_CFA, 32, WORD_CFA, INCLUDED_CFA]);
+
+
 ABORT_CFA = defWord("ABORT",
     [CLOSE_FILES_CFA, PSP0_CFA, PSPSTORE_CFA, QUIT_CFA])
 
@@ -1193,6 +1235,10 @@ BYE_CFA = defPrimWord("BYE", () -> begin
     return 0
 end)
 
+EOF_CFA = defPrimWord("\x04", () -> begin
+    return 0
+end)
+
 #### VM loop ####
 
 initialized = false
@@ -1205,6 +1251,10 @@ end
 
 function run(;initialize=true)
 
+    # Start with IP pointing to first instruction of outer interpreter
+    pushRS(QUIT_CFA+1)
+
+    # Load library files
     global initialized, initFileName
     if !initialized && initialize
         if initFileName != nothing
@@ -1218,12 +1268,10 @@ function run(;initialize=true)
         end
     end
 
-    # Start with IP pointing to first instruction of outer interpreter
-    reg.IP = QUIT_CFA + 1
 
     # Primitive processing loop.
     # Everyting else is simply a consequence of this loop!
-    jmp = NEXT
+    jmp = mem[EXIT_CFA]
     while jmp != 0
         try
             #println("Entering prim $(getPrimName(jmp))")