Main Page | Class List | Directories | File List | Class Members | File Members

profile.c

Go to the documentation of this file.
00001 /*
00002  * profile.c - gawk parse tree pretty-printer with counts
00003  */
00004 
00005 /* 
00006  * Copyright (C) 1999-2003 the Free Software Foundation, Inc.
00007  * 
00008  * This file is part of GAWK, the GNU implementation of the
00009  * AWK Programming Language.
00010  * 
00011  * GAWK is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  * 
00016  * GAWK is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  * 
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
00024  */
00025 
00026 #include "awk.h"
00027 
00028 /* where to place redirections for getline, print, printf */
00029 enum redir_placement {
00030         BEFORE = 0,
00031         AFTER = 1
00032 };
00033 
00034 #undef tree_eval
00035 static void tree_eval P((NODE *tree));
00036 static void parenthesize P((NODETYPE parent_type, NODE *tree));
00037 static void eval_condition P((NODE *tree));
00038 static void pp_op_assign P((NODE *tree));
00039 static void pp_func_call P((NODE *tree));
00040 static void pp_match_op P((NODE *tree));
00041 static void pp_lhs P((NODE *ptr));
00042 static void pp_print_stmt P((const char *command, NODE *tree));
00043 static void pp_delete P((NODE *tree));
00044 static void pp_in_array P((NODE *array, NODE *subscript));
00045 static void pp_getline P((NODE *tree));
00046 static void pp_builtin P((NODE *tree));
00047 static void pp_list P((NODE *tree));
00048 static void pp_string P((const char *str, size_t len, int delim));
00049 static int is_scalar P((NODETYPE type));
00050 static int prec_level P((NODETYPE type));
00051 #ifdef PROFILING
00052 static RETSIGTYPE dump_and_exit P((int signum)) ATTRIBUTE_NORETURN;
00053 static RETSIGTYPE just_dump P((int signum));
00054 #endif
00055 
00056 /* pretty printing related functions and variables */
00057 
00058 static char **fparms;   /* function parameter names */
00059 static FILE *prof_fp;   /* where to send the profile */
00060 
00061 static long indent_level = 0;
00062 
00063 static int in_BEGIN_or_END = FALSE;
00064 
00065 static int in_expr = FALSE;
00066 
00067 #define SPACEOVER       0
00068 
00069 /* init_profiling --- do needed initializations, see also main.c */
00070 
00071 void
00072 init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED)
00073 {
00074 #ifdef PROFILING
00075         if (*flag == FALSE) {
00076                 *flag = TRUE;
00077                 set_prof_file(def_file);
00078         }
00079 #endif
00080 }
00081 
00082 /* set_prof_file --- set the output file for profiling */
00083 
00084 void
00085 set_prof_file(const char *file)
00086 {
00087         assert(file != NULL);
00088 
00089         prof_fp = fopen(file, "w");
00090         if (prof_fp == NULL) {
00091                 warning(_("could not open `%s' for writing: %s"),
00092                                 file, strerror(errno));
00093                 warning(_("sending profile to standard error"));
00094                 prof_fp = stderr;
00095         }
00096 }
00097 
00098 /* init_profiling_signals --- set up signal handling for pgawk */
00099 
00100 void
00101 init_profiling_signals()
00102 {
00103 #ifdef PROFILING
00104 #ifdef __DJGPP__
00105         signal(SIGINT, dump_and_exit);
00106         signal(SIGQUIT, just_dump);
00107 #else  /* !__DJGPP__ */
00108 #ifdef SIGHUP
00109         signal(SIGHUP, dump_and_exit);
00110 #endif
00111 #ifdef SIGUSR1
00112         signal(SIGUSR1, just_dump);
00113 #endif
00114 #endif /* !__DJGPP__ */
00115 #endif /* PROFILING */
00116 }
00117 
00118 /* indent --- print out enough tabs */
00119 
00120 static void
00121 indent(long count)
00122 {
00123         int i;
00124 
00125         if (count == 0)
00126                 putc('\t', prof_fp);
00127         else
00128                 fprintf(prof_fp, "%6ld  ", count);
00129 
00130         assert(indent_level >= 0);
00131         for (i = 0; i < indent_level; i++)
00132                 putc('\t', prof_fp);
00133 }
00134 
00135 /* indent_in --- increase the level, with error checking */
00136 
00137 static void
00138 indent_in(void)
00139 {
00140         assert(indent_level >= 0);
00141         indent_level++;
00142 }
00143 
00144 /* indent_out --- decrease the level, with error checking */
00145 
00146 static void
00147 indent_out(void)
00148 {
00149         indent_level--;
00150         assert(indent_level >= 0);
00151 }
00152 
00153 /*
00154  * pprint:
00155  * Tree is a bunch of rules to run. Returns zero if it hit an exit()
00156  * statement 
00157  */
00158 static void
00159 pprint(register NODE *volatile tree)
00160 {
00161         register NODE *volatile t = NULL;       /* temporary */
00162         int volatile traverse = TRUE;   /* True => loop thru tree (Node_rule_list) */
00163 
00164         /* avoid false source indications */
00165         source = NULL;
00166         sourceline = 0;
00167 
00168         if (tree == NULL)
00169                 return;
00170         sourceline = tree->source_line;
00171         source = tree->source_file;
00172         switch (tree->type) {
00173         case Node_rule_node:
00174                 traverse = FALSE;  /* False => one for-loop iteration only */
00175                 /* FALL THROUGH */
00176         case Node_rule_list:
00177                 for (t = tree; t != NULL; t = t->rnode) {
00178                         if (traverse)
00179                                 tree = t->lnode;
00180                         sourceline = tree->source_line;
00181                         source = tree->source_file;
00182 
00183                         if (! in_BEGIN_or_END)
00184                                 indent(tree->exec_count);
00185 
00186                         if (tree->lnode) {
00187                                 eval_condition(tree->lnode);
00188                                 if (tree->rnode)
00189                                         fprintf(prof_fp, "\t");
00190                         }
00191 
00192                         if (tree->rnode) {
00193                                 if (! in_BEGIN_or_END) {
00194                                         fprintf(prof_fp, "{");
00195                                         if (tree->lnode != NULL
00196                                             && tree->lnode->exec_count)
00197                                                 fprintf(prof_fp, " # %ld",
00198                                                         tree->lnode->exec_count);
00199                                         fprintf(prof_fp, "\n");
00200                                 }
00201                                 indent_in();
00202                                 pprint(tree->rnode);
00203                                 indent_out();
00204                                 if (! in_BEGIN_or_END) {
00205                                         indent(SPACEOVER);
00206                                         fprintf(prof_fp, "}\n");
00207                                 }
00208                         }
00209 
00210                         if (! traverse)         /* case Node_rule_node */
00211                                 break;          /* don't loop */
00212 
00213                         if (t->rnode && ! in_BEGIN_or_END)
00214                                 fprintf(prof_fp, "\n");
00215                 }
00216                 break;
00217 
00218         case Node_statement_list:
00219                 for (t = tree; t != NULL; t = t->rnode) {
00220                         pprint(t->lnode);
00221                 }
00222                 break;
00223 
00224         case Node_K_if:
00225                 indent(tree->exec_count);
00226                 fprintf(prof_fp, "if (");
00227                 in_expr++;
00228                 eval_condition(tree->lnode);
00229                 in_expr--;
00230                 fprintf(prof_fp, ") {");
00231 #ifdef PROFILING
00232                 if (tree->rnode->exec_count)
00233                         fprintf(prof_fp, " # %ld", tree->rnode->exec_count);
00234 #endif
00235                 fprintf(prof_fp, "\n");
00236                 indent_in();
00237                 pprint(tree->rnode->lnode);
00238                 indent_out();
00239                 if (tree->rnode->rnode != NULL) {
00240                         if (tree->exec_count - tree->rnode->exec_count > 0)
00241                                 indent(tree->exec_count - tree->rnode->exec_count);
00242                         else
00243                                 indent(0);
00244                         fprintf(prof_fp, "} else {\n");
00245                         indent_in();
00246                         pprint(tree->rnode->rnode);
00247                         indent_out();
00248                 }
00249                 indent(SPACEOVER);
00250                 fprintf(prof_fp, "}\n");
00251                 break;
00252 
00253         case Node_K_switch:
00254                 indent(tree->exec_count);
00255                 fprintf(prof_fp, "switch (");
00256                 in_expr++;
00257                 pprint(tree->lnode);
00258                 in_expr--;
00259                 fprintf(prof_fp, ") {\n");
00260                 pprint(tree->rnode);
00261                 indent(SPACEOVER);
00262                 fprintf(prof_fp, "}\n");
00263                 break;
00264 
00265         case Node_switch_body:
00266         case Node_case_list:
00267                 pprint(tree->lnode);
00268                 pprint(tree->rnode);
00269                 break;
00270 
00271         case Node_K_case:
00272                 indent(tree->exec_count);
00273                 fprintf(prof_fp, "case ");
00274                 in_expr++;
00275                 pprint(tree->lnode);
00276                 in_expr--;
00277                 fprintf(prof_fp, ":\n");
00278                 indent_in();
00279                 pprint(tree->rnode);
00280                 indent_out();
00281                 break;
00282 
00283         case Node_K_default:
00284                 indent(tree->exec_count);
00285                 fprintf(prof_fp, "default:\n");
00286                 indent_in();
00287                 pprint(tree->rnode);
00288                 indent_out();
00289                 break;
00290 
00291         case Node_K_while:
00292                 indent(tree->exec_count);
00293                 fprintf(prof_fp, "while (");
00294                 in_expr++;
00295                 eval_condition(tree->lnode);
00296                 in_expr--;
00297                 fprintf(prof_fp, ") {\n");
00298                 indent_in();
00299                 pprint(tree->rnode);
00300                 indent_out();
00301                 indent(SPACEOVER);
00302                 fprintf(prof_fp, "}\n");
00303                 break;
00304 
00305         case Node_K_do:
00306                 indent(tree->exec_count);
00307                 fprintf(prof_fp, "do {\n");
00308                 indent_in();
00309                 pprint(tree->rnode);
00310                 indent_out();
00311                 indent(SPACEOVER);
00312                 fprintf(prof_fp, "} while (");
00313                 in_expr++;
00314                 eval_condition(tree->lnode);
00315                 in_expr--;
00316                 fprintf(prof_fp, ")\n");
00317                 break;
00318 
00319         case Node_K_for:
00320                 indent(tree->exec_count);
00321                 fprintf(prof_fp, "for (");
00322                 in_expr++;
00323                 pprint(tree->forloop->init);
00324                 fprintf(prof_fp, "; ");
00325                 eval_condition(tree->forloop->cond);
00326                 fprintf(prof_fp, "; ");
00327                 pprint(tree->forloop->incr);
00328                 fprintf(prof_fp, ") {\n");
00329                 in_expr--;
00330                 indent_in();
00331                 pprint(tree->lnode);
00332                 indent_out();
00333                 indent(SPACEOVER);
00334                 fprintf(prof_fp, "}\n");
00335                 break;
00336 
00337         case Node_K_arrayfor:
00338 #define hakvar forloop->init
00339 #define arrvar forloop->incr
00340                 indent(tree->exec_count);
00341                 fprintf(prof_fp, "for (");
00342                 in_expr++;
00343                 pp_lhs(tree->hakvar);
00344                 in_expr--;
00345                 fprintf(prof_fp, " in ");
00346                 t = tree->arrvar;
00347                 if (t->type == Node_param_list)
00348                         fprintf(prof_fp, "%s", fparms[t->param_cnt]);
00349                 else
00350                         fprintf(prof_fp, "%s", t->vname);
00351                 fprintf(prof_fp, ") {\n");
00352                 indent_in();
00353                 pprint(tree->lnode);
00354                 indent_out();
00355                 indent(SPACEOVER);
00356                 fprintf(prof_fp, "}\n");
00357                 break;
00358 #undef hakvar
00359 #undef arrvar
00360 
00361         case Node_K_break:
00362                 indent(tree->exec_count);
00363                 fprintf(prof_fp, "break\n");
00364                 break;
00365 
00366         case Node_K_continue:
00367                 indent(tree->exec_count);
00368                 fprintf(prof_fp, "continue\n");
00369                 break;
00370 
00371         case Node_K_print:
00372         case Node_K_print_rec:
00373                 pp_print_stmt("print", tree);
00374                 break;
00375 
00376         case Node_K_printf:
00377                 pp_print_stmt("printf", tree);
00378                 break;
00379 
00380         case Node_K_delete:
00381                 pp_delete(tree);
00382                 break;
00383 
00384         case Node_K_next:
00385                 indent(tree->exec_count);
00386                 fprintf(prof_fp, "next\n");
00387                 break;
00388 
00389         case Node_K_nextfile:
00390                 indent(tree->exec_count);
00391                 fprintf(prof_fp, "nextfile\n");
00392                 break;
00393 
00394         case Node_K_exit:
00395                 indent(tree->exec_count);
00396                 fprintf(prof_fp, "exit");
00397                 if (tree->lnode != NULL) {
00398                         fprintf(prof_fp, " ");
00399                         tree_eval(tree->lnode);
00400                 }
00401                 fprintf(prof_fp, "\n");
00402                 break;
00403 
00404         case Node_K_return:
00405                 indent(tree->exec_count);
00406                 fprintf(prof_fp, "return");
00407                 if (tree->lnode != NULL) {
00408                         fprintf(prof_fp, " ");
00409                         tree_eval(tree->lnode);
00410                 }
00411                 fprintf(prof_fp, "\n");
00412                 break;
00413 
00414         default:
00415                 /*
00416                  * Appears to be an expression statement.
00417                  * Throw away the value. 
00418                  */
00419                 if (in_expr)
00420                         tree_eval(tree);
00421                 else {
00422                         indent(tree->exec_count);
00423                         tree_eval(tree);
00424                         fprintf(prof_fp, "\n");
00425                 }
00426                 break;
00427         }
00428 }
00429 
00430 /* tree_eval --- evaluate a subtree */
00431 
00432 static void
00433 tree_eval(register NODE *tree)
00434 {
00435         if (tree == NULL)
00436                 return;
00437 
00438         switch (tree->type) {
00439         case Node_param_list:
00440                 fprintf(prof_fp, "%s", fparms[tree->param_cnt]);
00441                 return;
00442 
00443         case Node_var_new:
00444         case Node_var:
00445         case Node_var_array:
00446                 if (tree->vname != NULL)
00447                         fprintf(prof_fp, "%s", tree->vname);
00448                 else
00449                         fatal(_("internal error: %s with null vname"),
00450                                 nodetype2str(tree->type));
00451                 return;
00452 
00453         case Node_val:
00454                 if ((tree->flags & NUMBER) != 0)
00455                         fprintf(prof_fp, "%g", tree->numbr);
00456                 else {
00457                         if ((tree->flags & INTLSTR) != 0)
00458                                 fprintf(prof_fp, "_");
00459                         pp_string(tree->stptr, tree->stlen, '"');
00460                 }
00461                 return;
00462 
00463         case Node_and:
00464                 eval_condition(tree->lnode);
00465                 fprintf(prof_fp, " && ");
00466                 eval_condition(tree->rnode);
00467                 return;
00468 
00469         case Node_or:
00470                 eval_condition(tree->lnode);
00471                 fprintf(prof_fp, " || ");
00472                 eval_condition(tree->rnode);
00473                 return;
00474 
00475         case Node_not:
00476                 parenthesize(tree->type, tree->lnode);
00477                 return;
00478 
00479                 /* Builtins */
00480         case Node_builtin:
00481                 pp_builtin(tree);
00482                 return;
00483 
00484         case Node_in_array:
00485                 in_expr++;
00486                 pp_in_array(tree->lnode, tree->rnode);
00487                 in_expr--;
00488                 return;
00489 
00490         case Node_func_call:
00491                 pp_func_call(tree);
00492                 return;
00493 
00494         case Node_K_getline:
00495                 pp_getline(tree);
00496                 return;
00497 
00498         case Node_K_delete_loop:
00499         {
00500                 char *aname;
00501                 NODE *t;
00502 
00503                 t = tree->lnode;
00504                 if (t->type == Node_param_list)
00505                         aname = fparms[t->param_cnt];
00506                 else
00507                         aname = t->vname;
00508 
00509                 fprintf(prof_fp, "for (");
00510                 pp_lhs(tree->rnode->lnode);
00511                 fprintf(prof_fp, " in %s) { %s %s'\n", aname,
00512                         _("# treated internally as `delete'"), aname);
00513                 indent_in();
00514                 indent(SPACEOVER);
00515                 fprintf(prof_fp, "delete %s[", aname);
00516                 pp_lhs(tree->rnode->lnode);
00517                 fprintf(prof_fp, "]\n");
00518                 indent_out();
00519                 indent(SPACEOVER);
00520                 fprintf(prof_fp, "}");
00521         }
00522                 return;
00523 
00524                 /* unary operations */
00525         case Node_NR:
00526                 fprintf(prof_fp, "NR");
00527                 return;
00528 
00529         case Node_FNR:
00530                 fprintf(prof_fp, "FNR");
00531                 return;
00532 
00533         case Node_NF:
00534                 fprintf(prof_fp, "NF");
00535                 return;
00536 
00537         case Node_FIELDWIDTHS:
00538                 fprintf(prof_fp, "FIELDWIDTHS");
00539                 return;
00540 
00541         case Node_FS:
00542                 fprintf(prof_fp, "FS");
00543                 return;
00544 
00545         case Node_RS:
00546                 fprintf(prof_fp, "RS");
00547                 return;
00548 
00549         case Node_IGNORECASE:
00550                 fprintf(prof_fp, "IGNORECASE");
00551                 return;
00552 
00553         case Node_OFS:
00554                 fprintf(prof_fp, "OFS");
00555                 return;
00556 
00557         case Node_ORS:
00558                 fprintf(prof_fp, "ORS");
00559                 return;
00560 
00561         case Node_OFMT:
00562                 fprintf(prof_fp, "OFMT");
00563                 return;
00564 
00565         case Node_CONVFMT:
00566                 fprintf(prof_fp, "CONVFMT");
00567                 return;
00568 
00569         case Node_BINMODE:
00570                 fprintf(prof_fp, "BINMODE");
00571                 return;
00572 
00573         case Node_TEXTDOMAIN:
00574                 fprintf(prof_fp, "TEXTDOMAIN");
00575                 return;
00576 
00577         case Node_field_spec:
00578         case Node_subscript:
00579                 pp_lhs(tree);
00580                 return;
00581 
00582         case Node_unary_minus:
00583                 fprintf(prof_fp, " -");
00584                 if (is_scalar(tree->subnode->type))
00585                         tree_eval(tree->subnode);
00586                 else {
00587                         fprintf(prof_fp, "(");
00588                         tree_eval(tree->subnode);
00589                         fprintf(prof_fp, ")");
00590                 }
00591                 return;
00592 
00593         case Node_cond_exp:
00594                 eval_condition(tree->lnode);
00595                 fprintf(prof_fp, " ? ");
00596                 tree_eval(tree->rnode->lnode);
00597                 fprintf(prof_fp, " : ");
00598                 tree_eval(tree->rnode->rnode);
00599                 return;
00600 
00601         case Node_match:
00602         case Node_nomatch:
00603         case Node_regex:
00604         case Node_dynregex:
00605                 pp_match_op(tree);
00606                 return;
00607 
00608                 /* assignments */
00609         case Node_assign:
00610                 tree_eval(tree->lnode);
00611                 fprintf(prof_fp, " = ");
00612                 tree_eval(tree->rnode);
00613                 return;
00614 
00615         case Node_concat:
00616                 fprintf(prof_fp, "(");
00617                 tree_eval(tree->lnode);
00618                 fprintf(prof_fp, " ");
00619                 tree_eval(tree->rnode);
00620                 fprintf(prof_fp, ")");
00621                 return;
00622 
00623         /* other assignment types are easier because they are numeric */
00624         case Node_preincrement:
00625         case Node_predecrement:
00626         case Node_postincrement:
00627         case Node_postdecrement:
00628         case Node_assign_exp:
00629         case Node_assign_times:
00630         case Node_assign_quotient:
00631         case Node_assign_mod:
00632         case Node_assign_plus:
00633         case Node_assign_minus:
00634                 pp_op_assign(tree);
00635                 return;
00636 
00637         default:
00638                 break;  /* handled below */
00639         }
00640 
00641         /* handle binary ops */
00642         in_expr++;
00643         parenthesize(tree->type, tree->lnode);
00644 
00645         switch (tree->type) {
00646         case Node_geq:
00647                 fprintf(prof_fp, " >= ");
00648                 break;
00649         case Node_leq:
00650                 fprintf(prof_fp, " <= ");
00651                 break;
00652         case Node_greater:
00653                 fprintf(prof_fp, " > ");
00654                 break;
00655         case Node_less:
00656                 fprintf(prof_fp, " < ");
00657                 break;
00658         case Node_notequal:
00659                 fprintf(prof_fp, " != ");
00660                 break;
00661         case Node_equal:
00662                 fprintf(prof_fp, " == ");
00663                 break;
00664         case Node_exp:
00665                 fprintf(prof_fp, " ^ ");
00666                 break;
00667         case Node_times:
00668                 fprintf(prof_fp, " * ");
00669                 break;
00670         case Node_quotient:
00671                 fprintf(prof_fp, " / ");
00672                 break;
00673         case Node_mod:
00674                 fprintf(prof_fp, " %% ");
00675                 break;
00676         case Node_plus:
00677                 fprintf(prof_fp, " + ");
00678                 break;
00679         case Node_minus:
00680                 fprintf(prof_fp, " - ");
00681                 break;
00682         default:
00683                 fatal(_("illegal type (%s) in tree_eval"), nodetype2str(tree->type));
00684         }
00685         parenthesize(tree->type, tree->rnode);
00686         in_expr--;
00687 
00688         return;
00689 }
00690 
00691 /* eval_condition --- is TREE true or false */
00692 
00693 static void
00694 eval_condition(register NODE *tree)
00695 {
00696         if (tree == NULL)       /* Null trees are the easiest kinds */
00697                 return;
00698 
00699         if (tree->type == Node_line_range) {
00700                 /* /.../, /.../ */
00701                 eval_condition(tree->condpair->lnode);
00702                 fprintf(prof_fp,", ");
00703                 eval_condition(tree->condpair->rnode);
00704                 return;
00705         }
00706 
00707         /*
00708          * Could just be J.random expression. in which case, null and 0 are
00709          * false, anything else is true 
00710          */
00711 
00712         tree_eval(tree);
00713         return;
00714 }
00715 
00716 /* pp_op_assign --- do +=, -=, etc. */
00717 
00718 static void
00719 pp_op_assign(register NODE *tree)
00720 {
00721         const char *op = NULL;
00722         enum Order {
00723                 NA = 0,
00724                 PRE = 1,
00725                 POST = 2
00726         } order = NA;
00727 
00728         switch(tree->type) {
00729         case Node_preincrement:
00730                 op = "++";
00731                 order = PRE;
00732                 break;
00733 
00734         case Node_predecrement:
00735                 op = "--";
00736                 order = PRE;
00737                 break;
00738 
00739         case Node_postincrement:
00740                 op = "++";
00741                 order = POST;
00742                 break;
00743 
00744         case Node_postdecrement:
00745                 op = "--";
00746                 order = POST;
00747                 break;
00748 
00749         default:
00750                 break;  /* handled below */
00751         }
00752 
00753         if (order == PRE) {
00754                 fprintf(prof_fp, "%s", op);
00755                 pp_lhs(tree->lnode);
00756                 return;
00757         } else if (order == POST) {
00758                 pp_lhs(tree->lnode);
00759                 fprintf(prof_fp, "%s", op);
00760                 return;
00761         }
00762 
00763         /* a binary op */
00764         pp_lhs(tree->lnode);
00765 
00766         switch(tree->type) {
00767         case Node_assign_exp:
00768                 fprintf(prof_fp, " ^= ");
00769                 break;
00770 
00771         case Node_assign_times:
00772                 fprintf(prof_fp, " *= ");
00773                 break;
00774 
00775         case Node_assign_quotient:
00776                 fprintf(prof_fp, " /= ");
00777                 break;
00778 
00779         case Node_assign_mod:
00780                 fprintf(prof_fp, " %%= ");
00781                 break;
00782 
00783         case Node_assign_plus:
00784                 fprintf(prof_fp, " += ");
00785                 break;
00786 
00787         case Node_assign_minus:
00788                 fprintf(prof_fp, " -= ");
00789                 break;
00790 
00791         default:
00792                 cant_happen();
00793         }
00794 
00795         tree_eval(tree->rnode);
00796 }
00797 
00798 /* pp_lhs --- print the lhs */
00799 
00800 static void
00801 pp_lhs(register NODE *ptr)
00802 {
00803         register NODE *n;
00804 
00805         switch (ptr->type) {
00806         case Node_var_array:
00807                 fatal(_("attempt to use array `%s' in a scalar context"),
00808                         ptr->vname);
00809 
00810         case Node_var_new:
00811         case Node_var:
00812                 fprintf(prof_fp, "%s", ptr->vname);
00813                 break;
00814 
00815         case Node_FIELDWIDTHS:
00816                 fprintf(prof_fp, "FIELDWIDTHS");
00817                 break;
00818 
00819         case Node_RS:
00820                 fprintf(prof_fp, "RS");
00821                 break;
00822 
00823         case Node_FS:
00824                 fprintf(prof_fp, "FS");
00825                 break;
00826 
00827         case Node_FNR:
00828                 fprintf(prof_fp, "FNR");
00829                 break;
00830 
00831         case Node_NR:
00832                 fprintf(prof_fp, "NR");
00833                 break;
00834 
00835         case Node_NF:
00836                 fprintf(prof_fp, "NF");
00837                 break;
00838 
00839         case Node_IGNORECASE:
00840                 fprintf(prof_fp, "IGNORECASE");
00841                 break;
00842 
00843         case Node_BINMODE:
00844                 fprintf(prof_fp, "BINMODE");
00845                 break;
00846 
00847         case Node_LINT:
00848                 fprintf(prof_fp, "LINT");
00849                 break;
00850 
00851         case Node_OFMT:
00852                 fprintf(prof_fp, "OFMT");
00853                 break;
00854 
00855         case Node_CONVFMT:
00856                 fprintf(prof_fp, "CONVFMT");
00857                 break;
00858 
00859         case Node_ORS:
00860                 fprintf(prof_fp, "ORS");
00861                 break;
00862 
00863         case Node_OFS:
00864                 fprintf(prof_fp, "OFS");
00865                 break;
00866 
00867         case Node_TEXTDOMAIN:
00868                 fprintf(prof_fp, "TEXTDOMAIN");
00869                 break;
00870 
00871         case Node_param_list:
00872                 fprintf(prof_fp, "%s", fparms[ptr->param_cnt]);
00873                 break;
00874 
00875         case Node_field_spec:
00876                 fprintf(prof_fp, "$");
00877                 if (is_scalar(ptr->lnode->type))
00878                         tree_eval(ptr->lnode);
00879                 else {
00880                         fprintf(prof_fp, "(");
00881                         tree_eval(ptr->lnode);
00882                         fprintf(prof_fp, ")");
00883                 }
00884                 break;
00885 
00886         case Node_subscript:
00887                 n = ptr->lnode;
00888                 if (n->type == Node_param_list) {
00889                         fprintf(prof_fp, "%s[", fparms[n->param_cnt]);
00890                 } else
00891                         fprintf(prof_fp, "%s[", n->vname);
00892                 if (ptr->rnode->type == Node_expression_list)
00893                         pp_list(ptr->rnode);
00894                 else
00895                         tree_eval(ptr->rnode);
00896                 fprintf(prof_fp, "]");
00897                 break;
00898 
00899         case Node_builtin:
00900                 fatal(_("assignment is not allowed to result of builtin function"));
00901 
00902         default:
00903                 cant_happen();
00904         }
00905 }
00906 
00907 /* match_op --- do ~ and !~ */
00908 
00909 static void
00910 pp_match_op(register NODE *tree)
00911 {
00912         register NODE *re;
00913         const char *op;
00914         const char *restr;
00915         size_t relen;
00916         NODE *text = NULL;
00917 
00918         if (tree->type == Node_dynregex) {
00919                 tree_eval(tree->re_exp);
00920                 return;
00921         }
00922 
00923         if (tree->type == Node_regex) {
00924                 re = tree->re_exp;
00925                 restr = re->stptr;
00926                 relen = re->stlen;
00927                 pp_string(restr, relen, '/');
00928                 return;
00929         }
00930 
00931         /* at this point, have either ~ or !~ */
00932 
00933         text = tree->lnode;
00934         re = tree->rnode;
00935 
00936         if (tree->type == Node_nomatch)
00937                 op = "!~";
00938         else if (tree->type == Node_match)
00939                 op = "~";
00940         else
00941                 op = "";
00942 
00943         tree_eval(text);
00944         fprintf(prof_fp, " %s ", op);
00945         tree_eval(re);
00946 }
00947 
00948 /* pp_redir --- print a redirection */
00949 
00950 static void
00951 pp_redir(register NODE *tree, enum redir_placement dir)
00952 {
00953         const char *op = "[BOGUS]";     /* should never be seen */
00954 
00955         if (tree == NULL)
00956                 return;
00957 
00958         switch (tree->type) {
00959         case Node_redirect_output:
00960                 op = ">";
00961                 break;
00962         case Node_redirect_append:
00963                 op = ">>";
00964                 break;
00965         case Node_redirect_pipe:
00966                 op = "|";
00967                 break;
00968         case Node_redirect_pipein:
00969                 op = "|";
00970                 break;
00971         case Node_redirect_input:
00972                 op = "<";
00973                 break;
00974         case Node_redirect_twoway:
00975                 op = "|&";
00976                 break;
00977         default:
00978                 cant_happen();
00979         }
00980         
00981         if (dir == BEFORE) {
00982                 if (! is_scalar(tree->subnode->type)) {
00983                         fprintf(prof_fp, "(");
00984                         tree_eval(tree->subnode);
00985                         fprintf(prof_fp, ")");
00986                 } else
00987                         tree_eval(tree->subnode);
00988                 fprintf(prof_fp, " %s ", op);
00989         } else {
00990                 fprintf(prof_fp, " %s ", op);
00991                 if (! is_scalar(tree->subnode->type)) {
00992                         fprintf(prof_fp, "(");
00993                         tree_eval(tree->subnode);
00994                         fprintf(prof_fp, ")");
00995                 } else
00996                         tree_eval(tree->subnode);
00997         }
00998 }
00999 
01000 /* pp_list --- dump a list of arguments, without parens */
01001 
01002 static void
01003 pp_list(register NODE *tree)
01004 {
01005         for (; tree != NULL; tree = tree->rnode) {
01006                 if (tree->type != Node_expression_list) {
01007                         fprintf(stderr, "pp_list: got %s\n",
01008                                         nodetype2str(tree->type));
01009                         fflush(stderr);
01010                 }
01011                 assert(tree->type == Node_expression_list);
01012                 tree_eval(tree->lnode);
01013                 if (tree->rnode != NULL)
01014                         fprintf(prof_fp, ", ");
01015         }
01016 }
01017 
01018 /* pp_print_stmt --- print a "print" or "printf" statement */
01019 
01020 static void
01021 pp_print_stmt(const char *command, register NODE *tree)
01022 {
01023         NODE *redir = tree->rnode;
01024 
01025         indent(tree->exec_count);
01026         fprintf(prof_fp, "%s", command);
01027         if (redir != NULL) {
01028                 if (tree->lnode != NULL) {
01029                         /* parenthesize if have a redirection and a list */
01030                         fprintf(prof_fp, "(");
01031                         pp_list(tree->lnode);
01032                         fprintf(prof_fp, ")");
01033                 } else
01034                         fprintf(prof_fp, " $0");
01035                 pp_redir(redir, AFTER);
01036         } else {
01037                 fprintf(prof_fp, " ");
01038                 if (tree->lnode != NULL)
01039                         pp_list(tree->lnode);
01040                 else
01041                         fprintf(prof_fp, "$0");
01042         }
01043         fprintf(prof_fp, "\n");
01044 }
01045 
01046 /* pp_delete --- print a "delete" statement */
01047 
01048 static void
01049 pp_delete(register NODE *tree)
01050 {
01051         NODE *array, *subscript;
01052 
01053         array = tree->lnode;
01054         subscript = tree->rnode;
01055         indent(array->exec_count);
01056         if (array->type == Node_param_list)
01057                 fprintf(prof_fp, "delete %s", fparms[array->param_cnt]);
01058         else
01059                 fprintf(prof_fp, "delete %s", array->vname);
01060         if (subscript != NULL) {
01061                 fprintf(prof_fp, "[");
01062                 pp_list(subscript);
01063                 fprintf(prof_fp, "]");
01064         }
01065         fprintf(prof_fp, "\n");
01066 }
01067 
01068 /* pp_in_array --- pretty print "foo in array" test */
01069 
01070 static void
01071 pp_in_array(NODE *array, NODE *subscript)
01072 {
01073         if (subscript->type == Node_expression_list) {
01074                 fprintf(prof_fp, "(");
01075                 pp_list(subscript);
01076                 fprintf(prof_fp, ")");
01077         } else
01078                 pprint(subscript);
01079 
01080         if (array->type == Node_param_list)
01081                 fprintf(prof_fp, " in %s", fparms[array->param_cnt]);
01082         else
01083                 fprintf(prof_fp, " in %s", array->vname);
01084 }
01085 
01086 /* pp_getline --- print a getline statement */
01087 
01088 static void
01089 pp_getline(register NODE *tree)
01090 {
01091         NODE *redir = tree->rnode;
01092         int before, after;
01093 
01094         /*
01095          * command | getline
01096          *     or
01097          * command |& getline
01098          *     or
01099          * getline < file
01100          */
01101         if (redir != NULL) {
01102                 before = (redir->type == Node_redirect_pipein
01103                                 || redir->type == Node_redirect_twoway);
01104                 after = ! before;
01105         } else
01106                 before = after = FALSE;
01107 
01108         if (before)
01109                 pp_redir(redir, BEFORE);
01110 
01111         fprintf(prof_fp, "getline");
01112         if (tree->lnode != NULL) {      /* optional var */
01113                 fprintf(prof_fp, " ");
01114                 pp_lhs(tree->lnode);
01115         }
01116 
01117         if (after)
01118                 pp_redir(redir, AFTER);
01119 }
01120 
01121 /* pp_builtin --- print a builtin function */
01122 
01123 static void
01124 pp_builtin(register NODE *tree)
01125 {
01126         const char *func = getfname(tree->builtin);
01127 
01128         fprintf(prof_fp, "%s(", func ? func : "extension_function");
01129         if (func)
01130                 pp_list(tree->subnode);
01131         fprintf(prof_fp, ")");
01132 }
01133 
01134 /* pp_func_call --- print a function call */
01135 
01136 static void
01137 pp_func_call(NODE *tree)
01138 {
01139         NODE *name, *arglist;
01140 
01141         name = tree->rnode;
01142         arglist = tree->lnode;
01143         fprintf(prof_fp, "%s(", name->stptr);
01144         pp_list(arglist);
01145         fprintf(prof_fp, ")");
01146 }
01147 
01148 /* dump_prog --- dump the program */
01149 
01150 /*
01151  * XXX: I am not sure it is right to have the strings in the dump
01152  * be translated, but I'll leave it alone for now.
01153  */
01154 
01155 void
01156 dump_prog(NODE *begin, NODE *prog, NODE *end)
01157 {
01158         time_t now;
01159 
01160         (void) time(& now);
01161         /* \n on purpose, with \n in ctime() output */
01162         fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
01163 
01164         if (begin != NULL) {
01165                 fprintf(prof_fp, _("\t# BEGIN block(s)\n\n"));
01166                 fprintf(prof_fp, "\tBEGIN {\n");
01167                 in_BEGIN_or_END = TRUE;
01168                 pprint(begin);
01169                 in_BEGIN_or_END = FALSE;
01170                 fprintf(prof_fp, "\t}\n");
01171                 if (prog != NULL || end != NULL)
01172                         fprintf(prof_fp, "\n");
01173         }
01174         if (prog != NULL) {
01175                 fprintf(prof_fp, _("\t# Rule(s)\n\n"));
01176                 pprint(prog);
01177                 if (end != NULL)
01178                         fprintf(prof_fp, "\n");
01179         }
01180         if (end != NULL) {
01181                 fprintf(prof_fp, _("\t# END block(s)\n\n"));
01182                 fprintf(prof_fp, "\tEND {\n");
01183                 in_BEGIN_or_END = TRUE;
01184                 pprint(end);
01185                 in_BEGIN_or_END = FALSE;
01186                 fprintf(prof_fp, "\t}\n");
01187         }
01188 }
01189 
01190 /* pp_func --- pretty print a function */
01191 
01192 void
01193 pp_func(const char *name, size_t namelen, NODE *f)
01194 {
01195         int j;
01196         char **pnames;
01197         static int first = TRUE;
01198 
01199         if (first) {
01200                 first = FALSE;
01201                 fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
01202         }
01203 
01204         fprintf(prof_fp, "\n");
01205         indent(f->exec_count);
01206         fprintf(prof_fp, "function %.*s(", (int) namelen, name);
01207         pnames = f->parmlist;
01208         fparms = pnames;
01209         for (j = 0; j < f->lnode->param_cnt; j++) {
01210                 fprintf(prof_fp, "%s", pnames[j]);
01211                 if (j < f->lnode->param_cnt - 1)
01212                         fprintf(prof_fp, ", ");
01213         }
01214         fprintf(prof_fp, ")\n\t{\n");
01215         indent_in();
01216         pprint(f->rnode);       /* body */
01217         indent_out();
01218         fprintf(prof_fp, "\t}\n");
01219 }
01220 
01221 /* pp_string --- pretty print a string or regex constant */
01222 
01223 static void
01224 pp_string(const char *str, size_t len, int delim)
01225 {
01226         pp_string_fp(prof_fp, str, len, delim, FALSE);
01227 }
01228 
01229 /* pp_string_fp --- printy print a string to the fp */
01230 
01231 /*
01232  * This routine concentrates string pretty printing in one place,
01233  * so that it can be called from multiple places within gawk.
01234  */
01235 
01236 void
01237 pp_string_fp(FILE *fp, const char *in_str, size_t len, int delim, int breaklines)
01238 {
01239         static char escapes[] = "\b\f\n\r\t\v\\";
01240         static char printables[] = "bfnrtv\\";
01241         char *cp;
01242         int i;
01243         int count;
01244 #define BREAKPOINT      70 /* arbitrary */
01245         const unsigned char *str = (const unsigned char *) in_str;
01246 
01247         fprintf(fp, "%c", delim);
01248         for (count = 0; len > 0; len--, str++) {
01249                 if (++count >= BREAKPOINT && breaklines) {
01250                         fprintf(fp, "%c\n%c", delim, delim);
01251                         count = 0;
01252                 }
01253                 if (*str == delim) {
01254                         fprintf(fp, "\\%c", delim);
01255                         count++;
01256                 } else if (*str == BELL) {
01257                         fprintf(fp, "\\a");
01258                         count++;
01259                 } else if ((cp = strchr(escapes, *str)) != NULL) {
01260                         i = cp - escapes;
01261                         putc('\\', fp);
01262                         count++;
01263                         putc(printables[i], fp);
01264                         if (breaklines && *str == '\n' && delim == '"') {
01265                                 fprintf(fp, "\"\n\"");
01266                                 count = 0;
01267                         }
01268                 /* NB: Deliberate use of lower-case versions. */
01269                 } else if (isascii(*str) && isprint(*str)) {
01270                         putc(*str, fp);
01271                 } else {
01272                         char buf[10];
01273 
01274                         /* print 'em as they came if for whiny users */
01275                         if (whiny_users)
01276                                 sprintf(buf, "%c", *str & 0xff);
01277                         else
01278                                 sprintf(buf, "\\%03o", *str & 0xff);
01279                         count += strlen(buf) - 1;
01280                         fprintf(fp, "%s", buf);
01281                 }
01282         }
01283         fprintf(fp, "%c", delim);
01284 }
01285 
01286 /* is_scalar --- true or false if we'll get a scalar value */
01287 
01288 static int
01289 is_scalar(NODETYPE type)
01290 {
01291         switch (type) {
01292         case Node_var_new:
01293         case Node_var:
01294         case Node_var_array:
01295         case Node_val:
01296         case Node_BINMODE:
01297         case Node_CONVFMT:
01298