summaryrefslogtreecommitdiff
path: root/profile.c
diff options
context:
space:
mode:
Diffstat (limited to 'profile.c')
-rw-r--r--profile.c671
1 files changed, 476 insertions, 195 deletions
diff --git a/profile.c b/profile.c
index 5c581e8e..233bca0f 100644
--- a/profile.c
+++ b/profile.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1999-2011 the Free Software Foundation, Inc.
+ * Copyright (C) 1999-2013 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
@@ -25,28 +25,31 @@
#include "awk.h"
-static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header);
+static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header);
+static void end_line(INSTRUCTION *ip);
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 char *pp_group3(const char *s1, const char *s2, const char *s3);
+static char *pp_concat(int nargs);
+static bool is_binary(int type);
+static bool is_scalar(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);
+static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header);
+static void print_comment(INSTRUCTION *pc, long in);
const char *redir2str(int redirtype);
-#define pp_str hname
-#define pp_len hlength
+#define pp_str vname
+#define pp_len sub.nodep.reserved
+#define pp_next rnode
#define DONT_FREE 1
#define CAN_FREE 2
-#ifdef PROFILING
static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN;
static RETSIGTYPE just_dump(int signum);
-#endif
/* pretty printing related functions and variables */
@@ -59,20 +62,7 @@ static long indent_level = 0;
#define SPACEOVER 0
-/* init_profiling --- do needed initializations, see also main.c */
-
-void
-init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED)
-{
-#ifdef PROFILING
- if (*flag == FALSE) {
- *flag |= DO_PROFILING;
- set_prof_file(def_file);
- }
-#endif
-}
-
-/* set_prof_file --- set the output file for profiling */
+/* set_prof_file --- set the output file for profiling or pretty-printing */
void
set_prof_file(const char *file)
@@ -87,12 +77,11 @@ set_prof_file(const char *file)
}
}
-/* init_profiling_signals --- set up signal handling for pgawk */
+/* init_profiling_signals --- set up signal handling for gawk --profile */
void
init_profiling_signals()
{
-#ifdef PROFILING
#ifdef __DJGPP__
signal(SIGINT, dump_and_exit);
signal(SIGQUIT, just_dump);
@@ -104,7 +93,6 @@ init_profiling_signals()
signal(SIGUSR1, just_dump);
#endif
#endif /* !__DJGPP__ */
-#endif /* PROFILING */
}
/* indent --- print out enough tabs */
@@ -114,10 +102,12 @@ indent(long count)
{
int i;
- if (count == 0)
- fprintf(prof_fp, "\t");
- else
- fprintf(prof_fp, "%6ld ", count);
+ if (do_profile) {
+ if (count == 0)
+ fprintf(prof_fp, "\t");
+ else
+ fprintf(prof_fp, "%6ld ", count);
+ }
assert(indent_level >= 0);
for (i = 0; i < indent_level; i++)
@@ -142,6 +132,8 @@ indent_out(void)
assert(indent_level >= 0);
}
+/* pp_push --- push a pretty printed string onto the stack */
+
static void
pp_push(int type, char *s, int flag)
{
@@ -151,19 +143,23 @@ pp_push(int type, char *s, int flag)
n->pp_len = strlen(s);
n->flags = flag;
n->type = type;
- n->hnext = pp_stack;
+ n->pp_next = pp_stack;
pp_stack = n;
}
+/* pp_pop --- pop a pretty printed string off the stack */
+
static NODE *
pp_pop()
{
NODE *n;
n = pp_stack;
- pp_stack = n->hnext;
+ pp_stack = n->pp_next;
return n;
}
+/* pp_free --- release a pretty printed node */
+
static void
pp_free(NODE *n)
{
@@ -172,18 +168,17 @@ pp_free(NODE *n)
freenode(n);
}
-/*
- * pprint --- pretty print a program segment
- */
+/* pprint --- pretty print a program segment */
static void
-pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
+pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header)
{
INSTRUCTION *pc;
NODE *t1;
char *str;
NODE *t2;
- INSTRUCTION *ip;
+ INSTRUCTION *ip1;
+ INSTRUCTION *ip2;
NODE *m;
char *tmp;
int rule;
@@ -193,42 +188,74 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
if (pc->source_line > 0)
sourceline = pc->source_line;
+ /* skip leading EOL comment as it has already been printed */
+ if (pc->opcode == Op_comment
+ && pc->memory->comment_type == EOL_COMMENT)
+ continue;
switch (pc->opcode) {
case Op_rule:
+ /*
+ * Rules are three instructions long.
+ * See append_rule in awkgram.y.
+ * The first has the Rule Op Code, nexti etc.
+ * The second, (pc + 1) has firsti and lasti:
+ * the first/last ACTION instructions for this rule.
+ * The third has first_line and last_line:
+ * the first and last source line numbers.
+ */
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;
+ /* Allow for pre-non-rule-block comment */
+ if (pc->nexti != (pc +1)->firsti
+ && pc->nexti->opcode == Op_comment
+ && pc->nexti->memory->comment_type == FULL_COMMENT)
+ print_comment(pc->nexti, -1);
+ ip1 = (pc + 1)->firsti;
+ ip2 = (pc + 1)->lasti;
+
+ if (do_profile) {
+ if (! rule_count[rule]++)
+ fprintf(prof_fp, _("\t# %s rule(s)\n\n"), ruletab[rule]);
+ indent(0);
+ }
+ fprintf(prof_fp, "%s {", ruletab[rule]);
+ end_line(pc);
} else {
- if (! rule_count[rule]++)
+ if (do_profile && ! rule_count[rule]++)
fprintf(prof_fp, _("\t# Rule(s)\n\n"));
- 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 (ip->exec_count > 0)
- fprintf(prof_fp, " # %ld", ip->exec_count);
-#endif
- fprintf(prof_fp, "\n");
+ ip1 = pc->nexti;
+ if (ip1 != (pc + 1)->firsti) { /* non-empty pattern */
+ pprint(ip1->nexti, (pc + 1)->firsti, false);
+ /* Allow for case where the "pattern" is just a comment */
+ if (ip1->nexti->nexti->nexti != (pc +1)->firsti
+ || ip1->nexti->opcode != Op_comment) {
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s {", t1->pp_str);
+ pp_free(t1);
+ } else
+ fprintf(prof_fp, "{");
+ ip1 = (pc + 1)->firsti;
+ ip2 = (pc + 1)->lasti;
+
+ if (do_profile && ip1->exec_count > 0)
+ fprintf(prof_fp, " # %ld", ip1->exec_count);
+
+ end_line(ip1);
} else {
fprintf(prof_fp, "{\n");
- ip = (pc + 1)->firsti;
+ ip1 = (pc + 1)->firsti;
+ ip2 = (pc + 1)->lasti;
}
- ip = ip->nexti;
+ ip1 = ip1->nexti;
}
indent_in();
- pprint(ip, (pc + 1)->lasti, FALSE);
+ pprint(ip1, ip2, false);
indent_out();
- fprintf(prof_fp, "\t}\n\n");
+ if (do_profile)
+ indent(0);
+ fprintf(prof_fp, "}\n\n");
pc = (pc + 1)->lasti;
break;
@@ -244,12 +271,12 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
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);
+ pp_push(pc->opcode, pp_number(m), CAN_FREE);
else {
str = pp_string(m->stptr, m->stlen, '"');
if ((m->flags & INTLSTR) != 0) {
char *tmp = str;
- str = pp_concat("_", tmp, "");
+ str = pp_group3("_", tmp, "");
efree(tmp);
}
pp_push(pc->opcode, str, CAN_FREE);
@@ -306,14 +333,14 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
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);
+ tmp = pp_group3(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");
+ end_line(pc);
break;
default:
@@ -326,7 +353,7 @@ cleanup:
case Op_subscript:
tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
t1 = pp_pop();
- str = pp_concat(t1->pp_str, tmp, "");
+ str = pp_group3(t1->pp_str, tmp, "");
efree(tmp);
pp_free(t1);
pp_push(pc->opcode, str, CAN_FREE);
@@ -338,7 +365,7 @@ cleanup:
t2 = pp_pop();
t1 = pp_pop();
parenthesize(pc->opcode, t1, t2);
- str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
+ str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
pp_free(t1);
pp_free(t2);
pp_push(pc->opcode, str, CAN_FREE);
@@ -357,10 +384,10 @@ cleanup:
&& is_binary(t1->type)) /* (a - b) * 1 */
pp_parenthesize(t1);
if ((m->flags & NUMBER) != 0)
- tmp = pp_number(m->numbr);
+ tmp = pp_number(m);
else
tmp = pp_string(m->stptr, m->stlen, '"');
- str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp);
+ str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp);
efree(tmp);
pp_free(t1);
pp_push(pc->opcode, str, CAN_FREE);
@@ -381,7 +408,7 @@ cleanup:
t2 = pp_pop();
t1 = pp_pop();
parenthesize(pc->opcode, t1, t2);
- str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
+ str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
pp_free(t1);
pp_free(t2);
pp_push(pc->opcode, str, CAN_FREE);
@@ -393,9 +420,9 @@ cleanup:
case Op_postdecrement:
t1 = pp_pop();
if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
- str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
+ str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
else
- str = pp_concat(t1->pp_str, op2str(pc->opcode), "");
+ str = pp_group3(t1->pp_str, op2str(pc->opcode), "");
pp_free(t1);
pp_push(pc->opcode, str, CAN_FREE);
break;
@@ -405,11 +432,12 @@ cleanup:
case Op_unary_minus:
case Op_not:
t1 = pp_pop();
- if (is_binary(t1->type))
+ if (is_binary(t1->type)
+ || (((OPCODE) t1->type) == pc->opcode && pc->opcode == Op_unary_minus))
pp_parenthesize(t1);
/* optypes table (eval.c) includes space after ! */
- str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
+ str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
pp_free(t1);
pp_push(pc->opcode, str, CAN_FREE);
break;
@@ -423,7 +451,7 @@ cleanup:
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);
+ str = pp_group3(t2->pp_str, op2str(pc->opcode), t1->pp_str);
pp_free(t2);
pp_free(t1);
pp_push(pc->opcode, str, CAN_FREE);
@@ -438,12 +466,11 @@ cleanup:
pp_free(t2);
pp_free(t1);
if (! in_for_header)
- fprintf(prof_fp, "\n");
+ end_line(pc);
break;
case Op_concat:
- str = pp_list(pc->expr_count, NULL,
- (pc->concat_flag & CSUBSEP) ? ", " : op2str(Op_concat));
+ str = pp_concat(pc->expr_count);
pp_push(Op_concat, str, CAN_FREE);
break;
@@ -454,13 +481,13 @@ cleanup:
array = t1->pp_str;
if (pc->expr_count > 0) {
char *sub;
- sub = pp_list(pc->expr_count, NULL, ", ");
+ sub = pp_list(pc->expr_count, NULL, pc->expr_count > 1 ? "][" : ", ");
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");
+ end_line(pc);
pp_free(t1);
}
break;
@@ -477,12 +504,15 @@ cleanup:
array = t1->pp_str;
if (pc->expr_count > 1) {
sub = pp_list(pc->expr_count, "()", ", ");
- str = pp_concat(sub, op2str(Op_in_array), array);
+ str = pp_group3(sub, op2str(Op_in_array), array);
efree(sub);
} else {
t2 = pp_pop();
+ if (prec_level(t2->type) < prec_level(Op_in_array)) {
+ pp_parenthesize(t2);
+ }
sub = t2->pp_str;
- str = pp_concat(sub, op2str(Op_in_array), array);
+ str = pp_group3(sub, op2str(Op_in_array), array);
pp_free(t2);
}
pp_free(t1);
@@ -493,6 +523,7 @@ cleanup:
case Op_var_update:
case Op_var_assign:
case Op_field_assign:
+ case Op_subscript_assign:
case Op_arrayfor_init:
case Op_arrayfor_incr:
case Op_arrayfor_final:
@@ -513,12 +544,12 @@ cleanup:
case Op_sub_builtin:
{
const char *fname = "sub";
- if (pc->sub_flags & GSUB)
+ if ((pc->sub_flags & GSUB) != 0)
fname = "gsub";
- else if (pc->sub_flags & GENSUB)
+ else if ((pc->sub_flags & GENSUB) != 0)
fname = "gensub";
tmp = pp_list(pc->expr_count, "()", ", ");
- str = pp_concat(fname, tmp, "");
+ str = pp_group3(fname, tmp, "");
efree(tmp);
pp_push(Op_sub_builtin, str, CAN_FREE);
}
@@ -535,10 +566,10 @@ cleanup:
if (fname != NULL) {
if (pc->expr_count > 0) {
tmp = pp_list(pc->expr_count, "()", ", ");
- str = pp_concat(fname, tmp, "");
+ str = pp_group3(fname, tmp, "");
efree(tmp);
} else
- str = pp_concat(fname, "()", "");
+ str = pp_group3(fname, "()", "");
pp_push(Op_builtin, str, CAN_FREE);
} else
fatal(_("internal error: builtin with null fname"));
@@ -549,7 +580,7 @@ cleanup:
case Op_K_printf:
case Op_K_print_rec:
if (pc->opcode == Op_K_print_rec)
- tmp = pp_concat(" ", op2str(Op_field_spec), "0");
+ tmp = pp_group3(" ", op2str(Op_field_spec), "0");
else if (pc->redir_type != 0)
tmp = pp_list(pc->expr_count, "()", ", ");
else {
@@ -568,7 +599,7 @@ cleanup:
fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
efree(tmp);
if (! in_for_header)
- fprintf(prof_fp, "\n");
+ end_line(pc);
break;
case Op_push_re:
@@ -599,12 +630,12 @@ cleanup:
if (is_binary(t2->type))
pp_parenthesize(t2);
txt = t2->pp_str;
- str = pp_concat(txt, op2str(pc->opcode), restr);
+ str = pp_group3(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);
+ str = pp_group3(txt, op2str(pc->opcode), restr);
efree(restr);
}
pp_free(t1);
@@ -616,10 +647,10 @@ cleanup:
case Op_K_getline_redir:
if (pc->into_var) {
t1 = pp_pop();
- tmp = pp_concat(op2str(Op_K_getline), " ", t1->pp_str);
+ tmp = pp_group3(op2str(Op_K_getline), " ", t1->pp_str);
pp_free(t1);
} else
- tmp = pp_concat(op2str(Op_K_getline), "", "");
+ tmp = pp_group3(op2str(Op_K_getline), "", "");
if (pc->redir_type != 0) {
int before = (pc->redir_type == redirect_pipein
@@ -629,9 +660,9 @@ cleanup:
if (is_binary(t2->type))
pp_parenthesize(t2);
if (before)
- str = pp_concat(t2->pp_str, redir2str(pc->redir_type), tmp);
+ str = pp_group3(t2->pp_str, redir2str(pc->redir_type), tmp);
else
- str = pp_concat(tmp, redir2str(pc->redir_type), t2->pp_str);
+ str = pp_group3(tmp, redir2str(pc->redir_type), t2->pp_str);
efree(tmp);
pp_free(t2);
} else
@@ -653,10 +684,10 @@ cleanup:
pcount = (pc + 1)->expr_count;
if (pcount > 0) {
tmp = pp_list(pcount, "()", ", ");
- str = pp_concat(pre, fname, tmp);
+ str = pp_group3(pre, fname, tmp);
efree(tmp);
} else
- str = pp_concat(pre, fname, "()");
+ str = pp_group3(pre, fname, "()");
if (pc->opcode == Op_indirect_func_call) {
t1 = pp_pop(); /* indirect var */
pp_free(t1);
@@ -686,33 +717,33 @@ cleanup:
t1 = pp_pop();
fprintf(prof_fp, "%s", t1->pp_str);
if (! in_for_header)
- fprintf(prof_fp, "\n");
+ end_line(pc);
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);
+ ip1 = pc + 1;
+ pprint(pc->nexti, ip1->condpair_left, false);
+ pprint(ip1->condpair_left->nexti, ip1->condpair_right, false);
t2 = pp_pop();
t1 = pp_pop();
- str = pp_concat(t1->pp_str, ", ", t2->pp_str);
+ str = pp_group3(t1->pp_str, ", ", t2->pp_str);
pp_free(t1);
pp_free(t2);
pp_push(Op_line_range, str, CAN_FREE);
- pc = ip->condpair_right;
+ pc = ip1->condpair_right;
break;
case Op_K_while:
- ip = pc + 1;
- indent(ip->while_body->exec_count);
+ ip1 = pc + 1;
+ indent(ip1->while_body->exec_count);
fprintf(prof_fp, "%s (", op2str(pc->opcode));
- pprint(pc->nexti, ip->while_body, FALSE);
+ pprint(pc->nexti, ip1->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);
+ pprint(ip1->while_body->nexti, pc->target_break, false);
indent_out();
indent(SPACEOVER);
fprintf(prof_fp, "}\n");
@@ -720,13 +751,13 @@ cleanup:
break;
case Op_K_do:
- ip = pc + 1;
+ ip1 = pc + 1;
indent(pc->nexti->exec_count);
fprintf(prof_fp, "%s {\n", op2str(pc->opcode));
indent_in();
- pprint(pc->nexti->nexti, ip->doloop_cond, FALSE);
+ pprint(pc->nexti->nexti, ip1->doloop_cond, false);
indent_out();
- pprint(ip->doloop_cond, pc->target_break, FALSE);
+ pprint(ip1->doloop_cond, pc->target_break, false);
indent(SPACEOVER);
t1 = pp_pop();
fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str);
@@ -735,26 +766,34 @@ cleanup:
break;
case Op_K_for:
- ip = pc + 1;
- indent(ip->forloop_body->exec_count);
+ ip1 = pc + 1;
+ indent(ip1->forloop_body->exec_count);
fprintf(prof_fp, "%s (", op2str(pc->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)
+ /* If empty for looop header, print it a little more nicely. */
+ if ( pc->nexti->opcode == Op_no_op
+ && ip1->forloop_cond == pc->nexti
+ && pc->target_continue->opcode == Op_jmp) {
+ fprintf(prof_fp, ";;");
+ } else {
+ pprint(pc->nexti, ip1->forloop_cond, true);
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);
- }
- pprint(pc->target_continue, pc->target_break, TRUE);
+ if (ip1->forloop_cond->opcode == Op_no_op &&
+ ip1->forloop_cond->nexti == ip1->forloop_body)
+ fprintf(prof_fp, "; ");
+ else {
+ pprint(ip1->forloop_cond, ip1->forloop_body, true);
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s; ", t1->pp_str);
+ pp_free(t1);
+ }
+
+ pprint(pc->target_continue, pc->target_break, true);
+ }
fprintf(prof_fp, ") {\n");
indent_in();
- pprint(ip->forloop_body->nexti, pc->target_continue, FALSE);
+ pprint(ip1->forloop_body->nexti, pc->target_continue, false);
indent_out();
indent(SPACEOVER);
fprintf(prof_fp, "}\n");
@@ -766,20 +805,20 @@ cleanup:
char *array;
const char *item;
- ip = pc + 1;
+ ip1 = pc + 1;
t1 = pp_pop();
array = t1->pp_str;
- m = ip->forloop_cond->array_var;
+ m = ip1->forloop_cond->array_var;
if (m->type == Node_param_list)
item = func_params[m->param_cnt].param;
else
item = m->vname;
- indent(ip->forloop_body->exec_count);
+ indent(ip1->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);
+ pprint(ip1->forloop_body->nexti, pc->target_break, false);
indent_out();
indent(SPACEOVER);
fprintf(prof_fp, "}\n");
@@ -788,13 +827,13 @@ cleanup:
break;
case Op_K_switch:
- ip = pc + 1;
+ ip1 = pc + 1;
fprintf(prof_fp, "%s (", op2str(pc->opcode));
- pprint(pc->nexti, ip->switch_start, FALSE);
+ pprint(pc->nexti, ip1->switch_start, false);
t1 = pp_pop();
fprintf(prof_fp, "%s) {\n", t1->pp_str);
pp_free(t1);
- pprint(ip->switch_start, ip->switch_end, FALSE);
+ pprint(ip1->switch_start, ip1->switch_end, false);
indent(SPACEOVER);
fprintf(prof_fp, "}\n");
pc = pc->target_break;
@@ -810,23 +849,23 @@ cleanup:
} else
fprintf(prof_fp, "%s:\n", op2str(pc->opcode));
indent_in();
- pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, FALSE);
+ pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, false);
indent_out();
break;
case Op_K_if:
fprintf(prof_fp, "%s (", op2str(pc->opcode));
- pprint(pc->nexti, pc->branch_if, FALSE);
+ pprint(pc->nexti, pc->branch_if, false);
t1 = pp_pop();
fprintf(prof_fp, "%s) {", t1->pp_str);
pp_free(t1);
- ip = pc->branch_if;
- if (ip->exec_count > 0)
- fprintf(prof_fp, " # %ld", ip->exec_count);
- fprintf(prof_fp, "\n");
+ ip1 = pc->branch_if;
+ if (ip1->exec_count > 0)
+ fprintf(prof_fp, " # %ld", ip1->exec_count);
+ end_line(pc);
indent_in();
- pprint(ip->nexti, pc->branch_else, FALSE);
+ pprint(ip1->nexti, pc->branch_else, false);
indent_out();
pc = pc->branch_else;
if (pc->nexti->opcode == Op_no_op) {
@@ -838,7 +877,7 @@ cleanup:
case Op_K_else:
fprintf(prof_fp, "} %s {\n", op2str(pc->opcode));
indent_in();
- pprint(pc->nexti, pc->branch_end, FALSE);
+ pprint(pc->nexti, pc->branch_end, false);
indent_out();
indent(SPACEOVER);
fprintf(prof_fp, "}\n");
@@ -850,14 +889,14 @@ cleanup:
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;
+ pprint(pc->nexti, pc->branch_if, false);
+ ip1 = pc->branch_if;
+ pprint(ip1->nexti, pc->branch_else, false);
+ ip1 = pc->branch_else->nexti;
- pc = ip->nexti;
+ pc = ip1->nexti;
assert(pc->opcode == Op_cond_exp);
- pprint(pc->nexti, pc->branch_end, FALSE);
+ pprint(pc->nexti, pc->branch_end, false);
f = pp_pop();
t = pp_pop();
@@ -880,6 +919,13 @@ cleanup:
indent(pc->exec_count);
break;
+ case Op_comment:
+ print_comment(pc, 0);
+ break;
+
+ case Op_list:
+ break;
+
default:
cant_happen();
}
@@ -889,6 +935,21 @@ cleanup:
}
}
+/* end_line --- end pretty print line with new line or on-line comment */
+
+void
+end_line(INSTRUCTION *ip)
+{
+ if (ip->nexti->opcode == Op_comment
+ && ip->nexti->memory->comment_type == EOL_COMMENT) {
+ fprintf(prof_fp, "\t");
+ print_comment(ip->nexti, -1);
+ ip = ip->nexti->nexti;
+ }
+ else
+ fprintf(prof_fp, "\n");
+}
+
/* pp_string_fp --- printy print a string to the fp */
/*
@@ -898,7 +959,7 @@ cleanup:
void
pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
- size_t len, int delim, int breaklines)
+ size_t len, int delim, bool breaklines)
{
char *s = pp_string(in_str, len, delim);
int count;
@@ -908,16 +969,16 @@ pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
slen = strlen(str);
for (count = 0; slen > 0; slen--, str++) {
+ print_func(fp, "%c", *str);
if (++count >= BREAKPOINT && breaklines) {
print_func(fp, "%c\n%c", delim, delim);
count = 0;
- } else
- print_func(fp, "%c", *str);
+ }
}
efree(s);
}
-#ifdef PROFILING
+
/* just_dump --- dump the profile and function stack and keep going */
static RETSIGTYPE
@@ -938,10 +999,54 @@ static RETSIGTYPE
dump_and_exit(int signum)
{
just_dump(signum);
- exit(EXIT_FAILURE);
+ final_exit(EXIT_FAILURE);
}
-#endif
+/* print_lib_list --- print a list of all libraries loaded */
+
+static void
+print_lib_list(FILE *prof_fp)
+{
+ SRCFILE *s;
+ static bool printed_header = false;
+
+ for (s = srcfiles->next; s != srcfiles; s = s->next) {
+ if (s->stype == SRC_EXTLIB) {
+ if (! printed_header) {
+ printed_header = true;
+ fprintf(prof_fp, _("\t# Loaded extensions (-l and/or @load)\n\n"));
+ }
+ fprintf(prof_fp, "\t@load \"%s\"\n", s->src);
+ }
+ }
+ if (printed_header) /* we found some */
+ fprintf(prof_fp, "\n");
+}
+
+/* print_comment --- print comment text with proper indentation */
+
+static void
+print_comment(INSTRUCTION* pc, long in)
+{
+ char *text;
+ size_t count;
+ bool after_newline = false;
+
+ count = pc->memory->stlen;
+ text = pc->memory->stptr;
+
+ if (in >= 0)
+ indent(in); /* is this correct? Where should comments go? */
+ for (; count > 0; count--, text++) {
+ if (after_newline) {
+ indent(in);
+ after_newline = false;
+ }
+ putc(*text, prof_fp);
+ if (*text == '\n')
+ after_newline = true;
+ }
+}
/* dump_prog --- dump the program */
@@ -957,8 +1062,10 @@ dump_prog(INSTRUCTION *code)
(void) time(& now);
/* \n on purpose, with \n in ctime() output */
- fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
- pprint(code, NULL, FALSE);
+ if (do_profile)
+ fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
+ print_lib_list(prof_fp);
+ pprint(code, NULL, false);
}
/* prec_level --- return the precedence of an operator, for paren tests */
@@ -979,25 +1086,25 @@ prec_level(int type)
case Op_func_call:
case Op_K_delete_loop:
case Op_builtin:
- return 15;
+ return 16;
case Op_field_spec:
case Op_field_spec_lhs:
- return 14;
-
- case Op_exp:
- case Op_exp_i:
- return 13;
+ return 15;
case Op_preincrement:
case Op_predecrement:
case Op_postincrement:
case Op_postdecrement:
- return 12;
+ return 14;
+
+ case Op_exp:
+ case Op_exp_i:
+ return 13;
case Op_unary_minus:
case Op_not:
- return 11;
+ return 12;
case Op_times:
case Op_times_i:
@@ -1005,23 +1112,26 @@ prec_level(int type)
case Op_quotient_i:
case Op_mod:
case Op_mod_i:
- return 10;
+ return 11;
case Op_plus:
case Op_plus_i:
case Op_minus:
case Op_minus_i:
- return 9;
+ return 10;
case Op_concat:
case Op_assign_concat:
- return 8;
+ return 9;
case Op_equal:
case Op_notequal:
case Op_greater:
+ case Op_less:
case Op_leq:
case Op_geq:
+ return 8;
+
case Op_match:
case Op_nomatch:
return 7;
@@ -1030,9 +1140,6 @@ prec_level(int type)
case Op_K_getline_redir:
return 6;
- case Op_less:
- return 5;
-
case Op_in_array:
return 5;
@@ -1059,7 +1166,40 @@ prec_level(int type)
}
}
-static int
+/* is_scalar --- return true if scalar, false otherwise */
+
+static bool
+is_scalar(int type)
+{
+ switch (type) {
+ 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_subscript:
+ case Op_subscript_lhs:
+ case Op_func_call:
+ case Op_builtin:
+ case Op_field_spec:
+ case Op_field_spec_lhs:
+ case Op_preincrement:
+ case Op_predecrement:
+ case Op_postincrement:
+ case Op_postdecrement:
+ case Op_unary_minus:
+ case Op_not:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* is_binary --- return true if type represents a binary operator */
+
+static bool
is_binary(int type)
{
switch (type) {
@@ -1098,14 +1238,14 @@ is_binary(int type)
case Op_in_array:
case Op_K_getline_redir: /* sometimes */
case Op_K_getline:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
-/* parenthesize --- parenthesize an expression in stack */
+/* pp_parenthesize --- parenthesize an expression in stack */
static void
pp_parenthesize(NODE *sp)
@@ -1125,6 +1265,28 @@ pp_parenthesize(NODE *sp)
sp->flags |= CAN_FREE;
}
+/* div_on_left_mul_on_right --- have / or % on left and * on right */
+
+static bool
+div_on_left_mul_on_right(int o1, int o2)
+{
+ OPCODE op1 = (OPCODE) o1;
+ OPCODE op2 = (OPCODE) o2;
+
+ switch (op1) {
+ case Op_quotient:
+ case Op_quotient_i:
+ case Op_mod:
+ case Op_mod_i:
+ return (op2 == Op_times || op2 == Op_times_i);
+
+ default:
+ return false;
+ }
+}
+
+/* parenthesize --- parenthesize two nodes relative to parent node type */
+
static void
parenthesize(int type, NODE *left, NODE *right)
{
@@ -1132,15 +1294,12 @@ parenthesize(int type, NODE *left, NODE *right)
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);
- }
+ if (lprec < prec
+ || (lprec == prec && div_on_left_mul_on_right(left->type, type)))
+ pp_parenthesize(left);
+ if (rprec < prec
+ || (rprec == prec && div_on_left_mul_on_right(type, right->type)))
+ pp_parenthesize(right);
}
/* pp_string --- pretty format a string or regex constant */
@@ -1177,7 +1336,7 @@ pp_string(const char *in_str, size_t len, int delim)
obufout = obuf + olen; \
ofre += osiz; \
osiz *= 2; \
-} ofre -= (l)
+ } ofre -= (l)
osiz = len + 3 + 2; /* initial size; 3 for delim + terminating null */
emalloc(obuf, char *, osiz, "pp_string");
@@ -1190,6 +1349,13 @@ pp_string(const char *in_str, size_t len, int delim)
if (delim != '/' && *str == delim) {
*obufout++ = '\\';
*obufout++ = delim;
+ } else if (*str == '\0') {
+ chksize(4);
+
+ *obufout++ = '\\';
+ *obufout++ = '0';
+ *obufout++ = '0';
+ *obufout++ = '0';
} else if ((cp = strchr(escapes, *str)) != NULL) {
i = cp - escapes;
*obufout++ = '\\';
@@ -1209,7 +1375,7 @@ pp_string(const char *in_str, size_t len, int delim)
obufout += len;
}
}
- chksize(1);
+ chksize(2);
*obufout++ = delim;
*obufout = '\0';
return obuf;
@@ -1219,13 +1385,20 @@ pp_string(const char *in_str, size_t len, int delim)
/* pp_number --- pretty format a number */
char *
-pp_number(AWKNUM d)
+pp_number(NODE *n)
{
#define PP_PRECISION 6
char *str;
emalloc(str, char *, PP_PRECISION + 10, "pp_number");
- sprintf(str, "%0.*g", PP_PRECISION, d);
+#ifdef HAVE_MPFR
+ if (is_mpg_float(n))
+ mpfr_sprintf(str, "%0.*R*g", PP_PRECISION, ROUND_MODE, n->mpg_numbr);
+ else if (is_mpg_integer(n))
+ mpfr_sprintf(str, "%Zd", n->mpg_i);
+ else
+#endif
+ sprintf(str, "%0.*g", PP_PRECISION, n->numbr);
return str;
#undef PP_PRECISION
}
@@ -1236,10 +1409,12 @@ char *
pp_node(NODE *n)
{
if ((n->flags & NUMBER) != 0)
- return pp_number(n->numbr);
+ return pp_number(n);
return pp_string(n->stptr, n->stlen, '"');
}
+/* pp_list --- pretty print a list, with surrounding characters and separator */
+
static NODE **pp_args = NULL;
static int npp_args;
@@ -1295,8 +1470,101 @@ pp_list(int nargs, const char *paren, const char *delim)
return str;
}
+/* is_unary_minus --- return true if string starts with unary minus */
+
+static bool
+is_unary_minus(const char *str)
+{
+ return str[0] == '-' && str[1] != '-';
+}
+
+/* pp_concat --- handle concatenation and correct parenthesizing of expressions */
+
static char *
-pp_concat(const char *s1, const char *s2, const char *s3)
+pp_concat(int nargs)
+{
+ NODE *r;
+ char *str, *s;
+ size_t len;
+ static const size_t delimlen = 1; /* " " */
+ int i;
+ int pl_l, pl_r;
+
+ if (pp_args == NULL) {
+ npp_args = nargs;
+ emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
+ } else if (nargs > npp_args) {
+ npp_args = nargs;
+ erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
+ }
+
+ /*
+ * items are on the stack in reverse order that they
+ * will be printed to pop them off backwards.
+ */
+
+ len = -delimlen;
+ for (i = nargs; i >= 1; i--) {
+ r = pp_args[i] = pp_pop();
+ len += r->pp_len + delimlen + 2;
+ }
+
+ emalloc(str, char *, len + 1, "pp_concat");
+ s = str;
+
+ /* now copy in */
+ for (i = 1; i < nargs; i++) {
+ r = pp_args[i];
+
+ pl_l = prec_level(pp_args[i]->type);
+ pl_r = prec_level(pp_args[i+1]->type);
+
+ if (i >= 2 && is_unary_minus(r->pp_str)) {
+ *s++ = '(';
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ *s++ = ')';
+ } else if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) {
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ } else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) {
+ *s++ = '(';
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ *s++ = ')';
+ } else {
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ }
+ pp_free(r);
+
+ if (i < nargs) {
+ *s++ = ' ';
+ }
+ }
+
+ pl_l = prec_level(pp_args[nargs-1]->type);
+ pl_r = prec_level(pp_args[nargs]->type);
+ r = pp_args[nargs];
+ if (is_unary_minus(r->pp_str) || ((pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)))) {
+ *s++ = '(';
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ *s++ = ')';
+ } else {
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ }
+ pp_free(r);
+
+ *s = '\0';
+ return str;
+}
+
+/* pp_group3 --- string together up to 3 strings */
+
+static char *
+pp_group3(const char *s1, const char *s2, const char *s3)
{
size_t len1, len2, len3, l;
char *str, *s;
@@ -1305,7 +1573,7 @@ pp_concat(const char *s1, const char *s2, const char *s3)
len2 = strlen(s2);
len3 = strlen(s3);
l = len1 + len2 + len3 + 2;
- emalloc(str, char *, l, "pp_concat");
+ emalloc(str, char *, l, "pp_group3");
s = str;
if (len1 > 0) {
memcpy(s, s1, len1);
@@ -1329,17 +1597,27 @@ int
pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
{
int j;
- static int first = TRUE;
+ static bool first = true;
NODE *func;
int pcount;
+ INSTRUCTION *fp;
if (first) {
- first = FALSE;
- fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
+ first = false;
+ if (do_profile)
+ fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
}
+ fp = pc->nexti->nexti;
func = pc->func_body;
fprintf(prof_fp, "\n");
+
+ /* print any function comment */
+ if (fp->opcode == Op_comment && fp->source_line == 0) {
+ print_comment(fp, -1); /* -1 ==> don't indent */
+ fp = fp->nexti;
+ }
+
indent(pc->nexti->exec_count);
fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname);
pcount = func->param_cnt;
@@ -1349,11 +1627,16 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
if (j < pcount - 1)
fprintf(prof_fp, ", ");
}
- fprintf(prof_fp, ")\n\t{\n");
+ fprintf(prof_fp, ")\n");
+ if (do_profile)
+ indent(0);
+ fprintf(prof_fp, "{\n");
indent_in();
- pprint(pc->nexti->nexti, NULL, FALSE); /* function body */
+ pprint(fp, NULL, false); /* function body */
indent_out();
- fprintf(prof_fp, "\t}\n");
+ if (do_profile)
+ indent(0);
+ fprintf(prof_fp, "}\n");
return 0;
}
@@ -1368,13 +1651,11 @@ redir2str(int redirtype)
" >> ", /* redirect_append */
" | ", /* redirect_pipe */
" | ", /* redirect_pipein */
- " < " /* redirect_input */
- " |& " /* redirect_twoway */
+ " < ", /* redirect_input */
+ " |& ", /* redirect_twoway */
};
if (redirtype < 0 || redirtype > redirect_twoway)
fatal(_("redir2str: unknown redirection type %d"), redirtype);
return redirtab[redirtype];
}
-
-