|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- crim.lua: a library for miniforth.
-- Written by edrx@inx.com.br. Version: 2001dec04. GPL.
-- There's an htmlized version of this file at:
-- <http://angg.twu.net/miniforth/crim.lua>.
-- "Crim" is an idea that I've been cooking since 1995 for a
-- Forth-like language with very compact bytecodes. Crim has a
-- definite inner engine but no decent high-level syntax yet; any
-- "Crim compiler", like this one, is a tool for exploring possible
-- syntaxes.
-- «.heir» (to "heir")
-- «.newxprimclass» (to "newxprimclass")
-- «.hprimclass» (to "hprimclass")
-- «.fprimclass» (to "fprimclass")
-- «.fipprimclass» (to "fipprimclass")
-- «.fwordclass» (to "fwordclass")
-- «.sfprimclass» (to "sfprimclass")
-- «.declarehprims» (to "declarehprims")
-- «.declarefprims» (to "declarefprims")
-- «.standard_primitives» (to "standard_primitives")
-- «.defineLASTs» (to "defineLASTs")
-- «.unskeletize» (to "unskeletize")
asmcode = ""
nasm = function( nbytes, text ) asmcode = asmcode .. text end
dict = dict or {}
nasmify = function( str )
return gsub(str, "([^0-9A-Za-z_])",
function (c)
return format("x%02x", strbyte(c))
end)
end
--%%%%
--%
--% «heir» (to ".heir")
--%
--%%%%
heirtag = newtag()
heir = function( table ) settag(table, heirtag); return table end
settagmethod(heirtag, "gettable", function( table, index )
local a = rawget(table, index); if a then return a end
local up = rawget(table, "UP"); if up then return up[index] end
end)
settagmethod(heirtag, "function", function( ... )
call(arg[1].FUN, arg)
end)
--%%%%
--%
--% «newxprimclass» (to ".newxprimclass")
--%
--%%%%
newxprimclass = function( params )
local xprimclass = {
prefix = params.prefix,
def_format = params.def_format,
case_format = "case %s: %s\n",
case_formatter = function( xprim )
return format("case %s: PRIMp(\"%s\"); %s\n", xprim.aname, xprim.aname, xprim.Ccode)
end,
compile_format = params.compile_format,
nbytes = params.nbytes,
cdefs_str = "",
adefs_str = "",
case_str = "",
all = {},
used = {},
firstopcode = params.firstopcode,
nextopcode = params.firstopcode,
step = params.step,
declare = nil, -- class method
define_opcode = nil, -- class method
assert_used = nil, -- instance method
compile = nil -- instance method
}
xprimclass.declare = function( xprimclass, aname, Ccode )
local xprim = heir {
aname = aname,
compile_str = format(xprimclass.compile_format, aname),
opcode = nil,
Ccode = Ccode,
depends = nil,
UP = xprimclass,
FUN = xprimclass.compile,
}
tinsert(xprimclass.all, xprim)
return xprim
end
xprimclass.define_opcode = function( xprimclass, aname )
local c, opcode = xprimclass, xprimclass.nextopcode
c.adefs_str =
c.adefs_str .. format(c.def_format, "%", aname, opcode)
c.cdefs_str =
c.cdefs_str .. format(c.def_format, "#", aname, opcode)
end
xprimclass.assert_used = function( xprim )
if xprim.opcode then return end
local c = xprim.UP
c.define_opcode(c, xprim.aname)
xprim.opcode = c.nextopcode
c.nextopcode = c.nextopcode + c.step
c.case_str =
c.case_str .. c.case_formatter(xprim)
-- c.case_str .. format(c.case_format, xprim.aname, xprim.Ccode)
tinsert(c.used, xprim)
if xprim.depends then
foreachi(xprim.depends, function( i, depend )
if type(depend)=="string" then
dict[depend]:assert_used()
else
depend:assert_used()
end
end)
end
end
xprimclass.compile = function( xprim )
xprim:assert_used()
nasm(xprim.nbytes, xprim.compile_str)
end
return xprimclass
end
--%%%%
--%
--% «hprimclass» (to ".hprimclass")
--% «fprimclass» (to ".fprimclass")
--% «fipprimclass» (to ".fipprimclass")
--%
--%%%%
hprimclass = newxprimclass {
prefix = "H_",
def_format = "%sdefine %-16s 0x%02X\n",
compile_format = "\tdb %s\n",
nbytes = 1,
firstopcode = 0,
step = 1,
}
fprimclass = newxprimclass {
prefix = "F_",
def_format = "%sdefine %-16s 0x%04X\n",
compile_format = "\tdhl %s\n",
nbytes = 2,
firstopcode = ((255-10)*256)+255, -- space for 10 sfprims
step = -1,
}
fipprimclass = newxprimclass {
prefix = "FIP_",
def_format = "%sdefine %-16s 0x%04X\n",
compile_format = "\tdhl %s\n",
nbytes = 1,
firstopcode = 65535,
step = -1,
}
--%%%%
--%
--% «fwordclass» (to ".fwordclass")
--%
--%%%%
fwordclass = {
compile = function( fword )
nasm(2, fword.compile_str)
end,
declare = nil
}
fwordclass.declare = function( thisclass, wordname )
local aname = "ADR_" .. nasmify(wordname)
nasm(0, format("%s:\n", aname))
local fword = heir {
compile_str = format("\tdhl %s -_f0\n", aname),
UP = thisclass,
FUN = thisclass.compile
}
dict[wordname] = fword
end
fwordclass.gdeclare = function( thisclass, wordname )
local aname = "ADR_" .. nasmify(wordname)
nasm(0, format("global %s\n", aname))
thisclass:declare(wordname)
end
--%%%%
--%
--% «sfprimclass» (to ".sfprimclass")
--% Experimental! Ugly!
--% This supports both adding an sfprim to an existing fprim and
--% creating both at the same time with sfprimclass:declare.
--%
--%%%%
sfprimclass = newxprimclass {
prefix = "SF_",
def_format = "%sdefine %-16s 0x%02X\n",
compile_format = "\tdb %s\n",
nbytes = 1,
firstopcode = 255,
step = -1,
}
sfprimclass.transltable_str = ""
sfprimclass.assert_used_sfonly = sfprimclass.assert_used
sfprimclass.assert_used = function( sfprim )
local fprim = sfprim.fprim
fprim:assert_used()
if sfprim.opcode == nil then
sfprim.UP.transltable_str =
sfprim.UP.transltable_str .. fprim.aname .. ", "
end
sfprim:assert_used_sfonly()
end
sfprimclass.declare_sfonly = sfprimclass.declare
sfprimclass.declare = function( sfprimclass, sfaname, Ccode )
local faname = strsub(2, sfaname) -- hack; drop the "S" from "SF_"
local fprim = fprimclass:declare(faname, Ccode)
local sfprim = sfprimclass:declare_sfonly(sfaname, "??") -- no case for sfs
sfprim.fprim = fprim
fprim.sfprim = sfprim
return sfprim, fprim
end
fprimclass.assert_sfprim_exists = function( fprim )
if fprim.sfprim then return fprim.sfprim end
local faname = fprim.aname
local sfaname = "S"..faname
local sfprim = sfprimclass:declare_sfonly(sfaname, faname..", ") -- ugh
sfprim.fprim = fprim
fprim.sfprim = sfprim
return sfprim, fprim
end
--%%%%
--%
--% «declarehprims» (to ".declarehprims")
--% «declarefprims» (to ".declarefprims")
--%
--%%%%
declarexprims_helper = function( pairs, fun )
local i, words, aname_stem, Ccode
for i=1,getn(pairs),2 do
words = split(pairs[i])
aname_stem = nasmify(words[1])
Ccode = pairs[i+1]
fun(words, aname_stem, Ccode)
end
end
declarehprims = function( ... ) -- ... = words, Ccode, words, Ccode...
declarexprims_helper(arg, function( words, aname_stem, Ccode )
local c = hprimclass
local hprim, j = c:declare(c.prefix..aname_stem, Ccode)
for j=1,getn(words) do
dict[c.prefix..words[j]] = hprim
end
end)
end
declarefprims = function( ... ) -- ... = words, Ccode, words, Ccode...
declarexprims_helper(arg, function( words, aname_stem, Ccode )
local c = fprimclass
local fprim, j = c:declare(c.prefix .. aname_stem, Ccode)
for j=1,getn(words) do
dict[c.prefix..words[j]] = fprim
dict[words[j]] = fprim
end
end)
end
declarefipprims = function( ... ) -- ... = words, Ccode, words, Ccode...
declarexprims_helper(arg, function( words, aname_stem, Ccode )
local c = fipprimclass
local fipprim, j = c:declare(c.prefix .. aname_stem, Ccode)
for j=1,getn(words) do
dict[c.prefix..words[j]] = fipprim -- won't be used
end
end)
end
prefer_sf_form = function( wordsasstring )
foreachi(split(wordsasstring), function( i, word )
local sfprim, fprim = fprimclass.assert_sfprim_exists(dict["F_"..word])
dict["SF_"..word] = sfprim
dict[word] = sfprim
end)
end
--%%%%
--%
--% «standard_primitives» (to ".standard_primitives")
--%
--%%%%
declarehprims(
"COL "," goto forth;",
"CON "," DS[1]=*(int *)(_f0+RS[0]); DS++; RS--; goto forth;",
"TO "," *(int *)(_f0+RS[0]+1)=DS[0]; DS--; RS--; goto forth;",
"AT "," DS[1]=((int)_f0)+RS[0]+2; DS++; RS--; goto forth;",
"RSR "," SS[1]=((int)_f0)+RS[-1]; SS++; RS[-1]=FIP_RSREXIT; goto head;",
"C0 "," fun=*(funptr *)(_f0+RS[0]); DS[1]=(*fun)(); DS++;RS--; goto forth;",
"C1 "," fun=*(funptr *)(_f0+RS[0]); DS[0]=(*fun)(DS[0]); RS--; goto forth;",
"C2 "," fun=*(funptr *)(_f0+RS[0]); DS[-1]=(*fun)(DS[-1], DS[0]);"
.." DS--; RS--; goto forth;",
"C3 "," fun=*(funptr *)(_f0+RS[0]); DS[-2]=(*fun)(DS[-2], DS[-1], DS[0]);"
.." DS-=2; RS--; goto forth;",
"DROPPING"," RS[1]=RS[0]; RS[0]=FIP_FIPDROP; RS++; goto head;"
)
declarefprims(
"EXIT ; "," RS--; goto forth;",
"PLUS + "," DS[-1]+=DS[0]; DS--; goto forth;",
"DUP "," DS[1]=DS[0]; DS++; goto forth;",
"2DUP "," DS[1]=DS[-1]; DS[2]=DS[0]; DS+=2; goto forth;",
"SWAP "," itmp=DS[-1]; DS[-1]=DS[0]; DS[0]=itmp; goto forth;",
"DROP "," DS--; goto forth;",
"SBRANCH "," SS[0]=(int)_f0+*((ushort *)(SS[0])); goto forth;",
"S0BRANCH "," tmp=*((ushort *)(SS[0]))++; if(DS[0]==0) SS[0]=(int)_f0+tmp;"
.." DS--; goto forth;",
"0 "," DS[1]=0; DS++; goto forth;",
"1 "," DS[1]=1; DS++; goto forth;",
"TIMES * "," DS[-1]*=DS[0]; DS--; goto forth;",
"COUNT "," DS[1]=*((uchar *)(DS[0]))++; DS++; goto forth;",
"TYPE "," fwrite((void *)(DS[-1]), 1, DS[0], stdout); DS-=2; goto forth;",
"CR "," printf(\"\\n\"); goto forth;",
"STO S> "," DS[1]=SS[0]; DS++; SS--; goto forth;",
"TOS >S "," SS[1]=DS[0]; SS++; DS--; goto forth;",
"SGOBBLE1 "," DS[1]=*((uchar *)(SS[0]))++; DS++; goto forth;",
"SGOBBLE2 "," DS[1]=*((ushort *)(SS[0]))++; DS++; goto forth;",
"WSTORE W! "," *((ushort *)(DS[0]))=DS[1]; DS-=2; goto forth;",
"WFETCH W@ "," DS[0]=*((ushort *)(DS[0])); goto forth;"
)
declarefipprims(
"RETURN "," RS--; return;",
"RSREXIT "," RS[0]=SS[0]-((int)_f0); SS--; goto forth;",
"FIPDROP "," RS--; DS--; goto forth;"
)
dict["FIP_RETURN"]:assert_used()
dict["H_RSR"].depends = {"FIP_RSREXIT"}
prefer_sf_form("EXIT ; DUP")
dict["EXIT"]:assert_used()
--%%%%
--%
--% «defineLASTs» (to ".defineLASTs")
--% «unskeletize» (to ".unskeletize")
--%
--%%%%
-- (find-node "(lua)Patterns" "shortest")
defineLASTs = function()
hprimclass:define_opcode(hprimclass.prefix .. "LAST")
fprimclass:define_opcode(fprimclass.prefix .. "LAST")
sfprimclass:define_opcode(sfprimclass.prefix .. "LAST")
fipprimclass:define_opcode(fipprimclass.prefix .. "LAST")
end
unskeletize = function(fnamein, fnameout)
local bigstr = readfile(fnamein)
bigstr = gsub(bigstr, "<<LUA(.-)LUA>>", dostring)
writefile(fnameout, bigstr)
printf("Wrote %s\n", fnameout)
end
-- (find-angg "miniforth/")
-- (find-angg "miniforth/crim/")
-- (find-angg "miniforth/crim/crim.lua")
-- (find-angg "miniforth/crim/demo1.mflua")
comment = [[
# (find-fline "~/flua/")
# (find-fline "~/flua/demo1.bytecode.asm")
# (find-fline "~/flua/demo1.flua")
# (find-fline "~/flua/flua-comp.lua")
# (find-fline "~/flua/flua-demos.lua")
# (find-fline "~/flua/flua-lua.lua")
# (find-fline "~/flua/flua-prims.lua")
# (find-fline "~/flua/flua.lua")
#*
a2ps -=p2iso ~/miniforth/crim.lua
make -f ~/LATEX/Makefile /tmp/o.p01
#*
# (find-fline "~/o")
cd ~/miniforth/
mylua crim.lua |& tee ~/o
#*
# (find-fline "~/o")
cd ~/miniforth/
mylua -f miniforth1.lua crim/demo1.mflua |& tee ~/o
#*
]]