Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://angg.twu.net/LUA/miniforth2021.lua.html
--   http://angg.twu.net/LUA/miniforth2021.lua
--           (find-angg "LUA/miniforth2021.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- (defun e (interactive) (find-angg "LUA/miniforth2021.lua"))


-- «.savevars»		(to "savevars")
-- «.Stack»		(to "Stack")
-- «.Stack-test»	(to "Stack-test")
-- «.ds»		(to "ds")
-- «._F»		(to "_F")
-- «.MiniForth»		(to "MiniForth")


spaces = function (n) return string.rep(" ", n) end

-- «savevars»  (to ".savevars")
-- (find-es "lua5" "savevars")
savevars = function (restorefromargs, ...)
    local values = pack(...)
    local restorevars = function () restorefromargs(unpack(values)) end
    return restorevars
  end



-- «Stack»  (to ".Stack")
-- (find-dn6 "stacks.lua" "Stack")
--
mystacktostring = function (stack)
    local f = function (i) return {key=i, val=stack[i]} end
    local ps = map(f, seq(#stack, 1, -1))
    return (Tos{}):ps(ps, "\n")
  end
--
Stack = Class {
  type    = "Stack",
  new     = function () return Stack {} end,
  dowords = function (f, bigstr) return Stack{doword=f}:dowords(bigstr):pop() end,
  --
  __tostring = function (s) return s:tostring() end,
  __index = {
    push  = function (s, o) table.insert(s, o); return s end,
    pushs = function (s, ...) for _,v in ipairs({...}) do s:push(v) end end,
    --
    check     = function (s) assert(#s>0, s.msg or "Empty stack"); return s end,
    drop      = function (s) s:check(); s[#s]=nil; return s end,
    dropn     = function (s, n) for i=1,n  do s:drop() end; return s end,
    dropn0    = function (s, n) for i=1,n  do s:drop() end;          end,
    dropnr    = function (s, n, ...) s:dropn(n); return ...          end,
    dropuntil = function (s, n) while #s>n do s:drop() end; return s end,
    clear     = function (s)    return s:dropn(#s) end,
    --
    pop  = function (s) return s:dropnr(1,                            s[#s]) end,
    pop2 = function (s) return s:dropnr(2,                   s[#s-1], s[#s]) end,
    pop3 = function (s) return s:dropnr(3,          s[#s-2], s[#s-1], s[#s]) end,
    pop4 = function (s) return s:dropnr(4, s[#s-3], s[#s-2], s[#s-1], s[#s]) end,
    --
    pick = function (s, offset) return s[#s-offset] end,
    pock = function (s, offset, o)     s[#s-offset] = o; return s end,
    --
    tostring = function (s)
        -- return mapconcat(tostring, s, " ")
        return mapconcat(mytostring, s, " ")
      end,
    --
    PP    = function (s) PP(s); return s end,
    print = function (s) print(s); return s end,
    --
    dowords = function (s, bigstr)
        for _,word in ipairs(split(bigstr)) do s:doword(word) end
        return s
      end,
  },
}

-- «Stack-test»  (to ".Stack-test")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "miniforth2021.lua"
ds = Stack.new()
ds:push(2):push(3):push("ab cd")
= ds 

--]]


-- «ds»  (to ".ds")
ds = Stack.new()
push = function (o) ds:push(o) end
pop  = function () return ds:pop(o) end

-- «_F»  (to "._F")
_F = {}
_F["drop"] = function () pop() end
_F["dup"] = function () push(ds:pick(0)) end
_F["*"] = function () local a,b = pop(),pop(); push(a*b) end
_F["+"] = function () local a,b = pop(),pop(); push(a+b) end
_F["-"] = function () local b,a = pop(),pop(); push(a-b) end
_F["."] = function () PP((pop())) end

_F["__"] = function () print(subj); print(mf:show()) end
_F["_"]  = function () print(mf:show().." stack: "..ds:tostring()) end



-- «MiniForth»  (to ".MiniForth")
-- (find-lua51manual "")
-- (find-lua51manual "#pdf-string.match")
--
MiniForth = Class {
  type    = "MiniForth",
  __index = {
    --
    -- Low level stuff.
    setline0 = function (mf, linestr, altpos)
	subj,pos = linestr, altpos or 1
      end,
    sub = function (mf, b, p)
        return subj:sub(b, p-1)
      end,
    show = function (mf, b, p)
        b,p = b or beg, p or pos
        return spaces(b-1) .. mf:sub(b, p) .. spaces(#subj + 1 - p)
      end,
    --
    -- Medium level stuff.
    -- Add more parsers here (and change doword).
    getword0 = function (mf)
        local b,wrd,p = subj:match("^ *()([^ ]+)()", pos)
	if b then beg,word,pos = b,wrd,p; return word end
      end,
    doword = function (mf, word)
        local action = _F[word]
        if action then action() else push(word+0) end
      end,
    doline0 = function (mf)
	while mf:getword0() do mf:doword(word) end
      end,
    --
    doline  = function (mf, linestr, altpos)
        local restore = savevars(function (...)
          subj,pos,beg,word = ... end,
          subj,pos,beg,word)
        mf:setline0(linestr, altpos)
        mf:doline0()
        restore()
      end,
  },
}



--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "miniforth2021.lua"

mf = MiniForth {}
ds = Stack.new()

mf:setline0("2 3 4 + + .")
mf:doline0()

mf:doline("2 3 4 + + .")

ds = Stack.new()
mf:doline("__ 2 3 4 _ + _ + _ drop _")

--]]