1/*
2** $Id: luac.c $
3** Lua compiler (saves bytecodes to files; also lists bytecodes)
4** See Copyright Notice in lua.h
5*/
6
7#define luac_c
8#define LUA_CORE
9
10#include "lprefix.h"
11
12#include <ctype.h>
13#include <errno.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17
18#include "lua.h"
19#include "lauxlib.h"
20
21#include "ldebug.h"
22#include "lobject.h"
23#include "lopcodes.h"
24#include "lopnames.h"
25#include "lstate.h"
26#include "lundump.h"
27
28static void PrintFunction(const Proto* f, int full);
29#define luaU_print	PrintFunction
30
31#define PROGNAME	"luac"		/* default program name */
32#define OUTPUT		PROGNAME ".out"	/* default output file */
33
34static int listing=0;			/* list bytecodes? */
35static int dumping=1;			/* dump bytecodes? */
36static int stripping=0;			/* strip debug information? */
37static char Output[]={ OUTPUT };	/* default output file name */
38static const char* output=Output;	/* actual output file name */
39static const char* progname=PROGNAME;	/* actual program name */
40static TString **tmname;
41
42static void fatal(const char* message)
43{
44 fprintf(stderr,"%s: %s\n",progname,message);
45 exit(EXIT_FAILURE);
46}
47
48static void cannot(const char* what)
49{
50 fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
51 exit(EXIT_FAILURE);
52}
53
54static void usage(const char* message)
55{
56 if (*message=='-')
57  fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message);
58 else
59  fprintf(stderr,"%s: %s\n",progname,message);
60 fprintf(stderr,
61  "usage: %s [options] [filenames]\n"
62  "Available options are:\n"
63  "  -l       list (use -l -l for full listing)\n"
64  "  -o name  output to file 'name' (default is \"%s\")\n"
65  "  -p       parse only\n"
66  "  -s       strip debug information\n"
67  "  -v       show version information\n"
68  "  --       stop handling options\n"
69  "  -        stop handling options and process stdin\n"
70  ,progname,Output);
71 exit(EXIT_FAILURE);
72}
73
74#define IS(s)	(strcmp(argv[i],s)==0)
75
76static int doargs(int argc, char* argv[])
77{
78 int i;
79 int version=0;
80 if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
81 for (i=1; i<argc; i++)
82 {
83  if (*argv[i]!='-')			/* end of options; keep it */
84   break;
85  else if (IS("--"))			/* end of options; skip it */
86  {
87   ++i;
88   if (version) ++version;
89   break;
90  }
91  else if (IS("-"))			/* end of options; use stdin */
92   break;
93  else if (IS("-l"))			/* list */
94   ++listing;
95  else if (IS("-o"))			/* output file */
96  {
97   output=argv[++i];
98   if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
99    usage("'-o' needs argument");
100   if (IS("-")) output=NULL;
101  }
102  else if (IS("-p"))			/* parse only */
103   dumping=0;
104  else if (IS("-s"))			/* strip debug information */
105   stripping=1;
106  else if (IS("-v"))			/* show version */
107   ++version;
108  else					/* unknown option */
109   usage(argv[i]);
110 }
111 if (i==argc && (listing || !dumping))
112 {
113  dumping=0;
114  argv[--i]=Output;
115 }
116 if (version)
117 {
118  printf("%s\n",LUA_COPYRIGHT);
119  if (version==argc-1) exit(EXIT_SUCCESS);
120 }
121 return i;
122}
123
124#define FUNCTION "(function()end)();"
125
126static const char* reader(lua_State* L, void* ud, size_t* size)
127{
128 UNUSED(L);
129 if ((*(int*)ud)--)
130 {
131  *size=sizeof(FUNCTION)-1;
132  return FUNCTION;
133 }
134 else
135 {
136  *size=0;
137  return NULL;
138 }
139}
140
141#define toproto(L,i) getproto(s2v(L->top+(i)))
142
143static const Proto* combine(lua_State* L, int n)
144{
145 if (n==1)
146  return toproto(L,-1);
147 else
148 {
149  Proto* f;
150  int i=n;
151  if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1));
152  f=toproto(L,-1);
153  for (i=0; i<n; i++)
154  {
155   f->p[i]=toproto(L,i-n-1);
156   if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
157  }
158  f->sizelineinfo=0;
159  return f;
160 }
161}
162
163static int writer(lua_State* L, const void* p, size_t size, void* u)
164{
165 UNUSED(L);
166 return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
167}
168
169static int pmain(lua_State* L)
170{
171 int argc=(int)lua_tointeger(L,1);
172 char** argv=(char**)lua_touserdata(L,2);
173 const Proto* f;
174 int i;
175 tmname=G(L)->tmname;
176 if (!lua_checkstack(L,argc)) fatal("too many input files");
177 for (i=0; i<argc; i++)
178 {
179  const char* filename=IS("-") ? NULL : argv[i];
180  if (luaL_loadfile(L,filename)!=LUA_OK) fatal(lua_tostring(L,-1));
181 }
182 f=combine(L,argc);
183 if (listing) luaU_print(f,listing>1);
184 if (dumping)
185 {
186  FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
187  if (D==NULL) cannot("open");
188  lua_lock(L);
189  luaU_dump(L,f,writer,D,stripping);
190  lua_unlock(L);
191  if (ferror(D)) cannot("write");
192  if (fclose(D)) cannot("close");
193 }
194 return 0;
195}
196
197int main(int argc, char* argv[])
198{
199 lua_State* L;
200 int i=doargs(argc,argv);
201 argc-=i; argv+=i;
202 if (argc<=0) usage("no input files given");
203 L=luaL_newstate();
204 if (L==NULL) fatal("cannot create state: not enough memory");
205 lua_pushcfunction(L,&pmain);
206 lua_pushinteger(L,argc);
207 lua_pushlightuserdata(L,argv);
208 if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1));
209 lua_close(L);
210 return EXIT_SUCCESS;
211}
212
213/*
214** print bytecodes
215*/
216
217#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
218#define VOID(p) ((const void*)(p))
219#define eventname(i) (getstr(tmname[i]))
220
221static void PrintString(const TString* ts)
222{
223 const char* s=getstr(ts);
224 size_t i,n=tsslen(ts);
225 printf("\"");
226 for (i=0; i<n; i++)
227 {
228  int c=(int)(unsigned char)s[i];
229  switch (c)
230  {
231   case '"':
232	printf("\\\"");
233	break;
234   case '\\':
235	printf("\\\\");
236	break;
237   case '\a':
238	printf("\\a");
239	break;
240   case '\b':
241	printf("\\b");
242	break;
243   case '\f':
244	printf("\\f");
245	break;
246   case '\n':
247	printf("\\n");
248	break;
249   case '\r':
250	printf("\\r");
251	break;
252   case '\t':
253	printf("\\t");
254	break;
255   case '\v':
256	printf("\\v");
257	break;
258   default:
259	if (isprint(c)) printf("%c",c); else printf("\\%03d",c);
260	break;
261  }
262 }
263 printf("\"");
264}
265
266static void PrintType(const Proto* f, int i)
267{
268 const TValue* o=&f->k[i];
269 switch (ttypetag(o))
270 {
271  case LUA_VNIL:
272	printf("N");
273	break;
274  case LUA_VFALSE:
275  case LUA_VTRUE:
276	printf("B");
277	break;
278  case LUA_VNUMFLT:
279	printf("F");
280	break;
281  case LUA_VNUMINT:
282	printf("I");
283	break;
284  case LUA_VSHRSTR:
285  case LUA_VLNGSTR:
286	printf("S");
287	break;
288  default:				/* cannot happen */
289	printf("?%d",ttypetag(o));
290	break;
291 }
292 printf("\t");
293}
294
295static void PrintConstant(const Proto* f, int i)
296{
297 const TValue* o=&f->k[i];
298 switch (ttypetag(o))
299 {
300  case LUA_VNIL:
301	printf("nil");
302	break;
303  case LUA_VFALSE:
304	printf("false");
305	break;
306  case LUA_VTRUE:
307	printf("true");
308	break;
309  case LUA_VNUMFLT:
310	{
311	char buff[100];
312	sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
313	printf("%s",buff);
314	if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
315	break;
316	}
317  case LUA_VNUMINT:
318	printf(LUA_INTEGER_FMT,ivalue(o));
319	break;
320  case LUA_VSHRSTR:
321  case LUA_VLNGSTR:
322	PrintString(tsvalue(o));
323	break;
324  default:				/* cannot happen */
325	printf("?%d",ttypetag(o));
326	break;
327 }
328}
329
330#define COMMENT		"\t; "
331#define EXTRAARG	GETARG_Ax(code[pc+1])
332#define EXTRAARGC	(EXTRAARG*(MAXARG_C+1))
333#define ISK		(isk ? "k" : "")
334
335static void PrintCode(const Proto* f)
336{
337 const Instruction* code=f->code;
338 int pc,n=f->sizecode;
339 for (pc=0; pc<n; pc++)
340 {
341  Instruction i=code[pc];
342  OpCode o=GET_OPCODE(i);
343  int a=GETARG_A(i);
344  int b=GETARG_B(i);
345  int c=GETARG_C(i);
346  int ax=GETARG_Ax(i);
347  int bx=GETARG_Bx(i);
348  int sb=GETARG_sB(i);
349  int sc=GETARG_sC(i);
350  int sbx=GETARG_sBx(i);
351  int isk=GETARG_k(i);
352  int line=luaG_getfuncline(f,pc);
353  printf("\t%d\t",pc+1);
354  if (line>0) printf("[%d]\t",line); else printf("[-]\t");
355  printf("%-9s\t",opnames[o]);
356  switch (o)
357  {
358   case OP_MOVE:
359	printf("%d %d",a,b);
360	break;
361   case OP_LOADI:
362	printf("%d %d",a,sbx);
363	break;
364   case OP_LOADF:
365	printf("%d %d",a,sbx);
366	break;
367   case OP_LOADK:
368	printf("%d %d",a,bx);
369	printf(COMMENT); PrintConstant(f,bx);
370	break;
371   case OP_LOADKX:
372	printf("%d",a);
373	printf(COMMENT); PrintConstant(f,EXTRAARG);
374	break;
375   case OP_LOADFALSE:
376	printf("%d",a);
377	break;
378   case OP_LFALSESKIP:
379	printf("%d",a);
380	break;
381   case OP_LOADTRUE:
382	printf("%d",a);
383	break;
384   case OP_LOADNIL:
385	printf("%d %d",a,b);
386	printf(COMMENT "%d out",b+1);
387	break;
388   case OP_GETUPVAL:
389	printf("%d %d",a,b);
390	printf(COMMENT "%s",UPVALNAME(b));
391	break;
392   case OP_SETUPVAL:
393	printf("%d %d",a,b);
394	printf(COMMENT "%s",UPVALNAME(b));
395	break;
396   case OP_GETTABUP:
397	printf("%d %d %d",a,b,c);
398	printf(COMMENT "%s",UPVALNAME(b));
399	printf(" "); PrintConstant(f,c);
400	break;
401   case OP_GETTABLE:
402	printf("%d %d %d",a,b,c);
403	break;
404   case OP_GETI:
405	printf("%d %d %d",a,b,c);
406	break;
407   case OP_GETFIELD:
408	printf("%d %d %d",a,b,c);
409	printf(COMMENT); PrintConstant(f,c);
410	break;
411   case OP_SETTABUP:
412	printf("%d %d %d%s",a,b,c,ISK);
413	printf(COMMENT "%s",UPVALNAME(a));
414	printf(" "); PrintConstant(f,b);
415	if (isk) { printf(" "); PrintConstant(f,c); }
416	break;
417   case OP_SETTABLE:
418	printf("%d %d %d%s",a,b,c,ISK);
419	if (isk) { printf(COMMENT); PrintConstant(f,c); }
420	break;
421   case OP_SETI:
422	printf("%d %d %d%s",a,b,c,ISK);
423	if (isk) { printf(COMMENT); PrintConstant(f,c); }
424	break;
425   case OP_SETFIELD:
426	printf("%d %d %d%s",a,b,c,ISK);
427	printf(COMMENT); PrintConstant(f,b);
428	if (isk) { printf(" "); PrintConstant(f,c); }
429	break;
430   case OP_NEWTABLE:
431	printf("%d %d %d",a,b,c);
432	printf(COMMENT "%d",c+EXTRAARGC);
433	break;
434   case OP_SELF:
435	printf("%d %d %d%s",a,b,c,ISK);
436	if (isk) { printf(COMMENT); PrintConstant(f,c); }
437	break;
438   case OP_ADDI:
439	printf("%d %d %d",a,b,sc);
440	break;
441   case OP_ADDK:
442	printf("%d %d %d",a,b,c);
443	printf(COMMENT); PrintConstant(f,c);
444	break;
445   case OP_SUBK:
446	printf("%d %d %d",a,b,c);
447	printf(COMMENT); PrintConstant(f,c);
448	break;
449   case OP_MULK:
450	printf("%d %d %d",a,b,c);
451	printf(COMMENT); PrintConstant(f,c);
452	break;
453   case OP_MODK:
454	printf("%d %d %d",a,b,c);
455	printf(COMMENT); PrintConstant(f,c);
456	break;
457   case OP_POWK:
458	printf("%d %d %d",a,b,c);
459	printf(COMMENT); PrintConstant(f,c);
460	break;
461   case OP_DIVK:
462	printf("%d %d %d",a,b,c);
463	printf(COMMENT); PrintConstant(f,c);
464	break;
465   case OP_IDIVK:
466	printf("%d %d %d",a,b,c);
467	printf(COMMENT); PrintConstant(f,c);
468	break;
469   case OP_BANDK:
470	printf("%d %d %d",a,b,c);
471	printf(COMMENT); PrintConstant(f,c);
472	break;
473   case OP_BORK:
474	printf("%d %d %d",a,b,c);
475	printf(COMMENT); PrintConstant(f,c);
476	break;
477   case OP_BXORK:
478	printf("%d %d %d",a,b,c);
479	printf(COMMENT); PrintConstant(f,c);
480	break;
481   case OP_SHRI:
482	printf("%d %d %d",a,b,sc);
483	break;
484   case OP_SHLI:
485	printf("%d %d %d",a,b,sc);
486	break;
487   case OP_ADD:
488	printf("%d %d %d",a,b,c);
489	break;
490   case OP_SUB:
491	printf("%d %d %d",a,b,c);
492	break;
493   case OP_MUL:
494	printf("%d %d %d",a,b,c);
495	break;
496   case OP_MOD:
497	printf("%d %d %d",a,b,c);
498	break;
499   case OP_POW:
500	printf("%d %d %d",a,b,c);
501	break;
502   case OP_DIV:
503	printf("%d %d %d",a,b,c);
504	break;
505   case OP_IDIV:
506	printf("%d %d %d",a,b,c);
507	break;
508   case OP_BAND:
509	printf("%d %d %d",a,b,c);
510	break;
511   case OP_BOR:
512	printf("%d %d %d",a,b,c);
513	break;
514   case OP_BXOR:
515	printf("%d %d %d",a,b,c);
516	break;
517   case OP_SHL:
518	printf("%d %d %d",a,b,c);
519	break;
520   case OP_SHR:
521	printf("%d %d %d",a,b,c);
522	break;
523   case OP_MMBIN:
524	printf("%d %d %d",a,b,c);
525	printf(COMMENT "%s",eventname(c));
526	break;
527   case OP_MMBINI:
528	printf("%d %d %d %d",a,sb,c,isk);
529	printf(COMMENT "%s",eventname(c));
530	if (isk) printf(" flip");
531	break;
532   case OP_MMBINK:
533	printf("%d %d %d %d",a,b,c,isk);
534	printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
535	if (isk) printf(" flip");
536	break;
537   case OP_UNM:
538	printf("%d %d",a,b);
539	break;
540   case OP_BNOT:
541	printf("%d %d",a,b);
542	break;
543   case OP_NOT:
544	printf("%d %d",a,b);
545	break;
546   case OP_LEN:
547	printf("%d %d",a,b);
548	break;
549   case OP_CONCAT:
550	printf("%d %d",a,b);
551	break;
552   case OP_CLOSE:
553	printf("%d",a);
554	break;
555   case OP_TBC:
556	printf("%d",a);
557	break;
558   case OP_JMP:
559	printf("%d",GETARG_sJ(i));
560	printf(COMMENT "to %d",GETARG_sJ(i)+pc+2);
561	break;
562   case OP_EQ:
563	printf("%d %d %d",a,b,isk);
564	break;
565   case OP_LT:
566	printf("%d %d %d",a,b,isk);
567	break;
568   case OP_LE:
569	printf("%d %d %d",a,b,isk);
570	break;
571   case OP_EQK:
572	printf("%d %d %d",a,b,isk);
573	printf(COMMENT); PrintConstant(f,b);
574	break;
575   case OP_EQI:
576	printf("%d %d %d",a,sb,isk);
577	break;
578   case OP_LTI:
579	printf("%d %d %d",a,sb,isk);
580	break;
581   case OP_LEI:
582	printf("%d %d %d",a,sb,isk);
583	break;
584   case OP_GTI:
585	printf("%d %d %d",a,sb,isk);
586	break;
587   case OP_GEI:
588	printf("%d %d %d",a,sb,isk);
589	break;
590   case OP_TEST:
591	printf("%d %d",a,isk);
592	break;
593   case OP_TESTSET:
594	printf("%d %d %d",a,b,isk);
595	break;
596   case OP_CALL:
597	printf("%d %d %d",a,b,c);
598	printf(COMMENT);
599	if (b==0) printf("all in "); else printf("%d in ",b-1);
600	if (c==0) printf("all out"); else printf("%d out",c-1);
601	break;
602   case OP_TAILCALL:
603	printf("%d %d %d",a,b,c);
604	printf(COMMENT "%d in",b-1);
605	break;
606   case OP_RETURN:
607	printf("%d %d %d",a,b,c);
608	printf(COMMENT);
609	if (b==0) printf("all out"); else printf("%d out",b-1);
610	break;
611   case OP_RETURN0:
612	break;
613   case OP_RETURN1:
614	printf("%d",a);
615	break;
616   case OP_FORLOOP:
617	printf("%d %d",a,bx);
618	printf(COMMENT "to %d",pc-bx+2);
619	break;
620   case OP_FORPREP:
621	printf("%d %d",a,bx);
622	printf(COMMENT "to %d",pc+bx+2);
623	break;
624   case OP_TFORPREP:
625	printf("%d %d",a,bx);
626	printf(COMMENT "to %d",pc+bx+2);
627	break;
628   case OP_TFORCALL:
629	printf("%d %d",a,c);
630	break;
631   case OP_TFORLOOP:
632	printf("%d %d",a,bx);
633	printf(COMMENT "to %d",pc-bx+2);
634	break;
635   case OP_SETLIST:
636	printf("%d %d %d",a,b,c);
637	if (isk) printf(COMMENT "%d",c+EXTRAARGC);
638	break;
639   case OP_CLOSURE:
640	printf("%d %d",a,bx);
641	printf(COMMENT "%p",VOID(f->p[bx]));
642	break;
643   case OP_VARARG:
644	printf("%d %d",a,c);
645	printf(COMMENT);
646	if (c==0) printf("all out"); else printf("%d out",c-1);
647	break;
648   case OP_VARARGPREP:
649	printf("%d",a);
650	break;
651   case OP_EXTRAARG:
652	printf("%d",ax);
653	break;
654#if 0
655   default:
656	printf("%d %d %d",a,b,c);
657	printf(COMMENT "not handled");
658	break;
659#endif
660  }
661  printf("\n");
662 }
663}
664
665
666#define SS(x)	((x==1)?"":"s")
667#define S(x)	(int)(x),SS(x)
668
669static void PrintHeader(const Proto* f)
670{
671 const char* s=f->source ? getstr(f->source) : "=?";
672 if (*s=='@' || *s=='=')
673  s++;
674 else if (*s==LUA_SIGNATURE[0])
675  s="(bstring)";
676 else
677  s="(string)";
678 printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
679	(f->linedefined==0)?"main":"function",s,
680	f->linedefined,f->lastlinedefined,
681	S(f->sizecode),VOID(f));
682 printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
683	(int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
684	S(f->maxstacksize),S(f->sizeupvalues));
685 printf("%d local%s, %d constant%s, %d function%s\n",
686	S(f->sizelocvars),S(f->sizek),S(f->sizep));
687}
688
689static void PrintDebug(const Proto* f)
690{
691 int i,n;
692 n=f->sizek;
693 printf("constants (%d) for %p:\n",n,VOID(f));
694 for (i=0; i<n; i++)
695 {
696  printf("\t%d\t",i);
697  PrintType(f,i);
698  PrintConstant(f,i);
699  printf("\n");
700 }
701 n=f->sizelocvars;
702 printf("locals (%d) for %p:\n",n,VOID(f));
703 for (i=0; i<n; i++)
704 {
705  printf("\t%d\t%s\t%d\t%d\n",
706  i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
707 }
708 n=f->sizeupvalues;
709 printf("upvalues (%d) for %p:\n",n,VOID(f));
710 for (i=0; i<n; i++)
711 {
712  printf("\t%d\t%s\t%d\t%d\n",
713  i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
714 }
715}
716
717static void PrintFunction(const Proto* f, int full)
718{
719 int i,n=f->sizep;
720 PrintHeader(f);
721 PrintCode(f);
722 if (full) PrintDebug(f);
723 for (i=0; i<n; i++) PrintFunction(f->p[i],full);
724}
725