xref: /netbsd-src/external/mit/lua/dist/src/luac.c (revision bdda0531de537df87feb2bf576711ab1be9b3675)
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 
fatal(const char * message)44 static void fatal(const char* message)
45 {
46  fprintf(stderr,"%s: %s\n",progname,message);
47  exit(EXIT_FAILURE);
48 }
49 
cannot(const char * what)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 
usage(const char * message)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 
doargs(int argc,char * argv[])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 
reader(lua_State * L,void * ud,size_t * size)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 
combine(lua_State * L,int n)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 
writer(lua_State * L,const void * p,size_t size,void * u)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 
pmain(lua_State * L)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 
main(int argc,char * argv[])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 
PrintString(const TString * ts)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 
PrintType(const Proto * f,int i)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 
PrintConstant(const Proto * f,int i)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 
PrintCode(const Proto * f)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 
PrintHeader(const Proto * f)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 
PrintDebug(const Proto * f)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 
PrintFunction(const Proto * f,int full)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