source: vendor/gawk/3.1.5/profile.c@ 3386

Last change on this file since 3386 was 3076, checked in by bird, 18 years ago

gawk 3.1.5

File size: 29.0 KB
Line 
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 */
29enum redir_placement {
30 BEFORE = 0,
31 AFTER = 1
32};
33
34#undef tree_eval
35static void tree_eval P((NODE *tree));
36static void parenthesize P((NODETYPE parent_type, NODE *tree));
37static void eval_condition P((NODE *tree));
38static void pp_op_assign P((NODE *tree));
39static void pp_func_call P((NODE *tree));
40static void pp_match_op P((NODE *tree));
41static void pp_lhs P((NODE *ptr));
42static void pp_print_stmt P((const char *command, NODE *tree));
43static void pp_delete P((NODE *tree));
44static void pp_in_array P((NODE *array, NODE *subscript));
45static void pp_getline P((NODE *tree));
46static void pp_builtin P((NODE *tree));
47static void pp_list P((NODE *tree));
48static void pp_string P((const char *str, size_t len, int delim));
49static int is_scalar P((NODETYPE type));
50static int prec_level P((NODETYPE type));
51#ifdef PROFILING
52static RETSIGTYPE dump_and_exit P((int signum)) ATTRIBUTE_NORETURN;
53static RETSIGTYPE just_dump P((int signum));
54#endif
55
56/* pretty printing related functions and variables */
57
58static char **fparms; /* function parameter names */
59static FILE *prof_fp; /* where to send the profile */
60
61static long indent_level = 0;
62
63static int in_BEGIN_or_END = FALSE;
64
65static int in_expr = FALSE;
66
67#define SPACEOVER 0
68
69/* init_profiling --- do needed initializations, see also main.c */
70
71void
72init_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
84void
85set_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
100void
101init_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
120static void
121indent(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
137static void
138indent_in(void)
139{
140 assert(indent_level >= 0);
141 indent_level++;
142}
143
144/* indent_out --- decrease the level, with error checking */
145
146static void
147indent_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 */
158static void
159pprint(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
440static void
441varname(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
450static void
451tree_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
724static void
725eval_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
749static void
750pp_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
831static void
832pp_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
944static void
945pp_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
985static void
986pp_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
1037static void
1038pp_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
1055static void
1056pp_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
1083static void
1084pp_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
1105static void
1106pp_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
1123static void
1124pp_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
1158static void
1159pp_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
1173static void
1174pp_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
1192void
1193dump_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
1229void
1230pp_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
1260static void
1261pp_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
1273void
1274pp_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
1325static int
1326is_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
1357static int
1358prec_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
1460static void
1461parenthesize(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
1489static RETSIGTYPE
1490just_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
1503static RETSIGTYPE
1504dump_and_exit(int signum)
1505{
1506 just_dump(signum);
1507 exit(1);
1508}
1509#endif
Note: See TracBrowser for help on using the repository browser.