├── Makefile ├── test.lua ├── README.md ├── luacc.c └── luacc.lua /Makefile: -------------------------------------------------------------------------------- 1 | luacc.so : luacc.c 2 | gcc -g -Wall --shared -fPIC -o $@ $^ -ltcc -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | local luacc = require "luacc" 2 | 3 | luacc.struct ( "foo", { x = "int" , y = "int" }) 4 | luacc.struct ( "mytype", { 5 | obj = "object", 6 | n = "int", 7 | }) 8 | 9 | luacc.cfunction [[ 10 | void swap(foo *f) { 11 | int temp = f->x; 12 | f->x = f->y; 13 | f->y = temp; 14 | } 15 | ]] 16 | 17 | local f = luacc.routine [[ 18 | [inout] a foo 19 | [ret] x foo 20 | 21 | foo x = a; 22 | swap(&a); 23 | ]] 24 | 25 | local p1 = {x=2,y=3} 26 | local p2 = f(p1) 27 | 28 | for k,v in pairs(p1) do 29 | print("p1.",k,v) 30 | end 31 | 32 | 33 | for k,v in pairs(p2) do 34 | print("p2.",k,v) 35 | end 36 | 37 | local f2 = luacc.routine [[ 38 | [out] obj mytype 39 | [in] x object 40 | [in] n int 41 | 42 | mytype obj; 43 | obj.obj = x; 44 | obj.n = n; 45 | ]] 46 | 47 | local x = {} 48 | 49 | f2(x, p1, 5) 50 | 51 | for k,v in pairs(x) do 52 | print("x.",k,v) 53 | end 54 | 55 | for k,v in pairs(luacc.info()) do 56 | print("info",k,v) 57 | end 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LUACC allows you write C code in lua . 2 | 3 | It seems like Cython to python. 4 | 5 | ## Export C routine for lua 6 | 7 | ```Lua 8 | local luacc = require "luacc" 9 | 10 | local f = luacc.routine [[ 11 | [in] a int 12 | [in] b int 13 | [ret] c int 14 | [ret] d int 15 | 16 | int c = a + b; 17 | int d = a - b; 18 | ]] 19 | 20 | print(f(2,1)) -- 3 1 21 | ``` 22 | 23 | ## Import C function for later call from C routine 24 | 25 | ```Lua 26 | local luacc = require "luacc" 27 | 28 | luacc.cfunction [[ 29 | 30 | int max(int a, int b) { 31 | return a > b ? a:b; 32 | } 33 | 34 | int min(int a, int b) { 35 | return a < b ? a:b; 36 | } 37 | 38 | ]] 39 | 40 | local f = luacc.routine [[ 41 | [in] a int 42 | [in] b int 43 | [ret] c int 44 | [ret] d int 45 | 46 | int c = max(a,b); 47 | int d = min(a,b); 48 | ]] 49 | 50 | print(f(2,1)) -- 2 1 51 | ``` 52 | 53 | ## Define user type 54 | 55 | ```Lua 56 | local luacc = require "luacc" 57 | 58 | luacc.struct ( "foo", { x = "int" , y = "int" }) 59 | 60 | local luacc.cfunction [[ 61 | void swap(foo &f) { 62 | int temp = f->x; 63 | f->x = f->y; 64 | f->y = temp; 65 | } 66 | ]] 67 | 68 | local f = luacc.routine [[ 69 | [inout] x foo 70 | 71 | swap(&x); 72 | ]] 73 | 74 | local foo = { x = 1, y = 2} 75 | f(foo) 76 | 77 | print(foo.x, foo.y) -- 2 1 78 | ``` 79 | 80 | It doesn't support nest type yet. 81 | 82 | ## Build-in types 83 | 84 | * int 85 | * bool 86 | * float 87 | * double 88 | * string (const char *) 89 | * object (string table userdata nil) 90 | 91 | ## Make 92 | 93 | * install tcc from http://repo.or.cz/w/tinycc.git 94 | * install lua 5.2 95 | * make 96 | 97 | ## Question ? 98 | 99 | * See test.lua 100 | * Send me an email : http://www.codingnow.com/2000/gmail.gif 101 | * My Blog : http://blog.codingnow.com 102 | -------------------------------------------------------------------------------- /luacc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "libtcc.h" 5 | 6 | #define TCCSTATE "tccstate" 7 | 8 | struct ts { 9 | struct TCCState *state; 10 | void * code; 11 | }; 12 | 13 | static int 14 | ldelete(lua_State *L) { 15 | struct ts *t = lua_touserdata(L,1); 16 | if (t->state) { 17 | tcc_delete(t->state); 18 | t->state = NULL; 19 | } 20 | if (t->code) { 21 | free(t->code); 22 | t->code = NULL; 23 | } 24 | return 0; 25 | } 26 | 27 | static void 28 | errfunc(void *ud, const char *msg) { 29 | lua_State *L = ud; 30 | if (!lua_istable(L,-1)) { 31 | lua_newtable(L); 32 | } 33 | int n = lua_rawlen(L,-1); 34 | lua_pushstring(L, msg); 35 | lua_rawseti(L, -2, n+1); 36 | } 37 | 38 | static int 39 | throw_err(lua_State *L,struct ts *t) { 40 | if (t->code == NULL) { 41 | free(t->code); 42 | t->code = NULL; 43 | } 44 | tcc_delete(t->state); 45 | t->state = NULL; 46 | 47 | if (!lua_istable(L,-1)) { 48 | lua_pushboolean(L, 0); 49 | lua_pushstring(L, "compile error"); 50 | return 2; 51 | } 52 | int errtbl = lua_gettop(L); 53 | luaL_Buffer b; 54 | luaL_buffinit(L, &b); 55 | int n = lua_rawlen(L,errtbl); 56 | int i; 57 | for (i=1;i<=n;i++) { 58 | lua_rawgeti(L,errtbl,i); 59 | luaL_addvalue(&b); 60 | luaL_addchar(&b, '\n'); 61 | } 62 | luaL_pushresult(&b); 63 | lua_pushboolean(L, 0); 64 | lua_insert(L, -2); 65 | return 2; 66 | } 67 | 68 | static struct ts * 69 | _check(lua_State *L, const char *err) { 70 | struct ts * t = luaL_checkudata(L, 1, TCCSTATE); 71 | if (t->state == NULL) { 72 | luaL_error(L, "%s to a closed state %p", err, t); 73 | } 74 | if (t->code) { 75 | luaL_error(L, "%s to a relocated state %p", err, t); 76 | } 77 | return t; 78 | } 79 | 80 | static int 81 | lrelocate(lua_State *L) { 82 | struct ts * t = _check(L, "Relocate"); 83 | 84 | int sz = tcc_relocate(t->state, NULL); 85 | if (sz < 0) { 86 | return throw_err(L,t); 87 | } 88 | t->code = malloc(sz); 89 | int err = tcc_relocate(t->state, t->code); 90 | if (err <0) { 91 | return throw_err(L,t); 92 | } 93 | lua_pushinteger(L,sz); 94 | return 1; 95 | } 96 | 97 | static int 98 | lcompile(lua_State *L) { 99 | struct ts * t = _check(L, "Compile"); 100 | const char * source = luaL_checkstring(L,2); 101 | tcc_set_error_func(t->state, L, errfunc); 102 | int err = tcc_compile_string(t->state, source); 103 | if (err) { 104 | return throw_err(L,t); 105 | } 106 | lua_pushboolean(L,1); 107 | return 1; 108 | } 109 | 110 | static struct ts * 111 | _check_export(lua_State *L, const char *err) { 112 | struct ts * t = luaL_checkudata(L, 1, TCCSTATE); 113 | if (t->state == NULL) { 114 | luaL_error(L, "%s from a closed state %p", err, t); 115 | } 116 | if (t->code == NULL) { 117 | luaL_error(L, "%s from a unrelocate state %p", err, t); 118 | } 119 | return t; 120 | } 121 | 122 | static int 123 | lroutine(lua_State *L) { 124 | struct ts * t = _check_export(L, "Export routine"); 125 | const char * name = luaL_checkstring(L, 2); 126 | lua_CFunction f = (lua_CFunction)tcc_get_symbol(t->state, name); 127 | if (f == NULL) { 128 | return luaL_error(L, "Can't get %s from state %p", name, t); 129 | } 130 | lua_pushcfunction(L, f); 131 | return 1; 132 | } 133 | 134 | static int 135 | lexport(lua_State *L) { 136 | struct ts * t = _check_export(L, "Export"); 137 | luaL_checktype(L, 2, LUA_TTABLE); 138 | lua_pushnil(L); 139 | while (lua_next(L, 2) != 0) { 140 | lua_pop(L,1); 141 | lua_pushvalue(L,-1); 142 | const char * name = luaL_checkstring(L, -1); 143 | void *f = tcc_get_symbol(t->state, name); 144 | if (f == NULL) { 145 | return luaL_error(L, "Can't find %s in state %p", name, t); 146 | } 147 | lua_pushlightuserdata(L, f); 148 | lua_settable(L, 2); 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | static int 155 | limport(lua_State *L) { 156 | struct ts * t = _check(L, "Import"); 157 | luaL_checktype(L, 2, LUA_TTABLE); 158 | lua_pushnil(L); 159 | while (lua_next(L, 2) != 0) { 160 | luaL_checktype(L, -2, LUA_TSTRING); 161 | luaL_checktype(L, -1, LUA_TLIGHTUSERDATA); 162 | const char * name = lua_tostring(L, -2); 163 | void * func = lua_touserdata(L,-1); 164 | tcc_add_symbol(t->state, name, func); 165 | lua_pop(L,1); 166 | } 167 | return 0; 168 | } 169 | 170 | #define FUNC(x) tcc_add_symbol(state, #x , (const void *)x); 171 | 172 | static void 173 | import_sym(struct TCCState *state) { 174 | FUNC(lua_checkstack) 175 | FUNC(lua_pushnumber) 176 | FUNC(lua_tonumberx) 177 | FUNC(lua_settop) 178 | FUNC(lua_gettop) 179 | FUNC(luaL_error) 180 | FUNC(lua_pushboolean) 181 | FUNC(lua_toboolean) 182 | FUNC(lua_tolstring) 183 | FUNC(lua_topointer) 184 | FUNC(lua_pushstring) 185 | FUNC(lua_getfield) 186 | FUNC(lua_setfield) 187 | FUNC(lua_pushnil) 188 | FUNC(lua_rawgetp) 189 | FUNC(lua_rawsetp) 190 | FUNC(lua_pushvalue) 191 | FUNC(lua_createtable) 192 | FUNC(lua_replace) 193 | } 194 | 195 | static int 196 | lapi(lua_State *L) { 197 | struct ts * t = _check(L, "Import api"); 198 | import_sym(t->state); 199 | 200 | return 0; 201 | } 202 | 203 | static int 204 | lclose(lua_State *L) { 205 | struct ts * t = luaL_checkudata(L, 1, TCCSTATE); 206 | if (t->state == NULL) { 207 | return luaL_error(L, "Don't close twice %p", t); 208 | } 209 | tcc_delete(t->state); 210 | t->state = NULL; 211 | return 0; 212 | } 213 | 214 | static int 215 | lopen(lua_State *L) { 216 | struct ts * t = lua_newuserdata(L, sizeof(*t)); 217 | t->code = NULL; 218 | t->state = tcc_new(); 219 | 220 | if (luaL_newmetatable(L, TCCSTATE)) { 221 | luaL_Reg l[] = { 222 | { "close", lclose }, 223 | { "api", lapi }, 224 | { "import", limport }, 225 | { "export", lexport }, 226 | { "compile", lcompile }, 227 | { "relocate", lrelocate }, 228 | { "routine", lroutine }, 229 | { NULL , NULL }, 230 | }; 231 | luaL_newlib(L,l); 232 | lua_setfield(L, -2, "__index"); 233 | lua_pushcfunction(L, ldelete); 234 | lua_setfield(L, -2, "__gc"); 235 | } 236 | lua_setmetatable(L, -2); 237 | return 1; 238 | } 239 | 240 | int 241 | luaopen_luacc_core(lua_State *L) { 242 | luaL_checkversion(L); 243 | lua_pushcfunction(L, lopen); 244 | 245 | return 1; 246 | } 247 | -------------------------------------------------------------------------------- /luacc.lua: -------------------------------------------------------------------------------- 1 | local newstate = require "luacc.core" 2 | 3 | local type_funcs_define = "" 4 | local type_define = "" 5 | local cfunction_define = "" 6 | local codes = {} 7 | local types = {} 8 | local import_funcs = {} 9 | local c_funcs = {} 10 | local info = { 11 | bytes = 0, 12 | state = 0, 13 | struct = 0, 14 | cfunction = 0, 15 | routine = 0; 16 | } 17 | 18 | local luacc = {} 19 | 20 | local function extract_desc(source) 21 | local from = assert(string.find(source, "\n%s+[^[]")) 22 | return string.sub(source, 1, from-1), string.sub(source,from) 23 | end 24 | 25 | local function parser_desc(desc) 26 | local ret = { param = {} , result = {} } 27 | for attrib, name, type in string.gmatch(desc, "%s*%[(%a+)%]%s*([%w_]+)%s+([%a_]+)[^\n]*") do 28 | local v = { name = name , type = type, attrib = attrib } 29 | table.insert( attrib == "ret" and ret.result or ret.param, v) 30 | end 31 | return ret 32 | end 33 | 34 | local stddef = [[ 35 | #ifndef true 36 | typedef int bool; 37 | #define true 1 38 | #define false 0 39 | #endif 40 | #ifndef NULL 41 | #define NULL (void*)0 42 | #endif 43 | typedef const void * object; 44 | typedef unsigned long int size_t; 45 | ]] 46 | 47 | local lua_api = [[ 48 | typedef struct lua_State lua_State; 49 | typedef double lua_Number; 50 | 51 | int lua_checkstack(lua_State *L, int extra); 52 | void lua_pushnumber(lua_State *L, lua_Number n); 53 | lua_Number lua_tonumberx(lua_State *L, int index, int *isnum); 54 | void lua_settop(lua_State *L, int index); 55 | int lua_gettop(lua_State *L); 56 | int luaL_error(lua_State *L, ...); 57 | int lua_toboolean(lua_State *L, int index); 58 | const void * lua_topointer(lua_State *L, int index); 59 | void lua_pushboolean(lua_State *L, int b); 60 | const char *lua_tolstring(lua_State *L,int index, size_t *len); 61 | const char *lua_pushstring(lua_State *L, const char *s); 62 | void lua_getfield (lua_State *L, int index, const char *k); 63 | void lua_setfield (lua_State *L, int index, const char *k); 64 | void lua_pushnil (lua_State *L); 65 | void lua_rawgetp (lua_State *L, int index, const void *p); 66 | void lua_rawsetp (lua_State *L, int index, const void *p); 67 | void lua_pushvalue (lua_State *L, int index); 68 | void lua_createtable (lua_State *L, int narr, int nrec); 69 | void lua_replace (lua_State *L, int index); 70 | #define lua_pop(L,n) lua_settop(L, -(n)-1) 71 | 72 | ]] 73 | 74 | local ctype_conv = { 75 | int = "int", 76 | float = "float", 77 | double = "double", 78 | string = "const char *", 79 | bool = "int", 80 | object = "const void *", 81 | } 82 | 83 | local struct_define_pattern = [[ 84 | typedef struct { 85 | $FIELDS; 86 | } $STRUCTNAME; 87 | 88 | ]] 89 | 90 | local struct_getter_header = [[ 91 | $LAST 92 | 93 | void __$TYPENAME__get(lua_State *L, int index, $TYPENAME *t $HASOBJECT); 94 | void __$TYPENAME__set(lua_State *L, int index, $TYPENAME *t , int objindex); 95 | 96 | ]] 97 | 98 | local struct_getter_pattern = [[ 99 | $STDDEF 100 | $INCLUDE 101 | $STRUCTD 102 | 103 | void __get__(lua_State *L, int index, $TYPENAME *t $HASOBJECT) { 104 | $GSOURCE 105 | } 106 | 107 | void __set__(lua_State *L, int index, $TYPENAME *t , int objindex) { 108 | if (index == 0) { 109 | lua_createtable(L, 0, $SNUMBER); 110 | index = -2; 111 | objindex = 1; 112 | } 113 | $SSOURCE 114 | } 115 | 116 | ]] 117 | 118 | local function struct_getter(name, struct, structd) 119 | local temp = {} 120 | local temp2 = {} 121 | local has_object 122 | local n = 0 123 | for name,type in pairs(struct) do 124 | n = n + 1 125 | table.insert(temp, 'lua_getfield(L, index, "'.. name ..'");') 126 | if type == "object" then 127 | table.insert(temp, "t->"..name.."= lua_topointer(L,-1);") 128 | table.insert(temp, "if (t->"..name..") lua_rawsetp(L, objindex, t->" .. name .. ");") 129 | table.insert(temp2, "if (t->"..name..") lua_rawgetp(L, objindex, t->"..name.."); else lua_pushnil(L);") 130 | has_object = true 131 | else 132 | if type == "int" or type == "float" or type == "double" then 133 | table.insert(temp, "t->"..name.."=("..type..")lua_tonumberx(L,-1,NULL);") 134 | table.insert(temp2, "lua_pushnumber(L, ("..type..")t->" .. name ..");") 135 | elseif type == "boolean" then 136 | table.insert(temp, "t->"..name.."= lua_toboolean(L,-1);") 137 | table.insert(temp2, "lua_pushboolean(L, t->" .. name ..");") 138 | elseif type == "string" then 139 | table.insert(temp, "t->"..name.."= lua_tolstring(L,-1,NULL);") 140 | table.insert(temp2, "if (t->"..name.."==NULL) lua_pushnil(L); else lua_pushstring(L, t->" .. name ..");") 141 | end 142 | table.insert(temp, "lua_pop(L,1);") 143 | end 144 | table.insert(temp2, 'lua_setfield(L, index, "'..name..'");') 145 | end 146 | 147 | local objindex = has_object and ", int objindex" or "" 148 | local pat = { 149 | STDDEF = stddef, 150 | INCLUDE = lua_api, 151 | TYPENAME = name , 152 | IMPORT = headers , 153 | STRUCTD = structd , 154 | HASOBJECT = objindex, 155 | GSOURCE = table.concat(temp, "\n"), 156 | SSOURCE = table.concat(temp2, "\n"), 157 | SNUMBER = n, 158 | LAST = type_funcs_define, 159 | } 160 | 161 | local source = string.gsub( struct_getter_pattern, "%$(%u+)",pat) 162 | 163 | local state = newstate() 164 | state:api() 165 | assert(state:compile(source)) 166 | local sz = assert(state:relocate()) 167 | info.bytes = info.bytes + sz 168 | local export = { 169 | __get__ = true, 170 | __set__ = true, 171 | } 172 | state:export(export) 173 | import_funcs["__"..name.."__get"] = export.__get__ 174 | import_funcs["__"..name.."__set"] = export.__set__ 175 | state:close() 176 | table.insert(codes , state) 177 | 178 | type_funcs_define = string.gsub( struct_getter_header, "%$(%u+)",pat) 179 | 180 | return has_object 181 | end 182 | 183 | function luacc.struct(name, struct) 184 | assert(types[name] == nil) 185 | types[name] = false 186 | local temp = {} 187 | for name,type in pairs(struct) do 188 | local ctype = assert(ctype_conv[type]) 189 | table.insert(temp, ctype .. " " .. name) 190 | end 191 | local d = string.gsub( struct_define_pattern, "%$(%u+)", { STRUCTNAME = name , FIELDS = table.concat(temp, ";\n") }) 192 | type_define = type_define .. d 193 | if struct_getter(name, struct, d) then 194 | types[name] = "objects" 195 | end 196 | end 197 | 198 | local tcc_pattern = [[ 199 | $STDDEF 200 | $INCLUDE 201 | $STRUCTS 202 | $IMPORTS 203 | $GETFUNCS 204 | 205 | int $FUNCNAME(lua_State *_L) { 206 | int __objref = lua_gettop(_L); 207 | if (__objref != $NPARAM) 208 | return luaL_error(_L, "Need $NPARAM params, got %d", __objref); 209 | $HASOBJECT 210 | $VAR 211 | #define return goto __return 212 | $SOURCE 213 | __return: 214 | #undef return 215 | $OUTPUT 216 | $OBJREF 217 | $RETURN 218 | return $NRESULT; 219 | } 220 | ]] 221 | 222 | 223 | 224 | local function gen_var(desc) 225 | local max = math.max(#desc.param,#desc.result) 226 | local t = { "lua_checkstack(_L, " .. max+10 .. ");" } 227 | local has_object 228 | for k , v in ipairs(desc.param) do 229 | if v.attrib == "in" or v.attrib == "inout" then 230 | if v.type == "int" or v.type == "float" or v.type == "double" then 231 | table.insert(t, v.type .. " " .. v.name .. " = (" .. v.type .. ")lua_tonumberx(_L, " .. k ..", NULL);") 232 | elseif v.type == "bool" then 233 | table.insert(t, "bool " .. v.name .. " = lua_toboolean(_L, " .. k ..");") 234 | elseif v.type == "string" then 235 | table.insert(t, "const char *" .. v.name .. " = lua_tolstring(_L, " .. k ..", NULL);") 236 | elseif v.type == "object" then 237 | table.insert(t, "const void *" .. v.name .. " = lua_topointer(_L, " .. k ..");") 238 | table.insert(t, "if (" .. v.name .. ") { lua_pushvalue(_L," .. k .."); lua_rawsetp(_L, __objref, ".. v.name .."); }") 239 | has_object = true 240 | else 241 | local ho = types[v.type] 242 | assert(ho ~= nil, "Don't support in type : " .. v.type) 243 | table.insert(t, v.type .. " " .. v.name .. ";") 244 | if ho then 245 | table.insert(t, "__" .. v.type .. "__get(_L, " .. k .. ",&" .. v.name .. ", __objref);") 246 | hash_object = true 247 | else 248 | table.insert(t, "__" .. v.type .. "__get(_L, " .. k .. ",&" .. v.name .. ");") 249 | end 250 | end 251 | end 252 | end 253 | return table.concat(t, "\n") , has_object 254 | end 255 | 256 | local function gen_ret(result) 257 | local t = {} 258 | for _ , v in ipairs(result) do 259 | if v.type == "int" or v.type == "float" or v.type == "double" then 260 | table.insert(t, "lua_pushnumber(_L, (lua_Number)" .. v.name .. ");") 261 | elseif v.type == "bool" then 262 | table.insert(t, "lua_pushboolean(_L, " .. v.name .. ");") 263 | elseif v.type == "string" then 264 | table.insert(t, "if ("..v.name..") lua_pushstring(_L, " .. v.name .. "); else lua_pushnil(_L); ") 265 | elseif v.type == "object" then 266 | table.insert(t, "if ("..v.name..") { lua_rawgetp(_L, 1, "..v.name.."); } else lua_pushnil(_L);") 267 | else 268 | assert(types[v.type] ~= nil, "Don't support ret type : " .. v.type) 269 | table.insert(t, "__" .. v.type .. "__set(_L, 0, &" .. v.name ..", __objref);") 270 | end 271 | end 272 | 273 | return table.concat(t, "\n") 274 | end 275 | 276 | local function gen_out(param) 277 | local t = {} 278 | for k , v in ipairs(param) do 279 | if v.attrib == "out" or v.attrib == "inout" then 280 | assert(types[v.type] ~= nil, "Don't support out type : " .. v.type) 281 | table.insert(t, "__" .. v.type .. "__set(_L, "..k..", &" .. v.name ..", __objref);") 282 | end 283 | end 284 | return table.concat(t, "\n") 285 | end 286 | 287 | function luacc.routine(source) 288 | local desc, source = extract_desc(source) 289 | desc = parser_desc(desc) 290 | local var, has_object = gen_var(desc) 291 | local temp = { 292 | STDDEF = stddef, 293 | FUNCNAME = "__routine__", 294 | INCLUDE = lua_api, 295 | IMPORTS = cfunction_define, 296 | STRUCTS = type_define, 297 | GETFUNCS = type_funcs_define, 298 | SOURCE = source , 299 | NPARAM = tostring(#desc.param), 300 | NRESULT = tostring(#desc.result), 301 | HASOBJECT = has_object and "++__objref; lua_createtable(_L,0,0);" or "", 302 | VAR = var, 303 | OUTPUT = gen_out(desc.param), 304 | OBJREF = has_object and "lua_replace(_L,1); lua_settop(_L,1);" or "lua_settop(_L, 0);", 305 | RETURN = gen_ret(desc.result) 306 | } 307 | source = string.gsub( tcc_pattern, "%$(%u+)", temp) 308 | 309 | local state = newstate() 310 | state:api() 311 | state:import(import_funcs) 312 | 313 | assert(state:compile(source)) 314 | local sz = assert(state:relocate()) 315 | info.bytes = info.bytes + sz 316 | local f = state:routine(temp.FUNCNAME) 317 | state:close() 318 | table.insert(codes , state) 319 | info.routine = info.routine + 1 320 | return f 321 | end 322 | 323 | local cfunction_pattern = [[ 324 | $STDDEF 325 | $STRUCTS 326 | $IMPORTS 327 | 328 | $SOURCE 329 | ]] 330 | 331 | function luacc.cfunction(source) 332 | local state = newstate() 333 | state:import(c_funcs) 334 | 335 | source = string.gsub( cfunction_pattern, "%$(%u+)", { 336 | STDDEF = stddef, 337 | STRUCTS = type_define, 338 | IMPORTS = cfunction_define, 339 | SOURCE = source, 340 | }) 341 | assert(state:compile(source)) 342 | local sz = assert(state:relocate()) 343 | info.bytes = info.bytes + sz 344 | 345 | local export = {} 346 | local fdefine = {} 347 | for type, name, param, padding in string.gmatch(source, "([%w_]+)%s+([%w_]+)(%b())%s*([;{])") do 348 | if padding == '{' then 349 | export[name] = true 350 | table.insert(fdefine, type .. " " .. name .. param .. ";") 351 | end 352 | end 353 | table.insert(fdefine, "") 354 | 355 | cfunction_define = cfunction_define .. table.concat(fdefine, "\n") 356 | 357 | state:export(export) 358 | 359 | for k,v in pairs(export) do 360 | c_funcs[k] = v 361 | import_funcs[k] = v 362 | end 363 | 364 | state:close() 365 | table.insert(codes , state) 366 | end 367 | 368 | local function count_table(t) 369 | local n = 0 370 | for _ in pairs(t) do 371 | n = n + 1 372 | end 373 | return n 374 | end 375 | 376 | function luacc.info() 377 | info.state = #codes 378 | info.cfunction = count_table(c_funcs) 379 | info.struct = count_table(types) 380 | return info 381 | end 382 | 383 | return luacc 384 | --------------------------------------------------------------------------------