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-2014 Mike Pall. All rights reserved.
6 -- Released under the MIT license. See Copyright Notice in luajit.h
7 ----------------------------------------------------------------------------
9 local sub
, match
, gsub = string.sub
, string.match
, string.gsub
11 local LUA_VERSION
= "5.1.5"
14 local function usage()
15 io
.stderr
:write("Usage: ", arg
and arg
[0] or "genminilua",
16 " lua-", LUA_VERSION
, "-source-dir\n")
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")
26 LUA_SOURCE
= LUA_SOURCE
.."src/"
27 fp
= io
.open(LUA_SOURCE
.. "lua.h")
28 if not fp
then usage() end
30 local all
= fp
:read("*a")
32 if not match(all
, 'LUA_RELEASE%s*"Lua '..LUA_VERSION
..'"') then
33 io
.stderr
:write("Error: version mismatch\n")
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",
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
58 local REMOVE_EXTINC
= { ["<assert.h>"] = true, ["<locale.h>"] = true, }
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");
68 #define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
69 static int tobit(lua_State *L){
71 static int bnot(lua_State *L){
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){
93 int n=lua_isnone(L,2)?8:(int)barg(L,2);
94 const char *hexdigits="0123456789abcdef";
97 if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
99 for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
100 lua_pushlstring(L,buf,(size_t)n);
103 static const struct luaL_Reg bitlib[] = {
118 int main(int argc, char **argv){
119 lua_State *L = luaL_newstate();
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]))
130 for (i = 2; i < argc; i++)
131 lua_pushstring(L, argv[i]);
132 if (lua_pcall(L, argc - 2, 0, 0)) {
134 fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
142 local function read_sources()
144 for i
, name
in ipairs(LUA_FILES
) do
145 local fp
= assert(io
.open(LUA_SOURCE
..name
, "r"))
149 t
[#t
+1] = CUSTOM_MAIN
150 return table.concat(t
)
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")
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
)
168 local function get_license(src
)
169 return match(src
, "/%*+\n%* Copyright %(.-%*/\n")
172 local function fold_lines(src
)
173 return gsub(src
, "\\\n", " ")
178 local function save_str(str
)
184 local function save_strings(src
)
185 src
= gsub(src
, '"[^"\n]*"', save_str
)
186 return gsub(src
, "'[^'\n]*'", save_str
)
189 local function restore_strings(src
)
190 return gsub(src
, "\1(%d+)\2", function(numstr
)
191 return strings
[tonumber(numstr
)]
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
200 def
== "defined(LUA_CORE)" or
201 def
== "MINSTRTABSIZE" or
202 def
== "LUA_MINBUFFER" or
203 def
== "HARDSTACKTESTS" or
207 local head
, defs
= {[[
209 typedef unsigned __int64 U64;
211 typedef unsigned long long U64;
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
224 elseif pp
== "else" then
226 if on
== false then on
= true else on
= false end
228 elseif pp
== "elif" then
232 elseif pp
== "endif" then
236 if pp
== "include" then
237 if not head
[def
] and not REMOVE_EXTINC
[def
] then
239 head
[#head
+1] = "#include "..def
.."\n"
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
248 t
[#t
+1] = "#define "..def
.."\n"
250 elseif pp
~= "undef" then
251 error("unexpected directive: "..pp
.." "..def
)
254 if on
then t
[#t
+1] = txt
end
256 return gsub(table.concat(t
), "%a[%w_]*", function(tok
)
257 return defs
[tok
] or tok
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! */
266 return hdr
..license
..table.concat(head
)..src
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
275 local function strip_unused2(src
)
276 return gsub(src
, "Symbolic Execution.-}=", "")
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;",
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 return gsub(src
, "\n\n+", "\n")
306 local function strip_comments(src
)
307 return gsub(src
, "/%*.-%*/", " ")
310 local function strip_whitespace(src
)
311 src
= gsub(src
, "^%s+", "")
312 src
= gsub(src
, "%s*\n%s*", "\n")
313 src
= gsub(src
, "[ \t]+", " ")
314 src
= gsub(src
, "(%W) ", "%1")
315 return gsub(src
, " (%W)", "%1")
318 local function rename_tokens1(src
)
319 src
= gsub(src
, "getline", "getline_")
320 src
= gsub(src
, "struct ([%w_]+)", "ZX%1")
321 return gsub(src
, "union ([%w_]+)", "ZY%1")
324 local function rename_tokens2(src
)
325 src
= gsub(src
, "ZX([%w_]+)", "struct %1")
326 return gsub(src
, "ZY([%w_]+)", "union %1")
329 local function func_gather(src
)
330 local nodes
, list
= {}, {}
331 local pos
, len
= 1, #src
333 local d
, w
= match(src
, "^(#define ([%w_]+)[^\n]*\n)", pos
)
340 d
, w
, s
= match(src
, "^(([%w_]+)[^\n]*([{;])\n)", pos
)
342 d
, w
, s
= match(src
, "^(([%w_]+)[^(]*%b()([{;])\n)", pos
)
343 if not d
then d
= match(src
, "^[^\n]*\n", pos
) end
346 d
= d
..sub(match(src
, "^%b{}[^;\n]*;?\n", pos
+#d
-2), 3)
347 if sub(d
, -2) == "{\n" then
348 d
= d
..sub(match(src
, "^%b{}[^;\n]*;?\n", pos
+#d
-2), 3)
352 if w
== "typedef" then
353 if match(d
, "^typedef enum") then
356 k
= match(d
, "([%w_]+);\n$")
357 if not k
then k
= match(d
, "^.-%(.-([%w_]+)%)%(") end
359 elseif w
== "enum" then
362 k
= match(d
, "^[^\n]-([%w_]+)[(%[=]")
364 if w
~= "static" and k
~= "main" then v
= "static "..d
end
371 if o
then nodes
["*"..k
] = o
end
382 local function func_visit(nodes
, list
, used
, n
)
384 for m
in string.gmatch(list
[i
], "[%w_]+") do
389 func_visit(nodes
, list
, used
, m
)
397 local function func_collect(src
)
398 local nodes
, list
= func_gather(src
)
400 func_visit(nodes
, list
, used
, "main")
401 for n
,i
in pairs(nodes
) do
403 if j
and j
< i
then used
["*"..n
] = j
end
405 for n
,i
in pairs(nodes
) do
406 if not used
[n
] then list
[i
] = "" end
408 return table.concat(list
)
412 local src
= read_sources()
413 src
= merge_includes(src
)
414 local license
= get_license(src
)
415 src
= fold_lines(src
)
416 src
= strip_unused1(src
)
417 src
= save_strings(src
)
418 src
= strip_unused2(src
)
419 src
= strip_comments(src
)
420 src
= preprocess(src
)
421 src
= strip_whitespace(src
)
422 src
= strip_unused3(src
)
423 src
= rename_tokens1(src
)
424 src
= func_collect(src
)
425 src
= rename_tokens2(src
)
426 src
= restore_strings(src
)
427 src
= merge_header(src
, license
)