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 luaM_freearray(L,f->lineinfo,f->sizelineinfo);
159 f->sizelineinfo=0;
160 return f;
161 }
162}
163
164static 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
170static 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
198int 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
222static 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
267static 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
296static 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
336static 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
670static 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
690static 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
718static 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