2 * profile.c - gawk parse tree pretty-printer with counts
6 * Copyright (C) 1999-2005 the Free Software Foundation, Inc.
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
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.
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.
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
28 /* where to place redirections for getline, print, printf */
29 enum redir_placement {
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));
52 static RETSIGTYPE dump_and_exit P((int signum)) ATTRIBUTE_NORETURN;
53 static RETSIGTYPE just_dump P((int signum));
56 /* pretty printing related functions and variables */
58 static char **fparms; /* function parameter names */
59 static FILE *prof_fp; /* where to send the profile */
61 static long indent_level = 0;
63 static int in_BEGIN_or_END = FALSE;
65 static int in_expr = FALSE;
69 /* init_profiling --- do needed initializations, see also main.c */
72 init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED)
77 set_prof_file(def_file);
82 /* set_prof_file --- set the output file for profiling */
85 set_prof_file(const char *file)
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"));
98 /* init_profiling_signals --- set up signal handling for pgawk */
101 init_profiling_signals()
105 signal(SIGINT, dump_and_exit);
106 signal(SIGQUIT, just_dump);
107 #else /* !__DJGPP__ */
109 signal(SIGHUP, dump_and_exit);
112 signal(SIGUSR1, just_dump);
114 #endif /* !__DJGPP__ */
115 #endif /* PROFILING */
118 /* indent --- print out enough tabs */
128 fprintf(prof_fp, "%6ld ", count);
130 assert(indent_level >= 0);
131 for (i = 0; i < indent_level; i++)
135 /* indent_in --- increase the level, with error checking */
140 assert(indent_level >= 0);
144 /* indent_out --- decrease the level, with error checking */
150 assert(indent_level >= 0);
155 * Tree is a bunch of rules to run. Returns zero if it hit an exit()
159 pprint(register NODE *volatile tree)
161 register NODE *volatile t = NULL; /* temporary */
162 int volatile traverse = TRUE; /* True => loop thru tree (Node_rule_list) */
164 /* avoid false source indications */
170 sourceline = tree->source_line;
171 source = tree->source_file;
172 switch (tree->type) {
174 traverse = FALSE; /* False => one for-loop iteration only */
177 for (t = tree; t != NULL; t = t->rnode) {
180 sourceline = tree->source_line;
181 source = tree->source_file;
183 if (! in_BEGIN_or_END)
184 indent(tree->exec_count);
187 eval_condition(tree->lnode);
189 fprintf(prof_fp, "\t");
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");
204 if (! in_BEGIN_or_END) {
206 fprintf(prof_fp, "}\n");
210 if (! traverse) /* case Node_rule_node */
211 break; /* don't loop */
213 if (t->rnode && ! in_BEGIN_or_END)
214 fprintf(prof_fp, "\n");
218 case Node_statement_list:
219 for (t = tree; t != NULL; t = t->rnode) {
225 indent(tree->exec_count);
226 fprintf(prof_fp, "if (");
228 eval_condition(tree->lnode);
230 fprintf(prof_fp, ") {");
232 if (tree->rnode->exec_count)
233 fprintf(prof_fp, " # %ld", tree->rnode->exec_count);
235 fprintf(prof_fp, "\n");
237 pprint(tree->rnode->lnode);
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);
244 fprintf(prof_fp, "} else {\n");
246 pprint(tree->rnode->rnode);
250 fprintf(prof_fp, "}\n");
254 indent(tree->exec_count);
255 fprintf(prof_fp, "switch (");
259 fprintf(prof_fp, ") {\n");
262 fprintf(prof_fp, "}\n");
265 case Node_switch_body:
272 indent(tree->exec_count);
273 fprintf(prof_fp, "case ");
277 fprintf(prof_fp, ":\n");
284 indent(tree->exec_count);
285 fprintf(prof_fp, "default:\n");
292 indent(tree->exec_count);
293 fprintf(prof_fp, "while (");
295 eval_condition(tree->lnode);
297 fprintf(prof_fp, ") {\n");
302 fprintf(prof_fp, "}\n");
306 indent(tree->exec_count);
307 fprintf(prof_fp, "do {\n");
312 fprintf(prof_fp, "} while (");
314 eval_condition(tree->lnode);
316 fprintf(prof_fp, ")\n");
320 indent(tree->exec_count);
321 fprintf(prof_fp, "for (");
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");
334 fprintf(prof_fp, "}\n");
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 (");
343 pp_lhs(tree->hakvar);
345 fprintf(prof_fp, " in ");
347 if (t->type == Node_param_list)
348 fprintf(prof_fp, "%s", fparms[t->param_cnt]);
350 fprintf(prof_fp, "%s", t->vname);
351 fprintf(prof_fp, ") {\n");
356 fprintf(prof_fp, "}\n");
362 indent(tree->exec_count);
363 fprintf(prof_fp, "break\n");
366 case Node_K_continue:
367 indent(tree->exec_count);
368 fprintf(prof_fp, "continue\n");
372 case Node_K_print_rec:
373 pp_print_stmt("print", tree);
377 pp_print_stmt("printf", tree);
385 indent(tree->exec_count);
386 fprintf(prof_fp, "next\n");
389 case Node_K_nextfile:
390 indent(tree->exec_count);
391 fprintf(prof_fp, "nextfile\n");
395 indent(tree->exec_count);
396 fprintf(prof_fp, "exit");
397 if (tree->lnode != NULL) {
398 fprintf(prof_fp, " ");
399 tree_eval(tree->lnode);
401 fprintf(prof_fp, "\n");
405 indent(tree->exec_count);
406 fprintf(prof_fp, "return");
407 if (tree->lnode != NULL) {
408 fprintf(prof_fp, " ");
409 tree_eval(tree->lnode);
411 fprintf(prof_fp, "\n");
416 * Appears to be an expression statement.
417 * Throw away the value.
422 indent(tree->exec_count);
424 fprintf(prof_fp, "\n");
430 /* varname --- print a variable name, handling vars done with -v */
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
437 * XXX: This is a band-aid; we really should fix the -v code.
441 varname(const char *name)
443 for (; *name != '\0' && *name != '='; name++)
444 putc(*name, prof_fp);
448 /* tree_eval --- evaluate a subtree */
451 tree_eval(register NODE *tree)
456 switch (tree->type) {
457 case Node_param_list:
458 fprintf(prof_fp, "%s", fparms[tree->param_cnt]);
464 if (tree->vname != NULL)
465 varname(tree->vname);
467 fatal(_("internal error: %s with null vname"),
468 nodetype2str(tree->type));
472 if ((tree->flags & NUMBER) != 0)
473 fprintf(prof_fp, "%g", tree->numbr);
475 if ((tree->flags & INTLSTR) != 0)
476 fprintf(prof_fp, "_");
477 pp_string(tree->stptr, tree->stlen, '"');
482 eval_condition(tree->lnode);
483 fprintf(prof_fp, " && ");
484 eval_condition(tree->rnode);
488 eval_condition(tree->lnode);
489 fprintf(prof_fp, " || ");
490 eval_condition(tree->rnode);
494 fprintf(prof_fp, "! ");
495 parenthesize(tree->type, tree->lnode);
505 pp_in_array(tree->lnode, tree->rnode);
517 case Node_K_delete_loop:
523 if (t->type == Node_param_list)
524 aname = fparms[t->param_cnt];
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);
534 fprintf(prof_fp, "delete %s[", aname);
535 pp_lhs(tree->rnode->lnode);
536 fprintf(prof_fp, "]\n");
539 fprintf(prof_fp, "}");
543 /* unary operations */
545 fprintf(prof_fp, "NR");
549 fprintf(prof_fp, "FNR");
553 fprintf(prof_fp, "NF");
556 case Node_FIELDWIDTHS:
557 fprintf(prof_fp, "FIELDWIDTHS");
561 fprintf(prof_fp, "FS");
565 fprintf(prof_fp, "RS");
568 case Node_IGNORECASE:
569 fprintf(prof_fp, "IGNORECASE");
573 fprintf(prof_fp, "OFS");
577 fprintf(prof_fp, "ORS");
581 fprintf(prof_fp, "OFMT");
585 fprintf(prof_fp, "CONVFMT");
589 fprintf(prof_fp, "BINMODE");
593 fprintf(prof_fp, "SUBSEP");
596 case Node_TEXTDOMAIN:
597 fprintf(prof_fp, "TEXTDOMAIN");
600 case Node_field_spec:
605 case Node_unary_minus:
606 fprintf(prof_fp, " -");
607 if (is_scalar(tree->subnode->type))
608 tree_eval(tree->subnode);
610 fprintf(prof_fp, "(");
611 tree_eval(tree->subnode);
612 fprintf(prof_fp, ")");
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);
633 tree_eval(tree->lnode);
634 fprintf(prof_fp, " = ");
635 tree_eval(tree->rnode);
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);
647 fprintf(prof_fp, "(");
648 tree_eval(tree->lnode);
649 fprintf(prof_fp, " ");
650 tree_eval(tree->rnode);
651 fprintf(prof_fp, ")");
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:
669 break; /* handled below */
672 /* handle binary ops */
674 parenthesize(tree->type, tree->lnode);
676 switch (tree->type) {
678 fprintf(prof_fp, " >= ");
681 fprintf(prof_fp, " <= ");
684 fprintf(prof_fp, " > ");
687 fprintf(prof_fp, " < ");
690 fprintf(prof_fp, " != ");
693 fprintf(prof_fp, " == ");
696 fprintf(prof_fp, " ^ ");
699 fprintf(prof_fp, " * ");
702 fprintf(prof_fp, " / ");
705 fprintf(prof_fp, " %% ");
708 fprintf(prof_fp, " + ");
711 fprintf(prof_fp, " - ");
714 fatal(_("illegal type (%s) in tree_eval"), nodetype2str(tree->type));
716 parenthesize(tree->type, tree->rnode);
722 /* eval_condition --- is TREE true or false */
725 eval_condition(register NODE *tree)
727 if (tree == NULL) /* Null trees are the easiest kinds */
730 if (tree->type == Node_line_range) {
732 eval_condition(tree->condpair->lnode);
733 fprintf(prof_fp,", ");
734 eval_condition(tree->condpair->rnode);
739 * Could just be J.random expression. in which case, null and 0 are
740 * false, anything else is true
747 /* pp_op_assign --- do +=, -=, etc. */
750 pp_op_assign(register NODE *tree)
752 const char *op = NULL;
760 case Node_preincrement:
765 case Node_predecrement:
770 case Node_postincrement:
775 case Node_postdecrement:
781 break; /* handled below */
785 fprintf(prof_fp, "%s", op);
788 } else if (order == POST) {
790 fprintf(prof_fp, "%s", op);
798 case Node_assign_exp:
799 fprintf(prof_fp, " ^= ");
802 case Node_assign_times:
803 fprintf(prof_fp, " *= ");
806 case Node_assign_quotient:
807 fprintf(prof_fp, " /= ");
810 case Node_assign_mod:
811 fprintf(prof_fp, " %%= ");
814 case Node_assign_plus:
815 fprintf(prof_fp, " += ");
818 case Node_assign_minus:
819 fprintf(prof_fp, " -= ");
826 tree_eval(tree->rnode);
829 /* pp_lhs --- print the lhs */
832 pp_lhs(register NODE *ptr)
838 fatal(_("attempt to use array `%s' in a scalar context"),
843 fprintf(prof_fp, "%s", ptr->vname);
846 case Node_FIELDWIDTHS:
847 fprintf(prof_fp, "FIELDWIDTHS");
851 fprintf(prof_fp, "RS");
855 fprintf(prof_fp, "FS");
859 fprintf(prof_fp, "FNR");
863 fprintf(prof_fp, "NR");
867 fprintf(prof_fp, "NF");
870 case Node_IGNORECASE:
871 fprintf(prof_fp, "IGNORECASE");
875 fprintf(prof_fp, "BINMODE");
879 fprintf(prof_fp, "LINT");
883 fprintf(prof_fp, "OFMT");
887 fprintf(prof_fp, "CONVFMT");
891 fprintf(prof_fp, "ORS");
895 fprintf(prof_fp, "OFS");
899 fprintf(prof_fp, "SUBSEP");
902 case Node_TEXTDOMAIN:
903 fprintf(prof_fp, "TEXTDOMAIN");
906 case Node_param_list:
907 fprintf(prof_fp, "%s", fparms[ptr->param_cnt]);
910 case Node_field_spec:
911 fprintf(prof_fp, "$");
912 if (is_scalar(ptr->lnode->type))
913 tree_eval(ptr->lnode);
915 fprintf(prof_fp, "(");
916 tree_eval(ptr->lnode);
917 fprintf(prof_fp, ")");
923 if (n->type == Node_param_list) {
924 fprintf(prof_fp, "%s[", fparms[n->param_cnt]);
926 fprintf(prof_fp, "%s[", n->vname);
927 if (ptr->rnode->type == Node_expression_list)
930 tree_eval(ptr->rnode);
931 fprintf(prof_fp, "]");
935 fatal(_("assignment is not allowed to result of builtin function"));
942 /* match_op --- do ~ and !~ */
945 pp_match_op(register NODE *tree)
953 if (tree->type == Node_dynregex) {
954 tree_eval(tree->re_exp);
958 if (tree->type == Node_regex) {
962 pp_string(restr, relen, '/');
966 /* at this point, have either ~ or !~ */
971 if (tree->type == Node_nomatch)
973 else if (tree->type == Node_match)
979 fprintf(prof_fp, " %s ", op);
983 /* pp_redir --- print a redirection */
986 pp_redir(register NODE *tree, enum redir_placement dir)
988 const char *op = "[BOGUS]"; /* should never be seen */
993 switch (tree->type) {
994 case Node_redirect_output:
997 case Node_redirect_append:
1000 case Node_redirect_pipe:
1003 case Node_redirect_pipein:
1006 case Node_redirect_input:
1009 case Node_redirect_twoway:
1016 if (dir == BEFORE) {
1017 if (! is_scalar(tree->subnode->type)) {
1018 fprintf(prof_fp, "(");
1019 tree_eval(tree->subnode);
1020 fprintf(prof_fp, ")");
1022 tree_eval(tree->subnode);
1023 fprintf(prof_fp, " %s ", op);
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, ")");
1031 tree_eval(tree->subnode);
1035 /* pp_list --- dump a list of arguments, without parens */
1038 pp_list(register NODE *tree)
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));
1046 assert(tree->type == Node_expression_list);
1047 tree_eval(tree->lnode);
1048 if (tree->rnode != NULL)
1049 fprintf(prof_fp, ", ");
1053 /* pp_print_stmt --- print a "print" or "printf" statement */
1056 pp_print_stmt(const char *command, register NODE *tree)
1058 NODE *redir = tree->rnode;
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, ")");
1069 fprintf(prof_fp, " $0");
1070 pp_redir(redir, AFTER);
1072 fprintf(prof_fp, " ");
1073 if (tree->lnode != NULL)
1074 pp_list(tree->lnode);
1076 fprintf(prof_fp, "$0");
1078 fprintf(prof_fp, "\n");
1081 /* pp_delete --- print a "delete" statement */
1084 pp_delete(register NODE *tree)
1086 NODE *array, *subscript;
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]);
1094 fprintf(prof_fp, "delete %s", array->vname);
1095 if (subscript != NULL) {
1096 fprintf(prof_fp, "[");
1098 fprintf(prof_fp, "]");
1100 fprintf(prof_fp, "\n");
1103 /* pp_in_array --- pretty print "foo in array" test */
1106 pp_in_array(NODE *array, NODE *subscript)
1108 if (subscript->type == Node_expression_list) {
1109 fprintf(prof_fp, "(");
1111 fprintf(prof_fp, ")");
1115 if (array->type == Node_param_list)
1116 fprintf(prof_fp, " in %s", fparms[array->param_cnt]);
1118 fprintf(prof_fp, " in %s", array->vname);
1121 /* pp_getline --- print a getline statement */
1124 pp_getline(register NODE *tree)
1126 NODE *redir = tree->rnode;
1132 * command |& getline
1136 if (redir != NULL) {
1137 before = (redir->type == Node_redirect_pipein
1138 || redir->type == Node_redirect_twoway);
1141 before = after = FALSE;
1144 pp_redir(redir, BEFORE);
1146 fprintf(prof_fp, "getline");
1147 if (tree->lnode != NULL) { /* optional var */
1148 fprintf(prof_fp, " ");
1149 pp_lhs(tree->lnode);
1153 pp_redir(redir, AFTER);
1156 /* pp_builtin --- print a builtin function */
1159 pp_builtin(register NODE *tree)
1161 const char *func = getfname(tree->builtin);
1164 fprintf(prof_fp, "%s(", func);
1165 pp_list(tree->subnode);
1166 fprintf(prof_fp, ")");
1168 fprintf(prof_fp, _("# this is a dynamically loaded extension function"));
1171 /* pp_func_call --- print a function call */
1174 pp_func_call(NODE *tree)
1176 NODE *name, *arglist;
1179 arglist = tree->lnode;
1180 fprintf(prof_fp, "%s(", name->stptr);
1182 fprintf(prof_fp, ")");
1185 /* dump_prog --- dump the program */
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.
1193 dump_prog(NODE *begin, NODE *prog, NODE *end)
1198 /* \n on purpose, with \n in ctime() output */
1199 fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
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;
1206 in_BEGIN_or_END = FALSE;
1207 fprintf(prof_fp, "\t}\n");
1208 if (prog != NULL || end != NULL)
1209 fprintf(prof_fp, "\n");
1212 fprintf(prof_fp, _("\t# Rule(s)\n\n"));
1215 fprintf(prof_fp, "\n");
1218 fprintf(prof_fp, _("\t# END block(s)\n\n"));
1219 fprintf(prof_fp, "\tEND {\n");
1220 in_BEGIN_or_END = TRUE;
1222 in_BEGIN_or_END = FALSE;
1223 fprintf(prof_fp, "\t}\n");
1227 /* pp_func --- pretty print a function */
1230 pp_func(const char *name, size_t namelen, NODE *f)
1234 static int first = TRUE;
1238 fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
1241 fprintf(prof_fp, "\n");
1242 indent(f->exec_count);
1243 fprintf(prof_fp, "function %.*s(", (int) namelen, name);
1244 pnames = f->parmlist;
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, ", ");
1251 fprintf(prof_fp, ")\n\t{\n");
1253 pprint(f->rnode); /* body */
1255 fprintf(prof_fp, "\t}\n");
1258 /* pp_string --- pretty print a string or regex constant */
1261 pp_string(const char *str, size_t len, int delim)
1263 pp_string_fp(prof_fp, str, len, delim, FALSE);
1266 /* pp_string_fp --- printy print a string to the fp */
1269 * This routine concentrates string pretty printing in one place,
1270 * so that it can be called from multiple places within gawk.
1274 pp_string_fp(FILE *fp, const char *in_str, size_t len, int delim, int breaklines)
1276 static char escapes[] = "\b\f\n\r\t\v\\";
1277 static char printables[] = "bfnrtv\\";
1281 #define BREAKPOINT 70 /* arbitrary */
1282 const unsigned char *str = (const unsigned char *) in_str;
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);
1290 if (*str == delim) {
1291 fprintf(fp, "\\%c", delim);
1293 } else if (*str == BELL) {
1296 } else if ((cp = strchr(escapes, *str)) != NULL) {
1300 putc(printables[i], fp);
1301 if (breaklines && *str == '\n' && delim == '"') {
1302 fprintf(fp, "\"\n\"");
1305 /* NB: Deliberate use of lower-case versions. */
1306 } else if (isascii(*str) && isprint(*str)) {
1311 /* print 'em as they came if for whiny users */
1313 sprintf(buf, "%c", *str & 0xff);
1315 sprintf(buf, "\\%03o", *str & 0xff);
1316 count += strlen(buf) - 1;
1317 fprintf(fp, "%s", buf);
1320 fprintf(fp, "%c", delim);
1323 /* is_scalar --- true or false if we'll get a scalar value */
1326 is_scalar(NODETYPE type)
1331 case Node_var_array:
1335 case Node_FIELDWIDTHS:
1338 case Node_IGNORECASE:
1347 case Node_TEXTDOMAIN:
1348 case Node_subscript:
1355 /* prec_level --- return the precedence of an operator, for paren tests */
1358 prec_level(NODETYPE type)
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:
1372 case Node_FIELDWIDTHS:
1375 case Node_IGNORECASE:
1384 case Node_TEXTDOMAIN:
1387 case Node_field_spec:
1393 case Node_preincrement:
1394 case Node_predecrement:
1395 case Node_postincrement:
1396 case Node_postdecrement:
1399 case Node_unary_minus:
1424 case Node_K_getline:
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:
1453 fatal(_("unexpected type %s in prec_level"), nodetype2str(type));
1454 return 0; /* keep the compiler happy */
1458 /* parenthesize --- print a subtree in parentheses if need be */
1461 parenthesize(NODETYPE parent_type, NODE *tree)
1463 NODETYPE child_type;
1468 child_type = tree->type;
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, "(");
1480 fprintf(prof_fp, ")");
1487 /* just_dump --- dump the profile and function stack and keep going */
1490 just_dump(int signum)
1492 extern NODE *begin_block, *expression_value, *end_block;
1494 dump_prog(begin_block, expression_value, end_block);
1496 dump_fcall_stack(prof_fp);
1498 signal(signum, just_dump); /* for OLD Unix systems ... */
1501 /* dump_and_exit --- dump the profile, the function stack, and exit */
1504 dump_and_exit(int signum)