module forth
-import Base.REPLCompletions
+import Base.REPLCompletions, Base.invokelatest
# VM mem size
size_mem = 1000000 # 1 mega-int
# Handy functions for adding/retrieving strings to/from memory.
-getString(addr::Int64, len::Int64) = AbstractString([Char(c) for c in mem[addr:(addr+len-1)]])
+getString(addr::Int64, len::Int64) = String([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]
if addr >=0 || -addr>length(primitives)
error("Attempted to execute non-existent primitive at address $addr.")
else
- primitives[-addr]()
+ invokelatest(primitives[-addr])
end
end
getPrimName(addr::Int64) = primNames[-addr]
XOR_CFA = defPrimWord("XOR", () -> begin
b = popPS()
a = popPS()
- pushPS(a $ b)
+ pushPS(xor(a, b))
return NEXT
end)
addr = popPS()
fh = openFiles[fid]
- line = readline(fh)
+ line = readline(fh, chomp=false)
eofFlag = endswith(line, '\n') ? 0 : -1
line = chomp(line)
- #println("Reading: $line");
-
putString(line, addr, maxSize)
pushPS(length(line))
return NEXT
end)
+READ_FILE_CFA = defPrimWord("READ-FILE", () -> begin
+ fid = popPS()
+ size = popPS()
+ addr = popPS()
+
+ fh = openFiles[fid]
+
+ string = join(map(x -> Char(x), read(fh, size)), "")
+
+ eofFlag = length(string) == size ? 0 : -1 ;
+
+ putString(string, addr, length(string))
+
+ pushPS(length(string))
+ pushPS(eofFlag)
+
+ return NEXT
+end)
+
EMIT_CFA = defPrimWord("EMIT", () -> begin
print(Char(popPS()))
function getKey()
raw_mode!(true)
- byte = readbytes(STDIN, 1)[1]
+ byte = read(STDIN, 1)[1]
raw_mode!(false)
if byte == 0x0d
if key == '\n'
print(" ")
- return AbstractString(line)
+ return String(line)
elseif key == '\x04'
if isempty(line)
HIDDEN_CFA = defPrimWord("HIDDEN", () -> begin
lenAndFlagsAddr = mem[mem[CURRENT]+1] + 1
- mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_HIDDEN
+ mem[lenAndFlagsAddr] = xor(mem[lenAndFlagsAddr], F_HIDDEN)
return NEXT
end)
IMMEDIATE_CFA = defPrimWord("IMMEDIATE", () -> begin
lenAndFlagsAddr = mem[mem[CURRENT]+1] + 1
- mem[lenAndFlagsAddr] = mem[lenAndFlagsAddr] $ F_IMMED
+ mem[lenAndFlagsAddr] = xor(mem[lenAndFlagsAddr], F_IMMED)
return NEXT
end, flags=F_IMMED)
getString(addr, len), "\n",
"return NEXT\n",
"end")
- func = eval(parse(expString))
+ func = eval(parse(exprString))
pushPS(defPrim(func))
return NEXT
SWAP_CFA, FETCH_CFA,
INCLUDED_CFA, EXIT_CFA]);
+ABORT_CFA = defWord("ABORT",
+ [CLOSE_FILES_CFA, DROP_CFA, PSP0_CFA, PSPSTORE_CFA, QUIT_CFA])
+
+BYE_CFA = defPrimWord("BYE", () -> begin
+ if mem[SOURCE_ID_VAR] == 0
+ println("\nBye!")
+ end
+ return 0
+end)
+
+EOF_CFA = defPrimWord("\x04", () -> begin
+ return 0
+end)
+
+### Library loading ###
+
oldCWD = ""
SETLIBCWD_CFA = defPrimWord("SETLIBCWD", () -> begin
global oldCWD = pwd()
SWAP_CFA, FETCH_CFA,
INCLUDED_LIB_CFA, EXIT_CFA]);
-ABORT_CFA = defWord("ABORT",
- [CLOSE_FILES_CFA, DROP_CFA, PSP0_CFA, PSPSTORE_CFA, QUIT_CFA])
-
-BYE_CFA = defPrimWord("BYE", () -> begin
- println("\nBye!")
- return 0
-end)
-
-EOF_CFA = defPrimWord("\x04", () -> begin
- return 0
-end)
+SKIP_WELCOME, SKIP_WELCOME_CFA = defNewVar("SKIP-WELCOME", 0)
#### VM loop ####
initialized = false
-initFileName = "lib.4th"
+libFileName = "lib.4th"
-function run(;initialize=true)
+function run(fileName=nothing; initialize=true)
# Start with IP pointing to first instruction of outer interpreter
pushRS(QUIT_CFA+1)
+ # Include optional file
+ if fileName != nothing
+ putString(fileName, mem[H])
+ pushPS(mem[H])
+ mem[H] += length(fileName)
+ pushPS(length(fileName))
+ pushRS(INCLUDED_CFA+1)
+
+ mem[SKIP_WELCOME] = -1
+ end
+
# Load library files
- global initialized, initFileName
+ global initialized, libFileName
if !initialized && initialize
- if initFileName != nothing
- print("Including definitions from $initFileName...")
+ if libFileName != nothing
+ #print("Including definitions from $libFileName...")
- putString(initFileName, mem[H])
+ putString(libFileName, mem[H])
pushPS(mem[H])
- pushPS(length(initFileName))
+ pushPS(length(libFileName))
pushRS(INCLUDED_LIB_CFA+1)
initialized = true
i += 1
end
- println("\t", AbstractString(chars))
+ println("\t", String(chars))
end
end