diff options
Diffstat (limited to 'profile.c')
-rw-r--r-- | profile.c | 671 |
1 files changed, 476 insertions, 195 deletions
@@ -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]; } - - |