1 /*
2 ** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $
3 ** Lua compiler (saves bytecodes to files; also list bytecodes)
4 ** See Copyright Notice in lua.h
5 */
6 
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #define luac_c
13 #define LUA_CORE
14 
15 #include "lua.h"
16 #include "lauxlib.h"
17 
18 #include "ldo.h"
19 #include "lfunc.h"
20 #include "lmem.h"
21 #include "lobject.h"
22 #include "lopcodes.h"
23 #include "lstring.h"
24 #include "lundump.h"
25 
26 #define PROGNAME	"luac"		/* default program name */
27 #define	OUTPUT		PROGNAME ".out"	/* default output file */
28 
29 static int listing=0;			/* list bytecodes? */
30 static int dumping=1;			/* dump bytecodes? */
31 static int stripping=0;			/* strip debug information? */
32 static char Output[]={ OUTPUT };	/* default output file name */
33 static const char* output=Output;	/* actual output file name */
34 static const char* progname=PROGNAME;	/* actual program name */
35 
fatal(const char * message)36 static void fatal(const char* message)
37 {
38  fprintf(stderr,"%s: %s\n",progname,message);
39  exit(EXIT_FAILURE);
40 }
41 
cannot(const char * what)42 static void cannot(const char* what)
43 {
44  fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
45  exit(EXIT_FAILURE);
46 }
47 
usage(const char * message)48 static void usage(const char* message)
49 {
50  if (*message=='-')
51   fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
52  else
53   fprintf(stderr,"%s: %s\n",progname,message);
54  fprintf(stderr,
55  "usage: %s [options] [filenames].\n"
56  "Available options are:\n"
57  "  -        process stdin\n"
58  "  -l       list\n"
59  "  -o name  output to file " LUA_QL("name") " (default is \"%s\")\n"
60  "  -p       parse only\n"
61  "  -s       strip debug information\n"
62  "  -v       show version information\n"
63  "  --       stop handling options\n",
64  progname,Output);
65  exit(EXIT_FAILURE);
66 }
67 
68 #define	IS(s)	(strcmp(argv[i],s)==0)
69 
doargs(int argc,char * argv[])70 static int doargs(int argc, char* argv[])
71 {
72  int i;
73  int version=0;
74  if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
75  for (i=1; i<argc; i++)
76  {
77   if (*argv[i]!='-')			/* end of options; keep it */
78    break;
79   else if (IS("--"))			/* end of options; skip it */
80   {
81    ++i;
82    if (version) ++version;
83    break;
84   }
85   else if (IS("-"))			/* end of options; use stdin */
86    break;
87   else if (IS("-l"))			/* list */
88    ++listing;
89   else if (IS("-o"))			/* output file */
90   {
91    output=argv[++i];
92    if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument");
93    if (IS("-")) output=NULL;
94   }
95   else if (IS("-p"))			/* parse only */
96    dumping=0;
97   else if (IS("-s"))			/* strip debug information */
98    stripping=1;
99   else if (IS("-v"))			/* show version */
100    ++version;
101   else					/* unknown option */
102    usage(argv[i]);
103  }
104  if (i==argc && (listing || !dumping))
105  {
106   dumping=0;
107   argv[--i]=Output;
108  }
109  if (version)
110  {
111   printf("%s  %s\n",LUA_RELEASE,LUA_COPYRIGHT);
112   if (version==argc-1) exit(EXIT_SUCCESS);
113  }
114  return i;
115 }
116 
117 #define toproto(L,i) (clvalue(L->top+(i))->l.p)
118 
combine(lua_State * L,int n)119 static const Proto* combine(lua_State* L, int n)
120 {
121  if (n==1)
122   return toproto(L,-1);
123  else
124  {
125   int i,pc;
126   Proto* f=luaF_newproto(L);
127   setptvalue2s(L,L->top,f); incr_top(L);
128   f->source=luaS_newliteral(L,"=(" PROGNAME ")");
129   f->maxstacksize=1;
130   pc=2*n+1;
131   f->code=luaM_newvector(L,pc,Instruction);
132   f->sizecode=pc;
133   f->p=luaM_newvector(L,n,Proto*);
134   f->sizep=n;
135   pc=0;
136   for (i=0; i<n; i++)
137   {
138    f->p[i]=toproto(L,i-n-1);
139    f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
140    f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
141   }
142   f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
143   return f;
144  }
145 }
146 
writer(lua_State * L,const void * p,size_t size,void * u)147 static int writer(lua_State* L, const void* p, size_t size, void* u)
148 {
149  UNUSED(L);
150  return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
151 }
152 
153 struct Smain {
154  int argc;
155  char** argv;
156 };
157 
pmain(lua_State * L)158 static int pmain(lua_State* L)
159 {
160  struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
161  int argc=s->argc;
162  char** argv=s->argv;
163  const Proto* f;
164  int i;
165  if (!lua_checkstack(L,argc)) fatal("too many input files");
166  for (i=0; i<argc; i++)
167  {
168   const char* filename=IS("-") ? NULL : argv[i];
169   if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));
170  }
171  f=combine(L,argc);
172  if (listing) luaU_print(f,listing>1);
173  if (dumping)
174  {
175   FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
176   if (D==NULL) cannot("open");
177   lua_lock(L);
178   luaU_dump(L,f,writer,D,stripping);
179   lua_unlock(L);
180   if (ferror(D)) cannot("write");
181   if (fclose(D)) cannot("close");
182  }
183  return 0;
184 }
185 
main(int argc,char * argv[])186 int main(int argc, char* argv[])
187 {
188  lua_State* L;
189  struct Smain s;
190  int i=doargs(argc,argv);
191  argc-=i; argv+=i;
192  if (argc<=0) usage("no input files given");
193  L=lua_open();
194  if (L==NULL) fatal("not enough memory for state");
195  s.argc=argc;
196  s.argv=argv;
197  if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
198  lua_close(L);
199  return EXIT_SUCCESS;
200 }
201