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