|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- miniforth4.lua - 2007jun13, Edrx
-- For Lua-5.1 (because of string.match)
-- http://angg.twu.net/miniforth/miniforth4.lua.html
-- http://angg.twu.net/miniforth/miniforth3.abs.txt.html
-- (find-a2ps (buffer-file-name))
split = function (str, pat)
local A = {}
local f = function (word) table.insert(A, word) end
string.gsub(str, pat or "([^%s]+)", f)
return A
end
eval = function (str) return assert(loadstring(str))() end
-- Part I: The outer interpreter.
-- Global variables that hold the input:
subj = "5 DUP * ." -- what we are interpreting
pos = 1 -- where are are (1 = "at the beginning")
-- Low-level functions to read things from "pos" and advance "pos".
-- Note: the "pat" argument in "parsebypattern" is a pattern with
-- one "real" capture and then an empty capture.
parsebypattern = function (pat)
local capture, newpos = string.match(subj, pat, pos)
if newpos then pos = newpos; return capture end
end
parsespaces = function () return parsebypattern("^([ \t]*)()") end
parseword = function () return parsebypattern("^([^ \t\n]+)()") end
parsenewline = function () return parsebypattern("^(\n)()") end
parserestofline = function () return parsebypattern("^([^\n]*)()") end
parsewordornewline = function () return parseword() or parsenewline() end
-- A "word" is a sequence of one or more non-whitespace characters.
-- The outer interpreter reads one words at a time and executes it.
-- Note that `getwordornewline() or ""' returns a word, or a newline, or "".
getword = function () parsespaces(); return parseword() end
getwordornewline = function () parsespaces(); return parsewordornewline() end
-- The dictionary.
-- Entries whose values are functions are primitives.
-- We will only introduce non-primitives in part III.
_F = {}
_F["%L"] = function () eval(parserestofline()) end
-- The "processor", as a state machine.
-- Its initial behavior is to run states[state]() - i.e.,
-- states.interpret() - until `state' becomes "stop".
state = "interpret"
states = {}
printstate = function () end -- stub
runstate = function () printstate(); states[state]() end
run = function () while state ~= "stop" do runstate() end end
-- Initially the processor knows only this state, "interpret"...
-- Note that "word" is a global variable.
interpretprimitive = function ()
if type(_F[word]) == "function" then _F[word](); return true end
end
interpretnonprimitive = function () return false end -- stub
interpretnumber = function () return false end -- stub
PSI = function () end -- print state for "interpret"
states.interpret = function ()
word = getwordornewline() or ""
PSI()
local _ = interpretprimitive() or
interpretnonprimitive() or
intrpretnumber() or
error("Can't interpret: "..(word or "(EOT)"))
end
-- Our first program in MiniForth.
-- First it defines a behavior for newlines (just skip them),
-- for "" (change state to "stop"; note that `word' becomes "" on
-- end of text), and for "[L ... L]" blocks (eval "..." as Lua code).
-- Then it creates a data stack - DS - and four words - "5", "DUP",
-- "*", "." - that operate on it.
--
subj = [==[
%L _F["\n"] = function () end
%L _F[""] = function () state = "stop" end
%L _F["[L"] = function () eval(parsebypattern("^(.-)%sL]()")) end
[L
DS = { n = 0 }
push = function (stack, x) stack.n = stack.n + 1; stack[stack.n] = x end
pop = function (stack) local x = stack[stack.n]; stack[stack.n] = nil;
stack.n = stack.n - 1; return x end
_F["5"] = function () push(DS, 5) end
_F["DUP"] = function () push(DS, DS[DS.n]) end
_F["*"] = function () push(DS, pop(DS) * pop(DS)) end
_F["."] = function () io.write(" "..pop(DS)) end
L]
]==]
-- Now run it. There's no visible output.
pos = 1
state = "interpret"
run()
-- At this point the dictionary (_F) has eight words.
--- _ _ _ _
--- _ __ _ __(_)_ __ | |_ ___| |_ __ _| |_ ___
--- | '_ \| '__| | '_ \| __/ __| __/ _` | __/ _ \
--- | |_) | | | | | | | |_\__ \ || (_| | || __/
--- | .__/|_| |_|_| |_|\__|___/\__\__,_|\__\___|
--- |_|
vardiag = function (varname) return varname.."=".._G[varname] end
varDiag = function (varname) return varname.."="..mytostring(_G[varname]) end
stackdiag = function (stackname) return format("%s={ %s }", stackname, table.concat(_G[stackname])) end
diags3 = function () return format("%22s%18s%22s", stackdiag("RS"), vardiag("state"), stackdiag("DS")) end
diags4 = function (extravar) return diags3()..format("%12s", varDiag(extravar)) end
PSI = function () print(diags4("word")) end
PSC = function () print(diags4("word")) end
PSF = function () print(diags4("instr")) end
PSH = function () print(diags4("head")) end
RS = { n = 0 }
--- _ _ ____ ____
--- (_) |___ \| ___|
--- | | | __) |___ \
--- | | |/ __/ ___) |
--- |_|_|_____|____/
---
subj = [[ 5 DUP DUP * * . ]]
DS = { n = 0 }; pos = 1; state = "interpret"; run()
---
--- _ __ ___ ___ _ __ ___ ___ _ __ _ _
--- | '_ ` _ \ / _ \ '_ ` _ \ / _ \| '__| | | |
--- | | | | | | __/ | | | | | (_) | | | |_| |
--- |_| |_| |_|\___|_| |_| |_|\___/|_| \__, |
--- |___/
memory = { n = 0 }
here = 1
compile = function (...) for i = 1,arg.n do compile1(arg[i]) end end
compile1 = function (x)
memory[here] = x; here = here + 1
memory.n = math.max(memory.n, here)
end
--- _ ___ _____
--- _ _ | | |_ _|_ _|
--- (_) (_) | | | | | |
--- _ _ | |___ | | | |
--- (_) ( ) |_____|___| |_|
--- |/
IMMEDIATE = {}
_F[":"] = function ()
_F[parseword()] = here
compile("DOCOL")
state = "compile"
end
_F[";"] = function ()
compile("EXIT")
state = "interpret"
end
IMMEDIATE[";"] = true
--- _ _ _ _
--- ___| |_ __ _| |_ ___ ___ ___ ___ _ __ ___ _ __ (_) | ___
--- / __| __/ _` | __/ _ \/ __| / __/ _ \| '_ ` _ \| '_ \| | |/ _ \
--- \__ \ || (_| | || __/\__ \| (_| (_) | | | | | | |_) | | | __/
--- |___/\__\__,_|\__\___||___(_)___\___/|_| |_| |_| .__/|_|_|\___|
--- |_|
compileimmediateword = function ()
if word and _F[word] and IMMEDIATE[word] then
if type(_F[word]) == "function" then -- primitive
_F[word]()
else
push(RS, state)
push(RS, _F[word])
state = "head"
end
end
end
compilenonimmediateword = function ()
if word and _F[word] and not IMMEDIATE[word] then
compile1(_F[word]); return true
end
end
compilenumber = function ()
if word and tonumber(word) then
compile1("LIT"); compile1(tonumber(word)); return true
end
end
states.compile = function ()
word = parseword()
PSC()
local _ = compileimmediateword() or
compilenonimmediateword() or
compilenumber() or
error("Can't compile: "..(word or EOT))
end
RS = { n = 0 }
--- ____ _ _ ____ _____
--- _ / ___| | | | __ )| ____| _
--- (_) | | | | | | _ \| _| (_)
--- _ | |___| |_| | |_) | |___ _ _ _ _
--- (_) \____|\___/|____/|_____| (_|_|_) ( )
--- |/
memory = { n = 0 }; here = 1
subj = [[
: SQUARE DUP * ;
: CUBE DUP SQUARE * ;
5 CUBE .
]]
DS = { n = 0 }; pos = 1; state = "interpret"; run()
--- _ ___ _____
--- | | |_ _|_ _|
--- | | | | | |
--- | |___ | | | |
--- |_____|___| |_|
---
_F["LIT"] = function ()
push(DS, RS[RS.n])
RS[RS.n] = RS[RS.n + 1]
end
interpretnumber = function ()
if word and tonumber(word) then push(DS, tonumber(word)); return true end
end
--- ____ ___ _ _ ___ _ _
--- |___ \ / _ \| || | ( _ )| || |
--- __) | | | | || |_ / _ \| || |_
--- / __/| |_| |__ _| (_) |__ _|
--- |_____|\___/ |_| \___/ |_|
---
memory = { n = 0 }; here = 1
subj = [[
: +20000 20000 + ;
22 SQUARE +20000 .
]]
DS = { n = 0 }; pos = 1; state = "interpret"; run()
--[=[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "miniforth4.lua"
DSstate = function () return "DS={ "..table.concat(DS, " ").. " }" end
printstate = function () print("state="..state.." "..DSstate()) end
DS = { n = 0 }
subj = [[ 5 DUP DUP * * . ]]
pos = 1
state = "interpret"
run()
subj = [[ 5 DUP * . ]]
pos = 1
state = "interpret"
run = function () while state ~= "stop" do printstate(); states[state]() end end
--]=]
--[=====[
interpretnumber = function ()
if tonumber(word) then push(DS, tonumber(word)); return true end
end
--- ____ ____
--- | _ \/ ___|
--- | | | \___ \
--- | |_| |___) |
--- |____/|____/
---
DS = { n = 0 }
push = function (stack, x) stack.n = stack.n + 1; stack[stack.n] = x end
pop = function (stack) local x = stack[stack.n]; stack[stack.n] = nil;
stack.n = stack.n - 1; return x end
_F["5"] = function () push(DS, 5) end
_F["DUP"] = function () push(DS, DS[DS.n]) end
_F["*"] = function () push(DS, pop(DS) * pop(DS)) end
_F["."] = function () io.write(" "..pop(DS)) end
interpretnumber = function ()
if word and tonumber(word) then push(DS, tonumber(word)); return true end
end
(/ 55000.0 (* 14 365))
* (eepitch-lua51)
-- RS={interpret 5 1 2 3} state=interpret
RS = { n = 0 }
memory = { n = 0 }
here = 1
_F["SQUARE"] = here; compile("DOCOL", "DUP", "*", "EXIT")
_F["CUBE"] = here; compile("DOCOL", "DUP", _F["SQUARE"], "*", "EXIT")
_H = {}
_H["DOCOL"] = function ()
RS[RS.n] = RS[RS.n] + 1
state = "forth"
end
_F["EXIT"] = function ()
pop(RS)
if type(RS[RS.n]) == "string" then state = pop(RS) end
end
interpretnonprimitive = function ()
if type(_F[word]) == "number" then
push(RS, "interpret")
puhs(RS, _F[word])
state = "head"
return true
end
states.head = function ()
head = memory[RS[RS.n]]
head()
end
--[=[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile(ee_expand("~/miniforth/miniforth4.lua"))
--]=]
--[=[
DS = { n = 0 }
subj = [[ 5 DUP DUP * * . ]]
pos = 1
state = "interpret"
run()
-- state=interpret DS={ }
-- state=interpret DS={ 5 }
-- state=interpret DS={ 5 5 }
-- state=interpret DS={ 5 5 5 }
-- state=interpret DS={ 5 25 }
-- state=interpret DS={ 125 } 125
-- state=interpret DS={ }
subj = [==[ 5 . [lua print "foo" lua] 5 . ]==]
DS = { n = 0 }; pos = 1; state = "interpret"; run()
--]=]
--[=[
PP(memory)
PP(_F)
RS = { n = 0 }
if type(semantics) == "number" then -- "5", "22", etc
push(RS, "interpret")
push(RS, semantics)
state = "head"
return
end
-- what about numbers?
parseluablock = function () eval(parsebypattern("^(.-)lua%]")) end
readfile = function (fname)
local f = assert(io.open(fname, "r"))
local fcontents = f:read("*a"); f:close(); return fcontents
end
setsubjto = function (str) subj = str; pos = 1 end
runstring = function (str) setsubjto(str); outerloop() end
runfile = function (fname) runstring(readfile(fname)) end
-- runfile(arg[1])
-- (find-blogmefile "")
-- (find-blogmefile "blogme2-middle.lua")
-- (find-luamanualw3m "#pdf-string.match")
-- ee = function () runfile(ee_expand("$EEVTMPDIR/ee.mf3")) end
compile = function (...)
for i = 1,arg.n do
if type(arg[i]) == "string" then
for _,word in ipairs(split(arg[i])) do compile1(word) end
else
compile(arg[i])
end
end
end
--]=]
--]=====]