Introduced -devel and -extras subpackages for gawk
[platform/upstream/gawk.git] / profile.c
1 /*
2  * profile.c - gawk bytecode pretty-printer with counts
3  */
4
5 /* 
6  * Copyright (C) 1999-2011 the Free Software Foundation, Inc.
7  * 
8  * This file is part of GAWK, the GNU implementation of the
9  * AWK Programming Language.
10  * 
11  * GAWK is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  * 
16  * GAWK is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
24  */
25
26 #include "awk.h"
27
28 static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header);
29 static void pp_parenthesize(NODE *n);
30 static void parenthesize(int type, NODE *left, NODE *right);
31 static char *pp_list(int nargs, const char *paren, const char *delim);
32 static char *pp_concat(const char *s1, const char *s2, const char *s3);
33 static int is_binary(int type);
34 static int prec_level(int type);
35 static void pp_push(int type, char *s, int flag);
36 static NODE *pp_pop(void);
37 static void pp_free(NODE *n);
38 const char *redir2str(int redirtype);
39
40 #define pp_str  hname
41 #define pp_len  hlength
42
43 #define DONT_FREE 1
44 #define CAN_FREE  2
45
46 #ifdef PROFILING
47 static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN;
48 static RETSIGTYPE just_dump(int signum);
49 #endif
50
51 /* pretty printing related functions and variables */
52
53 static NODE *pp_stack = NULL;
54 static char **fparms;   /* function parameter names */
55 static FILE *prof_fp;   /* where to send the profile */
56
57 static long indent_level = 0;
58
59
60 #define SPACEOVER       0
61
62 /* init_profiling --- do needed initializations, see also main.c */
63
64 void
65 init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED)
66 {
67 #ifdef PROFILING
68         if (*flag == FALSE) {
69                 *flag = TRUE;
70                 set_prof_file(def_file);
71         }
72 #endif
73 }
74
75 /* set_prof_file --- set the output file for profiling */
76
77 void
78 set_prof_file(const char *file)
79 {
80         assert(file != NULL);
81         prof_fp = fopen(file, "w");
82         if (prof_fp == NULL) {
83                 warning(_("could not open `%s' for writing: %s"),
84                                 file, strerror(errno));
85                 warning(_("sending profile to standard error"));
86                 prof_fp = stderr;
87         }
88 }
89
90 /* init_profiling_signals --- set up signal handling for pgawk */
91
92 void
93 init_profiling_signals()
94 {
95 #ifdef PROFILING
96 #ifdef __DJGPP__
97         signal(SIGINT, dump_and_exit);
98         signal(SIGQUIT, just_dump);
99 #else  /* !__DJGPP__ */
100 #ifdef SIGHUP
101         signal(SIGHUP, dump_and_exit);
102 #endif
103 #ifdef SIGUSR1
104         signal(SIGUSR1, just_dump);
105 #endif
106 #endif /* !__DJGPP__ */
107 #endif /* PROFILING */
108 }
109
110 /* indent --- print out enough tabs */
111
112 static void
113 indent(long count)
114 {
115         int i;
116
117         if (count == 0)
118                 fprintf(prof_fp, "\t");
119         else
120                 fprintf(prof_fp, "%6ld  ", count);
121
122         assert(indent_level >= 0);
123         for (i = 0; i < indent_level; i++)
124                 fprintf(prof_fp, "\t");
125 }
126
127 /* indent_in --- increase the level, with error checking */
128
129 static void
130 indent_in(void)
131 {
132         assert(indent_level >= 0);
133         indent_level++;
134 }
135
136 /* indent_out --- decrease the level, with error checking */
137
138 static void
139 indent_out(void)
140 {
141         indent_level--;
142         assert(indent_level >= 0);
143 }
144
145 static void
146 pp_push(int type, char *s, int flag)
147 {
148         NODE *n;
149         getnode(n);
150         n->pp_str = s;
151         n->pp_len = strlen(s);
152         n->flags = flag;
153         n->type = type;
154         n->hnext = pp_stack;
155         pp_stack = n;
156 }
157
158 static NODE *
159 pp_pop()
160 {
161         NODE *n;
162         n = pp_stack;
163         pp_stack = n->hnext;
164         return n;
165 }
166
167 static void
168 pp_free(NODE *n)
169 {
170         if ((n->flags & CAN_FREE) != 0)
171                 efree(n->pp_str);
172         freenode(n);
173 }
174
175 /*
176  * pprint --- pretty print a program segment
177  */
178
179 static void
180 pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
181 {
182         INSTRUCTION *pc;
183         NODE *t1;
184         char *str;
185         NODE *t2;
186         INSTRUCTION *ip;
187         NODE *m;
188         char *tmp;
189         int rule;
190         static int rule_count[MAXRULE];
191
192         for (pc = startp; pc != endp; pc = pc->nexti) {
193                 if (pc->source_line > 0)
194                         sourceline = pc->source_line;
195
196                 switch (pc->opcode) {
197                 case Op_rule:
198                         source = pc->source_file;
199                         rule = pc->in_rule;
200
201                         if (rule != Rule) {
202                                 if (! rule_count[rule]++)
203                                         fprintf(prof_fp, _("\t# %s block(s)\n\n"), ruletab[rule]);
204                                 fprintf(prof_fp, "\t%s {\n", ruletab[rule]);
205                                 ip = (pc + 1)->firsti;
206                         } else {
207                                 if (! rule_count[rule]++)
208                                         fprintf(prof_fp, _("\t# Rule(s)\n\n"));
209                                 ip = pc->nexti;
210                                 indent(ip->exec_count);
211                                 if (ip != (pc + 1)->firsti) {           /* non-empty pattern */
212                                         pprint(ip->nexti, (pc + 1)->firsti, FALSE);
213                                         t1 = pp_pop();
214                                         fprintf(prof_fp, "%s {", t1->pp_str);
215                                         pp_free(t1);
216                                         ip = (pc + 1)->firsti;
217 #ifdef PROFILING
218                                         if (ip->exec_count > 0)
219                                                 fprintf(prof_fp, " # %ld", ip->exec_count);
220 #endif
221                                         fprintf(prof_fp, "\n");
222                                 } else {
223                                         fprintf(prof_fp, "{\n");
224                                         ip = (pc + 1)->firsti;
225                                 }
226                                 ip = ip->nexti;
227                         }
228                         indent_in();
229                         pprint(ip, (pc + 1)->lasti, FALSE);
230                         indent_out();
231                         fprintf(prof_fp, "\t}\n\n");
232                         pc = (pc + 1)->lasti;
233                         break;
234
235                 case Op_atexit:
236                         break;
237
238                 case Op_stop:
239                         memset(rule_count, 0, MAXRULE * sizeof(int));
240                         break;
241
242                 case Op_push_i:
243                         m = pc->memory;
244                         if (m == Nnull_string)  /* optional return or exit value; don't print 0 or "" */
245                                 pp_push(pc->opcode, m->stptr, DONT_FREE);
246                         else if ((m->flags & NUMBER) != 0)
247                                 pp_push(pc->opcode, pp_number(m->numbr), CAN_FREE);
248                         else {
249                                 str = pp_string(m->stptr, m->stlen, '"');
250                                 if ((m->flags & INTLSTR) != 0) {
251                                         char *tmp = str;
252                                         str = pp_concat("_", tmp, "");
253                                         efree(tmp);
254                                 }
255                                 pp_push(pc->opcode, str, CAN_FREE);
256                         }
257                         break;
258
259                 case Op_store_var:
260                 case Op_store_sub:
261                 case Op_assign_concat:
262                 case Op_push_lhs:
263                 case Op_push_param:
264                 case Op_push_array:
265                 case Op_push:
266                 case Op_push_arg:
267                         m = pc->memory;
268                         switch (m->type) {
269                         case Node_param_list:
270                                 pp_push(pc->opcode, fparms[m->param_cnt], DONT_FREE);
271                                 break;
272
273                         case Node_var:
274                         case Node_var_new:
275                         case Node_var_array:
276                                 if (m->vname != NULL)
277                                         pp_push(pc->opcode, m->vname, DONT_FREE);
278                                 else
279                                         fatal(_("internal error: %s with null vname"),
280                                                         nodetype2str(m->type));
281                                 break;
282
283                         default:
284                                 cant_happen();
285                         }
286
287                         switch (pc->opcode) {           
288                         case Op_store_var:
289                                 t2 = pp_pop(); /* l.h.s. */
290                                 t1 = pp_pop(); /* r.h.s. */
291                                 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(pc->opcode), t1->pp_str);
292                                 goto cleanup;
293
294                         case Op_store_sub:
295                                 t1 = pp_pop();  /* array */
296                                 tmp = pp_list(pc->expr_count, op2str(Op_subscript), ", "); /*subscript*/
297                                 t2 = pp_pop(); /* r.h.s. */
298                                 fprintf(prof_fp, "%s%s%s%s", t1->pp_str, tmp,
299                                                                         op2str(pc->opcode), t2->pp_str);
300                                 efree(tmp);
301                                 goto cleanup;
302
303                         case Op_assign_concat:
304                                 t2 = pp_pop(); /* l.h.s. */
305                                 t1 = pp_pop();
306                                 tmp = pp_concat(t2->pp_str, op2str(Op_concat), t1->pp_str);
307                                 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(Op_assign), tmp);
308                                 efree(tmp);
309 cleanup:
310                                 pp_free(t2);
311                                 pp_free(t1);
312                                 if (! in_for_header)
313                                         fprintf(prof_fp, "\n");
314                                 break;
315
316                         default:
317                                 break;
318                         }
319                         break;
320
321                 case Op_sub_array:
322                 case Op_subscript_lhs:
323                 case Op_subscript:
324                         tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
325                         t1 = pp_pop();
326                         str = pp_concat(t1->pp_str, tmp, "");
327                         efree(tmp);
328                         pp_free(t1);
329                         pp_push(pc->opcode, str, CAN_FREE);
330                         break;  
331
332                 case Op_and:
333                 case Op_or:
334                         pprint(pc->nexti, pc->target_jmp, in_for_header);
335                         t2 = pp_pop();
336                         t1 = pp_pop();
337                         parenthesize(pc->opcode, t1, t2);
338                         str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
339                         pp_free(t1);
340                         pp_free(t2);
341                         pp_push(pc->opcode, str, CAN_FREE);
342                         pc = pc->target_jmp;
343                         break;
344
345                 case Op_plus_i:
346                 case Op_minus_i:
347                 case Op_times_i:
348                 case Op_exp_i:
349                 case Op_quotient_i:
350                 case Op_mod_i:
351                         m = pc->memory;
352                         t1 = pp_pop();
353                         if (prec_level(pc->opcode) > prec_level(t1->type)
354                                         && is_binary(t1->type))  /* (a - b) * 1 */
355                                 pp_parenthesize(t1);
356                         if ((m->flags & NUMBER) != 0)
357                                 tmp = pp_number(m->numbr);
358                         else
359                                 tmp = pp_string(m->stptr, m->stlen, '"');
360                         str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp);
361                         efree(tmp);
362                         pp_free(t1);
363                         pp_push(pc->opcode, str, CAN_FREE);
364                         break;
365
366                 case Op_plus:
367                 case Op_minus:
368                 case Op_times:
369                 case Op_exp:
370                 case Op_quotient:
371                 case Op_mod:
372                 case Op_equal:
373                 case Op_notequal:
374                 case Op_less:
375                 case Op_greater:
376                 case Op_leq:
377                 case Op_geq:
378                         t2 = pp_pop();
379                         t1 = pp_pop();
380                         parenthesize(pc->opcode, t1, t2);
381                         str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
382                         pp_free(t1);
383                         pp_free(t2);
384                         pp_push(pc->opcode, str, CAN_FREE);
385                         break;
386
387                 case Op_preincrement:
388                 case Op_predecrement:
389                 case Op_postincrement:
390                 case Op_postdecrement:
391                         t1 = pp_pop();
392                         if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
393                                 str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
394                         else
395                                 str = pp_concat(t1->pp_str, op2str(pc->opcode), "");
396                         pp_free(t1);
397                         pp_push(pc->opcode, str, CAN_FREE);
398                         break;
399
400                 case Op_field_spec:
401                 case Op_field_spec_lhs:
402                 case Op_unary_minus:
403                 case Op_not:
404                         t1 = pp_pop();
405                         if (is_binary(t1->type))
406                                 pp_parenthesize(t1);
407
408                         /* optypes table (eval.c) includes space after ! */
409                         str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
410                         pp_free(t1);
411                         pp_push(pc->opcode, str, CAN_FREE);
412                         break;
413
414                 case Op_assign:
415                 case Op_assign_plus:
416                 case Op_assign_minus:
417                 case Op_assign_times:
418                 case Op_assign_quotient:
419                 case Op_assign_mod:
420                 case Op_assign_exp:
421                         t2 = pp_pop(); /* l.h.s. */
422                         t1 = pp_pop();
423                         str = pp_concat(t2->pp_str, op2str(pc->opcode), t1->pp_str);
424                         pp_free(t2);
425                         pp_free(t1);
426                         pp_push(pc->opcode, str, CAN_FREE);
427                         break;
428
429                 case Op_store_field:
430                         t1 = pp_pop(); /* field num */
431                         if (is_binary(t1->type))
432                                 pp_parenthesize(t1);
433                         t2 = pp_pop(); /* r.h.s. */
434                         fprintf(prof_fp, "$%s%s%s", t1->pp_str, op2str(pc->opcode), t2->pp_str);
435                         pp_free(t2);
436                         pp_free(t1);
437                         if (! in_for_header)
438                                 fprintf(prof_fp, "\n");
439                         break; 
440
441                 case Op_concat:
442                         str = pp_list(pc->expr_count, NULL,
443                                                         (pc->concat_flag & CSUBSEP) ? ", " : op2str(Op_concat));
444                         pp_push(Op_concat, str, CAN_FREE);
445                         break;
446
447                 case Op_K_delete:
448                 {
449                         char *array;
450                         t1 = pp_pop();
451                         array = t1->pp_str;
452                         if (pc->expr_count > 0) {
453                                 char *sub;
454                                 sub = pp_list(pc->expr_count, NULL, ", ");
455                                 fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
456                                 efree(sub);
457                         } else                          
458                                 fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
459                         if (! in_for_header)
460                                 fprintf(prof_fp, "\n");
461                         pp_free(t1);
462                 }
463                         break;
464
465                 case Op_K_delete_loop:
466                         /* Efficency hack not in effect because of exec_count instruction */
467                         cant_happen();
468                         break;
469                 
470                 case Op_in_array:
471                 {
472                         char *array, *sub;
473                         t1 = pp_pop();
474                         array = t1->pp_str;
475                         if (pc->expr_count > 1) {
476                                 sub = pp_list(pc->expr_count, "()", ", ");
477                                 str = pp_concat(sub, op2str(Op_in_array), array);
478                                 efree(sub);
479                         } else {
480                                 t2 = pp_pop();
481                                 sub = t2->pp_str;
482                                 str = pp_concat(sub, op2str(Op_in_array), array);
483                                 pp_free(t2);
484                         }
485                         pp_free(t1);
486                         pp_push(Op_in_array, str, CAN_FREE);
487                 }
488                         break;
489
490                 case Op_var_update:
491                 case Op_var_assign:
492                 case Op_field_assign:
493                 case Op_arrayfor_init:
494                 case Op_arrayfor_incr: 
495                 case Op_arrayfor_final:
496                 case Op_newfile:
497                 case Op_get_record:
498                 case Op_lint:
499                 case Op_jmp:
500                 case Op_jmp_false:
501                 case Op_jmp_true:
502                 case Op_no_op:
503                 case Op_and_final:
504                 case Op_or_final:
505                 case Op_cond_pair:
506                 case Op_after_beginfile:
507                 case Op_after_endfile:
508                         break;
509
510                 case Op_sub_builtin:
511                 {
512                         const char *fname = "sub";
513                         if (pc->sub_flags & GSUB)
514                                 fname = "gsub";
515                         else if (pc->sub_flags & GENSUB)
516                                 fname = "gensub";
517                         tmp = pp_list(pc->expr_count, "()", ", ");
518                         str = pp_concat(fname, tmp, "");
519                         efree(tmp);
520                         pp_push(Op_sub_builtin, str, CAN_FREE);
521                 }
522                         break;
523
524                 case Op_builtin:
525                 {
526                         static char *ext_func = "extension_function()";
527                         const char *fname = getfname(pc->builtin);
528                         if (fname != NULL) {
529                                 if (pc->expr_count > 0) {
530                                         tmp = pp_list(pc->expr_count, "()", ", ");
531                                         str = pp_concat(fname, tmp, "");
532                                         efree(tmp);
533                                 } else
534                                         str = pp_concat(fname, "()", "");
535                                 pp_push(Op_builtin, str, CAN_FREE);
536                         } else
537                                 pp_push(Op_builtin, ext_func, DONT_FREE);
538                 }
539                         break;
540         
541                 case Op_K_print:
542                 case Op_K_printf:
543                 case Op_K_print_rec:
544                         if (pc->opcode == Op_K_print_rec)
545                                 tmp = pp_concat(" ", op2str(Op_field_spec), "0");
546                         else if (pc->redir_type != 0)
547                                 tmp = pp_list(pc->expr_count, "()", ", ");
548                         else {
549                                 tmp = pp_list(pc->expr_count, "  ", ", ");
550                                 tmp[strlen(tmp) - 1] = '\0';    /* remove trailing space */
551                         }       
552
553                         if (pc->redir_type != 0) {
554                                 t1 = pp_pop();
555                                 if (is_binary(t1->type))
556                                         pp_parenthesize(t1);
557                                 fprintf(prof_fp, "%s%s%s%s", op2str(pc->opcode),
558                                                         tmp, redir2str(pc->redir_type), t1->pp_str);
559                                 pp_free(t1);
560                         } else
561                                 fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
562                         efree(tmp);
563                         if (! in_for_header)
564                                 fprintf(prof_fp, "\n");
565                         break;
566
567                 case Op_push_re:
568                         if (pc->memory->type != Node_regex)
569                                 break;
570                         /* else 
571                                 fall through */
572                 case Op_match_rec:
573                 {
574                         NODE *re = pc->memory->re_exp;
575                         str = pp_string(re->stptr, re->stlen, '/');
576                         pp_push(pc->opcode, str, CAN_FREE);
577                 }
578                         break;
579
580                 case Op_nomatch:
581                 case Op_match:
582                 {
583                         char *restr, *txt;
584                         t1 = pp_pop();
585                         if (is_binary(t1->type))
586                                 pp_parenthesize(t1);
587                         txt = t1->pp_str;
588                         m = pc->memory;
589                         if (m->type == Node_dynregex) {
590                                 restr = txt;
591                                 t2 = pp_pop();
592                                 if (is_binary(t2->type))
593                                         pp_parenthesize(t2);
594                                 txt = t2->pp_str;
595                                 str = pp_concat(txt, op2str(pc->opcode), restr);
596                                 pp_free(t2);
597                         } else {
598                                 NODE *re = m->re_exp;
599                                 restr = pp_string(re->stptr, re->stlen, '/');
600                                 str = pp_concat(txt, op2str(pc->opcode), restr);
601                                 efree(restr);
602                         }
603                         pp_free(t1);
604                         pp_push(pc->opcode, str, CAN_FREE);
605                 }
606                         break;
607
608                 case Op_K_getline:
609                 case Op_K_getline_redir:
610                         if (pc->into_var) {
611                                 t1 = pp_pop();
612                                 tmp = pp_concat(op2str(Op_K_getline), " ", t1->pp_str);
613                                 pp_free(t1);
614                         } else
615                                 tmp = pp_concat(op2str(Op_K_getline), "", "");
616
617                         if (pc->redir_type != 0) {
618                                 int before = (pc->redir_type == redirect_pipein
619                                                         || pc->redir_type == redirect_twoway);
620
621                                 t2 = pp_pop();
622                                 if (is_binary(t2->type))
623                                         pp_parenthesize(t2);
624                                 if (before)
625                                         str = pp_concat(t2->pp_str, redir2str(pc->redir_type), tmp);
626                                 else
627                                         str = pp_concat(tmp, redir2str(pc->redir_type), t2->pp_str);
628                                 efree(tmp);
629                                 pp_free(t2);
630                         } else
631                                 str = tmp;
632                         pp_push(pc->opcode, str, CAN_FREE);
633                         break;
634
635                 case Op_indirect_func_call:
636                 case Op_func_call:
637                 {
638                         char *fname = pc->func_name;
639                         char *pre;
640                         int pcount;
641
642                         if (pc->opcode == Op_indirect_func_call)
643                                 pre = "@";
644                         else
645                                 pre = "";               
646                         pcount = (pc + 1)->expr_count;
647                         if (pcount > 0) {
648                                 tmp = pp_list(pcount, "()", ", ");
649                                 str = pp_concat(pre, fname, tmp);
650                                 efree(tmp);
651                         } else
652                                 str = pp_concat(pre, fname, "()");
653                         if (pc->opcode == Op_indirect_func_call) {
654                                 t1 = pp_pop();  /* indirect var */
655                                 pp_free(t1);
656                         }
657                         pp_push(pc->opcode, str, CAN_FREE);
658                 }
659                         break;
660
661                 case Op_K_continue:
662                 case Op_K_break:
663                 case Op_K_nextfile:
664                 case Op_K_next:
665                         fprintf(prof_fp, "%s\n", op2str(pc->opcode));
666                         break;
667
668                 case Op_K_return:
669                 case Op_K_exit:
670                         t1 = pp_pop();
671                         if (is_binary(t1->type))
672                                 pp_parenthesize(t1);
673                         if (pc->source_line > 0)        /* don't print implicit 'return' at end of function */
674                                 fprintf(prof_fp, "%s %s\n", op2str(pc->opcode), t1->pp_str);
675                         pp_free(t1);
676                         break;
677
678                 case Op_pop:
679                         t1 = pp_pop();
680                         fprintf(prof_fp, "%s", t1->pp_str);
681                         if (! in_for_header)
682                                 fprintf(prof_fp, "\n");
683                         pp_free(t1);
684                         break;
685
686                 case Op_line_range:
687                         ip = pc + 1;
688                         pprint(pc->nexti, ip->condpair_left, FALSE);
689                         pprint(ip->condpair_left->nexti, ip->condpair_right, FALSE);
690                         t2 = pp_pop();
691                         t1 = pp_pop();
692                         str = pp_concat(t1->pp_str, ", ", t2->pp_str);
693                         pp_free(t1);
694                         pp_free(t2);
695                         pp_push(Op_line_range, str, CAN_FREE);
696                         pc = ip->condpair_right;
697                         break;
698
699                 case Op_K_while:
700                         ip = pc + 1;
701                         indent(ip->while_body->exec_count);
702                         fprintf(prof_fp, "%s (", op2str(pc->opcode));
703                         pprint(pc->nexti, ip->while_body, FALSE);
704                         t1 = pp_pop();
705                         fprintf(prof_fp, "%s) {\n", t1->pp_str);
706                         pp_free(t1);
707                         indent_in();
708                         pprint(ip->while_body->nexti, pc->target_break, FALSE);
709                         indent_out();
710                         indent(SPACEOVER);
711                         fprintf(prof_fp, "}\n");
712                         pc = pc->target_break;
713                         break;
714
715                 case Op_K_do:
716                         ip = pc + 1;
717                         indent(pc->nexti->exec_count);
718                         fprintf(prof_fp, "%s {\n", op2str(pc->opcode));
719                         indent_in();
720                         pprint(pc->nexti->nexti, ip->doloop_cond, FALSE);
721                         indent_out();
722                         pprint(ip->doloop_cond, pc->target_break, FALSE);
723                         indent(SPACEOVER);
724                         t1 = pp_pop();
725                         fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str);
726                         pp_free(t1);
727                         pc = pc->target_break;
728                         break;
729
730                 case Op_K_for:
731                         ip = pc + 1;
732                         indent(ip->forloop_body->exec_count);
733                         fprintf(prof_fp, "%s (", op2str(pc->opcode));   
734                         pprint(pc->nexti, ip->forloop_cond, TRUE);
735                         fprintf(prof_fp, "; ");
736
737                         if (ip->forloop_cond->opcode == Op_no_op &&
738                                         ip->forloop_cond->nexti == ip->forloop_body)
739                                 fprintf(prof_fp, "; ");
740                         else {
741                                 pprint(ip->forloop_cond, ip->forloop_body, TRUE);
742                                 t1 = pp_pop();
743                                 fprintf(prof_fp, "%s; ", t1->pp_str);
744                                 pp_free(t1);
745                         }
746
747                         pprint(pc->target_continue, pc->target_break, TRUE);
748                         fprintf(prof_fp, ") {\n");
749                         indent_in();
750                         pprint(ip->forloop_body->nexti, pc->target_continue, FALSE);
751                         indent_out();
752                         indent(SPACEOVER);
753                         fprintf(prof_fp, "}\n");
754                         pc = pc->target_break;
755                         break;
756
757                 case Op_K_arrayfor:
758                 {
759                         char *array, *item;
760
761                         ip = pc + 1;
762                         t1 = pp_pop();
763                         array = t1->pp_str;
764                         m = ip->forloop_cond->array_var;
765                         if (m->type == Node_param_list)
766                                 item = fparms[m->param_cnt];
767                         else
768                                 item = m->vname;
769                         indent(ip->forloop_body->exec_count);
770                         fprintf(prof_fp, "%s (%s%s%s) {\n", op2str(Op_K_arrayfor),
771                                                 item, op2str(Op_in_array), array);
772                         indent_in();
773                         pp_free(t1);
774                         pprint(ip->forloop_body->nexti, pc->target_break, FALSE);
775                         indent_out();
776                         indent(SPACEOVER);
777                         fprintf(prof_fp, "}\n");                        
778                         pc = pc->target_break;
779                 }
780                         break;
781
782                 case Op_K_switch:
783                         ip = pc + 1;
784                         fprintf(prof_fp, "%s (", op2str(pc->opcode));
785                         pprint(pc->nexti, ip->switch_start, FALSE);
786                         t1 = pp_pop();
787                         fprintf(prof_fp, "%s) {\n", t1->pp_str);
788                         pp_free(t1);
789                         pprint(ip->switch_start, ip->switch_end, FALSE);
790                         indent(SPACEOVER);
791                         fprintf(prof_fp, "}\n");
792                         pc = pc->target_break;
793                         break;
794
795                 case Op_K_case:
796                 case Op_K_default:
797                         indent(pc->stmt_start->exec_count);
798                         if (pc->opcode == Op_K_case) {
799                                 t1 = pp_pop();
800                                 fprintf(prof_fp, "%s %s:\n", op2str(pc->opcode), t1->pp_str);
801                                 pp_free(t1);
802                         } else
803                                 fprintf(prof_fp, "%s:\n", op2str(pc->opcode));
804                         indent_in();
805                         pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, FALSE);
806                         indent_out();
807                         break;
808
809                 case Op_K_if:
810                         fprintf(prof_fp, "%s (", op2str(pc->opcode));
811                         pprint(pc->nexti, pc->branch_if, FALSE);
812                         t1 = pp_pop();
813                         fprintf(prof_fp, "%s) {", t1->pp_str);
814                         pp_free(t1);
815
816                         ip = pc->branch_if;
817                         if (ip->exec_count > 0)
818                                 fprintf(prof_fp, " # %ld", ip->exec_count);
819                         fprintf(prof_fp, "\n");
820                         indent_in();
821                         pprint(ip->nexti, pc->branch_else, FALSE);
822                         indent_out();
823                         pc = pc->branch_else;
824                         if (pc->nexti->opcode == Op_no_op) {
825                                 indent(SPACEOVER);
826                                 fprintf(prof_fp, "}\n");
827                         }
828                         break;
829
830                 case Op_K_else:
831                         fprintf(prof_fp, "} %s {\n", op2str(pc->opcode));
832                         indent_in();
833                         pprint(pc->nexti, pc->branch_end, FALSE);
834                         indent_out();
835                         indent(SPACEOVER);
836                         fprintf(prof_fp, "}\n");
837                         pc = pc->branch_end;
838                         break;
839
840                 case Op_cond_exp:
841                 {
842                         NODE *f, *t, *cond;
843                         size_t len;
844
845                         pprint(pc->nexti, pc->branch_if, FALSE);
846                         ip = pc->branch_if;
847                         pprint(ip->nexti, pc->branch_else, FALSE);
848                         ip = pc->branch_else->nexti;
849
850                         pc = ip->nexti;
851                         assert(pc->opcode == Op_cond_exp);
852                         pprint(pc->nexti, pc->branch_end, FALSE);       
853
854                         f = pp_pop();
855                         t = pp_pop();
856                         cond = pp_pop();
857
858                         len =  f->pp_len + t->pp_len + cond->pp_len + 12;
859                         emalloc(str, char *, len, "pprint");
860                         sprintf(str, "(%s ? %s : %s)", cond->pp_str, t->pp_str, f->pp_str);
861
862                         pp_free(cond);
863                         pp_free(t);
864                         pp_free(f);
865                         pp_push(Op_cond_exp, str, CAN_FREE);
866                         pc = pc->branch_end;
867                 }
868                         break;                  
869
870                 case Op_exec_count:
871                         if (! in_for_header)
872                                 indent(pc->exec_count);
873                         break;
874
875                 default:
876                         cant_happen();
877                 }
878
879                 if (pc == endp)
880                         break;
881         }
882 }
883
884 /* pp_string_fp --- printy print a string to the fp */
885
886 /*
887  * This routine concentrates string pretty printing in one place,
888  * so that it can be called from multiple places within gawk.
889  */
890
891 void
892 pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
893                 size_t len, int delim, int breaklines)
894 {
895         char *s = pp_string(in_str, len, delim);
896         int count;
897         size_t slen;
898         const char *str = (const char *) s;
899 #define BREAKPOINT      70 /* arbitrary */
900
901         slen = strlen(str);
902         for (count = 0; slen > 0; slen--, str++) {
903                 if (++count >= BREAKPOINT && breaklines) {
904                         print_func(fp, "%c\n%c", delim, delim);
905                         count = 0;
906                 } else
907                         print_func(fp, "%c", *str);
908         }
909         efree(s);
910 }
911
912 #ifdef PROFILING
913 /* just_dump --- dump the profile and function stack and keep going */
914
915 static RETSIGTYPE
916 just_dump(int signum)
917 {
918         extern INSTRUCTION *code_block;
919
920         dump_prog(code_block);
921         dump_funcs();
922         dump_fcall_stack(prof_fp);
923         fflush(prof_fp);
924         signal(signum, just_dump);      /* for OLD Unix systems ... */
925 }
926
927 /* dump_and_exit --- dump the profile, the function stack, and exit */
928
929 static RETSIGTYPE
930 dump_and_exit(int signum)
931 {
932         just_dump(signum);
933         exit(EXIT_FAILURE);
934 }
935
936 #endif
937
938 /* dump_prog --- dump the program */
939
940 /*
941  * XXX: I am not sure it is right to have the strings in the dump
942  * be translated, but I'll leave it alone for now.
943  */
944
945 void
946 dump_prog(INSTRUCTION *code)
947 {
948         time_t now;
949
950         (void) time(& now);
951         /* \n on purpose, with \n in ctime() output */
952         fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
953         pprint(code, NULL, FALSE);
954 }
955
956 /* prec_level --- return the precedence of an operator, for paren tests */
957
958 static int
959 prec_level(int type)
960 {
961         switch (type) {
962         case Op_push_lhs:
963         case Op_push_param:
964         case Op_push_array:
965         case Op_push:
966         case Op_push_i:
967         case Op_push_re:
968         case Op_match_rec:
969         case Op_subscript:
970         case Op_subscript_lhs:
971         case Op_func_call:
972         case Op_K_delete_loop:
973         case Op_builtin:
974                 return 15;
975
976         case Op_field_spec:
977         case Op_field_spec_lhs:
978                 return 14;
979
980         case Op_exp:
981         case Op_exp_i:
982                 return 13;
983
984         case Op_preincrement:
985         case Op_predecrement:
986         case Op_postincrement:
987         case Op_postdecrement:
988                 return 12;
989
990         case Op_unary_minus:
991         case Op_not:
992                 return 11;
993
994         case Op_times:
995         case Op_times_i:
996         case Op_quotient:
997         case Op_quotient_i:
998         case Op_mod:
999         case Op_mod_i:
1000                 return 10;
1001
1002         case Op_plus:
1003         case Op_plus_i:
1004         case Op_minus:
1005         case Op_minus_i:
1006                 return 9;
1007
1008         case Op_concat:
1009         case Op_assign_concat:
1010                 return 8;
1011
1012         case Op_equal:
1013         case Op_notequal:
1014         case Op_greater:
1015         case Op_leq:
1016         case Op_geq:
1017         case Op_match:
1018         case Op_nomatch:
1019                 return 7;
1020
1021         case Op_K_getline:
1022         case Op_K_getline_redir:
1023                 return 6;
1024
1025         case Op_less:
1026                 return 5;
1027
1028         case Op_in_array:
1029                 return 5;
1030
1031         case Op_and:
1032                 return 4;
1033
1034         case Op_or:
1035                 return 3;
1036
1037         case Op_cond_exp:
1038                 return 2;
1039
1040         case Op_assign:
1041         case Op_assign_times:
1042         case Op_assign_quotient:
1043         case Op_assign_mod:
1044         case Op_assign_plus:
1045         case Op_assign_minus:
1046         case Op_assign_exp:
1047                 return 1;
1048
1049         default:
1050                 return 0;
1051         }
1052 }
1053
1054 static int
1055 is_binary(int type)
1056 {
1057         switch (type) {
1058         case Op_geq:
1059         case Op_leq:
1060         case Op_greater:
1061         case Op_less:
1062         case Op_notequal:
1063         case Op_equal:
1064         case Op_exp:
1065         case Op_times:
1066         case Op_quotient:
1067         case Op_mod:
1068         case Op_plus:
1069         case Op_minus:
1070         case Op_exp_i:
1071         case Op_times_i:
1072         case Op_quotient_i:
1073         case Op_mod_i:
1074         case Op_plus_i:
1075         case Op_minus_i:
1076         case Op_concat:
1077         case Op_assign_concat:
1078         case Op_match:
1079         case Op_nomatch:
1080         case Op_assign:
1081         case Op_assign_times:
1082         case Op_assign_quotient:
1083         case Op_assign_mod:
1084         case Op_assign_plus:
1085         case Op_assign_minus:
1086         case Op_assign_exp:
1087         case Op_cond_exp:
1088         case Op_and:
1089         case Op_or:
1090         case Op_in_array:
1091         case Op_K_getline_redir:        /* sometimes */
1092         case Op_K_getline:
1093                 return TRUE;
1094
1095         default:
1096                 return FALSE;
1097         }
1098 }
1099
1100 /* parenthesize --- parenthesize an expression in stack */
1101
1102 static void
1103 pp_parenthesize(NODE *sp)
1104 {
1105         char *p = sp->pp_str;
1106         size_t len = sp->pp_len;
1107
1108         emalloc(p, char *, len + 3, "pp_parenthesize");
1109         *p = '(';
1110         memcpy(p + 1, sp->pp_str, len);
1111         p[len + 1] = ')';
1112         p[len + 2] = '\0';
1113         if ((sp->flags & CAN_FREE) != 0)
1114                 efree(sp->pp_str);
1115         sp->pp_str = p;
1116         sp->pp_len += 2;
1117         sp->flags |= CAN_FREE;
1118 }
1119
1120 static void
1121 parenthesize(int type, NODE *left, NODE *right)
1122 {
1123         int rprec = prec_level(right->type);
1124         int lprec = prec_level(left->type);
1125         int prec = prec_level(type);
1126
1127         if (prec > lprec) {
1128                 if (is_binary(left->type))              /* (a - b) * c */
1129                         pp_parenthesize(left);
1130                 if (prec >= rprec && is_binary(right->type))    /* (a - b) * (c - d) */
1131                         pp_parenthesize(right);
1132         } else {
1133                 if (prec >= rprec && is_binary(right->type)) /* a - b - (c - d) */
1134                         pp_parenthesize(right);
1135         }
1136 }
1137
1138 /* pp_string --- pretty format a string or regex constant */
1139
1140 char *
1141 pp_string(const char *in_str, size_t len, int delim)
1142 {
1143         static char str_escapes[] = "\a\b\f\n\r\t\v\\";
1144         static char str_printables[] = "abfnrtv\\";
1145         static char re_escapes[] = "\a\b\f\n\r\t\v";
1146         static char re_printables[] = "abfnrtv";
1147         char *escapes;
1148         char *printables;
1149         char *cp;
1150         int i;
1151         const unsigned char *str = (const unsigned char *) in_str;
1152         size_t ofre, osiz;
1153         char *obuf, *obufout;
1154
1155         assert(delim == '"' || delim == '/');
1156
1157         if (delim == '/') {
1158                 escapes = re_escapes;
1159                 printables = re_printables;
1160         } else {
1161                 escapes = str_escapes;
1162                 printables = str_printables;
1163         }
1164
1165 /* make space for something l big in the buffer */
1166 #define chksize(l)  if ((l) > ofre) { \
1167                 long olen = obufout - obuf; \
1168                 erealloc(obuf, char *, osiz * 2, "pp_string"); \
1169                 obufout = obuf + olen; \
1170                 ofre += osiz; \
1171                 osiz *= 2; \
1172 } ofre -= (l)
1173
1174         osiz = len + 3 + 2;     /* initial size; 3 for delim + terminating null */
1175         emalloc(obuf, char *, osiz, "pp_string");
1176         obufout = obuf;
1177         ofre = osiz - 1;
1178
1179         *obufout++ = delim;
1180         for (; len > 0; len--, str++) {
1181                 chksize(2);             /* make space for 2 chars */
1182                 if (delim != '/' && *str == delim) {
1183                         *obufout++ = '\\';
1184                         *obufout++ = delim;
1185                 } else if ((cp = strchr(escapes, *str)) != NULL) {
1186                         i = cp - escapes;
1187                         *obufout++ = '\\';
1188                         *obufout++ = printables[i];
1189                 /* NB: Deliberate use of lower-case versions. */
1190                 } else if (isascii(*str) && isprint(*str)) {
1191                         *obufout++ = *str;
1192                         ofre += 1;
1193                 } else {
1194                         size_t len;
1195
1196                         chksize(8);             /* total available space is 10 */
1197
1198                         sprintf(obufout, "\\%03o", *str & 0xff);
1199                         len = strlen(obufout);
1200                         ofre += (10 - len);      /* adjust free space count */
1201                         obufout += len;
1202                 }
1203         }
1204         chksize(1);
1205         *obufout++ = delim;
1206         *obufout = '\0';
1207         return obuf;
1208 #undef chksize
1209 }
1210
1211 /* pp_number --- pretty format a number */
1212
1213 char *
1214 pp_number(AWKNUM d)
1215 {
1216 #define PP_PRECISION 6
1217         char *str;
1218
1219         emalloc(str, char *, PP_PRECISION + 10, "pp_number");
1220         sprintf(str, "%0.*g", PP_PRECISION, d);
1221         return str;
1222 #undef PP_PRECISION
1223 }
1224
1225 /* pp_node --- pretty format a node */
1226
1227 char *
1228 pp_node(NODE *n)
1229 {
1230         if ((n->flags & NUMBER) != 0)
1231                 return pp_number(n->numbr);
1232         return pp_string(n->stptr, n->stlen, '"');
1233 }
1234
1235 static NODE **pp_args = NULL;
1236 static int npp_args;
1237
1238 static char *
1239 pp_list(int nargs, const char *paren, const char *delim)
1240 {
1241         NODE *r;
1242         char *str, *s;
1243         size_t len;
1244         size_t delimlen;
1245         int i;
1246
1247         if (pp_args == NULL) {
1248                 npp_args = nargs;
1249                 emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
1250         } else if (nargs > npp_args) {
1251                 npp_args = nargs;
1252                 erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
1253         }
1254
1255         delimlen = strlen(delim);
1256         len = -delimlen;
1257         for (i = 1; i <= nargs; i++) {
1258                 r = pp_args[i] = pp_pop();
1259                 len += r->pp_len + delimlen;
1260         }
1261         if (paren != NULL) {
1262                 assert(strlen(paren) == 2);
1263                 len += 2;
1264         }
1265
1266         emalloc(str, char *, len + 1, "pp_list");
1267         s = str;
1268         if (paren != NULL)
1269                 *s++ = paren[0];  
1270         r = pp_args[nargs];
1271         memcpy(s, r->pp_str, r->pp_len);
1272         s += r->pp_len;
1273         pp_free(r);
1274         for (i = nargs - 1; i > 0; i--) {
1275                 if (delimlen > 0) {
1276                         memcpy(s, delim, delimlen);
1277                         s += delimlen;
1278                 }
1279                 r = pp_args[i];
1280                 memcpy(s, r->pp_str, r->pp_len);
1281                 s += r->pp_len;
1282                 pp_free(r);
1283         }
1284         if (paren != NULL)
1285                 *s++ = paren[1];
1286         *s = '\0';
1287         return str;                                     
1288 }
1289
1290 static char *
1291 pp_concat(const char *s1, const char *s2, const char *s3)
1292 {
1293         size_t len1, len2, len3, l;
1294         char *str, *s;
1295
1296         len1 = strlen(s1);
1297         len2 = strlen(s2);
1298         len3 = strlen(s3);
1299         l = len1 + len2 + len3 + 2;
1300         emalloc(str, char *, l, "pp_concat");
1301         s = str;
1302         if (len1 > 0) {
1303                 memcpy(s, s1, len1);
1304                 s += len1;
1305         }
1306         if (len2 > 0) {
1307                 memcpy(s, s2, len2);
1308                 s += len2;
1309         }
1310         if (len3 > 0) {
1311                 memcpy(s, s3, len3);
1312                 s += len3;
1313         }
1314         *s = '\0';
1315         return str;
1316 }
1317
1318 /* pp_func --- pretty print a function */
1319
1320 int
1321 pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
1322 {
1323         int j;
1324         char **pnames;
1325         NODE *f;
1326         static int first = TRUE;
1327         int pcount;
1328
1329         if (first) {
1330                 first = FALSE;
1331                 fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
1332         }
1333
1334         f = pc->func_body;
1335         fprintf(prof_fp, "\n");
1336         indent(pc->nexti->exec_count);
1337         fprintf(prof_fp, "%s %s(", op2str(Op_K_function), f->lnode->param);
1338         pnames = f->parmlist;
1339         fparms = pnames;
1340         pcount = f->lnode->param_cnt;
1341         for (j = 0; j < pcount; j++) {
1342                 fprintf(prof_fp, "%s", pnames[j]);
1343                 if (j < pcount - 1)
1344                         fprintf(prof_fp, ", ");
1345         }
1346         fprintf(prof_fp, ")\n\t{\n");
1347         indent_in();
1348         pprint(pc->nexti->nexti, NULL, FALSE);  /* function body */
1349         indent_out();
1350         fprintf(prof_fp, "\t}\n");
1351         return 0;
1352 }
1353
1354 /* redir2str --- convert a redirection type into a printable value */
1355
1356 const char *
1357 redir2str(int redirtype)
1358 {
1359         static const char *const redirtab[] = {
1360                 "",
1361                 " > ",  /* redirect_output */
1362                 " >> ", /* redirect_append */
1363                 " | ",  /* redirect_pipe */
1364                 " | ",  /* redirect_pipein */
1365                 " < ",  /* redirect_input */
1366                 " |& ", /* redirect_twoway */
1367         };
1368
1369         if (redirtype < 0 || redirtype > redirect_twoway)
1370                 fatal(_("redir2str: unknown redirection type %d"), redirtype);
1371         return redirtab[redirtype];
1372 }
1373
1374