/* ** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ #define LUAC_CROSS_FILE #include "luac_cross.h" #include C_HEADER_ERRNO #include C_HEADER_STDIO #include C_HEADER_STDLIB #include C_HEADER_STRING #define luac_c #define LUA_CORE #include "lua.h" #include "lauxlib.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstring.h" #include "lundump.h" #define PROGNAME "luac" /* default program name */ #define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ static char Output[]={ OUTPUT }; /* default output file name */ static const char* output=Output; /* actual output file name */ static const char* progname=PROGNAME; /* actual program name */ static DumpTargetInfo target; static void fatal(const char* message) { fprintf(stderr,"%s: %s\n",progname,message); exit(EXIT_FAILURE); } static void cannot(const char* what) { fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } static void usage(const char* message) { if (*message=='-') fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, "usage: %s [options] [filenames].\n" "Available options are:\n" " - process stdin\n" " -l list\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" " -cci bits cross-compile with given integer size\n" " -ccn type bits cross-compile with given lua_Number type and size\n" " -cce endian cross-compile with given endianness ('big' or 'little')\n" " -- stop handling options\n", progname,Output); exit(EXIT_FAILURE); } #define IS(s) (strcmp(argv[i],s)==0) static int doargs(int argc, char* argv[]) { int i; int version=0; if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; for (i=1; i<argc; i++) { if (*argv[i]!='-') /* end of options; keep it */ break; else if (IS("--")) /* end of options; skip it */ { ++i; if (version) ++version; break; } else if (IS("-")) /* end of options; use stdin */ break; else if (IS("-l")) /* list */ ++listing; else if (IS("-o")) /* output file */ { output=argv[++i]; if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ dumping=0; else if (IS("-s")) /* strip debug information */ stripping=1; else if (IS("-v")) /* show version */ ++version; else if (IS("-cci")) /* target integer size */ { int s = target.sizeof_int = atoi(argv[++i])/8; if (!(s==1 || s==2 || s==4)) fatal(LUA_QL("-cci") " must be 8, 16 or 32"); } else if (IS("-ccn")) /* target lua_Number type and size */ { const char *type=argv[++i]; if (strcmp(type,"int")==0) target.lua_Number_integral=1; else if (strcmp(type,"float")==0) target.lua_Number_integral=0; else if (strcmp(type,"float_arm")==0) { target.lua_Number_integral=0; target.is_arm_fpa=1; } else fatal(LUA_QL("-ccn") " type must be " LUA_QL("int") " or " LUA_QL("float") " or " LUA_QL("float_arm")); int s = target.sizeof_lua_Number = atoi(argv[++i])/8; if (target.lua_Number_integral && !(s==1 || s==2 || s==4)) fatal(LUA_QL("-ccn") " size must be 8, 16, or 32 for int"); if (!target.lua_Number_integral && !(s==4 || s==8)) fatal(LUA_QL("-ccn") " size must be 32 or 64 for float"); } else if (IS("-cce")) /* target endianness */ { const char *val=argv[++i]; if (strcmp(val,"big")==0) target.little_endian=0; else if (strcmp(val,"little")==0) target.little_endian=1; else fatal(LUA_QL("-cce") " must be " LUA_QL("big") " or " LUA_QL("little")); } else /* unknown option */ usage(argv[i]); } if (i==argc && (listing || !dumping)) { dumping=0; argv[--i]=Output; } if (version) { printf("%s %s\n",LUA_RELEASE,LUA_COPYRIGHT); if (version==argc-1) exit(EXIT_SUCCESS); } return i; } #define toproto(L,i) (clvalue(L->top+(i))->l.p) static const Proto* combine(lua_State* L, int n) { if (n==1) return toproto(L,-1); else { int i,pc; Proto* f=luaF_newproto(L); setptvalue2s(L,L->top,f); incr_top(L); f->source=luaS_newliteral(L,"=(" PROGNAME ")"); f->maxstacksize=1; pc=2*n+1; f->code=luaM_newvector(L,pc,Instruction); f->sizecode=pc; f->p=luaM_newvector(L,n,Proto*); f->sizep=n; pc=0; for (i=0; i<n; i++) { f->p[i]=toproto(L,i-n-1); f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); } f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); return f; } } static int writer(lua_State* L, const void* p, size_t size, void* u) { UNUSED(L); return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } struct Smain { int argc; char** argv; }; static int pmain(lua_State* L) { struct Smain* s = (struct Smain*)lua_touserdata(L, 1); int argc=s->argc; char** argv=s->argv; const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i<argc; i++) { const char* filename=IS("-") ? NULL : argv[i]; if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1)); } f=combine(L,argc); if (listing) luaU_print(f,listing>1); if (dumping) { FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); if (D==NULL) cannot("open"); lua_lock(L); int result=luaU_dump_crosscompile(L,f,writer,D,stripping,target); lua_unlock(L); if (result==LUA_ERR_CC_INTOVERFLOW) fatal("value too big or small for target integer type"); if (result==LUA_ERR_CC_NOTINTEGER) fatal("target lua_Number is integral but fractional value found"); if (ferror(D)) cannot("write"); if (fclose(D)) cannot("close"); } return 0; } int main(int argc, char* argv[]) { lua_State* L; struct Smain s; int test=1; target.little_endian=*(char*)&test; target.sizeof_int=sizeof(int); target.sizeof_strsize_t=sizeof(strsize_t); target.sizeof_lua_Number=sizeof(lua_Number); target.lua_Number_integral=(((lua_Number)0.5)==0); target.is_arm_fpa=0; int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); L=lua_open(); if (L==NULL) fatal("not enough memory for state"); s.argc=argc; s.argv=argv; if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; }