remove obsolete yaml files
[toolchains/gawk.git] / profile.c
1 /*
2  * profile.c - gawk parse tree pretty-printer with counts
3  */
4
5 /* 
6  * Copyright (C) 1999-2005 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 2 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 /* where to place redirections for getline, print, printf */
29 enum redir_placement {
30         BEFORE = 0,
31         AFTER = 1
32 };
33
34 #undef tree_eval
35 static void tree_eval P((NODE *tree));
36 static void parenthesize P((NODETYPE parent_type, NODE *tree));
37 static void eval_condition P((NODE *tree));
38 static void pp_op_assign P((NODE *tree));
39 static void pp_func_call P((NODE *tree));
40 static void pp_match_op P((NODE *tree));
41 static void pp_lhs P((NODE *ptr));
42 static void pp_print_stmt P((const char *command, NODE *tree));
43 static void pp_delete P((NODE *tree));
44 static void pp_in_array P((NODE *array, NODE *subscript));
45 static void pp_getline P((NODE *tree));
46 static void pp_builtin P((NODE *tree));
47 static void pp_list P((NODE *tree));
48 static void pp_string P((const char *str, size_t len, int delim));
49 static int is_scalar P((NODETYPE type));
50 static int prec_level P((NODETYPE type));
51 #ifdef PROFILING
52 static RETSIGTYPE dump_and_exit P((int signum)) ATTRIBUTE_NORETURN;
53 static RETSIGTYPE just_dump P((int signum));
54 #endif
55
56 /* pretty printing related functions and variables */
57
58 static char **fparms;   /* function parameter names */
59 static FILE *prof_fp;   /* where to send the profile */
60
61 static long indent_level = 0;
62
63 static int in_BEGIN_or_END = FALSE;
64
65 static int in_expr = FALSE;
66
67 #define SPACEOVER       0
68
69 /* init_profiling --- do needed initializations, see also main.c */
70
71 void
72 init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED)
73 {
74 #ifdef PROFILING
75         if (*flag == FALSE) {
76                 *flag = TRUE;
77                 set_prof_file(def_file);
78         }
79 #endif
80 }
81
82 /* set_prof_file --- set the output file for profiling */
83
84 void
85 set_prof_file(const char *file)
86 {
87         assert(file != NULL);
88
89         prof_fp = fopen(file, "w");
90         if (prof_fp == NULL) {
91                 warning(_("could not open `%s' for writing: %s"),
92                                 file, strerror(errno));
93                 warning(_("sending profile to standard error"));
94                 prof_fp = stderr;
95         }
96 }
97
98 /* init_profiling_signals --- set up signal handling for pgawk */
99
100 void
101 init_profiling_signals()
102 {
103 #ifdef PROFILING
104 #ifdef __DJGPP__
105         signal(SIGINT, dump_and_exit);
106         signal(SIGQUIT, just_dump);
107 #else  /* !__DJGPP__ */
108 #ifdef SIGHUP
109         signal(SIGHUP, dump_and_exit);
110 #endif
111 #ifdef SIGUSR1
112         signal(SIGUSR1, just_dump);
113 #endif
114 #endif /* !__DJGPP__ */
115 #endif /* PROFILING */
116 }
117
118 /* indent --- print out enough tabs */
119
120 static void
121 indent(long count)
122 {
123         int i;
124
125         if (count == 0)
126                 putc('\t', prof_fp);
127         else
128                 fprintf(prof_fp, "%6ld  ", count);
129
130         assert(indent_level >= 0);
131         for (i = 0; i < indent_level; i++)
132                 putc('\t', prof_fp);
133 }
134
135 /* indent_in --- increase the level, with error checking */
136
137 static void
138 indent_in(void)
139 {
140         assert(indent_level >= 0);
141         indent_level++;
142 }
143
144 /* indent_out --- decrease the level, with error checking */
145
146 static void
147 indent_out(void)
148 {
149         indent_level--;
150         assert(indent_level >= 0);
151 }
152
153 /*
154  * pprint:
155  * Tree is a bunch of rules to run. Returns zero if it hit an exit()
156  * statement 
157  */
158 static void
159 pprint(register NODE *volatile tree)
160 {
161         register NODE *volatile t = NULL;       /* temporary */
162         int volatile traverse = TRUE;   /* True => loop thru tree (Node_rule_list) */
163
164         /* avoid false source indications */
165         source = NULL;
166         sourceline = 0;
167
168         if (tree == NULL)
169                 return;
170         sourceline = tree->source_line;
171         source = tree->source_file;
172         switch (tree->type) {
173         case Node_rule_node:
174                 traverse = FALSE;  /* False => one for-loop iteration only */
175                 /* FALL THROUGH */
176         case Node_rule_list:
177                 for (t = tree; t != NULL; t = t->rnode) {
178                         if (traverse)
179                                 tree = t->lnode;
180                         sourceline = tree->source_line;
181                         source = tree->source_file;
182
183                         if (! in_BEGIN_or_END)
184                                 indent(tree->exec_count);
185
186                         if (tree->lnode) {
187                                 eval_condition(tree->lnode);
188                                 if (tree->rnode)
189                                         fprintf(prof_fp, "\t");
190                         }
191
192                         if (tree->rnode) {
193                                 if (! in_BEGIN_or_END) {
194                                         fprintf(prof_fp, "{");
195                                         if (tree->lnode != NULL
196                                             && tree->lnode->exec_count)
197                                                 fprintf(prof_fp, " # %ld",
198                                                         tree->lnode->exec_count);
199                                         fprintf(prof_fp, "\n");
200                                 }
201                                 indent_in();
202                                 pprint(tree->rnode);
203                                 indent_out();
204                                 if (! in_BEGIN_or_END) {
205                                         indent(SPACEOVER);
206                                         fprintf(prof_fp, "}\n");
207                                 }
208                         }
209
210                         if (! traverse)         /* case Node_rule_node */
211                                 break;          /* don't loop */
212
213                         if (t->rnode && ! in_BEGIN_or_END)
214                                 fprintf(prof_fp, "\n");
215                 }
216                 break;
217
218         case Node_statement_list:
219                 for (t = tree; t != NULL; t = t->rnode) {
220                         pprint(t->lnode);
221                 }
222                 break;
223
224         case Node_K_if:
225                 indent(tree->exec_count);
226                 fprintf(prof_fp, "if (");
227                 in_expr++;
228                 eval_condition(tree->lnode);
229                 in_expr--;
230                 fprintf(prof_fp, ") {");
231 #ifdef PROFILING
232                 if (tree->rnode->exec_count)
233                         fprintf(prof_fp, " # %ld", tree->rnode->exec_count);
234 #endif
235                 fprintf(prof_fp, "\n");
236                 indent_in();
237                 pprint(tree->rnode->lnode);
238                 indent_out();
239                 if (tree->rnode->rnode != NULL) {
240                         if (tree->exec_count - tree->rnode->exec_count > 0)
241                                 indent(tree->exec_count - tree->rnode->exec_count);
242                         else
243                                 indent(0);
244                         fprintf(prof_fp, "} else {\n");
245                         indent_in();
246                         pprint(tree->rnode->rnode);
247                         indent_out();
248                 }
249                 indent(SPACEOVER);
250                 fprintf(prof_fp, "}\n");
251                 break;
252
253         case Node_K_switch:
254                 indent(tree->exec_count);
255                 fprintf(prof_fp, "switch (");
256                 in_expr++;
257                 pprint(tree->lnode);
258                 in_expr--;
259                 fprintf(prof_fp, ") {\n");
260                 pprint(tree->rnode);
261                 indent(SPACEOVER);
262                 fprintf(prof_fp, "}\n");
263                 break;
264
265         case Node_switch_body:
266         case Node_case_list:
267                 pprint(tree->lnode);
268                 pprint(tree->rnode);
269                 break;
270
271         case Node_K_case:
272                 indent(tree->exec_count);
273                 fprintf(prof_fp, "case ");
274                 in_expr++;
275                 pprint(tree->lnode);
276                 in_expr--;
277                 fprintf(prof_fp, ":\n");
278                 indent_in();
279                 pprint(tree->rnode);
280                 indent_out();
281                 break;
282
283         case Node_K_default:
284                 indent(tree->exec_count);
285                 fprintf(prof_fp, "default:\n");
286                 indent_in();
287                 pprint(tree->rnode);
288                 indent_out();
289                 break;
290
291         case Node_K_while:
292                 indent(tree->exec_count);
293                 fprintf(prof_fp, "while (");
294                 in_expr++;
295                 eval_condition(tree->lnode);
296                 in_expr--;
297                 fprintf(prof_fp, ") {\n");
298                 indent_in();
299                 pprint(tree->rnode);
300                 indent_out();
301                 indent(SPACEOVER);
302                 fprintf(prof_fp, "}\n");
303                 break;
304
305         case Node_K_do:
306                 indent(tree->exec_count);
307                 fprintf(prof_fp, "do {\n");
308                 indent_in();
309                 pprint(tree->rnode);
310                 indent_out();
311                 indent(SPACEOVER);
312                 fprintf(prof_fp, "} while (");
313                 in_expr++;
314                 eval_condition(tree->lnode);
315                 in_expr--;
316                 fprintf(prof_fp, ")\n");
317                 break;
318
319         case Node_K_for:
320                 indent(tree->exec_count);
321                 fprintf(prof_fp, "for (");
322                 in_expr++;
323                 pprint(tree->forloop->init);
324                 fprintf(prof_fp, "; ");
325                 eval_condition(tree->forloop->cond);
326                 fprintf(prof_fp, "; ");
327                 pprint(tree->forloop->incr);
328                 fprintf(prof_fp, ") {\n");
329                 in_expr--;
330                 indent_in();
331                 pprint(tree->lnode);
332                 indent_out();
333                 indent(SPACEOVER);
334                 fprintf(prof_fp, "}\n");
335                 break;
336
337         case Node_K_arrayfor:
338 #define hakvar forloop->init
339 #define arrvar forloop->incr
340                 indent(tree->exec_count);
341                 fprintf(prof_fp, "for (");
342                 in_expr++;
343                 pp_lhs(tree->hakvar);
344                 in_expr--;
345                 fprintf(prof_fp, " in ");
346                 t = tree->arrvar;
347                 if (t->type == Node_param_list)
348                         fprintf(prof_fp, "%s", fparms[t->param_cnt]);
349                 else
350                         fprintf(prof_fp, "%s", t->vname);
351                 fprintf(prof_fp, ") {\n");
352                 indent_in();
353                 pprint(tree->lnode);
354                 indent_out();
355                 indent(SPACEOVER);
356                 fprintf(prof_fp, "}\n");
357                 break;
358 #undef hakvar
359 #undef arrvar
360
361         case Node_K_break:
362                 indent(tree->exec_count);
363                 fprintf(prof_fp, "break\n");
364                 break;
365
366         case Node_K_continue:
367                 indent(tree->exec_count);
368                 fprintf(prof_fp, "continue\n");
369                 break;
370
371         case Node_K_print:
372         case Node_K_print_rec:
373                 pp_print_stmt("print", tree);
374                 break;
375
376         case Node_K_printf:
377                 pp_print_stmt("printf", tree);
378                 break;
379
380         case Node_K_delete:
381                 pp_delete(tree);
382                 break;
383
384         case Node_K_next:
385                 indent(tree->exec_count);
386                 fprintf(prof_fp, "next\n");
387                 break;
388
389         case Node_K_nextfile:
390                 indent(tree->exec_count);
391                 fprintf(prof_fp, "nextfile\n");
392                 break;
393
394         case Node_K_exit:
395                 indent(tree->exec_count);
396                 fprintf(prof_fp, "exit");
397                 if (tree->lnode != NULL) {
398                         fprintf(prof_fp, " ");
399                         tree_eval(tree->lnode);
400                 }
401                 fprintf(prof_fp, "\n");
402                 break;
403
404         case Node_K_return:
405                 indent(tree->exec_count);
406                 fprintf(prof_fp, "return");
407                 if (tree->lnode != NULL) {
408                         fprintf(prof_fp, " ");
409                         tree_eval(tree->lnode);
410                 }
411                 fprintf(prof_fp, "\n");
412                 break;
413
414         default:
415                 /*
416                  * Appears to be an expression statement.
417                  * Throw away the value. 
418                  */
419                 if (in_expr)
420                         tree_eval(tree);
421                 else {
422                         indent(tree->exec_count);
423                         tree_eval(tree);
424                         fprintf(prof_fp, "\n");
425                 }
426                 break;
427         }
428 }
429
430 /* varname --- print a variable name, handling vars done with -v */
431
432 /*
433  * When `-v x=x' is given, the varname field ends up including the
434  * entire text.  This gets printed in the profiled output if we're
435  * not careful. Oops.
436  *
437  * XXX: This is a band-aid; we really should fix the -v code.
438  */
439
440 static void
441 varname(const char *name)
442 {
443         for (; *name != '\0' && *name != '='; name++)
444                 putc(*name, prof_fp);
445         return;
446 }
447
448 /* tree_eval --- evaluate a subtree */
449
450 static void
451 tree_eval(register NODE *tree)
452 {
453         if (tree == NULL)
454                 return;
455
456         switch (tree->type) {
457         case Node_param_list:
458                 fprintf(prof_fp, "%s", fparms[tree->param_cnt]);
459                 return;
460
461         case Node_var_new:
462         case Node_var:
463         case Node_var_array:
464                 if (tree->vname != NULL)
465                         varname(tree->vname);
466                 else
467                         fatal(_("internal error: %s with null vname"),
468                                 nodetype2str(tree->type));
469                 return;
470
471         case Node_val:
472                 if ((tree->flags & NUMBER) != 0)
473                         fprintf(prof_fp, "%g", tree->numbr);
474                 else {
475                         if ((tree->flags & INTLSTR) != 0)
476                                 fprintf(prof_fp, "_");
477                         pp_string(tree->stptr, tree->stlen, '"');
478                 }
479                 return;
480
481         case Node_and:
482                 eval_condition(tree->lnode);
483                 fprintf(prof_fp, " && ");
484                 eval_condition(tree->rnode);
485                 return;
486
487         case Node_or:
488                 eval_condition(tree->lnode);
489                 fprintf(prof_fp, " || ");
490                 eval_condition(tree->rnode);
491                 return;
492
493         case Node_not:
494                 fprintf(prof_fp, "! ");
495                 parenthesize(tree->type, tree->lnode);
496                 return;
497
498                 /* Builtins */
499         case Node_builtin:
500                 pp_builtin(tree);
501                 return;
502
503         case Node_in_array:
504                 in_expr++;
505                 pp_in_array(tree->lnode, tree->rnode);
506                 in_expr--;
507                 return;
508
509         case Node_func_call:
510                 pp_func_call(tree);
511                 return;
512
513         case Node_K_getline:
514                 pp_getline(tree);
515                 return;
516
517         case Node_K_delete_loop:
518         {
519                 char *aname;
520                 NODE *t;
521
522                 t = tree->lnode;
523                 if (t->type == Node_param_list)
524                         aname = fparms[t->param_cnt];
525                 else
526                         aname = t->vname;
527
528                 fprintf(prof_fp, "for (");
529                 pp_lhs(tree->rnode->lnode);
530                 fprintf(prof_fp, " in %s) { %s %s'\n", aname,
531                         _("# treated internally as `delete'"), aname);
532                 indent_in();
533                 indent(SPACEOVER);
534                 fprintf(prof_fp, "delete %s[", aname);
535                 pp_lhs(tree->rnode->lnode);
536                 fprintf(prof_fp, "]\n");
537                 indent_out();
538                 indent(SPACEOVER);
539                 fprintf(prof_fp, "}");
540         }
541                 return;
542
543                 /* unary operations */
544         case Node_NR:
545                 fprintf(prof_fp, "NR");
546                 return;
547
548         case Node_FNR:
549                 fprintf(prof_fp, "FNR");
550                 return;
551
552         case Node_NF:
553                 fprintf(prof_fp, "NF");
554                 return;
555
556         case Node_FIELDWIDTHS:
557                 fprintf(prof_fp, "FIELDWIDTHS");
558                 return;
559
560         case Node_FS:
561                 fprintf(prof_fp, "FS");
562                 return;
563
564         case Node_RS:
565                 fprintf(prof_fp, "RS");
566                 return;
567
568         case Node_IGNORECASE:
569                 fprintf(prof_fp, "IGNORECASE");
570                 return;
571
572         case Node_OFS:
573                 fprintf(prof_fp, "OFS");
574                 return;
575
576         case Node_ORS:
577                 fprintf(prof_fp, "ORS");
578                 return;
579
580         case Node_OFMT:
581                 fprintf(prof_fp, "OFMT");
582                 return;
583
584         case Node_CONVFMT:
585                 fprintf(prof_fp, "CONVFMT");
586                 return;
587
588         case Node_BINMODE:
589                 fprintf(prof_fp, "BINMODE");
590                 return;
591
592         case Node_SUBSEP:
593                 fprintf(prof_fp, "SUBSEP");
594                 return;
595
596         case Node_TEXTDOMAIN:
597                 fprintf(prof_fp, "TEXTDOMAIN");
598                 return;
599
600         case Node_field_spec:
601         case Node_subscript:
602                 pp_lhs(tree);
603                 return;
604
605         case Node_unary_minus:
606                 fprintf(prof_fp, " -");
607                 if (is_scalar(tree->subnode->type))
608                         tree_eval(tree->subnode);
609                 else {
610                         fprintf(prof_fp, "(");
611                         tree_eval(tree->subnode);
612                         fprintf(prof_fp, ")");
613                 }
614                 return;
615
616         case Node_cond_exp:
617                 eval_condition(tree->lnode);
618                 fprintf(prof_fp, " ? ");
619                 tree_eval(tree->rnode->lnode);
620                 fprintf(prof_fp, " : ");
621                 tree_eval(tree->rnode->rnode);
622                 return;
623
624         case Node_match:
625         case Node_nomatch:
626         case Node_regex:
627         case Node_dynregex:
628                 pp_match_op(tree);
629                 return;
630
631                 /* assignments */
632         case Node_assign:
633                 tree_eval(tree->lnode);
634                 fprintf(prof_fp, " = ");
635                 tree_eval(tree->rnode);
636                 return;
637
638         case Node_assign_concat:
639                 tree_eval(tree->lnode);
640                 fprintf(prof_fp, " = ");
641                 tree_eval(tree->lnode);
642                 fprintf(prof_fp, " ");
643                 tree_eval(tree->rnode);
644                 return;
645
646         case Node_concat:
647                 fprintf(prof_fp, "(");
648                 tree_eval(tree->lnode);
649                 fprintf(prof_fp, " ");
650                 tree_eval(tree->rnode);
651                 fprintf(prof_fp, ")");
652                 return;
653
654         /* other assignment types are easier because they are numeric */
655         case Node_preincrement:
656         case Node_predecrement:
657         case Node_postincrement:
658         case Node_postdecrement:
659         case Node_assign_exp:
660         case Node_assign_times:
661         case Node_assign_quotient:
662         case Node_assign_mod:
663         case Node_assign_plus:
664         case Node_assign_minus:
665                 pp_op_assign(tree);
666                 return;
667
668         default:
669                 break;  /* handled below */
670         }
671
672         /* handle binary ops */
673         in_expr++;
674         parenthesize(tree->type, tree->lnode);
675
676         switch (tree->type) {
677         case Node_geq:
678                 fprintf(prof_fp, " >= ");
679                 break;
680         case Node_leq:
681                 fprintf(prof_fp, " <= ");
682                 break;
683         case Node_greater:
684                 fprintf(prof_fp, " > ");
685                 break;
686         case Node_less:
687                 fprintf(prof_fp, " < ");
688                 break;
689         case Node_notequal:
690                 fprintf(prof_fp, " != ");
691                 break;
692         case Node_equal:
693                 fprintf(prof_fp, " == ");
694                 break;
695         case Node_exp:
696                 fprintf(prof_fp, " ^ ");
697                 break;
698         case Node_times:
699                 fprintf(prof_fp, " * ");
700                 break;
701         case Node_quotient:
702                 fprintf(prof_fp, " / ");
703                 break;
704         case Node_mod:
705                 fprintf(prof_fp, " %% ");
706                 break;
707         case Node_plus:
708                 fprintf(prof_fp, " + ");
709                 break;
710         case Node_minus:
711                 fprintf(prof_fp, " - ");
712                 break;
713         default:
714                 fatal(_("illegal type (%s) in tree_eval"), nodetype2str(tree->type));
715         }
716         parenthesize(tree->type, tree->rnode);
717         in_expr--;
718
719         return;
720 }
721
722 /* eval_condition --- is TREE true or false */
723
724 static void
725 eval_condition(register NODE *tree)
726 {
727         if (tree == NULL)       /* Null trees are the easiest kinds */
728                 return;
729
730         if (tree->type == Node_line_range) {
731                 /* /.../, /.../ */
732                 eval_condition(tree->condpair->lnode);
733                 fprintf(prof_fp,", ");
734                 eval_condition(tree->condpair->rnode);
735                 return;
736         }
737
738         /*
739          * Could just be J.random expression. in which case, null and 0 are
740          * false, anything else is true 
741          */
742
743         tree_eval(tree);
744         return;
745 }
746
747 /* pp_op_assign --- do +=, -=, etc. */
748
749 static void
750 pp_op_assign(register NODE *tree)
751 {
752         const char *op = NULL;
753         enum Order {
754                 NA = 0,
755                 PRE = 1,
756                 POST = 2
757         } order = NA;
758
759         switch(tree->type) {
760         case Node_preincrement:
761                 op = "++";
762                 order = PRE;
763                 break;
764
765         case Node_predecrement:
766                 op = "--";
767                 order = PRE;
768                 break;
769
770         case Node_postincrement:
771                 op = "++";
772                 order = POST;
773                 break;
774
775         case Node_postdecrement:
776                 op = "--";
777                 order = POST;
778                 break;
779
780         default:
781                 break;  /* handled below */
782         }
783
784         if (order == PRE) {
785                 fprintf(prof_fp, "%s", op);
786                 pp_lhs(tree->lnode);
787                 return;
788         } else if (order == POST) {
789                 pp_lhs(tree->lnode);
790                 fprintf(prof_fp, "%s", op);
791                 return;
792         }
793
794         /* a binary op */
795         pp_lhs(tree->lnode);
796
797         switch(tree->type) {
798         case Node_assign_exp:
799                 fprintf(prof_fp, " ^= ");
800                 break;
801
802         case Node_assign_times:
803                 fprintf(prof_fp, " *= ");
804                 break;
805
806         case Node_assign_quotient:
807                 fprintf(prof_fp, " /= ");
808                 break;
809
810         case Node_assign_mod:
811                 fprintf(prof_fp, " %%= ");
812                 break;
813
814         case Node_assign_plus:
815                 fprintf(prof_fp, " += ");
816                 break;
817
818         case Node_assign_minus:
819                 fprintf(prof_fp, " -= ");
820                 break;
821
822         default:
823                 cant_happen();
824         }
825
826         tree_eval(tree->rnode);
827 }
828
829 /* pp_lhs --- print the lhs */
830
831 static void
832 pp_lhs(register NODE *ptr)
833 {
834         register NODE *n;
835
836         switch (ptr->type) {
837         case Node_var_array:
838                 fatal(_("attempt to use array `%s' in a scalar context"),
839                         ptr->vname);
840
841         case Node_var_new:
842         case Node_var:
843                 fprintf(prof_fp, "%s", ptr->vname);
844                 break;
845
846         case Node_FIELDWIDTHS:
847                 fprintf(prof_fp, "FIELDWIDTHS");
848                 break;
849
850         case Node_RS:
851                 fprintf(prof_fp, "RS");
852                 break;
853
854         case Node_FS:
855                 fprintf(prof_fp, "FS");
856                 break;
857
858         case Node_FNR:
859                 fprintf(prof_fp, "FNR");
860                 break;
861
862         case Node_NR:
863                 fprintf(prof_fp, "NR");
864                 break;
865
866         case Node_NF:
867                 fprintf(prof_fp, "NF");
868                 break;
869
870         case Node_IGNORECASE:
871                 fprintf(prof_fp, "IGNORECASE");
872                 break;
873
874         case Node_BINMODE:
875                 fprintf(prof_fp, "BINMODE");
876                 break;
877
878         case Node_LINT:
879                 fprintf(prof_fp, "LINT");
880                 break;
881
882         case Node_OFMT:
883                 fprintf(prof_fp, "OFMT");
884                 break;
885
886         case Node_CONVFMT:
887                 fprintf(prof_fp, "CONVFMT");
888                 break;
889
890         case Node_ORS:
891                 fprintf(prof_fp, "ORS");
892                 break;
893
894         case Node_OFS:
895                 fprintf(prof_fp, "OFS");
896                 break;
897
898         case Node_SUBSEP:
899                 fprintf(prof_fp, "SUBSEP");
900                 break;
901
902         case Node_TEXTDOMAIN:
903                 fprintf(prof_fp, "TEXTDOMAIN");
904                 break;
905
906         case Node_param_list:
907                 fprintf(prof_fp, "%s", fparms[ptr->param_cnt]);
908                 break;
909
910         case Node_field_spec:
911                 fprintf(prof_fp, "$");
912                 if (is_scalar(ptr->lnode->type))
913                         tree_eval(ptr->lnode);
914                 else {
915                         fprintf(prof_fp, "(");
916                         tree_eval(ptr->lnode);
917                         fprintf(prof_fp, ")");
918                 }
919                 break;
920
921         case Node_subscript:
922                 n = ptr->lnode;
923                 if (n->type == Node_param_list) {
924                         fprintf(prof_fp, "%s[", fparms[n->param_cnt]);
925                 } else
926                         fprintf(prof_fp, "%s[", n->vname);
927                 if (ptr->rnode->type == Node_expression_list)
928                         pp_list(ptr->rnode);
929                 else
930                         tree_eval(ptr->rnode);
931                 fprintf(prof_fp, "]");
932                 break;
933
934         case Node_builtin:
935                 fatal(_("assignment is not allowed to result of builtin function"));
936
937         default:
938                 cant_happen();
939         }
940 }
941
942 /* match_op --- do ~ and !~ */
943
944 static void
945 pp_match_op(register NODE *tree)
946 {
947         register NODE *re;
948         const char *op;
949         const char *restr;
950         size_t relen;
951         NODE *text = NULL;
952
953         if (tree->type == Node_dynregex) {
954                 tree_eval(tree->re_exp);
955                 return;
956         }
957
958         if (tree->type == Node_regex) {
959                 re = tree->re_exp;
960                 restr = re->stptr;
961                 relen = re->stlen;
962                 pp_string(restr, relen, '/');
963                 return;
964         }
965
966         /* at this point, have either ~ or !~ */
967
968         text = tree->lnode;
969         re = tree->rnode;
970
971         if (tree->type == Node_nomatch)
972                 op = "!~";
973         else if (tree->type == Node_match)
974                 op = "~";
975         else
976                 op = "";
977
978         tree_eval(text);
979         fprintf(prof_fp, " %s ", op);
980         tree_eval(re);
981 }
982
983 /* pp_redir --- print a redirection */
984
985 static void
986 pp_redir(register NODE *tree, enum redir_placement dir)
987 {
988         const char *op = "[BOGUS]";     /* should never be seen */
989
990         if (tree == NULL)
991                 return;
992
993         switch (tree->type) {
994         case Node_redirect_output:
995                 op = ">";
996                 break;
997         case Node_redirect_append:
998                 op = ">>";
999                 break;
1000         case Node_redirect_pipe:
1001                 op = "|";
1002                 break;
1003         case Node_redirect_pipein:
1004                 op = "|";
1005                 break;
1006         case Node_redirect_input:
1007                 op = "<";
1008                 break;
1009         case Node_redirect_twoway:
1010                 op = "|&";
1011                 break;
1012         default:
1013                 cant_happen();
1014         }
1015         
1016         if (dir == BEFORE) {
1017                 if (! is_scalar(tree->subnode->type)) {
1018                         fprintf(prof_fp, "(");
1019                         tree_eval(tree->subnode);
1020                         fprintf(prof_fp, ")");
1021                 } else
1022                         tree_eval(tree->subnode);
1023                 fprintf(prof_fp, " %s ", op);
1024         } else {
1025                 fprintf(prof_fp, " %s ", op);
1026                 if (! is_scalar(tree->subnode->type)) {
1027                         fprintf(prof_fp, "(");
1028                         tree_eval(tree->subnode);
1029                         fprintf(prof_fp, ")");
1030                 } else
1031                         tree_eval(tree->subnode);
1032         }
1033 }
1034
1035 /* pp_list --- dump a list of arguments, without parens */
1036
1037 static void
1038 pp_list(register NODE *tree)
1039 {
1040         for (; tree != NULL; tree = tree->rnode) {
1041                 if (tree->type != Node_expression_list) {
1042                         fprintf(stderr, "pp_list: got %s\n",
1043                                         nodetype2str(tree->type));
1044                         fflush(stderr);
1045                 }
1046                 assert(tree->type == Node_expression_list);
1047                 tree_eval(tree->lnode);
1048                 if (tree->rnode != NULL)
1049                         fprintf(prof_fp, ", ");
1050         }
1051 }
1052
1053 /* pp_print_stmt --- print a "print" or "printf" statement */
1054
1055 static void
1056 pp_print_stmt(const char *command, register NODE *tree)
1057 {
1058         NODE *redir = tree->rnode;
1059
1060         indent(tree->exec_count);
1061         fprintf(prof_fp, "%s", command);
1062         if (redir != NULL) {
1063                 if (tree->lnode != NULL) {
1064                         /* parenthesize if have a redirection and a list */
1065                         fprintf(prof_fp, "(");
1066                         pp_list(tree->lnode);
1067                         fprintf(prof_fp, ")");
1068                 } else
1069                         fprintf(prof_fp, " $0");
1070                 pp_redir(redir, AFTER);
1071         } else {
1072                 fprintf(prof_fp, " ");
1073                 if (tree->lnode != NULL)
1074                         pp_list(tree->lnode);
1075                 else
1076                         fprintf(prof_fp, "$0");
1077         }
1078         fprintf(prof_fp, "\n");
1079 }
1080
1081 /* pp_delete --- print a "delete" statement */
1082
1083 static void
1084 pp_delete(register NODE *tree)
1085 {
1086         NODE *array, *subscript;
1087
1088         array = tree->lnode;
1089         subscript = tree->rnode;
1090         indent(array->exec_count);
1091         if (array->type == Node_param_list)
1092                 fprintf(prof_fp, "delete %s", fparms[array->param_cnt]);
1093         else
1094                 fprintf(prof_fp, "delete %s", array->vname);
1095         if (subscript != NULL) {
1096                 fprintf(prof_fp, "[");
1097                 pp_list(subscript);
1098                 fprintf(prof_fp, "]");
1099         }
1100         fprintf(prof_fp, "\n");
1101 }
1102
1103 /* pp_in_array --- pretty print "foo in array" test */
1104
1105 static void
1106 pp_in_array(NODE *array, NODE *subscript)
1107 {
1108         if (subscript->type == Node_expression_list) {
1109                 fprintf(prof_fp, "(");
1110                 pp_list(subscript);
1111                 fprintf(prof_fp, ")");
1112         } else
1113                 pprint(subscript);
1114
1115         if (array->type == Node_param_list)
1116                 fprintf(prof_fp, " in %s", fparms[array->param_cnt]);
1117         else
1118                 fprintf(prof_fp, " in %s", array->vname);
1119 }
1120
1121 /* pp_getline --- print a getline statement */
1122
1123 static void
1124 pp_getline(register NODE *tree)
1125 {
1126         NODE *redir = tree->rnode;
1127         int before, after;
1128
1129         /*
1130          * command | getline
1131          *     or
1132          * command |& getline
1133          *     or
1134          * getline < file
1135          */
1136         if (redir != NULL) {
1137                 before = (redir->type == Node_redirect_pipein
1138                                 || redir->type == Node_redirect_twoway);
1139                 after = ! before;
1140         } else
1141                 before = after = FALSE;
1142
1143         if (before)
1144                 pp_redir(redir, BEFORE);
1145
1146         fprintf(prof_fp, "getline");
1147         if (tree->lnode != NULL) {      /* optional var */
1148                 fprintf(prof_fp, " ");
1149                 pp_lhs(tree->lnode);
1150         }
1151
1152         if (after)
1153                 pp_redir(redir, AFTER);
1154 }
1155
1156 /* pp_builtin --- print a builtin function */
1157
1158 static void
1159 pp_builtin(register NODE *tree)
1160 {
1161         const char *func = getfname(tree->builtin);
1162
1163         if (func != NULL) {
1164                 fprintf(prof_fp, "%s(", func);
1165                 pp_list(tree->subnode);
1166                 fprintf(prof_fp, ")");
1167         } else
1168                 fprintf(prof_fp, _("# this is a dynamically loaded extension function"));
1169 }
1170
1171 /* pp_func_call --- print a function call */
1172
1173 static void
1174 pp_func_call(NODE *tree)
1175 {
1176         NODE *name, *arglist;
1177
1178         name = tree->rnode;
1179         arglist = tree->lnode;
1180         fprintf(prof_fp, "%s(", name->stptr);
1181         pp_list(arglist);
1182         fprintf(prof_fp, ")");
1183 }
1184
1185 /* dump_prog --- dump the program */
1186
1187 /*
1188  * XXX: I am not sure it is right to have the strings in the dump
1189  * be translated, but I'll leave it alone for now.
1190  */
1191
1192 void
1193 dump_prog(NODE *begin, NODE *prog, NODE *end)
1194 {
1195         time_t now;
1196
1197         (void) time(& now);
1198         /* \n on purpose, with \n in ctime() output */
1199         fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
1200
1201         if (begin != NULL) {
1202                 fprintf(prof_fp, _("\t# BEGIN block(s)\n\n"));
1203                 fprintf(prof_fp, "\tBEGIN {\n");
1204                 in_BEGIN_or_END = TRUE;
1205                 pprint(begin);
1206                 in_BEGIN_or_END = FALSE;
1207                 fprintf(prof_fp, "\t}\n");
1208                 if (prog != NULL || end != NULL)
1209                         fprintf(prof_fp, "\n");
1210         }
1211         if (prog != NULL) {
1212                 fprintf(prof_fp, _("\t# Rule(s)\n\n"));
1213                 pprint(prog);
1214                 if (end != NULL)
1215                         fprintf(prof_fp, "\n");
1216         }
1217         if (end != NULL) {
1218                 fprintf(prof_fp, _("\t# END block(s)\n\n"));
1219                 fprintf(prof_fp, "\tEND {\n");
1220                 in_BEGIN_or_END = TRUE;
1221                 pprint(end);
1222                 in_BEGIN_or_END = FALSE;
1223                 fprintf(prof_fp, "\t}\n");
1224         }
1225 }
1226
1227 /* pp_func --- pretty print a function */
1228
1229 void
1230 pp_func(const char *name, size_t namelen, NODE *f)
1231 {
1232         int j;
1233         char **pnames;
1234         static int first = TRUE;
1235
1236         if (first) {
1237                 first = FALSE;
1238                 fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
1239         }
1240
1241         fprintf(prof_fp, "\n");
1242         indent(f->exec_count);
1243         fprintf(prof_fp, "function %.*s(", (int) namelen, name);
1244         pnames = f->parmlist;
1245         fparms = pnames;
1246         for (j = 0; j < f->lnode->param_cnt; j++) {
1247                 fprintf(prof_fp, "%s", pnames[j]);
1248                 if (j < f->lnode->param_cnt - 1)
1249                         fprintf(prof_fp, ", ");
1250         }
1251         fprintf(prof_fp, ")\n\t{\n");
1252         indent_in();
1253         pprint(f->rnode);       /* body */
1254         indent_out();
1255         fprintf(prof_fp, "\t}\n");
1256 }
1257
1258 /* pp_string --- pretty print a string or regex constant */
1259
1260 static void
1261 pp_string(const char *str, size_t len, int delim)
1262 {
1263         pp_string_fp(prof_fp, str, len, delim, FALSE);
1264 }
1265
1266 /* pp_string_fp --- printy print a string to the fp */
1267
1268 /*
1269  * This routine concentrates string pretty printing in one place,
1270  * so that it can be called from multiple places within gawk.
1271  */
1272
1273 void
1274 pp_string_fp(FILE *fp, const char *in_str, size_t len, int delim, int breaklines)
1275 {
1276         static char escapes[] = "\b\f\n\r\t\v\\";
1277         static char printables[] = "bfnrtv\\";
1278         char *cp;
1279         int i;
1280         int count;
1281 #define BREAKPOINT      70 /* arbitrary */
1282         const unsigned char *str = (const unsigned char *) in_str;
1283
1284         fprintf(fp, "%c", delim);
1285         for (count = 0; len > 0; len--, str++) {
1286                 if (++count >= BREAKPOINT && breaklines) {
1287                         fprintf(fp, "%c\n%c", delim, delim);
1288                         count = 0;
1289                 }
1290                 if (*str == delim) {
1291                         fprintf(fp, "\\%c", delim);
1292                         count++;
1293                 } else if (*str == BELL) {
1294                         fprintf(fp, "\\a");
1295                         count++;
1296                 } else if ((cp = strchr(escapes, *str)) != NULL) {
1297                         i = cp - escapes;
1298                         putc('\\', fp);
1299                         count++;
1300                         putc(printables[i], fp);
1301                         if (breaklines && *str == '\n' && delim == '"') {
1302                                 fprintf(fp, "\"\n\"");
1303                                 count = 0;
1304                         }
1305                 /* NB: Deliberate use of lower-case versions. */
1306                 } else if (isascii(*str) && isprint(*str)) {
1307                         putc(*str, fp);
1308                 } else {
1309                         char buf[10];
1310
1311                         /* print 'em as they came if for whiny users */
1312                         if (whiny_users)
1313                                 sprintf(buf, "%c", *str & 0xff);
1314                         else
1315                                 sprintf(buf, "\\%03o", *str & 0xff);
1316                         count += strlen(buf) - 1;
1317                         fprintf(fp, "%s", buf);
1318                 }
1319         }
1320         fprintf(fp, "%c", delim);
1321 }
1322
1323 /* is_scalar --- true or false if we'll get a scalar value */
1324
1325 static int
1326 is_scalar(NODETYPE type)
1327 {
1328         switch (type) {
1329         case Node_var_new:
1330         case Node_var:
1331         case Node_var_array:
1332         case Node_val:
1333         case Node_BINMODE:
1334         case Node_CONVFMT:
1335         case Node_FIELDWIDTHS:
1336         case Node_FNR:
1337         case Node_FS:
1338         case Node_IGNORECASE:
1339         case Node_LINT:
1340         case Node_NF:
1341         case Node_NR:
1342         case Node_OFMT:
1343         case Node_OFS:
1344         case Node_ORS:
1345         case Node_RS:
1346         case Node_SUBSEP:
1347         case Node_TEXTDOMAIN:
1348         case Node_subscript:
1349                 return TRUE;
1350         default:
1351                 return FALSE;
1352         }
1353 }
1354
1355 /* prec_level --- return the precedence of an operator, for paren tests */
1356
1357 static int
1358 prec_level(NODETYPE type)
1359 {
1360         switch (type) {
1361         case Node_var_new:
1362         case Node_var:
1363         case Node_var_array:
1364         case Node_param_list:
1365         case Node_subscript:
1366         case Node_func_call:
1367         case Node_K_delete_loop:
1368         case Node_val:
1369         case Node_builtin:
1370         case Node_BINMODE:
1371         case Node_CONVFMT:
1372         case Node_FIELDWIDTHS:
1373         case Node_FNR:
1374         case Node_FS:
1375         case Node_IGNORECASE:
1376         case Node_LINT:
1377         case Node_NF:
1378         case Node_NR:
1379         case Node_OFMT:
1380         case Node_OFS:
1381         case Node_ORS:
1382         case Node_RS:
1383         case Node_SUBSEP:
1384         case Node_TEXTDOMAIN:
1385                 return 15;
1386
1387         case Node_field_spec:
1388                 return 14;
1389
1390         case Node_exp:
1391                 return 13;
1392
1393         case Node_preincrement:
1394         case Node_predecrement:
1395         case Node_postincrement:
1396         case Node_postdecrement:
1397                 return 12;
1398
1399         case Node_unary_minus:
1400         case Node_not:
1401                 return 11;
1402
1403         case Node_times:
1404         case Node_quotient:
1405         case Node_mod:
1406                 return 10;
1407
1408         case Node_plus:
1409         case Node_minus:
1410                 return 9;
1411
1412         case Node_concat:
1413                 return 8;
1414
1415         case Node_equal:
1416         case Node_notequal:
1417         case Node_greater:
1418         case Node_leq:
1419         case Node_geq:
1420         case Node_match:
1421         case Node_nomatch:
1422                 return 7;
1423
1424         case Node_K_getline:
1425                 return 6;
1426
1427         case Node_less:
1428                 return 5;
1429
1430         case Node_in_array:
1431                 return 5;
1432
1433         case Node_and:
1434                 return 4;
1435
1436         case Node_or:
1437                 return 3;
1438
1439         case Node_cond_exp:
1440                 return 2;
1441
1442         case Node_assign:
1443         case Node_assign_times:
1444         case Node_assign_quotient:
1445         case Node_assign_mod:
1446         case Node_assign_plus:
1447         case Node_assign_minus:
1448         case Node_assign_exp:
1449         case Node_assign_concat:
1450                 return 1;
1451
1452         default:
1453                 fatal(_("unexpected type %s in prec_level"), nodetype2str(type));
1454                 return 0;       /* keep the compiler happy */
1455         }
1456 }
1457
1458 /* parenthesize --- print a subtree in parentheses if need be */
1459
1460 static void
1461 parenthesize(NODETYPE parent_type, NODE *tree)
1462 {
1463         NODETYPE child_type;
1464
1465         if (tree == NULL)
1466                 return;
1467
1468         child_type = tree->type;
1469
1470         in_expr++;
1471         /* first the special cases, then the general ones */
1472         if (parent_type == Node_not && child_type == Node_in_array) {
1473                 fprintf(prof_fp, "! (");
1474                 pp_in_array(tree->lnode, tree->rnode);
1475                 fprintf(prof_fp, ")");
1476         /* other special cases here, as needed */
1477         } else if (prec_level(child_type) < prec_level(parent_type)) {
1478                 fprintf(prof_fp, "(");
1479                 tree_eval(tree);
1480                 fprintf(prof_fp, ")");
1481         } else
1482                 tree_eval(tree);
1483         in_expr--;
1484 }
1485
1486 #ifdef PROFILING
1487 /* just_dump --- dump the profile and function stack and keep going */
1488
1489 static RETSIGTYPE
1490 just_dump(int signum)
1491 {
1492         extern NODE *begin_block, *expression_value, *end_block;
1493
1494         dump_prog(begin_block, expression_value, end_block);
1495         dump_funcs();
1496         dump_fcall_stack(prof_fp);
1497         fflush(prof_fp);
1498         signal(signum, just_dump);      /* for OLD Unix systems ... */
1499 }
1500
1501 /* dump_and_exit --- dump the profile, the function stack, and exit */
1502
1503 static RETSIGTYPE
1504 dump_and_exit(int signum)
1505 {
1506         just_dump(signum);
1507         exit(1);
1508 }
1509 #endif