genminilua.lua (12039B)
1 ---------------------------------------------------------------------------- 2 -- Lua script to generate a customized, minified version of Lua. 3 -- The resulting 'minilua' is used for the build process of LuaJIT. 4 ---------------------------------------------------------------------------- 5 -- Copyright (C) 2005-2016 Mike Pall. All rights reserved. 6 -- Released under the MIT license. See Copyright Notice in luajit.h 7 ---------------------------------------------------------------------------- 8 9 local sub, match, gsub = string.sub, string.match, string.gsub 10 11 local LUA_VERSION = "5.1.5" 12 local LUA_SOURCE 13 14 local function usage() 15 io.stderr:write("Usage: ", arg and arg[0] or "genminilua", 16 " lua-", LUA_VERSION, "-source-dir\n") 17 os.exit(1) 18 end 19 20 local function find_sources() 21 LUA_SOURCE = arg and arg[1] 22 if not LUA_SOURCE then usage() end 23 if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end 24 local fp = io.open(LUA_SOURCE .. "lua.h") 25 if not fp then 26 LUA_SOURCE = LUA_SOURCE.."src/" 27 fp = io.open(LUA_SOURCE .. "lua.h") 28 if not fp then usage() end 29 end 30 local all = fp:read("*a") 31 fp:close() 32 if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then 33 io.stderr:write("Error: version mismatch\n") 34 usage() 35 end 36 end 37 38 local LUA_FILES = { 39 "lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c", 40 "lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c", 41 "llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c", 42 "lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c", 43 } 44 45 local REMOVE_LIB = {} 46 gsub([[ 47 collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset 48 select tostring xpcall 49 foreach foreachi getn maxn setn 50 popen tmpfile seek setvbuf __tostring 51 clock date difftime execute getenv rename setlocale time tmpname 52 dump gfind len reverse 53 LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME 54 ]], "%S+", function(name) 55 REMOVE_LIB[name] = true 56 end) 57 58 local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, } 59 60 local CUSTOM_MAIN = [[ 61 typedef unsigned int UB; 62 static UB barg(lua_State *L,int idx){ 63 union{lua_Number n;U64 b;}bn; 64 bn.n=lua_tonumber(L,idx)+6755399441055744.0; 65 if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number"); 66 return(UB)bn.b; 67 } 68 #define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1; 69 static int tobit(lua_State *L){ 70 BRET(barg(L,1))} 71 static int bnot(lua_State *L){ 72 BRET(~barg(L,1))} 73 static int band(lua_State *L){ 74 int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)} 75 static int bor(lua_State *L){ 76 int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)} 77 static int bxor(lua_State *L){ 78 int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)} 79 static int lshift(lua_State *L){ 80 UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)} 81 static int rshift(lua_State *L){ 82 UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)} 83 static int arshift(lua_State *L){ 84 UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)} 85 static int rol(lua_State *L){ 86 UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))} 87 static int ror(lua_State *L){ 88 UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))} 89 static int bswap(lua_State *L){ 90 UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)} 91 static int tohex(lua_State *L){ 92 UB b=barg(L,1); 93 int n=lua_isnone(L,2)?8:(int)barg(L,2); 94 const char *hexdigits="0123456789abcdef"; 95 char buf[8]; 96 int i; 97 if(n<0){n=-n;hexdigits="0123456789ABCDEF";} 98 if(n>8)n=8; 99 for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;} 100 lua_pushlstring(L,buf,(size_t)n); 101 return 1; 102 } 103 static const struct luaL_Reg bitlib[] = { 104 {"tobit",tobit}, 105 {"bnot",bnot}, 106 {"band",band}, 107 {"bor",bor}, 108 {"bxor",bxor}, 109 {"lshift",lshift}, 110 {"rshift",rshift}, 111 {"arshift",arshift}, 112 {"rol",rol}, 113 {"ror",ror}, 114 {"bswap",bswap}, 115 {"tohex",tohex}, 116 {NULL,NULL} 117 }; 118 int main(int argc, char **argv){ 119 lua_State *L = luaL_newstate(); 120 int i; 121 luaL_openlibs(L); 122 luaL_register(L, "bit", bitlib); 123 if (argc < 2) return sizeof(void *); 124 lua_createtable(L, 0, 1); 125 lua_pushstring(L, argv[1]); 126 lua_rawseti(L, -2, 0); 127 lua_setglobal(L, "arg"); 128 if (luaL_loadfile(L, argv[1])) 129 goto err; 130 for (i = 2; i < argc; i++) 131 lua_pushstring(L, argv[i]); 132 if (lua_pcall(L, argc - 2, 0, 0)) { 133 err: 134 fprintf(stderr, "Error: %s\n", lua_tostring(L, -1)); 135 return 1; 136 } 137 lua_close(L); 138 return 0; 139 } 140 ]] 141 142 local function read_sources() 143 local t = {} 144 for i, name in ipairs(LUA_FILES) do 145 local fp = assert(io.open(LUA_SOURCE..name, "r")) 146 t[i] = fp:read("*a") 147 assert(fp:close()) 148 end 149 t[#t+1] = CUSTOM_MAIN 150 return table.concat(t) 151 end 152 153 local includes = {} 154 155 local function merge_includes(src) 156 return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name) 157 if includes[name] then return "" end 158 includes[name] = true 159 local fp = assert(io.open(LUA_SOURCE..name, "r")) 160 local src = fp:read("*a") 161 assert(fp:close()) 162 src = gsub(src, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "") 163 src = gsub(src, "#endif%s*$", "") 164 return merge_includes(src) 165 end) 166 end 167 168 local function get_license(src) 169 return match(src, "/%*+\n%* Copyright %(.-%*/\n") 170 end 171 172 local function fold_lines(src) 173 return gsub(src, "\\\n", " ") 174 end 175 176 local strings = {} 177 178 local function save_str(str) 179 local n = #strings+1 180 strings[n] = str 181 return "\1"..n.."\2" 182 end 183 184 local function save_strings(src) 185 src = gsub(src, '"[^"\n]*"', save_str) 186 return gsub(src, "'[^'\n]*'", save_str) 187 end 188 189 local function restore_strings(src) 190 return gsub(src, "\1(%d+)\2", function(numstr) 191 return strings[tonumber(numstr)] 192 end) 193 end 194 195 local function def_istrue(def) 196 return def == "INT_MAX > 2147483640L" or 197 def == "LUAI_BITSINT >= 32" or 198 def == "SIZE_Bx < LUAI_BITSINT-1" or 199 def == "cast" or 200 def == "defined(LUA_CORE)" or 201 def == "MINSTRTABSIZE" or 202 def == "LUA_MINBUFFER" or 203 def == "HARDSTACKTESTS" or 204 def == "UNUSED" 205 end 206 207 local head, defs = {[[ 208 #ifdef _MSC_VER 209 typedef unsigned __int64 U64; 210 #else 211 typedef unsigned long long U64; 212 #endif 213 int _CRT_glob = 0; 214 ]]}, {} 215 216 local function preprocess(src) 217 local t = { match(src, "^(.-)#") } 218 local lvl, on, oldon = 0, true, {} 219 for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do 220 if pp == "if" or pp == "ifdef" or pp == "ifndef" then 221 lvl = lvl + 1 222 oldon[lvl] = on 223 on = def_istrue(def) 224 elseif pp == "else" then 225 if oldon[lvl] then 226 if on == false then on = true else on = false end 227 end 228 elseif pp == "elif" then 229 if oldon[lvl] then 230 on = def_istrue(def) 231 end 232 elseif pp == "endif" then 233 on = oldon[lvl] 234 lvl = lvl - 1 235 elseif on then 236 if pp == "include" then 237 if not head[def] and not REMOVE_EXTINC[def] then 238 head[def] = true 239 head[#head+1] = "#include "..def.."\n" 240 end 241 elseif pp == "define" then 242 local k, sp, v = match(def, "([%w_]+)(%s*)(.*)") 243 if k and not (sp == "" and sub(v, 1, 1) == "(") then 244 defs[k] = gsub(v, "%a[%w_]*", function(tok) 245 return defs[tok] or tok 246 end) 247 else 248 t[#t+1] = "#define "..def.."\n" 249 end 250 elseif pp ~= "undef" then 251 error("unexpected directive: "..pp.." "..def) 252 end 253 end 254 if on then t[#t+1] = txt end 255 end 256 return gsub(table.concat(t), "%a[%w_]*", function(tok) 257 return defs[tok] or tok 258 end) 259 end 260 261 local function merge_header(src, license) 262 local hdr = string.format([[ 263 /* This is a heavily customized and minimized copy of Lua %s. */ 264 /* It's only used to build LuaJIT. It does NOT have all standard functions! */ 265 ]], LUA_VERSION) 266 return hdr..license..table.concat(head)..src 267 end 268 269 local function strip_unused1(src) 270 return gsub(src, '( {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func) 271 return REMOVE_LIB[func] and "" or line 272 end) 273 end 274 275 local function strip_unused2(src) 276 return gsub(src, "Symbolic Execution.-}=", "") 277 end 278 279 local function strip_unused3(src) 280 src = gsub(src, "extern", "static") 281 src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(") 282 src = gsub(src, "#define lua_assert[^\n]*\n", "") 283 src = gsub(src, "lua_assert%b();?", "") 284 src = gsub(src, "default:\n}", "default:;\n}") 285 src = gsub(src, "lua_lock%b();", "") 286 src = gsub(src, "lua_unlock%b();", "") 287 src = gsub(src, "luai_threadyield%b();", "") 288 src = gsub(src, "luai_userstateopen%b();", "{}") 289 src = gsub(src, "luai_userstate%w+%b();", "") 290 src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser") 291 src = gsub(src, "trydecpoint%(ls,seminfo%)", 292 "luaX_lexerror(ls,\"malformed number\",TK_NUMBER)") 293 src = gsub(src, "int c=luaZ_lookahead%b();", "") 294 src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;", 295 "return 1;") 296 src = gsub(src, "getfuncname%b():", "NULL:") 297 src = gsub(src, "getobjname%b():", "NULL:") 298 src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "") 299 src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "") 300 src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "") 301 src = gsub(src, "(twoto%b()%()", "%1(size_t)") 302 src = gsub(src, "i<sizenode", "i<(int)sizenode") 303 src = gsub(src, "cast%(unsigned int,key%-1%)", "cast(unsigned int,key)-1") 304 return gsub(src, "\n\n+", "\n") 305 end 306 307 local function strip_comments(src) 308 return gsub(src, "/%*.-%*/", " ") 309 end 310 311 local function strip_whitespace(src) 312 src = gsub(src, "^%s+", "") 313 src = gsub(src, "%s*\n%s*", "\n") 314 src = gsub(src, "[ \t]+", " ") 315 src = gsub(src, "(%W) ", "%1") 316 return gsub(src, " (%W)", "%1") 317 end 318 319 local function rename_tokens1(src) 320 src = gsub(src, "getline", "getline_") 321 src = gsub(src, "struct ([%w_]+)", "ZX%1") 322 return gsub(src, "union ([%w_]+)", "ZY%1") 323 end 324 325 local function rename_tokens2(src) 326 src = gsub(src, "ZX([%w_]+)", "struct %1") 327 return gsub(src, "ZY([%w_]+)", "union %1") 328 end 329 330 local function func_gather(src) 331 local nodes, list = {}, {} 332 local pos, len = 1, #src 333 while pos < len do 334 local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos) 335 if d then 336 local n = #list+1 337 list[n] = d 338 nodes[w] = n 339 else 340 local s 341 d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos) 342 if not d then 343 d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos) 344 if not d then d = match(src, "^[^\n]*\n", pos) end 345 end 346 if s == "{" then 347 d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3) 348 if sub(d, -2) == "{\n" then 349 d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3) 350 end 351 end 352 local k, v = nil, d 353 if w == "typedef" then 354 if match(d, "^typedef enum") then 355 head[#head+1] = d 356 else 357 k = match(d, "([%w_]+);\n$") 358 if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end 359 end 360 elseif w == "enum" then 361 head[#head+1] = v 362 elseif w ~= nil then 363 k = match(d, "^[^\n]-([%w_]+)[(%[=]") 364 if k then 365 if w ~= "static" and k ~= "main" then v = "static "..d end 366 else 367 k = w 368 end 369 end 370 if w and k then 371 local o = nodes[k] 372 if o then nodes["*"..k] = o end 373 local n = #list+1 374 list[n] = v 375 nodes[k] = n 376 end 377 end 378 pos = pos + #d 379 end 380 return nodes, list 381 end 382 383 local function func_visit(nodes, list, used, n) 384 local i = nodes[n] 385 for m in string.gmatch(list[i], "[%w_]+") do 386 if nodes[m] then 387 local j = used[m] 388 if not j then 389 used[m] = i 390 func_visit(nodes, list, used, m) 391 elseif i < j then 392 used[m] = i 393 end 394 end 395 end 396 end 397 398 local function func_collect(src) 399 local nodes, list = func_gather(src) 400 local used = {} 401 func_visit(nodes, list, used, "main") 402 for n,i in pairs(nodes) do 403 local j = used[n] 404 if j and j < i then used["*"..n] = j end 405 end 406 for n,i in pairs(nodes) do 407 if not used[n] then list[i] = "" end 408 end 409 return table.concat(list) 410 end 411 412 find_sources() 413 local src = read_sources() 414 src = merge_includes(src) 415 local license = get_license(src) 416 src = fold_lines(src) 417 src = strip_unused1(src) 418 src = save_strings(src) 419 src = strip_unused2(src) 420 src = strip_comments(src) 421 src = preprocess(src) 422 src = strip_whitespace(src) 423 src = strip_unused3(src) 424 src = rename_tokens1(src) 425 src = func_collect(src) 426 src = rename_tokens2(src) 427 src = restore_strings(src) 428 src = merge_header(src, license) 429 io.write(src)