LIVM/faxm.lua
2022-04-16 01:22:30 +10:00

216 lines
5.8 KiB
Lua

local date = require"date"
local opcode = require"faxmopcode"
local FX = {
--require"faxm/fraCinize",
require"fraxinizator/string",
require"fraxinizator/ximplifier",
require"fraxinizator/fraxevice",
require"fraxinizator/freeform"
}
local source
local destination = "out.fx"
do
local parsestate = 0
for _, a in ipairs(arg) do
if parsestate == 1 then parsestate = 0; destination = a;
elseif a:sub(1, 1) == "-" then
if a == "-o" then parsestate = 1;
end
elseif a then source = a end
end
end
assert(source)
code = {}
data = {}
const = {}
ptr = {
cptr = {},
dptr = {}
}
function raw(x) return x end
function string.trim(s)
local n = s:find"%S"
return n and s:match(".*%S", n) or ""
end
function string.split(str, sep)
if sep == nil then
sep = "%s"
end
local t = {}
for x in string.gmatch(str, "([^"..sep.."]+)") do
table.insert(t, x)
end
return t
end
function string.split_8(str)
local result = {}
for i = 0, math.floor(#str / 8) do
result[#result + 1] = str:sub(i * 8, (i + 1) * 8)
end
return result
end
function parseCode(source, code, data)
for k, v in pairs(FX) do if v.source then source = v.source(source) end end
print(source)
local dminsize, cminsize, xtype = -1, -1, "8u"
local section, segment
local objects = {}
for line in source:gmatch("([^;]+)") do
for k, v in pairs(FX) do if v.any_line then line = v.any_line(line) end end
if line:sub(1, 1) == '[' then
for k, v in pairs(date.decode(raw(line:sub(2, #line - 1):gsub("+", ":")))) do
if type(k) == "number" then
if v:sub(1, 1) == 'x' then xtype = v:sub(2, #v)
elseif v == "CODE" then section = code;
elseif v == "DATA" then section = data;
elseif k == "noalign" then
if section == code then cminsize = -1
else dminsize = -1 end
end
elseif k == "align" then
if section == code then cminsize = v else dminsize = v end
end
end
else
if #line > 5 and line:sub(1, 6) == "object" then
segment = { t = "object", p = "data" }
elseif #line > 7 and line:sub(1, 7) == "section" then
segment = { t = "section" }
end
if segment and segment.t == "object" then
if line:sub(1, 6) == "object" then
segment.name = line:sub(8, #line - 1):trim()
if ptr.dptr[segment.name] then error"equal pointer name" end
ptr.dptr[segment.name] = #data
objects[segment.name] = {}
else
local vdata, fields = table.unpack(line:split("?"))
vdata = vdata:trim():gsub(",", " "):gsub("%s+", " ")
for _, v in ipairs(vdata:split" ") do
if v:sub(1, 1) == "|" then
v = v:sub(2)
if v:sub(1, 1) == "x" then v = "0" .. v end
v = load("return " .. v)()
if type(v) == "string" then
for _, i in ipairs(v:split_8()) do data[#data+1] = i end
elseif type(v) == "number" then
data[#data+1] = v
else error"wrong type"
end
end
end
fields = fields:trim():gsub(",", " "):gsub("%s+", " ")
for _, v in ipairs(fields:split(" ")) do
local k, e = table.unpack(v:split"=")
e = load("return " .. e:sub(2, #e))()
if type(e) == "number" then
objects[segment.name][k] = e
else error"object fields must be numbers"
end
end
end
elseif segment and segment.t == "section" then
if line:sub(1, 7) == "section" then
segment.name = line:sub(9, #line - 1):trim()
if ptr.cptr[segment.name] then error"equal pointer name" end
ptr.cptr[segment.name] = #code
else
for k, v in pairs(FX) do if v.line then line = v.line(line) end end
for i, v in ipairs(line) do
if i == 1 then
code[#code + 1] = opcode.getIndex(v)
code[#code + 1] = #line - 1
else
if v:sub(1, 1) == "|" then
v = v:sub(2)
if v:sub(1, 1) == "x" then v = "0" .. v end
if v:gsub("-", ""):gsub("%d", ""):gsub("%.", "") == "" then
code[#code + 1] = tonumber(v)
elseif v:gsub("%.", "") then
code[#code + 1] = load("return (...)." .. v)(objects)
end
elseif v:sub(1, 1) == "^" then
code[#code + 1] = v:sub(1)
elseif v:sub(1, 1) == "!" then
code[#code + 1] = v:sub(1)
elseif v:sub(1, 1) == "#" then
code[#code + 1] = v:sub(1)
else error("unknown token") end
end
end
end
end
end
end
if dminsize > 0 then
while #data < dminsize do data[#data + 1] = 0 end
end
for k, v in pairs(ptr.cptr) do ptr.cptr[k] = v + #data + 8 end
for i = 1, 4 do code[#code + 1] = 0 end
for i, v in ipairs(code) do
if type(v) == "string" then
if v:sub(1, 1) == "^" then
code[i] = ptr.dptr[v:sub(2)]
elseif v:sub(1, 1) == "!" then
code[i] = ptr.cptr[v:sub(2)] - 8
elseif v:sub(1, 1) == "#" then
v = v:sub(2)
if v:sub(1, 1) == "x" then v = "0" .. v end
if v:gsub("-", ""):gsub("%d", ""):gsub("%.", "") == "" then
const[#const + 1] = tonumber(v)
elseif v:gsub("%.", "") then
const[#const + 1] = load("return (...)." .. v)(objects)
end
code[i] = #data + #code + #const - 1
else error("unknown expression") end
end
end
end
local file = io.open(source)
if file then
file:seek("set", 0)
parseCode(file:read"*a", code, data)
file:close()
end
local loader_segment = {
--[[
setdp data
goto start
1004 - checksum
]]--
opcode.getIndex"setdp", 1,
6, opcode.getIndex"goto",
1, ptr.cptr["start"],
8, 1004
}
local result = {}
for i, v in ipairs(loader_segment) do result[#result + 1] = v end
for _, v in ipairs(data) do result[#result + 1] = v end
for _, v in ipairs(code) do result[#result + 1] = v end
for _, v in ipairs(const) do result[#result + 1] = v end
file = io.open(destination, "w")
if file then
for i, v in ipairs(result) do
if type(v) == "string" then
for _, v_ in ipairs(v) do file:write('str2u64("'..v..'")') end
elseif type(v) == "number" then
file:write(v)
else error"invalid type" end
if i < #result then file:write(", ") end
end
file:close()
end