-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
Options:
https://github.com/zhaojh329/lua-ffi
https://github.com/q66/cffi-lua
Or roll our own:
c11 = require("c11")
lpegrex = require("lpegrex")
node = c11([[
struct A {
int a;
short b;
char c;
void * d;
char field_0x100;
char e[100];
char * f;
};
]], "struct_test")
type_size_lookup = {
["char"] = 1,
["byte"] = 1,
["short"] = 2,
["int"] = 4,
["void *"] = 4,
["char *"] = 4,
}
type_getter_lookup = {
["char"] = "readByte",
["byte"] = "readByte",
["short"] = "readSmallInteger",
["int"] = "readInteger",
["void *"] = "readInteger",
["char *"] = "readInteger",
["char[*]"] = "readString",
}
type_setter_lookup = {
["char"] = "writeByte",
["byte"] = "writeByte",
["short"] = "writeSmallInteger",
["int"] = "writeInteger",
["void *"] = "writeInteger",
["char *"] = "writeInteger",
["char[*]"] = "writeString",
}
-- todo implement this before c11 parsing
type_preprocessor = {
["undefined"] = "char",
["byte"] = "char",
["undefined2"] = "short",
["undefined4"] = "int",
}
function generate_struct(node, ignore_prefix)
local ignoring = false
if ignore_prefix ~= nil then
ignoring = true
end
if node.tag ~= "struct-or-union-specifier" then error() end
if node[1] ~= "struct" then error() end
name = node[3]
print(string.format("generate_struct: struct name: %s", name))
sdl = node[4]
offset = 0
getters = {}
setters = {}
for k, sd in ipairs(sdl) do
type_size = nil
sql = sd[1]
tp = sql[1]
type_string = tp[1]
dl = sd[2]
sdr = dl[1]
d = sdr[1]
pointer_string = nil
if d[1].tag == "identifier" then
id = d[1]
identifier_string = id[1]
full_type_string = type_string
elseif d[1].tag == "pointer" then
p = d[1]
id = p[3]
identifier_string = id[1]
pointer_string = (pointer_string or "") .. "*"
full_type_string = type_string .. " " .. pointer_string
elseif d[1].tag == "declarator-subscript" then
node_to_solve = d[1]
subscript = d[1]
id = subscript[1]
identifier_string = id[1]
integer_constant = subscript[3]
type_size = integer_constant[1] * type_size_lookup[type_string]
-- error("node_to_solve")
full_type_string = type_string .. "[*]"
else
error(d[1].tag)
end
if ignoring and identifier_string:sub(1, ignore_prefix:len()) == ignore_prefix then
-- continue
else
-- if identifier_string == "new" or identifier_string == "at" then
-- error(string.format("reserved name: %s", identifier_string))
-- end
if type_size == nil then
type_size = type_size_lookup[full_type_string]
end
if type_size == nil then error(full_type_string) end
print(string.format("name: %s, type: %s, size: %s, offset: %s", identifier_string, full_type_string, type_size, offset))
g = type_getter_lookup[full_type_string]
if g == nil then error(full_type_string) end
if full_type_string == "char[*]" then
getter = string.format([[
if k == "%s" then
return %s(address + %s, %s)
end
]], identifier_string, g, offset, type_size)
s = type_setter_lookup[full_type_string]
if s == nil then error(full_type_string) end
setter = string.format([[
if k == "%s" then
if v:len() >= %s then
error("string too large")
end
return %s(address + %s, v)
end
]], identifier_string, type_size, s, offset)
else
getter = string.format([[
if k == "%s" then
return %s(address + %s)
end
]], identifier_string, g, offset)
s = type_setter_lookup[full_type_string]
if s == nil then error(full_type_string) end
setter = string.format([[
if k == "%s" then
return %s(address + %s, v)
end
]], identifier_string, s, offset)
end
table.insert(getters, getter)
table.insert(setters, setter)
end
offset = offset + type_size
end
size = offset
return string.format([[
return function(address)
local allocated = false
local deallocated = nil
local size = %s
if address == nil then
print("allocating")
allocated = true
deallocated = false
address = allocate(size)
end
if type(address) ~= "number" then
error("not a valid address:" .. tostring(address))
end
local mt = {
__index = function(t, k)
%s
end,
__newindex = function(t, k, v)
%s
end,
__gc = function(t)
if allocated and deallocated == false then
deallocate(address)
deallocated = true
end
end,
__len = function(t)
return size
end,
}
return setmetatable({}, mt)
end
]], size, table.concat(getters, "\n\n"), table.concat(setters, "\n\n"))
end
function translation_unit_to_struct_specifier(node)
return node[1][1][1][1][1] -- todo: ignores possibility of multiple struct definitions
end
lua = generate_struct(translation_unit_to_struct_specifier(node))
compile = load(lua, "generator", 't', {
error = error,
tostring = tostring,
print = print,
type = type,
table = table,
string = string,
setmetatable = setmetatable,
allocate = function(size) fakeResult = 0x400000 + size; print(string.format("allocate %s => %X", size, fakeResult)); return fakeResult end,
deallocate = function(address) print(string.format("deallocate %X", address)) end,
readByte = function(address) print(string.format("readByte %X", address)) end,
readSmallInteger = function(address) print(string.format("readSmallInteger %X", address)) end,
readInteger = function(address) print(string.format("readInteger %X", address)) end,
readString = function(address, size) print(string.format("readString %X %s", address, size)) end,
writeByte = function(address) print(string.format("writeByte %X", address)) end,
writeSmallInteger = function(address) print(string.format("writeSmallInteger %X", address)) end,
writeInteger = function(address) print(string.format("writeInteger %X", address)) end,
writeString = function(address, data) print(string.format("writeString %X %s", address, data)) end,
})
A = compile()
a = A(0x400000)
b = A() -- allocated
print(#b)
b = nil
collectgarbage()Metadata
Metadata
Assignees
Labels
No labels