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 parsingtype_preprocessor= {
["undefined"] ="char",
["byte"] ="char",
["undefined2"] ="short",
["undefined4"] ="int",
}
functiongenerate_struct(node, ignore_prefix)
localignoring=falseifignore_prefix~=nilthenignoring=trueendifnode.tag~="struct-or-union-specifier" thenerror() endifnode[1] ~="struct" thenerror() endname=node[3]
print(string.format("generate_struct: struct name: %s", name))
sdl=node[4]
offset=0getters= {}
setters= {}
fork, sdinipairs(sdl) dotype_size=nilsql=sd[1]
tp=sql[1]
type_string=tp[1]
dl=sd[2]
sdr=dl[1]
d=sdr[1]
pointer_string=nilifd[1].tag=="identifier" thenid=d[1] identifier_string=id[1]
full_type_string=type_stringelseifd[1].tag=="pointer" thenp=d[1]
id=p[3]
identifier_string=id[1]
pointer_string= (pointer_stringor"") .."*"full_type_string=type_string.."" ..pointer_stringelseifd[1].tag=="declarator-subscript" thennode_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.."[*]"elseerror(d[1].tag)
endifignoringandidentifier_string:sub(1, ignore_prefix:len()) ==ignore_prefixthen-- continueelse-- if identifier_string == "new" or identifier_string == "at" then-- error(string.format("reserved name: %s", identifier_string))-- endiftype_size==nilthentype_size=type_size_lookup[full_type_string]
endiftype_size==nilthenerror(full_type_string) endprint(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]
ifg==nilthenerror(full_type_string) endiffull_type_string=="char[*]" thengetter=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]
ifs==nilthenerror(full_type_string) endsetter=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)
elsegetter=string.format([[ if k == "%s" then return %s(address + %s) end]], identifier_string, g, offset)
s=type_setter_lookup[full_type_string]
ifs==nilthenerror(full_type_string) endsetter=string.format([[ if k == "%s" then return %s(address + %s, v) end]], identifier_string, s, offset)
endtable.insert(getters, getter)
table.insert(setters, setter)
endoffset=offset+type_sizeendsize=offsetreturnstring.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"))
endfunctiontranslation_unit_to_struct_specifier(node)
returnnode[1][1][1][1][1] -- todo: ignores possibility of multiple struct definitionsendlua=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)); returnfakeResultend,
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() -- allocatedprint(#b)
b=nilcollectgarbage()
Options:
https://github.com/zhaojh329/lua-ffi
https://github.com/q66/cffi-lua
Or roll our own: