Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- The kernel of LForth: an inner interpreter, plus an outer -- interpreter implemented as a set of new states for the inner one. -- The inner interpreter - minimal, but very extensible. -- The data stack and the return stack: -- «.ds» (to "ds") -- «.rs» (to "rs") -- The "memory", implemented as a Lua array: -- «.mem» (to "mem") -- Functions to add primitives and Forth words to the `forths' dictionary: -- «.prim» (to "prim") -- «.compile» (to "compile") -- Dictionaries for the inner interpreter: heads and forths. -- «.heads» (to "heads") -- «.forths» (to "forths") -- The "inner" states of the inner interpreter. -- «.states.head» (to "states.head") -- «.states.forth» (to "states.forth") -- «.states.forthret» (to "states.forthret") -- The inner interpreter loop. -- «.innerloop» (to "innerloop") -- The standard way to invoke Forth functions or primitives... the -- tricky part is that the loop of the inner interpreter must stop -- looping when everything is done. -- «.invoke» (to "invoke") -- An extension to the inner interpreter: support for RSR words. -- «.ss» (to "ss") -- «.RSR» (to "RSR") -- «.rsrprim» (to "rsrprim") -- The outer interpreter. -- The basic parsing functions, and the array on which they operate. -- «.p» (to "p") -- «.p.parseluare» (to "p.parseluare") -- «.getword» (to "getword") -- «.getuntilluare» (to "getuntilluare") -- The outer interpreter is implemented as two new states for the -- inner interpreter. -- «.states.outer_interpreter» (to "states.outer_interpreter") -- «.states.outer_compiler» (to "states.outer_compiler") -- The outer interpreter's dictionaries: -- Words common to both the interpreter mode and the compiler mode, -- «.dict» (to "dict") -- Words specific to interpreter mode, -- «.dict_interpreter» (to "dict_interpreter") -- Words specific to compiler mode. -- «.dict_compiler» (to "dict_compiler") -- The standard way to invoke the outer interpreter on a piece of -- text, kind of like what `invoke' does for bytecodes. -- «.interpret» (to "interpret") -- (find-angg "LFORTH/outer.lua") -- (find-angg "LFORTH/README") -- «ds» (to ".ds") ds = {} dspush = function (v) table.insert(ds, 1, v); return v end dspop = function () return table.remove(ds, 1) end -- «rs» (to ".rs") rs = {} rspush = function (v) table.insert(rs, 1, v); return v end rspop = function () return table.remove(rs, 1) end -- «mem» (to ".mem") mem = {} mem.here = 0 mem.compile = function (...) for i = 1,table.getn(arg) do mem[mem.here] = arg[i] mem.here = mem.here + 1 end end -- «prim» (to ".prim") prim = function (name, fun) forths[name] = fun end -- «compile» (to ".compile") compile = function (name, ...) forths[name] = mem.here mem.compile(unpack(arg)) end -- «heads» (to ".heads") heads = {} heads["h_forth"] = function () state = states.forth end -- «forths» (to ".forths") forths = {} forths["exit"] = function () ip = rspop(); state = states.forthret end -- «states» (to ".states") -- «states.head» (to ".states.head") states = {} states.head = function () local instr = mem[ip]; ip = ip+1; heads[instr]() end -- «states.forth» (to ".states.forth") states.forth = function () local v = mem[ip]; ip = ip+1 if type(v)=="string" then v = forths[v] end if type(v)=="function" then v(); return end if type(v)=="number" then rspush(ip) ip = v state = states.head return end error() end -- «states.forthret» (to ".states.forthret") states.forthret = function () if type(ip)=="number" then state = states.forth; return end if type(ip)=="function" then ip(); return end PP("forthret error: ip=", ip) error() end -- «innerloop» (to ".innerloop") innerloop = function () while state do if DBG then P(ip, mem[ip]) end state() end end -- «invoke» (to ".invoke") invoke = function (f) if type(f)=="string" then f = forths[f] end if type(f)=="function" then f(); return end if type(f)=="number" then local oldstate, oldip = state, ip rspush(function () state = nil end) ip = f state = states.head innerloop() ip = oldip state = oldstate return end error() end invoke_ = function (f, stateafter) if type(f)=="string" then f = forths[f] end if type(f)=="function" then f(); return end if type(f)=="number" then rspush(function () state = stateafter end) ip = f state = states.head return end error() end -- «ss» (to ".ss") ss = {} sspush = function (v) table.insert(ss, 1, v); return v end sspop = function () return table.remove(ss, 1) end -- «RSR» (to ".RSR") heads["h_rsr"] = function () sspush(rspop()) rspush(function () ip = sspop() end) end -- «rsrprim» (to ".rsrprim") rsrprim = function (rname, sname, fun) prim(sname, fun) compile(rname, "h_rsr", "h_forth", sname, "exit") end -- Tests for the inner interpreter: -- (find-angg "LFORTH/README" "kernel-innertest1") -- (find-angg "LFORTH/README" "kernel-innertestrsr") -- «p» (to ".p") p = {} p.pos = 0 -- p.text = ?? -- «p.parseluare» (to ".p.parseluare") p.parseluare = function (errfunction, luare) local arr = pack(string.find(p.text, luare, p.pos+1)) if arr[1] == nil then return errfunction(luare) end local startre = table.remove(arr, 1) local endre = table.remove(arr, 1) if DBG then P(p.pos, luare, startre-p.pos-1, endre-startre+1, unpack(arr)) end return startre-p.pos-1, endre-startre+1, unpack(arr) end -- «getword» (to ".getword") getword = function () local _, nspaces = p.parseluare(nil, "^[ \t]*") p.pos = p.pos + nspaces local __, dpos, word = p.parseluare(nil, "^([^ \t\n]*)") if dpos == 0 then _, dpos, word = p.parseluare(nil, "^(\n?)") end p.pos = p.pos + dpos return word end -- «getuntilluare» (to ".getuntilluare") getuntilluare = function (errfunction, luare) local arr = pack(p.parseluare(errfunction, luare)) local _, len = table.remove(arr, 1), table.remove(arr, 1) p.pos = p.pos+_+len return unpack(arr) end -- «states.outer_interpreter» (to ".states.outer_interpreter") states.outer_interpreter = function () word = getword() local immed = dict_interpreter[word] or dict[word] or forths[word] if immed then invoke_(immed, states.outer_interpreter); return end local n = tonumber(word) if n then dspush(n); return end unkown(word) end -- «states.outer_compiler» (to ".states.outer_compiler") states.outer_compiler = function () word = getword() local immed = dict_compiler[word] or dict[word] if immed then invoke_(immed, states.outer_compiler); return end if forths[word] then mem.compile(word); return end local n = tonumber(word) if n then mem.compile("lit", n); return end unkown(word) end -- «dict» (to ".dict") dict = {} dict[""] = function () ip = rspop(); state = states.forthret end -- EOF dict["\n"] = function () end -- just skip the newline dict["[lua"] = function () assert(loadstring(getuntilluare(nil, "^(.-)lua%]")))() end -- «dict_interpreter» (to ".dict_interpreter") dict_interpreter = {} dict_interpreter[":lua"] = function () local word, code = getword(), getuntilluare(nil, "^(.-)lua;") forths[word] = assert(loadstring(code)) end dict_interpreter[":"] = function () compile(getword(), "h_forth") state = states.outer_compiler end -- «dict_compiler» (to ".dict_compiler") dict_compiler = {} dict_compiler[";"] = function () mem.compile("exit") state = states.outer_interpreter end -- «interpret» (to ".interpret") -- (to "test2") interpret = function (str) local oldstate = state; interpret_(str, nil); innerloop(); state = oldstate end interpret_ = function (str, stateafter) p.text = str p.pos = 0 state = states.outer_interpreter rspush(function () state = stateafter end) end -- prim("dup", function () dspush(ds[1]) end) -- prim("*", function () ds[2] = ds[2]*ds[1]; dspop() end) -- prim("swap", function () ds[2], ds[1] = ds[1], ds[2] end) -- prim("drop", function () dspop() end) -- prim(".", function () print(dspop()) end) -- prim("..", function () ds[2] = ds[2]..ds[1]; dspop() end)