OC-KittenOS/inst/libs/lexcrunch.lua

192 lines
3.9 KiB
Lua

-- This is released into the public domain.
-- No warranty is provided, implied or otherwise.
-- This library helps in crunching down the installer a bit further.
local sequences = {
{"\n", " "},
{" ", " "},
{" #", "#"},
{"# ", "#"},
{" ,", ","},
{", ", ","},
{" (", "("},
{"( ", "("},
{" )", ")"},
{") ", ")"},
{" {", "{"},
{"{ ", "{"},
{" }", "}"},
{"} ", "}"},
{" <", "<"},
{"< ", "<"},
{" >", ">"},
{"> ", ">"},
{" *", "*"},
{"* ", "*"},
{" ~", "~"},
{"~ ", "~"},
{" /", "/"},
{"/ ", "/"},
{" %", "%"},
{"% ", "%"},
{" =", "="},
{"= ", "="},
{" -", "-"},
{"- ", "-"},
{" +", "+"},
{"+ ", "+"},
{".. ", ".."},
{" ..", ".."},
{"\"\" ", "\"\""},
{"=0 t", "=0t"},
{">0 t", ">0t"},
{">1 t", ">1t"},
{"=1 w", "=1w"},
{"=380 l", "=380l"},
{"=127 t", "=127t"},
{"<128 t", "<128t"},
{"=128 t", "=128t"},
{">255 t", ">255t"},
{"=512 t", "=512t"}
}
local function pass(buffer)
local ob = ""
local smode = false
while #buffer > 0 do
if not smode then
local ds = true
while ds do
ds = false
for _, v in ipairs(sequences) do
if buffer:sub(1, #(v[1])) == v[1] then
buffer = v[2] .. buffer:sub(#(v[1]) + 1)
ds = true
end
end
end
end
local ch = buffer:sub(1, 1)
buffer = buffer:sub(2)
ob = ob .. ch
if ch == "\"" then
smode = not smode
end
end
return ob
end
-- Context creation --
return function ()
local forwardSymTab = {}
local reverseSymTab = {}
local temporaryPool = {}
local stackFrames = {}
local log = {}
local possible = {}
for i = 1, 52 do
possible[i] = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"):sub(i, i)
end
local function allocate(reason)
for _, v in pairs(possible) do
if not reverseSymTab[v] then
reverseSymTab[v] = reason
return v
end
end
end
local function allocTmp(id)
assert(not forwardSymTab[id], "var already exists: " .. id)
local val = table.remove(temporaryPool, 1)
if not val then val = allocate("temporary") end
forwardSymTab[id] = val
table.insert(log, "allocTmp " .. id .. " -> " .. val)
return val
end
local lexCrunch = {}
function lexCrunch.dump(file)
file:write("forward table:\n")
for k, v in pairs(forwardSymTab) do
file:write(k .. " -> " .. v .. "\n")
end
file:write("reverse table (where differing):\n")
for k, v in pairs(reverseSymTab) do
if forwardSymTab[v] ~= k then
file:write(v .. " -> " .. k .. "\n")
end
end
file:write("log:\n")
for k, v in ipairs(log) do
file:write(v .. "\n")
end
end
function lexCrunch.process(op, defines)
-- symbol replacement
op = op:gsub("%$[%$a-z%{%}%|A-Z0-9]*", function (str)
if str:sub(2, 2) == "$" then
-- defines
assert(defines[str], "no define " .. str)
return defines[str]
end
local com = {}
for v in str:sub(2):gmatch("[^%|]*") do
table.insert(com, v)
end
if com[1] == "L" then
assert(#com == 2)
local id = "$" .. com[2]
assert(stackFrames[1], "allocation of " .. id .. " outside of stack frame")
table.insert(stackFrames[1], id)
return allocTmp(id)
elseif com[1] == "{" then
assert(#com == 1)
table.insert(stackFrames, 1, {})
return ""
elseif com[1] == "}" then
assert(#com == 1)
for _, id in ipairs(table.remove(stackFrames, 1)) do
table.insert(temporaryPool, forwardSymTab[id])
forwardSymTab[id] = nil
end
return ""
else
assert(#com == 1)
local id = "$" .. com[1]
-- normal handling
if forwardSymTab[id] then
return forwardSymTab[id]
end
local v = allocate(id)
forwardSymTab[id] = v
return v
end
end)
-- comment removal
while true do
local np = op:gsub("%-%-[^\n]*\n", " ")
np = np:gsub("%-%-[^\n]*$", "")
if np == op then
break
end
op = np
end
-- stripping
while true do
local np = pass(op)
if np == op then
return np
end
op = np
end
return op
end
return lexCrunch
end