Home | History | Annotate | Line # | Download | only in src
      1 /*	$NetBSD: luac.c,v 1.12 2023/06/08 21:12:08 nikita Exp $	*/
      2 
      3 /*
      4 ** Id: luac.c
      5 ** Lua compiler (saves bytecodes to files; also lists bytecodes)
      6 ** See Copyright Notice in lua.h
      7 */
      8 
      9 #define luac_c
     10 #define LUA_CORE
     11 
     12 #include "lprefix.h"
     13 
     14 #include <ctype.h>
     15 #include <errno.h>
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 #include "lua.h"
     21 #include "lauxlib.h"
     22 
     23 #include "ldebug.h"
     24 #include "lobject.h"
     25 #include "lopcodes.h"
     26 #include "lopnames.h"
     27 #include "lstate.h"
     28 #include "lundump.h"
     29 
     30 static void PrintFunction(const Proto* f, int full);
     31 #define luaU_print	PrintFunction
     32 
     33 #define PROGNAME	"luac"		/* default program name */
     34 #define OUTPUT		PROGNAME ".out"	/* default output file */
     35 
     36 static int listing=0;			/* list bytecodes? */
     37 static int dumping=1;			/* dump bytecodes? */
     38 static int stripping=0;			/* strip debug information? */
     39 static char Output[]={ OUTPUT };	/* default output file name */
     40 static const char* output=Output;	/* actual output file name */
     41 static const char* progname=PROGNAME;	/* actual program name */
     42 static TString **tmname;
     43 
     44 static void fatal(const char* message)
     45 {
     46  fprintf(stderr,"%s: %s\n",progname,message);
     47  exit(EXIT_FAILURE);
     48 }
     49 
     50 static void cannot(const char* what)
     51 {
     52  fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
     53  exit(EXIT_FAILURE);
     54 }
     55 
     56 static void usage(const char* message)
     57 {
     58  if (*message=='-')
     59   fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message);
     60  else
     61   fprintf(stderr,"%s: %s\n",progname,message);
     62  fprintf(stderr,
     63   "usage: %s [options] [filenames]\n"
     64   "Available options are:\n"
     65   "  -l       list (use -l -l for full listing)\n"
     66   "  -o name  output to file 'name' (default is \"%s\")\n"
     67   "  -p       parse only\n"
     68   "  -s       strip debug information\n"
     69   "  -v       show version information\n"
     70   "  --       stop handling options\n"
     71   "  -        stop handling options and process stdin\n"
     72   ,progname,Output);
     73  exit(EXIT_FAILURE);
     74 }
     75 
     76 #define IS(s)	(strcmp(argv[i],s)==0)
     77 
     78 static int doargs(int argc, char* argv[])
     79 {
     80  int i;
     81  int version=0;
     82  if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
     83  for (i=1; i<argc; i++)
     84  {
     85   if (*argv[i]!='-')			/* end of options; keep it */
     86    break;
     87   else if (IS("--"))			/* end of options; skip it */
     88   {
     89    ++i;
     90    if (version) ++version;
     91    break;
     92   }
     93   else if (IS("-"))			/* end of options; use stdin */
     94    break;
     95   else if (IS("-l"))			/* list */
     96    ++listing;
     97   else if (IS("-o"))			/* output file */
     98   {
     99    output=argv[++i];
    100    if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
    101     usage("'-o' needs argument");
    102    if (IS("-")) output=NULL;
    103   }
    104   else if (IS("-p"))			/* parse only */
    105    dumping=0;
    106   else if (IS("-s"))			/* strip debug information */
    107    stripping=1;
    108   else if (IS("-v"))			/* show version */
    109    ++version;
    110   else					/* unknown option */
    111    usage(argv[i]);
    112  }
    113  if (i==argc && (listing || !dumping))
    114  {
    115   dumping=0;
    116   argv[--i]=Output;
    117  }
    118  if (version)
    119  {
    120   printf("%s\n",LUA_COPYRIGHT);
    121   if (version==argc-1) exit(EXIT_SUCCESS);
    122  }
    123  return i;
    124 }
    125 
    126 #define FUNCTION "(function()end)();\n"
    127 
    128 static const char* reader(lua_State* L, void* ud, size_t* size)
    129 {
    130  UNUSED(L);
    131  if ((*(int*)ud)--)
    132  {
    133   *size=sizeof(FUNCTION)-1;
    134   return FUNCTION;
    135  }
    136  else
    137  {
    138   *size=0;
    139   return NULL;
    140  }
    141 }
    142 
    143 #define toproto(L,i) getproto(s2v(L->top.p+(i)))
    144 
    145 static const Proto* combine(lua_State* L, int n)
    146 {
    147  if (n==1)
    148   return toproto(L,-1);
    149  else
    150  {
    151   Proto* f;
    152   int i=n;
    153   if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1));
    154   f=toproto(L,-1);
    155   for (i=0; i<n; i++)
    156   {
    157    f->p[i]=toproto(L,i-n-1);
    158    if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
    159   }
    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 #ifndef __NetBSD__
    314 	sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
    315 #else /* __NetBSD__ */
    316 	l_sprintf(buff, sizeof(buff), LUA_NUMBER_FMT,fltvalue(o));
    317 #endif /* __NetBSD__ */
    318 	printf("%s",buff);
    319 	if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
    320 	break;
    321 	}
    322   case LUA_VNUMINT:
    323 	printf(LUA_INTEGER_FMT,ivalue(o));
    324 	break;
    325   case LUA_VSHRSTR:
    326   case LUA_VLNGSTR:
    327 	PrintString(tsvalue(o));
    328 	break;
    329   default:				/* cannot happen */
    330 	printf("?%d",ttypetag(o));
    331 	break;
    332  }
    333 }
    334 
    335 #define COMMENT		"\t; "
    336 #define EXTRAARG	GETARG_Ax(code[pc+1])
    337 #define EXTRAARGC	(EXTRAARG*(MAXARG_C+1))
    338 #define ISK		(isk ? "k" : "")
    339 
    340 static void PrintCode(const Proto* f)
    341 {
    342  const Instruction* code=f->code;
    343  int pc,n=f->sizecode;
    344  for (pc=0; pc<n; pc++)
    345  {
    346   Instruction i=code[pc];
    347   OpCode o=GET_OPCODE(i);
    348   int a=GETARG_A(i);
    349   int b=GETARG_B(i);
    350   int c=GETARG_C(i);
    351   int ax=GETARG_Ax(i);
    352   int bx=GETARG_Bx(i);
    353   int sb=GETARG_sB(i);
    354   int sc=GETARG_sC(i);
    355   int sbx=GETARG_sBx(i);
    356   int isk=GETARG_k(i);
    357   int line=luaG_getfuncline(f,pc);
    358   printf("\t%d\t",pc+1);
    359   if (line>0) printf("[%d]\t",line); else printf("[-]\t");
    360   printf("%-9s\t",opnames[o]);
    361   switch (o)
    362   {
    363    case OP_MOVE:
    364 	printf("%d %d",a,b);
    365 	break;
    366    case OP_LOADI:
    367 	printf("%d %d",a,sbx);
    368 	break;
    369    case OP_LOADF:
    370 	printf("%d %d",a,sbx);
    371 	break;
    372    case OP_LOADK:
    373 	printf("%d %d",a,bx);
    374 	printf(COMMENT); PrintConstant(f,bx);
    375 	break;
    376    case OP_LOADKX:
    377 	printf("%d",a);
    378 	printf(COMMENT); PrintConstant(f,EXTRAARG);
    379 	break;
    380    case OP_LOADFALSE:
    381 	printf("%d",a);
    382 	break;
    383    case OP_LFALSESKIP:
    384 	printf("%d",a);
    385 	break;
    386    case OP_LOADTRUE:
    387 	printf("%d",a);
    388 	break;
    389    case OP_LOADNIL:
    390 	printf("%d %d",a,b);
    391 	printf(COMMENT "%d out",b+1);
    392 	break;
    393    case OP_GETUPVAL:
    394 	printf("%d %d",a,b);
    395 	printf(COMMENT "%s",UPVALNAME(b));
    396 	break;
    397    case OP_SETUPVAL:
    398 	printf("%d %d",a,b);
    399 	printf(COMMENT "%s",UPVALNAME(b));
    400 	break;
    401    case OP_GETTABUP:
    402 	printf("%d %d %d",a,b,c);
    403 	printf(COMMENT "%s",UPVALNAME(b));
    404 	printf(" "); PrintConstant(f,c);
    405 	break;
    406    case OP_GETTABLE:
    407 	printf("%d %d %d",a,b,c);
    408 	break;
    409    case OP_GETI:
    410 	printf("%d %d %d",a,b,c);
    411 	break;
    412    case OP_GETFIELD:
    413 	printf("%d %d %d",a,b,c);
    414 	printf(COMMENT); PrintConstant(f,c);
    415 	break;
    416    case OP_SETTABUP:
    417 	printf("%d %d %d%s",a,b,c,ISK);
    418 	printf(COMMENT "%s",UPVALNAME(a));
    419 	printf(" "); PrintConstant(f,b);
    420 	if (isk) { printf(" "); PrintConstant(f,c); }
    421 	break;
    422    case OP_SETTABLE:
    423 	printf("%d %d %d%s",a,b,c,ISK);
    424 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
    425 	break;
    426    case OP_SETI:
    427 	printf("%d %d %d%s",a,b,c,ISK);
    428 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
    429 	break;
    430    case OP_SETFIELD:
    431 	printf("%d %d %d%s",a,b,c,ISK);
    432 	printf(COMMENT); PrintConstant(f,b);
    433 	if (isk) { printf(" "); PrintConstant(f,c); }
    434 	break;
    435    case OP_NEWTABLE:
    436 	printf("%d %d %d",a,b,c);
    437 	printf(COMMENT "%d",c+EXTRAARGC);
    438 	break;
    439    case OP_SELF:
    440 	printf("%d %d %d%s",a,b,c,ISK);
    441 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
    442 	break;
    443    case OP_ADDI:
    444 	printf("%d %d %d",a,b,sc);
    445 	break;
    446    case OP_ADDK:
    447 	printf("%d %d %d",a,b,c);
    448 	printf(COMMENT); PrintConstant(f,c);
    449 	break;
    450    case OP_SUBK:
    451 	printf("%d %d %d",a,b,c);
    452 	printf(COMMENT); PrintConstant(f,c);
    453 	break;
    454    case OP_MULK:
    455 	printf("%d %d %d",a,b,c);
    456 	printf(COMMENT); PrintConstant(f,c);
    457 	break;
    458    case OP_MODK:
    459 	printf("%d %d %d",a,b,c);
    460 	printf(COMMENT); PrintConstant(f,c);
    461 	break;
    462    case OP_POWK:
    463 	printf("%d %d %d",a,b,c);
    464 	printf(COMMENT); PrintConstant(f,c);
    465 	break;
    466    case OP_DIVK:
    467 	printf("%d %d %d",a,b,c);
    468 	printf(COMMENT); PrintConstant(f,c);
    469 	break;
    470    case OP_IDIVK:
    471 	printf("%d %d %d",a,b,c);
    472 	printf(COMMENT); PrintConstant(f,c);
    473 	break;
    474    case OP_BANDK:
    475 	printf("%d %d %d",a,b,c);
    476 	printf(COMMENT); PrintConstant(f,c);
    477 	break;
    478    case OP_BORK:
    479 	printf("%d %d %d",a,b,c);
    480 	printf(COMMENT); PrintConstant(f,c);
    481 	break;
    482    case OP_BXORK:
    483 	printf("%d %d %d",a,b,c);
    484 	printf(COMMENT); PrintConstant(f,c);
    485 	break;
    486    case OP_SHRI:
    487 	printf("%d %d %d",a,b,sc);
    488 	break;
    489    case OP_SHLI:
    490 	printf("%d %d %d",a,b,sc);
    491 	break;
    492    case OP_ADD:
    493 	printf("%d %d %d",a,b,c);
    494 	break;
    495    case OP_SUB:
    496 	printf("%d %d %d",a,b,c);
    497 	break;
    498    case OP_MUL:
    499 	printf("%d %d %d",a,b,c);
    500 	break;
    501    case OP_MOD:
    502 	printf("%d %d %d",a,b,c);
    503 	break;
    504    case OP_POW:
    505 	printf("%d %d %d",a,b,c);
    506 	break;
    507    case OP_DIV:
    508 	printf("%d %d %d",a,b,c);
    509 	break;
    510    case OP_IDIV:
    511 	printf("%d %d %d",a,b,c);
    512 	break;
    513    case OP_BAND:
    514 	printf("%d %d %d",a,b,c);
    515 	break;
    516    case OP_BOR:
    517 	printf("%d %d %d",a,b,c);
    518 	break;
    519    case OP_BXOR:
    520 	printf("%d %d %d",a,b,c);
    521 	break;
    522    case OP_SHL:
    523 	printf("%d %d %d",a,b,c);
    524 	break;
    525    case OP_SHR:
    526 	printf("%d %d %d",a,b,c);
    527 	break;
    528    case OP_MMBIN:
    529 	printf("%d %d %d",a,b,c);
    530 	printf(COMMENT "%s",eventname(c));
    531 	break;
    532    case OP_MMBINI:
    533 	printf("%d %d %d %d",a,sb,c,isk);
    534 	printf(COMMENT "%s",eventname(c));
    535 	if (isk) printf(" flip");
    536 	break;
    537    case OP_MMBINK:
    538 	printf("%d %d %d %d",a,b,c,isk);
    539 	printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
    540 	if (isk) printf(" flip");
    541 	break;
    542    case OP_UNM:
    543 	printf("%d %d",a,b);
    544 	break;
    545    case OP_BNOT:
    546 	printf("%d %d",a,b);
    547 	break;
    548    case OP_NOT:
    549 	printf("%d %d",a,b);
    550 	break;
    551    case OP_LEN:
    552 	printf("%d %d",a,b);
    553 	break;
    554    case OP_CONCAT:
    555 	printf("%d %d",a,b);
    556 	break;
    557    case OP_CLOSE:
    558 	printf("%d",a);
    559 	break;
    560    case OP_TBC:
    561 	printf("%d",a);
    562 	break;
    563    case OP_JMP:
    564 	printf("%d",GETARG_sJ(i));
    565 	printf(COMMENT "to %d",GETARG_sJ(i)+pc+2);
    566 	break;
    567    case OP_EQ:
    568 	printf("%d %d %d",a,b,isk);
    569 	break;
    570    case OP_LT:
    571 	printf("%d %d %d",a,b,isk);
    572 	break;
    573    case OP_LE:
    574 	printf("%d %d %d",a,b,isk);
    575 	break;
    576    case OP_EQK:
    577 	printf("%d %d %d",a,b,isk);
    578 	printf(COMMENT); PrintConstant(f,b);
    579 	break;
    580    case OP_EQI:
    581 	printf("%d %d %d",a,sb,isk);
    582 	break;
    583    case OP_LTI:
    584 	printf("%d %d %d",a,sb,isk);
    585 	break;
    586    case OP_LEI:
    587 	printf("%d %d %d",a,sb,isk);
    588 	break;
    589    case OP_GTI:
    590 	printf("%d %d %d",a,sb,isk);
    591 	break;
    592    case OP_GEI:
    593 	printf("%d %d %d",a,sb,isk);
    594 	break;
    595    case OP_TEST:
    596 	printf("%d %d",a,isk);
    597 	break;
    598    case OP_TESTSET:
    599 	printf("%d %d %d",a,b,isk);
    600 	break;
    601    case OP_CALL:
    602 	printf("%d %d %d",a,b,c);
    603 	printf(COMMENT);
    604 	if (b==0) printf("all in "); else printf("%d in ",b-1);
    605 	if (c==0) printf("all out"); else printf("%d out",c-1);
    606 	break;
    607    case OP_TAILCALL:
    608 	printf("%d %d %d%s",a,b,c,ISK);
    609 	printf(COMMENT "%d in",b-1);
    610 	break;
    611    case OP_RETURN:
    612 	printf("%d %d %d%s",a,b,c,ISK);
    613 	printf(COMMENT);
    614 	if (b==0) printf("all out"); else printf("%d out",b-1);
    615 	break;
    616    case OP_RETURN0:
    617 	break;
    618    case OP_RETURN1:
    619 	printf("%d",a);
    620 	break;
    621    case OP_FORLOOP:
    622 	printf("%d %d",a,bx);
    623 	printf(COMMENT "to %d",pc-bx+2);
    624 	break;
    625    case OP_FORPREP:
    626 	printf("%d %d",a,bx);
    627 	printf(COMMENT "exit to %d",pc+bx+3);
    628 	break;
    629    case OP_TFORPREP:
    630 	printf("%d %d",a,bx);
    631 	printf(COMMENT "to %d",pc+bx+2);
    632 	break;
    633    case OP_TFORCALL:
    634 	printf("%d %d",a,c);
    635 	break;
    636    case OP_TFORLOOP:
    637 	printf("%d %d",a,bx);
    638 	printf(COMMENT "to %d",pc-bx+2);
    639 	break;
    640    case OP_SETLIST:
    641 	printf("%d %d %d",a,b,c);
    642 	if (isk) printf(COMMENT "%d",c+EXTRAARGC);
    643 	break;
    644    case OP_CLOSURE:
    645 	printf("%d %d",a,bx);
    646 	printf(COMMENT "%p",VOID(f->p[bx]));
    647 	break;
    648    case OP_VARARG:
    649 	printf("%d %d",a,c);
    650 	printf(COMMENT);
    651 	if (c==0) printf("all out"); else printf("%d out",c-1);
    652 	break;
    653    case OP_VARARGPREP:
    654 	printf("%d",a);
    655 	break;
    656    case OP_EXTRAARG:
    657 	printf("%d",ax);
    658 	break;
    659 #if 0
    660    default:
    661 	printf("%d %d %d",a,b,c);
    662 	printf(COMMENT "not handled");
    663 	break;
    664 #endif
    665   }
    666   printf("\n");
    667  }
    668 }
    669 
    670 
    671 #define SS(x)	((x==1)?"":"s")
    672 #define S(x)	(int)(x),SS(x)
    673 
    674 static void PrintHeader(const Proto* f)
    675 {
    676  const char* s=f->source ? getstr(f->source) : "=?";
    677  if (*s=='@' || *s=='=')
    678   s++;
    679  else if (*s==LUA_SIGNATURE[0])
    680   s="(bstring)";
    681  else
    682   s="(string)";
    683  printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
    684 	(f->linedefined==0)?"main":"function",s,
    685 	f->linedefined,f->lastlinedefined,
    686 	S(f->sizecode),VOID(f));
    687  printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
    688 	(int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
    689 	S(f->maxstacksize),S(f->sizeupvalues));
    690  printf("%d local%s, %d constant%s, %d function%s\n",
    691 	S(f->sizelocvars),S(f->sizek),S(f->sizep));
    692 }
    693 
    694 static void PrintDebug(const Proto* f)
    695 {
    696  int i,n;
    697  n=f->sizek;
    698  printf("constants (%d) for %p:\n",n,VOID(f));
    699  for (i=0; i<n; i++)
    700  {
    701   printf("\t%d\t",i);
    702   PrintType(f,i);
    703   PrintConstant(f,i);
    704   printf("\n");
    705  }
    706  n=f->sizelocvars;
    707  printf("locals (%d) for %p:\n",n,VOID(f));
    708  for (i=0; i<n; i++)
    709  {
    710   printf("\t%d\t%s\t%d\t%d\n",
    711   i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
    712  }
    713  n=f->sizeupvalues;
    714  printf("upvalues (%d) for %p:\n",n,VOID(f));
    715  for (i=0; i<n; i++)
    716  {
    717   printf("\t%d\t%s\t%d\t%d\n",
    718   i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
    719  }
    720 }
    721 
    722 static void PrintFunction(const Proto* f, int full)
    723 {
    724  int i,n=f->sizep;
    725  PrintHeader(f);
    726  PrintCode(f);
    727  if (full) PrintDebug(f);
    728  for (i=0; i<n; i++) PrintFunction(f->p[i],full);
    729 }
    730