# Stack manipulation functions
-type StackUnderflow <: Exception end
+type ParamStackUnderflow <: Exception end
+type ReturnStackUnderflow <: Exception end
+
+Base.showerror(io::IO, ex::ParamStackUnderflow) = print(io, "Parameter stack underflow.")
+Base.showerror(io::IO, ex::ReturnStackUnderflow) = print(io, "Return stack underflow.")
getRSDepth() = reg.RSP - mem[RSP0]
getPSDepth() = reg.PSP - mem[PSP0]
function ensurePSDepth(depth::Int64)
if getPSDepth()<depth
- throw(StackUnderflow())
+ throw(ParamStackUnderflow())
end
end
function ensureRSDepth(depth::Int64)
if getRSDepth()<depth
- throw(StackUnderflow())
+ throw(ReturnStackUnderflow())
end
end
return NEXT
end)
-ROT = defPrimWord("ROT", () -> begin
+NROT = defPrimWord("-ROT", () -> begin
a = popPS()
b = popPS()
c = popPS()
+ pushPS(b)
pushPS(a)
pushPS(c)
- pushPS(b)
return NEXT
end)
-NROT = defPrimWord("-ROT", () -> begin
+ROT = defPrimWord("ROT", () -> begin
a = popPS()
b = popPS()
c = popPS()
- pushPS(b)
pushPS(a)
pushPS(c)
+ pushPS(b)
return NEXT
end)
+
TWODROP = defPrimWord("2DROP", () -> begin
popPS()
popPS()
return NEXT
end)
+TWOMUL = defPrimWord("2*", () -> begin
+ pushPS(popPS() << 1)
+ return NEXT
+end)
+
+TWODIV = defPrimWord("2/", () -> begin
+ pushPS(popPS() >> 1)
+ return NEXT
+end)
+
EQU = defPrimWord("=", () -> begin
b = popPS()
a = popPS()
return NEXT
end)
+RFETCH = defPrimWord("R@", () -> begin
+ pushPS(mem[reg.RSP])
+ return NEXT
+end)
+
RSPFETCH = defPrimWord("RSP@", () -> begin
pushPS(reg.RSP)
return NEXT
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])
- #println("... ", replace(replace(wordName, "\004", "EOF"), "\n", "\\n"), " ...")
+ if mem[DEBUG] != 0
+ println("... ", replace(replace(wordName, "\004", "EOF"), "\n", "\\n"), " ...")
+ end
callPrim(mem[TWODUP])
callPrim(mem[FIND])
callPrim(mem[NUMBER])
if popPS() != 0
- println("Parse error at word: '$wordName'")
- return NEXT
+ throw(ParseError(wordName))
end
if mem[STATE] == 0
return 0
end)
+PROMPT = defPrimWord("PROMPT", () -> begin
+ println(" ok")
+end)
+
NL = defPrimWord("\n", () -> begin
if mem[STATE] == 0 && currentSource() == STDIN
- println(" ok")
+ callPrim(mem[PROMPT])
end
return NEXT
end, flags=F_IMMED)
pop!(sources)
if length(sources)>0
+ if currentSource() == STDIN
+ callPrim(mem[PROMPT])
+ end
+
return NEXT
else
return 0
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
+
+
#### VM loop ####
-function run()
+function run(;initialize=true)
# Begin with STDIN as source
push!(sources, STDIN)
+ global initialized, initFileName
+ if !initialized && initialize
+ if initFileName != nothing
+ print("Including definitions from $initFileName...")
+ push!(sources, open(initFileName, "r"))
+ initialized = true
+ else
+ println("No library file found. Only primitive words available.")
+ end
+ end
+
# Start with IP pointing to first instruction of outer interpreter
reg.IP = QUIT + 1
jmp = NEXT
while jmp != 0
try
- #println("Evaluating prim ", jmp," ", primNames[-jmp])
+ if mem[DEBUG] != 0
+ println("Evaluating prim ", jmp," ", primNames[-jmp])
+ end
+
jmp = callPrim(jmp)
catch ex
- if isa(ex, StackUnderflow)
- println("Stack underflow!")
+ showerror(STDOUT, ex)
+ println()
- mem[NUMTIB] = 0
- reg.IP = QUIT + 1
- jmp = NEXT
- else
- rethrow(ex)
+ while !isempty(sources) && currentSource() != STDIN
+ close(pop!(sources))
end
+
+ mem[STATE] = 0
+ mem[NUMTIB] = 0
+ reg.IP = QUIT + 1
+ jmp = NEXT
end
end
end
end
end
-DOT = defPrimWord(".", () -> begin
- print(popPS())
- return NEXT
-end)
-
-DOTS = defPrimWord(".s", () -> begin
- printPS()
- return NEXT
-end)
-
DUMP = defPrimWord("DUMP", () -> begin
count = popPS()
addr = popPS()