aboutsummaryrefslogtreecommitdiffstats
path: root/profile.c
diff options
context:
space:
mode:
Diffstat (limited to 'profile.c')
-rw-r--r--profile.c2428
1 files changed, 1107 insertions, 1321 deletions
diff --git a/profile.c b/profile.c
index 26df9de9..f307786d 100644
--- a/profile.c
+++ b/profile.c
@@ -1,5 +1,5 @@
/*
- * profile.c - gawk parse tree pretty-printer with counts
+ * profile.c - gawk bytecode pretty-printer with counts
*/
/*
@@ -25,47 +25,37 @@
#include "awk.h"
-/* where to place redirections for getline, print, printf */
-enum redir_placement {
- BEFORE = 0,
- AFTER = 1
-};
-
-#undef tree_eval
-static void tree_eval P((NODE *tree));
-static void parenthesize P((NODETYPE parent_type, NODE *tree));
-static void parenthesize_expr P((NODETYPE parent_type, NODE *tree));
-static void eval_condition P((NODE *tree));
-static void pp_op_assign P((NODE *tree));
-static void pp_func_call P((NODE *tree));
-static void pp_match_op P((NODE *tree));
-static void pp_lhs P((NODE *ptr));
-static void pp_print_stmt P((const char *command, NODE *tree));
-static void pp_delete P((NODE *tree));
-static void pp_in_array P((NODE *array, NODE *subscript));
-static void pp_getline P((NODE *tree));
-static void pp_builtin P((NODE *tree));
-static void pp_list P((NODE *tree));
-static void pp_string P((const char *str, size_t len, int delim));
-static void pp_concat P((NODE *tree, int level));
-static void pp_var P((NODE *tree));
-static int is_scalar P((NODETYPE type));
-static int prec_level P((NODETYPE type));
+static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header);
+static void pp_parenthesize(NODE *n);
+static void parenthesize(int type, NODE *left, NODE *right);
+static char *pp_list(int nargs, const char *paren, const char *delim);
+static char *pp_concat(const char *s1, const char *s2, const char *s3);
+static int is_binary(int type);
+static int prec_level(int type);
+static void pp_push(int type, char *s, int flag);
+static NODE *pp_pop(void);
+static void pp_free(NODE *n);
+const char *redir2str(int redirtype);
+
+#define pp_str hname
+#define pp_len hlength
+
+#define DONT_FREE 1
+#define CAN_FREE 2
+
#ifdef PROFILING
-static RETSIGTYPE dump_and_exit P((int signum)) ATTRIBUTE_NORETURN;
-static RETSIGTYPE just_dump P((int signum));
+static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN;
+static RETSIGTYPE just_dump(int signum);
#endif
/* pretty printing related functions and variables */
+static NODE *pp_stack = NULL;
static char **fparms; /* function parameter names */
static FILE *prof_fp; /* where to send the profile */
static long indent_level = 0;
-static int in_BEGIN_or_END = FALSE;
-
-static int in_expr = FALSE;
#define SPACEOVER 0
@@ -88,7 +78,6 @@ void
set_prof_file(const char *file)
{
assert(file != NULL);
-
prof_fp = fopen(file, "w");
if (prof_fp == NULL) {
warning(_("could not open `%s' for writing: %s"),
@@ -126,13 +115,13 @@ indent(long count)
int i;
if (count == 0)
- putc('\t', prof_fp);
+ fprintf(prof_fp, "\t");
else
fprintf(prof_fp, "%6ld ", count);
assert(indent_level >= 0);
for (i = 0; i < indent_level; i++)
- putc('\t', prof_fp);
+ fprintf(prof_fp, "\t");
}
/* indent_in --- increase the level, with error checking */
@@ -153,944 +142,791 @@ indent_out(void)
assert(indent_level >= 0);
}
+static void
+pp_push(int type, char *s, int flag)
+{
+ NODE *n;
+ getnode(n);
+ n->pp_str = s;
+ n->pp_len = strlen(s);
+ n->flags = flag;
+ n->type = type;
+ n->hnext = pp_stack;
+ pp_stack = n;
+}
+
+static NODE *
+pp_pop()
+{
+ NODE *n;
+ n = pp_stack;
+ pp_stack = n->hnext;
+ return n;
+}
+
+static void
+pp_free(NODE *n)
+{
+ if ((n->flags & CAN_FREE) != 0)
+ efree(n->pp_str);
+ freenode(n);
+}
+
/*
- * pprint:
- * Tree is a bunch of rules to run. Returns zero if it hit an exit()
- * statement
+ * pprint --- pretty print a program segment
*/
+
static void
-pprint(register NODE *volatile tree)
+pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
{
- register NODE *volatile t = NULL; /* temporary */
- int volatile traverse = TRUE; /* True => loop thru tree (Node_rule_list) */
-
- /* avoid false source indications */
- source = NULL;
- sourceline = 0;
-
- if (tree == NULL)
- return;
- sourceline = tree->source_line;
- source = tree->source_file;
- switch (tree->type) {
- case Node_rule_node:
- traverse = FALSE; /* False => one for-loop iteration only */
- /* FALL THROUGH */
- case Node_rule_list:
- for (t = tree; t != NULL; t = t->rnode) {
- if (traverse)
- tree = t->lnode;
- sourceline = tree->source_line;
- source = tree->source_file;
-
- if (! in_BEGIN_or_END)
- indent(tree->exec_count);
-
- if (tree->lnode) {
- eval_condition(tree->lnode);
- if (tree->rnode)
- fprintf(prof_fp, "\t");
- }
-
- if (tree->rnode) {
- if (! in_BEGIN_or_END) {
- fprintf(prof_fp, "{");
+ INSTRUCTION *pc;
+ NODE *t1;
+ char *str;
+ NODE *t2;
+ INSTRUCTION *ip;
+ NODE *m;
+ char *tmp;
+ int rule;
+ static int rule_count[MAXRULE];
+
+ for (pc = startp; pc != endp; pc = pc->nexti) {
+ if (pc->source_line > 0)
+ sourceline = pc->source_line;
+
+ switch (pc->opcode) {
+ case Op_rule:
+ source = pc->source_file;
+ rule = pc->in_rule;
+
+ if (rule != Rule) {
+ if (! rule_count[rule]++)
+ fprintf(prof_fp, _("\t# %s block(s)\n\n"), ruletab[rule]);
+ fprintf(prof_fp, "\t%s {\n", ruletab[rule]);
+ ip = (pc + 1)->firsti;
+ } else {
+ if (! rule_count[rule]++)
+ fprintf(prof_fp, _("\t# %s(s)\n\n"), ruletab[rule]);
+ ip = pc->nexti;
+ indent(ip->exec_count);
+ if (ip != (pc + 1)->firsti) { /* non-empty pattern */
+ pprint(ip->nexti, (pc + 1)->firsti, FALSE);
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s {", t1->pp_str);
+ pp_free(t1);
+ ip = (pc + 1)->firsti;
#ifdef PROFILING
- if (tree->lnode != NULL
- && tree->lnode->exec_count)
- fprintf(prof_fp, " # %ld",
- tree->lnode->exec_count);
+ if (ip->exec_count > 0)
+ fprintf(prof_fp, " # %ld", ip->exec_count);
#endif
fprintf(prof_fp, "\n");
+ } else {
+ fprintf(prof_fp, "{\n");
+ ip = (pc + 1)->firsti;
}
- indent_in();
- pprint(tree->rnode);
- indent_out();
- if (! in_BEGIN_or_END) {
- indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
+ ip = ip->nexti;
+ }
+ indent_in();
+ pprint(ip, (pc + 1)->lasti, FALSE);
+ indent_out();
+ fprintf(prof_fp, "\t}\n\n");
+ pc = (pc + 1)->lasti;
+ break;
+
+ case Op_atexit:
+ break;
+
+ case Op_stop:
+ memset(rule_count, 0, MAXRULE * sizeof(int));
+ break;
+
+ case Op_push_i:
+ m = pc->memory;
+ if (m == Nnull_string) /* optional return or exit value; don't print 0 or "" */
+ pp_push(pc->opcode, m->stptr, DONT_FREE);
+ else if ((m->flags & NUMBER) != 0)
+ pp_push(pc->opcode, pp_number(m->numbr), CAN_FREE);
+ else {
+ str = pp_string(m->stptr, m->stlen, '"');
+ if ((m->flags & INTLSTR) != 0) {
+ char *tmp = str;
+ str = pp_concat("_", tmp, "");
+ efree(tmp);
}
+ pp_push(pc->opcode, str, CAN_FREE);
+ }
+ break;
+
+ case Op_store_var:
+ case Op_store_sub:
+ case Op_assign_concat:
+ case Op_push_lhs:
+ case Op_push_param:
+ case Op_push_array:
+ case Op_push:
+ m = pc->memory;
+ switch (m->type) {
+ case Node_param_list:
+ pp_push(pc->opcode, fparms[m->param_cnt], DONT_FREE);
+ break;
+
+ case Node_var:
+ case Node_var_new:
+ case Node_var_array:
+ if (m->vname != NULL)
+ pp_push(pc->opcode, m->vname, DONT_FREE);
+ else
+ fatal(_("internal error: %s with null vname"),
+ nodetype2str(m->type));
+ break;
+
+ default:
+ cant_happen();
}
- if (! traverse) /* case Node_rule_node */
- break; /* don't loop */
-
- if (t->rnode && ! in_BEGIN_or_END)
- fprintf(prof_fp, "\n");
- }
- break;
+ switch (pc->opcode) {
+ case Op_store_var:
+ t2 = pp_pop(); /* l.h.s. */
+ t1 = pp_pop(); /* r.h.s. */
+ fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(pc->opcode), t1->pp_str);
+ goto cleanup;
+
+ case Op_store_sub:
+ t1 = pp_pop(); /* array */
+ tmp = pp_list(pc->expr_count, op2str(Op_subscript), ", "); /*subscript*/
+ t2 = pp_pop(); /* r.h.s. */
+ fprintf(prof_fp, "%s%s%s%s", t1->pp_str, tmp,
+ op2str(pc->opcode), t2->pp_str);
+ efree(tmp);
+ goto cleanup;
+
+ case Op_assign_concat:
+ t2 = pp_pop(); /* l.h.s. */
+ t1 = pp_pop();
+ tmp = pp_concat(t2->pp_str, op2str(Op_concat), t1->pp_str);
+ fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(Op_assign), tmp);
+ efree(tmp);
+cleanup:
+ pp_free(t2);
+ pp_free(t1);
+ if (! in_for_header)
+ fprintf(prof_fp, "\n");
+ break;
- case Node_statement_list:
- for (t = tree; t != NULL; t = t->rnode) {
- pprint(t->lnode);
- }
- break;
-
- case Node_K_if:
- indent(tree->exec_count);
- fprintf(prof_fp, "if (");
- in_expr++;
- eval_condition(tree->lnode);
- in_expr--;
- fprintf(prof_fp, ") {");
-#ifdef PROFILING
- if (tree->rnode->exec_count)
- fprintf(prof_fp, " # %ld", tree->rnode->exec_count);
-#endif
- fprintf(prof_fp, "\n");
- indent_in();
- pprint(tree->rnode->lnode);
- indent_out();
- if (tree->rnode->rnode != NULL) {
- if (tree->exec_count - tree->rnode->exec_count > 0)
- indent(tree->exec_count - tree->rnode->exec_count);
+ default:
+ break;
+ }
+ break;
+
+ case Op_sub_array:
+ case Op_subscript_lhs:
+ case Op_subscript:
+ tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
+ t1 = pp_pop();
+ str = pp_concat(t1->pp_str, tmp, "");
+ efree(tmp);
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_and:
+ case Op_or:
+ pprint(pc->nexti, pc->target_jmp, in_for_header);
+ t2 = pp_pop();
+ t1 = pp_pop();
+ parenthesize(pc->opcode, t1, t2);
+ str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
+ pp_free(t1);
+ pp_free(t2);
+ pp_push(pc->opcode, str, CAN_FREE);
+ pc = pc->target_jmp;
+ break;
+
+ case Op_plus_i:
+ case Op_minus_i:
+ case Op_times_i:
+ case Op_exp_i:
+ case Op_quotient_i:
+ case Op_mod_i:
+ m = pc->memory;
+ t1 = pp_pop();
+ if (prec_level(pc->opcode) > prec_level(t1->type)
+ && is_binary(t1->type)) /* (a - b) * 1 */
+ pp_parenthesize(t1);
+ if ((m->flags & NUMBER) != 0)
+ tmp = pp_number(m->numbr);
else
- indent(0);
- fprintf(prof_fp, "} else {\n");
- indent_in();
- pprint(tree->rnode->rnode);
- indent_out();
+ tmp = pp_string(m->stptr, m->stlen, '"');
+ str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp);
+ efree(tmp);
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_plus:
+ case Op_minus:
+ case Op_times:
+ case Op_exp:
+ case Op_quotient:
+ case Op_mod:
+ case Op_equal:
+ case Op_notequal:
+ case Op_less:
+ case Op_greater:
+ case Op_leq:
+ case Op_geq:
+ t2 = pp_pop();
+ t1 = pp_pop();
+ parenthesize(pc->opcode, t1, t2);
+ str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
+ pp_free(t1);
+ pp_free(t2);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_preincrement:
+ case Op_predecrement:
+ case Op_postincrement:
+ case Op_postdecrement:
+ t1 = pp_pop();
+ if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
+ str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
+ else
+ str = pp_concat(t1->pp_str, op2str(pc->opcode), "");
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_field_spec:
+ case Op_field_spec_lhs:
+ case Op_unary_minus:
+ case Op_not:
+ t1 = pp_pop();
+ if (is_binary(t1->type))
+ pp_parenthesize(t1);
+
+ /* optypes table (eval.c) includes space after ! */
+ str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_assign:
+ case Op_assign_plus:
+ case Op_assign_minus:
+ case Op_assign_times:
+ case Op_assign_quotient:
+ case Op_assign_mod:
+ case Op_assign_exp:
+ t2 = pp_pop(); /* l.h.s. */
+ t1 = pp_pop();
+ str = pp_concat(t2->pp_str, op2str(pc->opcode), t1->pp_str);
+ pp_free(t2);
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_store_field:
+ t1 = pp_pop(); /* field num */
+ if (is_binary(t1->type))
+ pp_parenthesize(t1);
+ t2 = pp_pop(); /* r.h.s. */
+ fprintf(prof_fp, "$%s%s%s", t1->pp_str, op2str(pc->opcode), t2->pp_str);
+ pp_free(t2);
+ pp_free(t1);
+ if (! in_for_header)
+ fprintf(prof_fp, "\n");
+ break;
+
+ case Op_concat:
+ str = pp_list(pc->expr_count, NULL,
+ (pc->concat_flag & CSUBSEP) ? ", " : op2str(Op_concat));
+ pp_push(Op_concat, str, CAN_FREE);
+ break;
+
+ case Op_K_delete:
+ {
+ char *array;
+ t1 = pp_pop();
+ array = t1->pp_str;
+ if (pc->expr_count > 0) {
+ char *sub;
+ sub = pp_list(pc->expr_count, NULL, ", ");
+ fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
+ efree(sub);
+ } else
+ fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
+ if (! in_for_header)
+ fprintf(prof_fp, "\n");
+ pp_free(t1);
}
- indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
- break;
-
- case Node_K_switch:
- indent(tree->exec_count);
- fprintf(prof_fp, "switch (");
- in_expr++;
- pprint(tree->lnode);
- in_expr--;
- fprintf(prof_fp, ") {\n");
- pprint(tree->rnode);
- indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
- break;
-
- case Node_switch_body:
- pprint(tree->lnode);
- break;
-
- case Node_case_list:
- pprint(tree->lnode);
- pprint(tree->rnode);
- break;
-
- case Node_K_case:
- indent(tree->exec_count);
- fprintf(prof_fp, "case ");
- in_expr++;
- pprint(tree->lnode);
- in_expr--;
- fprintf(prof_fp, ":\n");
- indent_in();
- pprint(tree->rnode);
- indent_out();
- break;
-
- case Node_K_default:
- indent(tree->exec_count);
- fprintf(prof_fp, "default:\n");
- indent_in();
- pprint(tree->rnode);
- indent_out();
- break;
-
- case Node_K_while:
- indent(tree->exec_count);
- fprintf(prof_fp, "while (");
- in_expr++;
- eval_condition(tree->lnode);
- in_expr--;
- fprintf(prof_fp, ") {\n");
- indent_in();
- pprint(tree->rnode);
- indent_out();
- indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
- break;
-
- case Node_K_do:
- indent(tree->exec_count);
- fprintf(prof_fp, "do {\n");
- indent_in();
- pprint(tree->rnode);
- indent_out();
- indent(SPACEOVER);
- fprintf(prof_fp, "} while (");
- in_expr++;
- eval_condition(tree->lnode);
- in_expr--;
- fprintf(prof_fp, ")\n");
- break;
-
- case Node_K_for:
- indent(tree->exec_count);
- fprintf(prof_fp, "for (");
- in_expr++;
- pprint(tree->forloop->init);
- fprintf(prof_fp, "; ");
- eval_condition(tree->forloop->cond);
- fprintf(prof_fp, "; ");
- pprint(tree->forloop->incr);
- fprintf(prof_fp, ") {\n");
- in_expr--;
- indent_in();
- pprint(tree->lnode);
- indent_out();
- indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
- break;
-
- case Node_K_arrayfor:
-#define hakvar forloop->init
-#define arrvar forloop->incr
- indent(tree->exec_count);
- fprintf(prof_fp, "for (");
- in_expr++;
- pp_lhs(tree->hakvar);
- in_expr--;
- fprintf(prof_fp, " in ");
- t = tree->arrvar;
- if (t->type == Node_param_list)
- fprintf(prof_fp, "%s", fparms[t->param_cnt]);
- else
- fprintf(prof_fp, "%s", t->vname);
- fprintf(prof_fp, ") {\n");
- indent_in();
- pprint(tree->lnode);
- indent_out();
- indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
- break;
-#undef hakvar
-#undef arrvar
-
- case Node_K_break:
- indent(tree->exec_count);
- fprintf(prof_fp, "break\n");
- break;
-
- case Node_K_continue:
- indent(tree->exec_count);
- fprintf(prof_fp, "continue\n");
- break;
-
- case Node_K_print:
- case Node_K_print_rec:
- pp_print_stmt("print", tree);
- break;
-
- case Node_K_printf:
- pp_print_stmt("printf", tree);
- break;
-
- case Node_K_delete:
- pp_delete(tree);
- break;
-
- case Node_K_next:
- indent(tree->exec_count);
- fprintf(prof_fp, "next\n");
- break;
-
- case Node_K_nextfile:
- indent(tree->exec_count);
- fprintf(prof_fp, "nextfile\n");
- break;
-
- case Node_K_exit:
- indent(tree->exec_count);
- fprintf(prof_fp, "exit");
- if (tree->lnode != NULL) {
- fprintf(prof_fp, " ");
- tree_eval(tree->lnode);
+ break;
+
+ case Op_K_delete_loop:
+ /* Efficency hack not in effect because of exec_count instruction */
+ cant_happen();
+ break;
+
+ case Op_in_array:
+ {
+ char *array, *sub;
+ t1 = pp_pop();
+ array = t1->pp_str;
+ if (pc->expr_count > 1) {
+ sub = pp_list(pc->expr_count, "()", ", ");
+ str = pp_concat(sub, op2str(Op_in_array), array);
+ efree(sub);
+ } else {
+ t2 = pp_pop();
+ sub = t2->pp_str;
+ str = pp_concat(sub, op2str(Op_in_array), array);
+ pp_free(t2);
+ }
+ pp_free(t1);
+ pp_push(Op_in_array, str, CAN_FREE);
}
- fprintf(prof_fp, "\n");
- break;
-
- case Node_K_return:
- indent(tree->exec_count);
- fprintf(prof_fp, "return");
- if (tree->lnode != NULL) {
- fprintf(prof_fp, " ");
- tree_eval(tree->lnode);
+ break;
+
+ case Op_var_update:
+ case Op_var_assign:
+ case Op_field_assign:
+ case Op_arrayfor_init:
+ case Op_arrayfor_incr:
+ case Op_arrayfor_final:
+ case Op_newfile:
+ case Op_get_record:
+ case Op_lint:
+ case Op_pop_loop:
+ case Op_jmp:
+ case Op_jmp_false:
+ case Op_jmp_true:
+ case Op_no_op:
+ case Op_and_final:
+ case Op_or_final:
+ case Op_cond_pair:
+ case Op_after_beginfile:
+ case Op_after_endfile:
+ break;
+
+ case Op_builtin:
+ {
+ static char *ext_func = "extension_function()";
+ const char *fname = getfname(pc->builtin);
+ if (fname != NULL) {
+ if (pc->expr_count > 0) {
+ tmp = pp_list(pc->expr_count, "()", ", ");
+ str = pp_concat(fname, tmp, "");
+ efree(tmp);
+ } else
+ str = pp_concat(fname, "()", "");
+ pp_push(Op_builtin, str, CAN_FREE);
+ } else
+ pp_push(Op_builtin, ext_func, DONT_FREE);
}
- fprintf(prof_fp, "\n");
- break;
-
- default:
- /*
- * Appears to be an expression statement.
- * Throw away the value.
- */
- if (in_expr)
- tree_eval(tree);
- else {
- indent(tree->exec_count);
- tree_eval(tree);
- fprintf(prof_fp, "\n");
+ break;
+
+ case Op_K_print:
+ case Op_K_printf:
+ case Op_K_print_rec:
+ if (pc->opcode == Op_K_print_rec)
+ tmp = pp_concat(" ", op2str(Op_field_spec), "0");
+ else if (pc->redir_type != 0)
+ tmp = pp_list(pc->expr_count, "()", ", ");
+ else {
+ tmp = pp_list(pc->expr_count, " ", ", ");
+ tmp[strlen(tmp) - 1] = '\0'; /* remove trailing space */
+ }
+
+ if (pc->redir_type != 0) {
+ t1 = pp_pop();
+ if (is_binary(t1->type))
+ pp_parenthesize(t1);
+ fprintf(prof_fp, "%s%s%s%s", op2str(pc->opcode),
+ tmp, redir2str(pc->redir_type), t1->pp_str);
+ pp_free(t1);
+ } else
+ fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
+ efree(tmp);
+ if (! in_for_header)
+ fprintf(prof_fp, "\n");
+ break;
+
+ case Op_push_re:
+ if (pc->memory->type != Node_regex)
+ break;
+ /* else
+ fall through */
+ case Op_match_rec:
+ {
+ NODE *re = pc->memory->re_exp;
+ str = pp_string(re->stptr, re->stlen, '/');
+ pp_push(pc->opcode, str, CAN_FREE);
}
- break;
- }
-}
-
-/* tree_eval --- evaluate a subtree */
-
-static void
-tree_eval(register NODE *tree)
-{
- if (tree == NULL)
- return;
-
- switch (tree->type) {
- case Node_param_list:
- fprintf(prof_fp, "%s", fparms[tree->param_cnt]);
- return;
-
- case Node_var_new:
- case Node_var:
- case Node_var_array:
- if (tree->vname != NULL)
- fprintf(prof_fp, "%s", tree->vname);
- else
- fatal(_("internal error: %s with null vname"),
- nodetype2str(tree->type));
- return;
-
- case Node_val:
- if ((tree->flags & NUMBER) != 0)
- fprintf(prof_fp, "%g", tree->numbr);
- else {
- if ((tree->flags & INTLSTR) != 0)
- fprintf(prof_fp, "_");
- pp_string(tree->stptr, tree->stlen, '"');
+ break;
+
+ case Op_nomatch:
+ case Op_match:
+ {
+ char *restr, *txt;
+ t1 = pp_pop();
+ if (is_binary(t1->type))
+ pp_parenthesize(t1);
+ txt = t1->pp_str;
+ m = pc->memory;
+ if (m->type == Node_dynregex) {
+ restr = txt;
+ t2 = pp_pop();
+ if (is_binary(t2->type))
+ pp_parenthesize(t2);
+ txt = t2->pp_str;
+ str = pp_concat(txt, op2str(pc->opcode), restr);
+ pp_free(t2);
+ } else {
+ NODE *re = m->re_exp;
+ restr = pp_string(re->stptr, re->stlen, '/');
+ str = pp_concat(txt, op2str(pc->opcode), restr);
+ efree(restr);
+ }
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
}
- return;
-
- case Node_and:
- parenthesize_expr(Node_and, tree->lnode);
- fprintf(prof_fp, " && ");
- parenthesize_expr(Node_and, tree->rnode);
- return;
-
- case Node_or:
- parenthesize_expr(Node_or, tree->lnode);
- fprintf(prof_fp, " || ");
- parenthesize_expr(Node_or, tree->rnode);
- return;
-
- case Node_not:
- fprintf(prof_fp, "! ");
- parenthesize(tree->type, tree->lnode);
- return;
-
- /* Builtins */
- case Node_builtin:
- pp_builtin(tree);
- return;
-
- case Node_in_array:
- in_expr++;
- pp_in_array(tree->lnode, tree->rnode);
- in_expr--;
- return;
-
- case Node_func_call:
- case Node_indirect_func_call:
- pp_func_call(tree);
- return;
-
- case Node_K_getline:
- pp_getline(tree);
- return;
-
- case Node_K_delete_loop:
- {
- char *aname;
- NODE *t;
-
- t = tree->lnode;
- if (t->type == Node_param_list)
- aname = fparms[t->param_cnt];
- else
- aname = t->vname;
-
- fprintf(prof_fp, "for (");
- pp_lhs(tree->rnode->lnode);
- fprintf(prof_fp, " in %s) { %s %s'\n", aname,
- _("# treated internally as `delete'"), aname);
- indent_in();
- indent(SPACEOVER);
- fprintf(prof_fp, "delete %s[", aname);
- pp_lhs(tree->rnode->lnode);
- fprintf(prof_fp, "]\n");
- indent_out();
- indent(SPACEOVER);
- fprintf(prof_fp, "}");
- }
- return;
-
- /* unary operations */
- case Node_CONVFMT:
- case Node_FIELDWIDTHS:
- case Node_FNR:
- case Node_FPAT:
- case Node_FS:
- case Node_IGNORECASE:
- case Node_LINT:
- case Node_NF:
- case Node_NR:
- case Node_OFMT:
- case Node_OFS:
- case Node_ORS:
- case Node_RS:
- case Node_TEXTDOMAIN:
- case Node_SUBSEP:
- pp_var(tree);
- return;
-
- case Node_field_spec:
- case Node_subscript:
- pp_lhs(tree);
- return;
-
- case Node_unary_minus:
- fprintf(prof_fp, " -");
- if (is_scalar(tree->subnode->type))
- tree_eval(tree->subnode);
- else {
- fprintf(prof_fp, "(");
- tree_eval(tree->subnode);
- fprintf(prof_fp, ")");
+ break;
+
+ case Op_K_getline:
+ case Op_K_getline_redir:
+ if (pc->into_var) {
+ t1 = pp_pop();
+ tmp = pp_concat(op2str(Op_K_getline), " ", t1->pp_str);
+ pp_free(t1);
+ } else
+ tmp = pp_concat(op2str(Op_K_getline), "", "");
+
+ if (pc->redir_type != 0) {
+ int before = (pc->redir_type == redirect_pipein
+ || pc->redir_type == redirect_twoway);
+
+ t2 = pp_pop();
+ if (is_binary(t2->type))
+ pp_parenthesize(t2);
+ if (before)
+ str = pp_concat(t2->pp_str, redir2str(pc->redir_type), tmp);
+ else
+ str = pp_concat(tmp, redir2str(pc->redir_type), t2->pp_str);
+ efree(tmp);
+ pp_free(t2);
+ } else
+ str = tmp;
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
+ case Op_indirect_func_call:
+ t1 = pp_pop(); /* indirect var */
+ pp_free(t1);
+ case Op_func_call:
+ {
+ char *fname = pc->func_name;
+ char *pre;
+ int pcount;
+
+ if (pc->opcode == Op_indirect_func_call)
+ pre = "@";
+ else
+ pre = "";
+ pcount = (pc + 1)->expr_count;
+ if (pcount > 0) {
+ tmp = pp_list(pcount, "()", ", ");
+ str = pp_concat(pre, fname, tmp);
+ efree(tmp);
+ } else
+ str = pp_concat(pre, fname, "()");
+ pp_push(pc->opcode, str, CAN_FREE);
}
- return;
-
- case Node_cond_exp:
- eval_condition(tree->lnode);
- fprintf(prof_fp, " ? ");
- tree_eval(tree->rnode->lnode);
- fprintf(prof_fp, " : ");
- tree_eval(tree->rnode->rnode);
- return;
-
- case Node_match:
- case Node_nomatch:
- case Node_regex:
- case Node_dynregex:
- pp_match_op(tree);
- return;
-
- /* assignments */
- case Node_assign:
- tree_eval(tree->lnode);
- fprintf(prof_fp, " = ");
- tree_eval(tree->rnode);
- return;
-
- case Node_assign_concat:
- tree_eval(tree->lnode);
- fprintf(prof_fp, " = ");
- tree_eval(tree->lnode);
- fprintf(prof_fp, " ");
- tree_eval(tree->rnode);
- return;
-
- case Node_concat:
- pp_concat(tree, 0);
- return;
-
- /* other assignment types are easier because they are numeric */
- case Node_preincrement:
- case Node_predecrement:
- case Node_postincrement:
- case Node_postdecrement:
- case Node_assign_exp:
- case Node_assign_times:
- case Node_assign_quotient:
- case Node_assign_mod:
- case Node_assign_plus:
- case Node_assign_minus:
- pp_op_assign(tree);
- return;
-
- default:
- break; /* handled below */
- }
-
- /* handle binary ops */
- in_expr++;
- parenthesize(tree->type, tree->lnode);
-
- switch (tree->type) {
- case Node_geq:
- fprintf(prof_fp, " >= ");
- break;
- case Node_leq:
- fprintf(prof_fp, " <= ");
- break;
- case Node_greater:
- fprintf(prof_fp, " > ");
- break;
- case Node_less:
- fprintf(prof_fp, " < ");
- break;
- case Node_notequal:
- fprintf(prof_fp, " != ");
- break;
- case Node_equal:
- fprintf(prof_fp, " == ");
- break;
- case Node_exp:
- fprintf(prof_fp, " ^ ");
- break;
- case Node_times:
- fprintf(prof_fp, " * ");
- break;
- case Node_quotient:
- fprintf(prof_fp, " / ");
- break;
- case Node_mod:
- fprintf(prof_fp, " %% ");
- break;
- case Node_plus:
- fprintf(prof_fp, " + ");
- break;
- case Node_minus:
- fprintf(prof_fp, " - ");
- break;
- default:
- fatal(_("illegal type (%s) in tree_eval"), nodetype2str(tree->type));
- }
- parenthesize(tree->type, tree->rnode);
- in_expr--;
-
- return;
-}
-
-/* eval_condition --- is TREE true or false */
-
-static void
-eval_condition(register NODE *tree)
-{
- if (tree == NULL) /* Null trees are the easiest kinds */
- return;
-
- if (tree->type == Node_line_range) {
- /* /.../, /.../ */
- eval_condition(tree->condpair->lnode);
- fprintf(prof_fp,", ");
- eval_condition(tree->condpair->rnode);
- return;
- }
-
- /*
- * Could just be J.random expression. in which case, null and 0 are
- * false, anything else is true
- */
-
- tree_eval(tree);
- return;
-}
-
-/* pp_op_assign --- do +=, -=, etc. */
-
-static void
-pp_op_assign(register NODE *tree)
-{
- const char *op = NULL;
- enum Order {
- NA = 0,
- PRE = 1,
- POST = 2
- } order = NA;
-
- switch(tree->type) {
- case Node_preincrement:
- op = "++";
- order = PRE;
- break;
-
- case Node_predecrement:
- op = "--";
- order = PRE;
- break;
-
- case Node_postincrement:
- op = "++";
- order = POST;
- break;
-
- case Node_postdecrement:
- op = "--";
- order = POST;
- break;
-
- default:
- break; /* handled below */
- }
-
- if (order == PRE) {
- fprintf(prof_fp, "%s", op);
- pp_lhs(tree->lnode);
- return;
- } else if (order == POST) {
- pp_lhs(tree->lnode);
- fprintf(prof_fp, "%s", op);
- return;
- }
-
- /* a binary op */
- pp_lhs(tree->lnode);
-
- switch(tree->type) {
- case Node_assign_exp:
- fprintf(prof_fp, " ^= ");
- break;
-
- case Node_assign_times:
- fprintf(prof_fp, " *= ");
- break;
-
- case Node_assign_quotient:
- fprintf(prof_fp, " /= ");
- break;
+ break;
+
+ case Op_K_continue:
+ case Op_K_break:
+ case Op_K_nextfile:
+ case Op_K_next:
+ fprintf(prof_fp, "%s\n", op2str(pc->opcode));
+ break;
+
+ case Op_K_return:
+ case Op_K_exit:
+ t1 = pp_pop();
+ if (is_binary(t1->type))
+ pp_parenthesize(t1);
+ if (pc->source_line > 0) /* don't print implicit 'return' at end of function */
+ fprintf(prof_fp, "%s %s\n", op2str(pc->opcode), t1->pp_str);
+ pp_free(t1);
+ break;
+
+ case Op_pop:
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s", t1->pp_str);
+ if (! in_for_header)
+ fprintf(prof_fp, "\n");
+ pp_free(t1);
+ break;
+
+ case Op_line_range:
+ ip = pc + 1;
+ pprint(pc->nexti, ip->condpair_left, FALSE);
+ pprint(ip->condpair_left->nexti, ip->condpair_right, FALSE);
+ t2 = pp_pop();
+ t1 = pp_pop();
+ str = pp_concat(t1->pp_str, ", ", t2->pp_str);
+ pp_free(t1);
+ pp_free(t2);
+ pp_push(Op_line_range, str, CAN_FREE);
+ pc = ip->condpair_right;
+ break;
+
+ case Op_push_loop:
+ ip = pc + 1;
+ switch (ip->opcode) {
+ case Op_K_while:
+ indent(ip->while_body->exec_count);
+ fprintf(prof_fp, "%s (", op2str(ip->opcode));
+ pprint(pc->nexti, ip->while_body, FALSE);
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s) {\n", t1->pp_str);
+ pp_free(t1);
+ indent_in();
+ pprint(ip->while_body->nexti, pc->target_break, FALSE);
+ indent_out();
+ indent(SPACEOVER);
+ fprintf(prof_fp, "}\n");
+ break;
- case Node_assign_mod:
- fprintf(prof_fp, " %%= ");
- break;
+ case Op_K_do:
+ indent(pc->nexti->exec_count);
+ fprintf(prof_fp, "%s {\n", op2str(ip->opcode));
+ indent_in();
+ pprint(pc->nexti->nexti, ip->doloop_cond, FALSE);
+ indent_out();
+ pprint(ip->doloop_cond, pc->target_break, FALSE);
+ indent(SPACEOVER);
+ t1 = pp_pop();
+ fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str);
+ pp_free(t1);
+ break;
+
+ case Op_K_for:
+ indent(ip->forloop_body->exec_count);
+ fprintf(prof_fp, "%s (", op2str(ip->opcode));
+ pprint(pc->nexti, ip->forloop_cond, TRUE);
+ fprintf(prof_fp, "; ");
+
+ if (ip->forloop_cond->opcode == Op_no_op &&
+ ip->forloop_cond->nexti == ip->forloop_body)
+ fprintf(prof_fp, "; ");
+ else {
+ pprint(ip->forloop_cond, ip->forloop_body, TRUE);
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s; ", t1->pp_str);
+ pp_free(t1);
+ }
- case Node_assign_plus:
- fprintf(prof_fp, " += ");
- break;
+ pprint(pc->target_continue, pc->target_break, TRUE);
+ fprintf(prof_fp, ") {\n");
+ indent_in();
+ pprint(ip->forloop_body->nexti, pc->target_continue, FALSE);
+ indent_out();
+ indent(SPACEOVER);
+ fprintf(prof_fp, "}\n");
+ break;
+
+ case Op_K_arrayfor:
+ {
+ char *array, *item;
+ t1 = pp_pop();
+ array = t1->pp_str;
+ m = ip->forloop_cond->array_var;
+ if (m->type == Node_param_list)
+ item = fparms[m->param_cnt];
+ else
+ item = m->vname;
+ indent(ip->forloop_body->exec_count);
+ fprintf(prof_fp, "%s (%s%s%s) {\n", op2str(Op_K_arrayfor),
+ item, op2str(Op_in_array), array);
+ indent_in();
+ pp_free(t1);
+ pprint(ip->forloop_body->nexti, pc->target_break, FALSE);
+ indent_out();
+ indent(SPACEOVER);
+ fprintf(prof_fp, "}\n");
+ }
+ break;
+
+ case Op_K_switch:
+ {
+ INSTRUCTION *curr;
+
+ fprintf(prof_fp, "%s (", op2str(ip->opcode));
+ pprint(pc->nexti, ip->switch_body, FALSE);
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s) {\n", t1->pp_str);
+ pp_free(t1);
+
+ for (curr = ip->switch_body->case_val; curr != NULL; curr = curr->nexti) {
+ indent(curr->target_stmt->exec_count);
+ if (curr->opcode == Op_K_case) {
+ m = curr->memory;
+ if (m->type == Node_regex) {
+ m = m->re_exp;
+ tmp = pp_string(m->stptr, m->stlen, '/');
+ } else if ((m->flags & NUMBER) != 0)
+ tmp = pp_number(m->numbr);
+ else
+ tmp = pp_string(m->stptr, m->stlen, '"');
+ fprintf(prof_fp, "%s %s:\n", op2str(Op_K_case), tmp);
+ efree(tmp);
+ } else
+ fprintf(prof_fp, "%s:\n", op2str(Op_K_default));
+ indent_in();
+ pprint(curr->target_stmt->nexti, curr->nexti ?
+ curr->nexti->target_stmt : pc->target_break, FALSE);
+ indent_out();
+ }
+ indent(SPACEOVER);
+ fprintf(prof_fp, "}\n");
+ }
+ break;
- case Node_assign_minus:
- fprintf(prof_fp, " -= ");
- break;
+ default:
+ cant_happen();
+ }
- default:
- cant_happen();
- }
+ pc = pc->target_break;
+ break;
- tree_eval(tree->rnode);
-}
+ case Op_K_if:
+ fprintf(prof_fp, "%s (", op2str(pc->opcode));
+ pprint(pc->nexti, pc->branch_if, FALSE);
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s) {", t1->pp_str);
+ pp_free(t1);
-/* pp_lhs --- print the lhs */
+ ip = pc->branch_if;
+ if (ip->exec_count > 0)
+ fprintf(prof_fp, " # %ld", ip->exec_count);
+ fprintf(prof_fp, "\n");
+ indent_in();
+ pprint(ip->nexti, pc->branch_else, FALSE);
+ indent_out();
+ pc = pc->branch_else;
+ if (pc->nexti->opcode == Op_no_op) {
+ indent(SPACEOVER);
+ fprintf(prof_fp, "}\n");
+ }
+ break;
-static void
-pp_lhs(register NODE *ptr)
-{
- register NODE *n;
-
- switch (ptr->type) {
- case Node_var_array:
- fatal(_("attempt to use array `%s' in a scalar context"),
- ptr->vname);
-
- case Node_var_new:
- case Node_var:
- fprintf(prof_fp, "%s", ptr->vname);
- break;
-
- case Node_BINMODE:
- case Node_CONVFMT:
- case Node_FIELDWIDTHS:
- case Node_FNR:
- case Node_FPAT:
- case Node_FS:
- case Node_IGNORECASE:
- case Node_LINT:
- case Node_NF:
- case Node_NR:
- case Node_OFMT:
- case Node_OFS:
- case Node_ORS:
- case Node_RS:
- case Node_SUBSEP:
- case Node_TEXTDOMAIN:
- pp_var(ptr);
- break;
-
- case Node_param_list:
- fprintf(prof_fp, "%s", fparms[ptr->param_cnt]);
- break;
-
- case Node_field_spec:
- fprintf(prof_fp, "$");
- if (is_scalar(ptr->lnode->type))
- tree_eval(ptr->lnode);
- else {
- fprintf(prof_fp, "(");
- tree_eval(ptr->lnode);
- fprintf(prof_fp, ")");
+ case Op_K_else:
+ fprintf(prof_fp, "} %s {\n", op2str(pc->opcode));
+ indent_in();
+ pprint(pc->nexti, pc->branch_end, FALSE);
+ indent_out();
+ indent(SPACEOVER);
+ fprintf(prof_fp, "}\n");
+ pc = pc->branch_end;
+ break;
+
+ case Op_cond_exp:
+ {
+ NODE *f, *t, *cond;
+ size_t len;
+
+ pprint(pc->nexti, pc->branch_if, FALSE);
+ ip = pc->branch_if;
+ pprint(ip->nexti, pc->branch_else, FALSE);
+ ip = pc->branch_else->nexti;
+
+ pc = ip->nexti;
+ assert(pc->opcode == Op_cond_exp);
+ pprint(pc->nexti, pc->branch_end, FALSE);
+
+ f = pp_pop();
+ t = pp_pop();
+ cond = pp_pop();
+
+ len = f->pp_len + t->pp_len + cond->pp_len + 12;
+ emalloc(str, char *, len, "pprint");
+ sprintf(str, "(%s ? %s : %s)", cond->pp_str, t->pp_str, f->pp_str);
+
+ pp_free(cond);
+ pp_free(t);
+ pp_free(f);
+ pp_push(Op_cond_exp, str, CAN_FREE);
+ pc = pc->branch_end;
}
- break;
+ break;
- case Node_subscript:
- n = ptr->lnode;
- if (n->type == Node_param_list) {
- fprintf(prof_fp, "%s[", fparms[n->param_cnt]);
- } else
- fprintf(prof_fp, "%s[", n->vname);
- if (ptr->rnode->type == Node_expression_list)
- pp_list(ptr->rnode);
- else
- tree_eval(ptr->rnode);
- fprintf(prof_fp, "]");
- break;
+ case Op_exec_count:
+ if (! in_for_header)
+ indent(pc->exec_count);
+ break;
- case Node_builtin:
- fatal(_("assignment is not allowed to result of builtin function"));
+ default:
+ cant_happen();
+ }
- default:
- cant_happen();
+ if (pc == endp)
+ break;
}
}
-/* match_op --- do ~ and !~ */
-
-static void
-pp_match_op(register NODE *tree)
-{
- register NODE *re;
- const char *op;
- const char *restr;
- size_t relen;
- NODE *text = NULL;
-
- if (tree->type == Node_dynregex) {
- tree_eval(tree->re_exp);
- return;
- }
-
- if (tree->type == Node_regex) {
- re = tree->re_exp;
- restr = re->stptr;
- relen = re->stlen;
- pp_string(restr, relen, '/');
- return;
- }
-
- /* at this point, have either ~ or !~ */
-
- text = tree->lnode;
- re = tree->rnode;
-
- if (tree->type == Node_nomatch)
- op = "!~";
- else if (tree->type == Node_match)
- op = "~";
- else
- op = "";
-
- tree_eval(text);
- fprintf(prof_fp, " %s ", op);
- tree_eval(re);
-}
-
-/* pp_redir --- print a redirection */
-
-static void
-pp_redir(register NODE *tree, enum redir_placement dir)
-{
- const char *op = "[BOGUS]"; /* should never be seen */
-
- if (tree == NULL)
- return;
-
- switch (tree->type) {
- case Node_redirect_output:
- op = ">";
- break;
- case Node_redirect_append:
- op = ">>";
- break;
- case Node_redirect_pipe:
- op = "|";
- break;
- case Node_redirect_pipein:
- op = "|";
- break;
- case Node_redirect_input:
- op = "<";
- break;
- case Node_redirect_twoway:
- op = "|&";
- break;
- default:
- cant_happen();
- }
-
- if (dir == BEFORE) {
- if (! is_scalar(tree->subnode->type)) {
- fprintf(prof_fp, "(");
- tree_eval(tree->subnode);
- fprintf(prof_fp, ")");
- } else
- tree_eval(tree->subnode);
- fprintf(prof_fp, " %s ", op);
- } else {
- fprintf(prof_fp, " %s ", op);
- if (! is_scalar(tree->subnode->type)) {
- fprintf(prof_fp, "(");
- tree_eval(tree->subnode);
- fprintf(prof_fp, ")");
- } else
- tree_eval(tree->subnode);
- }
-}
+/* pp_string_fp --- printy print a string to the fp */
-/* pp_list --- dump a list of arguments, without parens */
+/*
+ * This routine concentrates string pretty printing in one place,
+ * so that it can be called from multiple places within gawk.
+ */
-static void
-pp_list(register NODE *tree)
+void
+pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
+ size_t len, int delim, int breaklines)
{
- for (; tree != NULL; tree = tree->rnode) {
- if (tree->type != Node_expression_list) {
- fprintf(stderr, "pp_list: got %s\n",
- nodetype2str(tree->type));
- fflush(stderr);
- }
- assert(tree->type == Node_expression_list);
- tree_eval(tree->lnode);
- if (tree->rnode != NULL)
- fprintf(prof_fp, ", ");
- }
-}
-
-/* pp_print_stmt --- print a "print" or "printf" statement */
+ char *s = pp_string(in_str, len, delim);
+ int count;
+ size_t slen;
+ const char *str = (const char *) s;
+#define BREAKPOINT 70 /* arbitrary */
-static void
-pp_print_stmt(const char *command, register NODE *tree)
-{
- NODE *redir = tree->rnode;
-
- indent(tree->exec_count);
- fprintf(prof_fp, "%s", command);
- if (redir != NULL) {
- if (tree->lnode != NULL) {
- /* parenthesize if have a redirection and a list */
- fprintf(prof_fp, "(");
- pp_list(tree->lnode);
- fprintf(prof_fp, ")");
+ slen = strlen(str);
+ for (count = 0; slen > 0; slen--, str++) {
+ if (++count >= BREAKPOINT && breaklines) {
+ print_func(fp, "%c\n%c", delim, delim);
+ count = 0;
} else
- fprintf(prof_fp, " $0");
- pp_redir(redir, AFTER);
- } else {
- fprintf(prof_fp, " ");
- if (tree->lnode != NULL)
- pp_list(tree->lnode);
- else
- fprintf(prof_fp, "$0");
+ print_func(fp, "%c", *str);
}
- fprintf(prof_fp, "\n");
-}
-
-/* pp_delete --- print a "delete" statement */
-
-static void
-pp_delete(register NODE *tree)
-{
- NODE *array, *subscript;
-
- array = tree->lnode;
- subscript = tree->rnode;
- indent(tree->exec_count);
- if (array->type == Node_param_list)
- fprintf(prof_fp, "delete %s", fparms[array->param_cnt]);
- else
- fprintf(prof_fp, "delete %s", array->vname);
- if (subscript != NULL) {
- fprintf(prof_fp, "[");
- pp_list(subscript);
- fprintf(prof_fp, "]");
- }
- fprintf(prof_fp, "\n");
-}
-
-/* pp_in_array --- pretty print "foo in array" test */
-
-static void
-pp_in_array(NODE *array, NODE *subscript)
-{
- if (subscript->type == Node_expression_list) {
- fprintf(prof_fp, "(");
- pp_list(subscript);
- fprintf(prof_fp, ")");
- } else
- pprint(subscript);
-
- if (array->type == Node_param_list)
- fprintf(prof_fp, " in %s", fparms[array->param_cnt]);
- else
- fprintf(prof_fp, " in %s", array->vname);
+ efree(s);
}
-/* pp_getline --- print a getline statement */
+#ifdef PROFILING
+/* just_dump --- dump the profile and function stack and keep going */
-static void
-pp_getline(register NODE *tree)
+static RETSIGTYPE
+just_dump(int signum)
{
- NODE *redir = tree->rnode;
- int before, after;
-
- /*
- * command | getline
- * or
- * command |& getline
- * or
- * getline < file
- */
- if (redir != NULL) {
- before = (redir->type == Node_redirect_pipein
- || redir->type == Node_redirect_twoway);
- after = ! before;
- } else
- before = after = FALSE;
-
- if (before)
- pp_redir(redir, BEFORE);
-
- fprintf(prof_fp, "getline");
- if (tree->lnode != NULL) { /* optional var */
- fprintf(prof_fp, " ");
- pp_lhs(tree->lnode);
- }
+ extern INSTRUCTION *code_block;
- if (after)
- pp_redir(redir, AFTER);
+ dump_prog(code_block);
+ dump_funcs();
+ dump_fcall_stack(prof_fp);
+ fflush(prof_fp);
+ signal(signum, just_dump); /* for OLD Unix systems ... */
}
-/* pp_builtin --- print a builtin function */
+/* dump_and_exit --- dump the profile, the function stack, and exit */
-static void
-pp_builtin(register NODE *tree)
+static RETSIGTYPE
+dump_and_exit(int signum)
{
- const char *func = getfname(tree->builtin);
-
- if (func != NULL) {
- fprintf(prof_fp, "%s(", func);
- pp_list(tree->subnode);
- fprintf(prof_fp, ")");
- } else
- fprintf(prof_fp, _("# this is a dynamically loaded extension function"));
+ just_dump(signum);
+ exit(EXIT_FAILURE);
}
-/* pp_func_call --- print a function call */
-
-static void
-pp_func_call(NODE *tree)
-{
- NODE *name, *arglist;
-
- name = tree->rnode;
- arglist = tree->lnode;
- if (tree->type == Node_indirect_func_call)
- fprintf(prof_fp, "@");
- fprintf(prof_fp, "%s(", name->stptr);
- pp_list(arglist);
- fprintf(prof_fp, ")");
-}
+#endif
/* dump_prog --- dump the program */
@@ -1100,486 +936,436 @@ pp_func_call(NODE *tree)
*/
void
-dump_prog(NODE *begin, NODE *beginfile, NODE *prog, NODE *endfile, NODE *end)
+dump_prog(INSTRUCTION *code)
{
time_t now;
(void) time(& now);
/* \n on purpose, with \n in ctime() output */
fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
-
- if (begin != NULL) {
- fprintf(prof_fp, _("\t# BEGIN block(s)\n\n"));
- fprintf(prof_fp, "\tBEGIN {\n");
- in_BEGIN_or_END = TRUE;
- pprint(begin);
- in_BEGIN_or_END = FALSE;
- fprintf(prof_fp, "\t}\n");
- if (prog != NULL || end != NULL)
- fprintf(prof_fp, "\n");
- }
- if (beginfile != NULL) {
- fprintf(prof_fp, _("\t# BEGINFILE block(s)\n\n"));
- fprintf(prof_fp, "\tBEGINFILE {\n");
- in_BEGIN_or_END = TRUE;
- pprint(beginfile);
- in_BEGIN_or_END = FALSE;
- fprintf(prof_fp, "\t}\n");
- if (prog != NULL || endfile != NULL)
- fprintf(prof_fp, "\n");
- }
- if (prog != NULL) {
- fprintf(prof_fp, _("\t# Rule(s)\n\n"));
- pprint(prog);
- if (endfile != NULL || end != NULL)
- fprintf(prof_fp, "\n");
- }
- if (endfile != NULL) {
- fprintf(prof_fp, _("\t# ENDFILE block(s)\n\n"));
- fprintf(prof_fp, "\tENDFILE {\n");
- in_BEGIN_or_END = TRUE;
- pprint(endfile);
- in_BEGIN_or_END = FALSE;
- fprintf(prof_fp, "\t}\n");
- if (end != NULL)
- fprintf(prof_fp, "\n");
- }
- if (end != NULL) {
- fprintf(prof_fp, _("\t# END block(s)\n\n"));
- fprintf(prof_fp, "\tEND {\n");
- in_BEGIN_or_END = TRUE;
- pprint(end);
- in_BEGIN_or_END = FALSE;
- fprintf(prof_fp, "\t}\n");
- }
-}
-
-/* pp_func --- pretty print a function */
-
-void
-pp_func(const char *name, size_t namelen, NODE *f)
-{
- int j;
- char **pnames;
- static int first = TRUE;
-
- if (first) {
- first = FALSE;
- fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
- }
-
- fprintf(prof_fp, "\n");
- indent(f->exec_count);
- fprintf(prof_fp, "function %.*s(", (int) namelen, name);
- pnames = f->parmlist;
- fparms = pnames;
- for (j = 0; j < f->lnode->param_cnt; j++) {
- fprintf(prof_fp, "%s", pnames[j]);
- if (j < f->lnode->param_cnt - 1)
- fprintf(prof_fp, ", ");
- }
- fprintf(prof_fp, ")\n\t{\n");
- indent_in();
- pprint(f->rnode); /* body */
- indent_out();
- fprintf(prof_fp, "\t}\n");
-}
-
-/*
- * pp_concat --- print string concatenations
- *
- * Multiple string concatenations grow downwards to the left.
- * This routine attempts to print multiple concatenations with
- * the minimal amount of parentheses.
- */
-
-static void
-pp_concat(NODE *tree, int level)
-{
- static int left_printed = FALSE;
-
- if (tree->lnode->type == Node_concat)
- pp_concat(tree->lnode, level + 1); /* recurse down one level */
- else if (tree->lnode == Nnull_string) {
- tree_eval(tree->rnode);
- return;
- } else {
- fprintf(prof_fp, "("); /* outermost left paren */
- left_printed = TRUE;
-
- if (is_scalar(tree->lnode->type))
- tree_eval(tree->lnode);
- else {
- fprintf(prof_fp, "(");
- tree_eval(tree->lnode);
- fprintf(prof_fp, ")");
- }
- }
-
- fprintf(prof_fp, " ");
-
- if (is_scalar(tree->rnode->type))
- tree_eval(tree->rnode);
- else {
- fprintf(prof_fp, "(");
- tree_eval(tree->rnode);
- fprintf(prof_fp, ")");
- }
-
- if (level == 0 && left_printed) {
- fprintf(prof_fp, ")"); /* outermost right paren */
- left_printed = FALSE;
- }
-}
-
-/* pp_string --- pretty print a string or regex constant */
-
-static void
-pp_string(const char *str, size_t len, int delim)
-{
- pp_string_fp(prof_fp, str, len, delim, FALSE);
-}
-
-/* pp_string_fp --- printy print a string to the fp */
-
-/*
- * This routine concentrates string pretty printing in one place,
- * so that it can be called from multiple places within gawk.
- */
-
-void
-pp_string_fp(FILE *fp, const char *in_str, size_t len, int delim, int breaklines)
-{
- static char escapes[] = "\b\f\n\r\t\v\\";
- static char printables[] = "bfnrtv\\";
- char *cp;
- int i;
- int count;
-#define BREAKPOINT 70 /* arbitrary */
- const unsigned char *str = (const unsigned char *) in_str;
-
- fprintf(fp, "%c", delim);
- for (count = 0; len > 0; len--, str++) {
- if (++count >= BREAKPOINT && breaklines) {
- fprintf(fp, "%c\n%c", delim, delim);
- count = 0;
- }
- if (*str == delim) {
- fprintf(fp, "\\%c", delim);
- count++;
- } else if (*str == BELL) {
- fprintf(fp, "\\a");
- count++;
- } else if ((cp = strchr(escapes, *str)) != NULL) {
- i = cp - escapes;
- putc('\\', fp);
- count++;
- putc(printables[i], fp);
- if (breaklines && *str == '\n' && delim == '"') {
- fprintf(fp, "\"\n\"");
- count = 0;
- }
- /* NB: Deliberate use of lower-case versions. */
- } else if (isascii(*str) && isprint(*str)) {
- putc(*str, fp);
- } else {
- char buf[10];
-
- /* print 'em as they came if for whiny users */
- if (whiny_users)
- sprintf(buf, "%c", *str & 0xff);
- else
- sprintf(buf, "\\%03o", *str & 0xff);
- count += strlen(buf) - 1;
- fprintf(fp, "%s", buf);
- }
- }
- fprintf(fp, "%c", delim);
-}
-
-/* is_scalar --- true or false if we'll get a scalar value */
-
-static int
-is_scalar(NODETYPE type)
-{
- switch (type) {
- case Node_var_new:
- case Node_var:
- case Node_var_array:
- case Node_val:
- case Node_BINMODE:
- case Node_CONVFMT:
- case Node_FIELDWIDTHS:
- case Node_FNR:
- case Node_FPAT:
- case Node_FS:
- case Node_IGNORECASE:
- case Node_LINT:
- case Node_NF:
- case Node_NR:
- case Node_OFMT:
- case Node_OFS:
- case Node_ORS:
- case Node_RS:
- case Node_SUBSEP:
- case Node_TEXTDOMAIN:
- case Node_subscript:
- case Node_func_call:
- return TRUE;
- default:
- return FALSE;
- }
+ pprint(code, NULL, FALSE);
}
/* prec_level --- return the precedence of an operator, for paren tests */
static int
-prec_level(NODETYPE type)
+prec_level(int type)
{
switch (type) {
- case Node_var_new:
- case Node_var:
- case Node_var_array:
- case Node_param_list:
- case Node_subscript:
- case Node_func_call:
- case Node_K_delete_loop:
- case Node_val:
- case Node_builtin:
- case Node_BINMODE:
- case Node_CONVFMT:
- case Node_FIELDWIDTHS:
- case Node_FNR:
- case Node_FS:
- case Node_IGNORECASE:
- case Node_LINT:
- case Node_NF:
- case Node_NR:
- case Node_OFMT:
- case Node_OFS:
- case Node_ORS:
- case Node_RS:
- case Node_SUBSEP:
- case Node_TEXTDOMAIN:
- case Node_regex:
+ case Op_push_lhs:
+ case Op_push_param:
+ case Op_push_array:
+ case Op_push:
+ case Op_push_i:
+ case Op_push_re:
+ case Op_match_rec:
+ case Op_subscript:
+ case Op_subscript_lhs:
+ case Op_func_call:
+ case Op_K_delete_loop:
+ case Op_builtin:
return 15;
- case Node_field_spec:
+ case Op_field_spec:
+ case Op_field_spec_lhs:
return 14;
- case Node_exp:
+ case Op_exp:
+ case Op_exp_i:
return 13;
- case Node_preincrement:
- case Node_predecrement:
- case Node_postincrement:
- case Node_postdecrement:
+ case Op_preincrement:
+ case Op_predecrement:
+ case Op_postincrement:
+ case Op_postdecrement:
return 12;
- case Node_unary_minus:
- case Node_not:
+ case Op_unary_minus:
+ case Op_not:
return 11;
- case Node_times:
- case Node_quotient:
- case Node_mod:
+ case Op_times:
+ case Op_times_i:
+ case Op_quotient:
+ case Op_quotient_i:
+ case Op_mod:
+ case Op_mod_i:
return 10;
- case Node_plus:
- case Node_minus:
+ case Op_plus:
+ case Op_plus_i:
+ case Op_minus:
+ case Op_minus_i:
return 9;
- case Node_concat:
+ case Op_concat:
+ case Op_assign_concat:
return 8;
- case Node_equal:
- case Node_notequal:
- case Node_greater:
- case Node_leq:
- case Node_geq:
- case Node_match:
- case Node_nomatch:
+ case Op_equal:
+ case Op_notequal:
+ case Op_greater:
+ case Op_leq:
+ case Op_geq:
+ case Op_match:
+ case Op_nomatch:
return 7;
- case Node_K_getline:
+ case Op_K_getline:
+ case Op_K_getline_redir:
return 6;
- case Node_less:
- case Node_in_array:
+ case Op_less:
+ return 5;
+
+ case Op_in_array:
return 5;
- case Node_and:
+ case Op_and:
return 4;
- case Node_or:
+ case Op_or:
return 3;
- case Node_cond_exp:
+ case Op_cond_exp:
return 2;
- case Node_assign:
- case Node_assign_times:
- case Node_assign_quotient:
- case Node_assign_mod:
- case Node_assign_plus:
- case Node_assign_minus:
- case Node_assign_exp:
- case Node_assign_concat:
+ case Op_assign:
+ case Op_assign_times:
+ case Op_assign_quotient:
+ case Op_assign_mod:
+ case Op_assign_plus:
+ case Op_assign_minus:
+ case Op_assign_exp:
return 1;
default:
- fatal(_("unexpected type %s in prec_level"), nodetype2str(type));
- return 0; /* keep the compiler happy */
+ return 0;
}
}
-/* parenthesize --- print a subtree in parentheses if need be */
-
-static void
-parenthesize(NODETYPE parent_type, NODE *tree)
+static int
+is_binary(int type)
{
- NODETYPE child_type;
-
- if (tree == NULL)
- return;
-
- child_type = tree->type;
-
- in_expr++;
- /* first the special cases, then the general ones */
- if (parent_type == Node_not && child_type == Node_in_array) {
- fprintf(prof_fp, "(");
- pp_in_array(tree->lnode, tree->rnode);
- fprintf(prof_fp, ")");
- /* other special cases here, as needed */
- } else if (prec_level(child_type) < prec_level(parent_type)) {
- fprintf(prof_fp, "(");
- tree_eval(tree);
- fprintf(prof_fp, ")");
- } else
- tree_eval(tree);
- in_expr--;
+ switch (type) {
+ case Op_geq:
+ case Op_leq:
+ case Op_greater:
+ case Op_less:
+ case Op_notequal:
+ case Op_equal:
+ case Op_exp:
+ case Op_times:
+ case Op_quotient:
+ case Op_mod:
+ case Op_plus:
+ case Op_minus:
+ case Op_exp_i:
+ case Op_times_i:
+ case Op_quotient_i:
+ case Op_mod_i:
+ case Op_plus_i:
+ case Op_minus_i:
+ case Op_concat:
+ case Op_assign_concat:
+ case Op_match:
+ case Op_nomatch:
+ case Op_assign:
+ case Op_assign_times:
+ case Op_assign_quotient:
+ case Op_assign_mod:
+ case Op_assign_plus:
+ case Op_assign_minus:
+ case Op_assign_exp:
+ case Op_cond_exp:
+ case Op_and:
+ case Op_or:
+ case Op_in_array:
+ case Op_K_getline_redir: /* sometimes */
+ case Op_K_getline:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
}
-/* parenthesize_expr --- print an expression subtree in parentheses if need be */
+/* parenthesize --- parenthesize an expression in stack */
static void
-parenthesize_expr(NODETYPE parent_type, NODE *tree)
+pp_parenthesize(NODE *sp)
{
- NODETYPE child_type;
-
- if (tree == NULL)
- return;
-
- child_type = tree->type;
+ char *p = sp->pp_str;
+ size_t len = sp->pp_len;
+
+ emalloc(p, char *, len + 3, "pp_parenthesize");
+ *p = '(';
+ memcpy(p + 1, sp->pp_str, len);
+ p[len + 1] = ')';
+ p[len + 2] = '\0';
+ if ((sp->flags & CAN_FREE) != 0)
+ efree(sp->pp_str);
+ sp->pp_str = p;
+ sp->pp_len += 2;
+ sp->flags |= CAN_FREE;
+}
- in_expr++;
- if (prec_level(child_type) < prec_level(parent_type)) {
- fprintf(prof_fp, "(");
- eval_condition(tree);
- fprintf(prof_fp, ")");
- } else
- eval_condition(tree);
- in_expr--;
+static void
+parenthesize(int type, NODE *left, NODE *right)
+{
+ int rprec = prec_level(right->type);
+ int lprec = prec_level(left->type);
+ int prec = prec_level(type);
+
+ if (prec > lprec) {
+ if (is_binary(left->type)) /* (a - b) * c */
+ pp_parenthesize(left);
+ if (prec >= rprec && is_binary(right->type)) /* (a - b) * (c - d) */
+ pp_parenthesize(right);
+ } else {
+ if (prec >= rprec && is_binary(right->type)) /* a - b - (c - d) */
+ pp_parenthesize(right);
+ }
}
-/* pp_var --- print builtin variables, do it in one place */
+/* pp_string --- pretty format a string or regex constant */
-static void
-pp_var(NODE *tree)
+char *
+pp_string(const char *in_str, size_t len, int delim)
{
- switch (tree->type) {
- case Node_BINMODE:
- fprintf(prof_fp, "BINMODE");
- return;
+ static char str_escapes[] = "\a\b\f\n\r\t\v\\";
+ static char str_printables[] = "abfnrtv\\";
+ static char re_escapes[] = "\a\b\f\n\r\t\v";
+ static char re_printables[] = "abfnrtv";
+ char *escapes;
+ char *printables;
+ char *cp;
+ int i;
+ const unsigned char *str = (const unsigned char *) in_str;
+ size_t ofre, osiz;
+ char *obuf, *obufout;
- case Node_CONVFMT:
- fprintf(prof_fp, "CONVFMT");
- return;
+ assert(delim == '"' || delim == '/');
- case Node_FIELDWIDTHS:
- fprintf(prof_fp, "FIELDWIDTHS");
- return;
+ if (delim == '/') {
+ escapes = re_escapes;
+ printables = re_printables;
+ } else {
+ escapes = str_escapes;
+ printables = str_printables;
+ }
- case Node_FNR:
- fprintf(prof_fp, "FNR");
- return;
+/* make space for something l big in the buffer */
+#define chksize(l) if ((l) > ofre) { \
+ long olen = obufout - obuf; \
+ erealloc(obuf, char *, osiz * 2, "pp_string"); \
+ obufout = obuf + olen; \
+ ofre += osiz; \
+ osiz *= 2; \
+} ofre -= (l)
+
+ osiz = len + 3 + 2; /* initial size; 3 for delim + terminating null */
+ emalloc(obuf, char *, osiz, "pp_string");
+ obufout = obuf;
+ ofre = osiz - 1;
+
+ *obufout++ = delim;
+ for (; len > 0; len--, str++) {
+ chksize(2); /* make space for 2 chars */
+ if (delim != '/' && *str == delim) {
+ *obufout++ = '\\';
+ *obufout++ = delim;
+ } else if ((cp = strchr(escapes, *str)) != NULL) {
+ i = cp - escapes;
+ *obufout++ = '\\';
+ *obufout++ = printables[i];
+ /* NB: Deliberate use of lower-case versions. */
+ } else if (isascii(*str) && isprint(*str)) {
+ *obufout++ = *str;
+ ofre += 1;
+ } else {
+ size_t len;
- case Node_FPAT:
- fprintf(prof_fp, "FPAT");
- return;
+ chksize(8); /* total available space is 10 */
- case Node_FS:
- fprintf(prof_fp, "FS");
- return;
+ /* print 'em as they came if for whiny users */
+ if (whiny_users)
+ sprintf(obufout, "%c", *str & 0xff);
+ else
+ sprintf(obufout, "\\%03o", *str & 0xff);
+ len = strlen(obufout);
+ ofre += (10 - len); /* adjust free space count */
+ obufout += len;
+ }
+ }
+ chksize(1);
+ *obufout++ = delim;
+ *obufout = '\0';
+ return obuf;
+#undef chksize
+}
- case Node_IGNORECASE:
- fprintf(prof_fp, "IGNORECASE");
- return;
+/* pp_number --- pretty format a number */
- case Node_LINT:
- fprintf(prof_fp, "LINT");
- return;
+char *
+pp_number(AWKNUM d)
+{
+#define PP_PRECISION 6
+ char *str;
- case Node_NF:
- fprintf(prof_fp, "NF");
- return;
+ emalloc(str, char *, PP_PRECISION + 10, "pp_number");
+ sprintf(str, "%0.*g", PP_PRECISION, d);
+ return str;
+#undef PP_PRECISION
+}
- case Node_NR:
- fprintf(prof_fp, "NR");
- return;
+/* pp_node --- pretty format a node */
- case Node_OFMT:
- fprintf(prof_fp, "OFMT");
- return;
+char *
+pp_node(NODE *n)
+{
+ if ((n->flags & NUMBER) != 0)
+ return pp_number(n->numbr);
+ return pp_string(n->stptr, n->stlen, '"');
+}
- case Node_OFS:
- fprintf(prof_fp, "OFS");
- return;
+static NODE **pp_args = NULL;
+static int npp_args;
- case Node_ORS:
- fprintf(prof_fp, "ORS");
- return;
+static char *
+pp_list(int nargs, const char *paren, const char *delim)
+{
+ NODE *r;
+ char *str, *s;
+ size_t len;
+ size_t delimlen;
+ int i;
- case Node_RS:
- fprintf(prof_fp, "RS");
- return;
+ if (pp_args == NULL) {
+ npp_args = nargs;
+ emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
+ } else if (nargs > npp_args) {
+ npp_args = nargs;
+ erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
+ }
- case Node_SUBSEP:
- fprintf(prof_fp, "SUBSEP");
- return;
+ delimlen = strlen(delim);
+ len = -delimlen;
+ for (i = 1; i <= nargs; i++) {
+ r = pp_args[i] = pp_pop();
+ len += r->pp_len + delimlen;
+ }
+ if (paren != NULL) {
+ assert(strlen(paren) == 2);
+ len += 2;
+ }
- case Node_TEXTDOMAIN:
- fprintf(prof_fp, "TEXTDOMAIN");
- return;
+ emalloc(str, char *, len + 1, "pp_list");
+ s = str;
+ if (paren != NULL)
+ *s++ = paren[0];
+ r = pp_args[nargs];
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ pp_free(r);
+ for (i = nargs - 1; i > 0; i--) {
+ if (delimlen > 0) {
+ memcpy(s, delim, delimlen);
+ s += delimlen;
+ }
+ r = pp_args[i];
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ pp_free(r);
+ }
+ if (paren != NULL)
+ *s++ = paren[1];
+ *s = '\0';
+ return str;
+}
- default:
- fatal(_("Unknown node type %s in pp_var"), nodetype2str(tree->type));
- break;
+static char *
+pp_concat(const char *s1, const char *s2, const char *s3)
+{
+ size_t len1, len2, len3, l;
+ char *str, *s;
+
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+ len3 = strlen(s3);
+ l = len1 + len2 + len3 + 2;
+ emalloc(str, char *, l, "pp_concat");
+ s = str;
+ if (len1 > 0) {
+ memcpy(s, s1, len1);
+ s += len1;
}
+ if (len2 > 0) {
+ memcpy(s, s2, len2);
+ s += len2;
+ }
+ if (len3 > 0) {
+ memcpy(s, s3, len3);
+ s += len3;
+ }
+ *s = '\0';
+ return str;
}
-#ifdef PROFILING
-/* just_dump --- dump the profile and function stack and keep going */
+/* pp_func --- pretty print a function */
-static RETSIGTYPE
-just_dump(int signum)
+int
+pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
{
- extern NODE *begin_block, *expression_value, *end_block, *beginfile_block, *endfile_block;
+ int j;
+ char **pnames;
+ NODE *f;
+ static int first = TRUE;
+ int pcount;
- dump_prog(begin_block, beginfile_block, expression_value, endfile_block, end_block);
- dump_funcs();
- dump_fcall_stack(prof_fp);
- fflush(prof_fp);
- signal(signum, just_dump); /* for OLD Unix systems ... */
+ if (first) {
+ first = FALSE;
+ fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
+ }
+
+ f = pc->func_body;
+ fprintf(prof_fp, "\n");
+ indent(pc->nexti->exec_count);
+ fprintf(prof_fp, "%s %s(", op2str(Op_K_function), f->lnode->param);
+ pnames = f->parmlist;
+ fparms = pnames;
+ pcount = f->lnode->param_cnt;
+ for (j = 0; j < pcount; j++) {
+ fprintf(prof_fp, "%s", pnames[j]);
+ if (j < pcount - 1)
+ fprintf(prof_fp, ", ");
+ }
+ fprintf(prof_fp, ")\n\t{\n");
+ indent_in();
+ pprint(pc->nexti->nexti, NULL, FALSE); /* function body */
+ indent_out();
+ fprintf(prof_fp, "\t}\n");
+ return 0;
}
-/* dump_and_exit --- dump the profile, the function stack, and exit */
+/* redir2str --- convert a redirection type into a printable value */
-static RETSIGTYPE
-dump_and_exit(int signum)
+const char *
+redir2str(int redirtype)
{
- just_dump(signum);
- exit(EXIT_FAILURE);
+ static const char *const redirtab[] = {
+ "",
+ " > ", /* redirect_output */
+ " >> ", /* redirect_append */
+ " | ", /* redirect_pipe */
+ " | ", /* redirect_pipein */
+ " < " /* redirect_input */
+ " |& " /* redirect_twoway */
+ };
+
+ if (redirtype < 0 || redirtype > redirect_twoway)
+ fatal(_("redir2str: unknown redirection type %d"), redirtype);
+ return redirtab[redirtype];
}
-#endif
+
+