diff options
Diffstat (limited to 'profile.c')
-rw-r--r-- | profile.c | 451 |
1 files changed, 292 insertions, 159 deletions
@@ -2,22 +2,22 @@ * profile.c - gawk bytecode pretty-printer with counts */ -/* +/* * Copyright (C) 1999-2016 the Free Software Foundation, Inc. - * + * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. - * + * * GAWK is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. - * + * * GAWK is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA @@ -26,17 +26,19 @@ #include "awk.h" static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags); +static INSTRUCTION *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_group3(const char *s1, const char *s2, const char *s3); static char *pp_concat(int nargs); +static char *pp_string_or_strong_regex(const char *in_str, size_t len, int delim, bool strong_regex); 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 print_comment(INSTRUCTION *pc, long in); const char *redir2str(int redirtype); #define pp_str vname @@ -46,8 +48,8 @@ const char *redir2str(int redirtype); #define DONT_FREE 1 #define CAN_FREE 2 -static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN; -static RETSIGTYPE just_dump(int signum); +static void dump_and_exit(int signum) ATTRIBUTE_NORETURN; +static void just_dump(int signum); /* pretty printing related functions and variables */ @@ -123,10 +125,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++) @@ -196,52 +200,94 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) NODE *t1; char *str; NODE *t2; - INSTRUCTION *ip; + INSTRUCTION *ip1; + INSTRUCTION *ip2; NODE *m; char *tmp; int rule; static int rule_count[MAXRULE]; + static bool skip_comment = false; for (pc = startp; pc != endp; pc = pc->nexti) { 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 + && skip_comment) { + skip_comment = false; + continue; + } + skip_comment = false; + 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 rule(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); + skip_comment = true; } 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, NO_PPRINT_FLAGS); - t1 = pp_pop(); - fprintf(prof_fp, "%s {", t1->pp_str); - pp_free(t1); - ip = (pc + 1)->firsti; - - if (do_profile && ip->exec_count > 0) - fprintf(prof_fp, " # %ld", ip->exec_count); - - fprintf(prof_fp, "\n"); + ip1 = pc->nexti; + indent(ip1->exec_count); + if (ip1 != (pc + 1)->firsti) { /* non-empty pattern */ + pprint(ip1->nexti, (pc + 1)->firsti, NO_PPRINT_FLAGS); + /* 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); + skip_comment = true; } 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, NO_PPRINT_FLAGS); + pprint(ip1, ip2, NO_PPRINT_FLAGS); indent_out(); - fprintf(prof_fp, "\t}\n\n"); + if (do_profile) + indent(0); + fprintf(prof_fp, "}\n\n"); pc = (pc + 1)->lasti; break; @@ -280,6 +326,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) case Op_push_array: case Op_push: case Op_push_arg: + case Op_push_arg_untyped: m = pc->memory; switch (m->type) { case Node_param_list: @@ -300,7 +347,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) cant_happen(); } - switch (pc->opcode) { + switch (pc->opcode) { case Op_store_var: t2 = pp_pop(); /* l.h.s. */ t1 = pp_pop(); /* r.h.s. */ @@ -326,7 +373,7 @@ cleanup: pp_free(t2); pp_free(t1); if ((flags & IN_FOR_HEADER) == 0) - fprintf(prof_fp, "\n"); + pc = end_line(pc); break; default: @@ -343,7 +390,7 @@ cleanup: efree(tmp); pp_free(t1); pp_push(pc->opcode, str, CAN_FREE); - break; + break; case Op_and: case Op_or: @@ -416,10 +463,13 @@ cleanup: case Op_field_spec: case Op_field_spec_lhs: case Op_unary_minus: + case Op_unary_plus: case Op_not: t1 = pp_pop(); if (is_binary(t1->type) - || (((OPCODE) t1->type) == pc->opcode && pc->opcode == Op_unary_minus)) + || (((OPCODE) t1->type) == pc->opcode + && (pc->opcode == Op_unary_minus + || pc->opcode == Op_unary_plus))) pp_parenthesize(t1); /* optypes table (eval.c) includes space after ! */ @@ -452,8 +502,8 @@ cleanup: pp_free(t2); pp_free(t1); if ((flags & IN_FOR_HEADER) == 0) - fprintf(prof_fp, "\n"); - break; + pc = end_line(pc); + break; case Op_concat: str = pp_concat(pc->expr_count); @@ -470,10 +520,10 @@ cleanup: 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 + } else fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array); if ((flags & IN_FOR_HEADER) == 0) - fprintf(prof_fp, "\n"); + pc = end_line(pc); pp_free(t1); } break; @@ -482,7 +532,7 @@ cleanup: /* Efficency hack not in effect because of exec_count instruction */ cant_happen(); break; - + case Op_in_array: { char *array, *sub; @@ -511,7 +561,7 @@ cleanup: case Op_field_assign: case Op_subscript_assign: case Op_arrayfor_init: - case Op_arrayfor_incr: + case Op_arrayfor_incr: case Op_arrayfor_final: case Op_newfile: case Op_get_record: @@ -572,7 +622,7 @@ cleanup: else { tmp = pp_list(pc->expr_count, " ", ", "); tmp[strlen(tmp) - 1] = '\0'; /* remove trailing space */ - } + } if (pc->redir_type != 0) { t1 = pp_pop(); @@ -585,13 +635,13 @@ cleanup: fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp); efree(tmp); if ((flags & IN_FOR_HEADER) == 0) - fprintf(prof_fp, "\n"); + pc = end_line(pc); break; case Op_push_re: if (pc->memory->type != Node_regex) break; - /* else + /* else fall through */ case Op_match_rec: { @@ -666,7 +716,7 @@ cleanup: if (pc->opcode == Op_indirect_func_call) pre = "@"; else - pre = ""; + pre = ""; pcount = (pc + 1)->expr_count; if (pcount > 0) { tmp = pp_list(pcount, "()", ", "); @@ -686,7 +736,8 @@ cleanup: case Op_K_break: case Op_K_nextfile: case Op_K_next: - fprintf(prof_fp, "%s\n", op2str(pc->opcode)); + fprintf(prof_fp, "%s", op2str(pc->opcode)); + pc = end_line(pc); break; case Op_K_return: @@ -694,8 +745,10 @@ cleanup: 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); + if (pc->source_line > 0) { /* don't print implicit 'return' at end of function */ + fprintf(prof_fp, "%s %s", op2str(pc->opcode), t1->pp_str); + pc = end_line(pc); + } pp_free(t1); break; @@ -703,73 +756,78 @@ cleanup: t1 = pp_pop(); fprintf(prof_fp, "%s", t1->pp_str); if ((flags & IN_FOR_HEADER) == 0) - fprintf(prof_fp, "\n"); + pc = end_line(pc); pp_free(t1); break; case Op_line_range: - ip = pc + 1; - pprint(pc->nexti, ip->condpair_left, NO_PPRINT_FLAGS); - pprint(ip->condpair_left->nexti, ip->condpair_right, NO_PPRINT_FLAGS); + ip1 = pc + 1; + pprint(pc->nexti, ip1->condpair_left, NO_PPRINT_FLAGS); + pprint(ip1->condpair_left->nexti, ip1->condpair_right, NO_PPRINT_FLAGS); t2 = pp_pop(); t1 = pp_pop(); 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, NO_PPRINT_FLAGS); + pprint(pc->nexti, ip1->while_body, NO_PPRINT_FLAGS); t1 = pp_pop(); - fprintf(prof_fp, "%s) {\n", t1->pp_str); + fprintf(prof_fp, "%s) {", t1->pp_str); pp_free(t1); + ip1->while_body = end_line(ip1->while_body); indent_in(); - pprint(ip->while_body->nexti, pc->target_break, NO_PPRINT_FLAGS); + pprint(ip1->while_body->nexti, pc->target_break, NO_PPRINT_FLAGS); indent_out(); indent(SPACEOVER); - fprintf(prof_fp, "}\n"); - pc = pc->target_break; + fprintf(prof_fp, "}"); + pc = end_line(pc->target_break); break; case Op_K_do: - ip = pc + 1; + ip1 = pc + 1; indent(pc->nexti->exec_count); - fprintf(prof_fp, "%s {\n", op2str(pc->opcode)); + fprintf(prof_fp, "%s {", op2str(pc->opcode)); + end_line(pc->nexti); + skip_comment = true; indent_in(); - pprint(pc->nexti->nexti, ip->doloop_cond, NO_PPRINT_FLAGS); + pprint(pc->nexti->nexti, ip1->doloop_cond, NO_PPRINT_FLAGS); indent_out(); - pprint(ip->doloop_cond, pc->target_break, NO_PPRINT_FLAGS); + pprint(ip1->doloop_cond, pc->target_break, NO_PPRINT_FLAGS); indent(SPACEOVER); t1 = pp_pop(); - fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str); + fprintf(prof_fp, "} %s (%s)", op2str(Op_K_while), t1->pp_str); pp_free(t1); + end_line(pc->target_break); + skip_comment = true; pc = pc->target_break; break; case Op_K_for: - ip = pc + 1; - indent(ip->forloop_body->exec_count); - fprintf(prof_fp, "%s (", op2str(pc->opcode)); + ip1 = pc + 1; + indent(ip1->forloop_body->exec_count); + fprintf(prof_fp, "%s (", op2str(pc->opcode)); /* If empty for looop header, print it a little more nicely. */ if ( pc->nexti->opcode == Op_no_op - && ip->forloop_cond == pc->nexti + && ip1->forloop_cond == pc->nexti && pc->target_continue->opcode == Op_jmp) { fprintf(prof_fp, ";;"); } else { - pprint(pc->nexti, ip->forloop_cond, IN_FOR_HEADER); + pprint(pc->nexti, ip1->forloop_cond, IN_FOR_HEADER); fprintf(prof_fp, "; "); - if (ip->forloop_cond->opcode == Op_no_op && - ip->forloop_cond->nexti == ip->forloop_body) + if (ip1->forloop_cond->opcode == Op_no_op && + ip1->forloop_cond->nexti == ip1->forloop_body) fprintf(prof_fp, "; "); else { - pprint(ip->forloop_cond, ip->forloop_body, IN_FOR_HEADER); + pprint(ip1->forloop_cond, ip1->forloop_body, IN_FOR_HEADER); t1 = pp_pop(); fprintf(prof_fp, "%s; ", t1->pp_str); pp_free(t1); @@ -777,12 +835,16 @@ cleanup: pprint(pc->target_continue, pc->target_break, IN_FOR_HEADER); } - fprintf(prof_fp, ") {\n"); + fprintf(prof_fp, ") {"); + end_line(ip1->forloop_body); + skip_comment = true; indent_in(); - pprint(ip->forloop_body->nexti, pc->target_continue, NO_PPRINT_FLAGS); + pprint(ip1->forloop_body->nexti, pc->target_continue, NO_PPRINT_FLAGS); indent_out(); indent(SPACEOVER); - fprintf(prof_fp, "}\n"); + fprintf(prof_fp, "}"); + end_line(pc->target_break); + skip_comment = true; pc = pc->target_break; break; @@ -791,35 +853,39 @@ 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); - fprintf(prof_fp, "%s (%s%s%s) {\n", op2str(Op_K_arrayfor), + indent(ip1->forloop_body->exec_count); + fprintf(prof_fp, "%s (%s%s%s) {", op2str(Op_K_arrayfor), item, op2str(Op_in_array), array); + end_line(ip1->forloop_body); + skip_comment = true; indent_in(); pp_free(t1); - pprint(ip->forloop_body->nexti, pc->target_break, NO_PPRINT_FLAGS); + pprint(ip1->forloop_body->nexti, pc->target_break, NO_PPRINT_FLAGS); indent_out(); indent(SPACEOVER); - fprintf(prof_fp, "}\n"); + fprintf(prof_fp, "}"); + end_line(pc->target_break); + skip_comment = true; pc = pc->target_break; } break; case Op_K_switch: - ip = pc + 1; + ip1 = pc + 1; fprintf(prof_fp, "%s (", op2str(pc->opcode)); - pprint(pc->nexti, ip->switch_start, NO_PPRINT_FLAGS); + pprint(pc->nexti, ip1->switch_start, NO_PPRINT_FLAGS); t1 = pp_pop(); fprintf(prof_fp, "%s) {\n", t1->pp_str); pp_free(t1); - pprint(ip->switch_start, ip->switch_end, NO_PPRINT_FLAGS); + pprint(ip1->switch_start, ip1->switch_end, NO_PPRINT_FLAGS); indent(SPACEOVER); fprintf(prof_fp, "}\n"); pc = pc->target_break; @@ -830,10 +896,13 @@ cleanup: indent(pc->stmt_start->exec_count); if (pc->opcode == Op_K_case) { t1 = pp_pop(); - fprintf(prof_fp, "%s %s:\n", op2str(pc->opcode), t1->pp_str); + fprintf(prof_fp, "%s %s:", op2str(pc->opcode), t1->pp_str); + pc = end_line(pc); pp_free(t1); - } else - fprintf(prof_fp, "%s:\n", op2str(pc->opcode)); + } else { + fprintf(prof_fp, "%s:", op2str(pc->opcode)); + pc = end_line(pc); + } indent_in(); pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, NO_PPRINT_FLAGS); indent_out(); @@ -846,17 +915,22 @@ cleanup: 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); + ip1 = end_line(ip1); indent_in(); - pprint(ip->nexti, pc->branch_else, NO_PPRINT_FLAGS); + pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS); indent_out(); pc = pc->branch_else; if (pc->nexti->opcode == Op_no_op) { /* no following else */ indent(SPACEOVER); - fprintf(prof_fp, "}\n"); + fprintf(prof_fp, "}"); + if (pc->nexti->nexti->opcode != Op_comment + || pc->nexti->nexti->memory->comment_type == FULL_COMMENT) + fprintf(prof_fp, "\n"); + /* else + It will be printed at the top. */ } /* * See next case; turn off the flag so that the @@ -885,13 +959,22 @@ cleanup: && pc->branch_end == pc->nexti->nexti->branch_else->lasti) { pprint(pc->nexti, pc->branch_end, IN_ELSE_IF); } else { - fprintf(prof_fp, "{\n"); + fprintf(prof_fp, "{"); + end_line(pc); + skip_comment = true; indent_in(); pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); indent_out(); indent(SPACEOVER); - fprintf(prof_fp, "}\n"); + fprintf(prof_fp, "}"); + end_line(pc->branch_end); + skip_comment = true; } + /* + * Don't do end_line() here, we get multiple blank lines after + * the final else in a chain of else-ifs since they all point + * to the same branch_end. + */ pc = pc->branch_end; break; @@ -901,13 +984,13 @@ cleanup: size_t len; pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS); - ip = pc->branch_if; - pprint(ip->nexti, pc->branch_else, NO_PPRINT_FLAGS); - ip = pc->branch_else->nexti; + ip1 = pc->branch_if; + pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS); + ip1 = pc->branch_else->nexti; - pc = ip->nexti; + pc = ip1->nexti; assert(pc->opcode == Op_cond_exp); - pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); + pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); f = pp_pop(); t = pp_pop(); @@ -923,13 +1006,20 @@ cleanup: pp_push(Op_cond_exp, str, CAN_FREE); pc = pc->branch_end; } - break; + break; case Op_exec_count: if (flags == NO_PPRINT_FLAGS) indent(pc->exec_count); break; + case Op_comment: + print_comment(pc, 0); + break; + + case Op_list: + break; + default: cant_happen(); } @@ -939,6 +1029,25 @@ cleanup: } } +/* end_line --- end pretty print line with new line or on-line comment */ + +INSTRUCTION * +end_line(INSTRUCTION *ip) +{ + INSTRUCTION *ret = ip; + + if (ip->nexti->opcode == Op_comment + && ip->nexti->memory->comment_type == EOL_COMMENT) { + fprintf(prof_fp, "\t"); + print_comment(ip->nexti, -1); + ret = ip->nexti; + } + else + fprintf(prof_fp, "\n"); + + return ret; +} + /* pp_string_fp --- printy print a string to the fp */ /* @@ -970,7 +1079,7 @@ pp_string_fp(Func_print print_func, FILE *fp, const char *in_str, /* just_dump --- dump the profile and function stack and keep going */ -static RETSIGTYPE +static void just_dump(int signum) { extern INSTRUCTION *code_block; @@ -984,7 +1093,7 @@ just_dump(int signum) /* dump_and_exit --- dump the profile, the function stack, and exit */ -static RETSIGTYPE +static void dump_and_exit(int signum) { just_dump(signum); @@ -1012,6 +1121,31 @@ print_lib_list(FILE *prof_fp) 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 */ /* @@ -1026,7 +1160,8 @@ 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)); + if (do_profile) + fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now)); print_lib_list(prof_fp); pprint(code, NULL, NO_PPRINT_FLAGS); } @@ -1066,6 +1201,7 @@ prec_level(int type) return 13; case Op_unary_minus: + case Op_unary_plus: case Op_not: return 12; @@ -1152,6 +1288,7 @@ is_scalar(int type) case Op_postincrement: case Op_postdecrement: case Op_unary_minus: + case Op_unary_plus: case Op_not: return true; @@ -1265,11 +1402,20 @@ parenthesize(int type, NODE *left, NODE *right) pp_parenthesize(right); } -/* pp_string --- pretty format a string or regex constant */ +/* pp_string --- pretty format a string or regular regex constant */ char * pp_string(const char *in_str, size_t len, int delim) { + return pp_string_or_strong_regex(in_str, len, delim, false); +} + + +/* pp_string_or_strong_regex --- pretty format a string, regex, or hard regex constant */ + +char * +pp_string_or_strong_regex(const char *in_str, size_t len, int delim, bool strong_regex) +{ 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"; @@ -1301,7 +1447,8 @@ pp_string(const char *in_str, size_t len, int delim) osiz *= 2; \ } ofre -= (l) - osiz = len + 3 + 2; /* initial size; 3 for delim + terminating null */ + /* initial size; 3 for delim + terminating null, 1 for @ */ + osiz = len + 3 + 1 + (strong_regex == true); emalloc(obuf, char *, osiz, "pp_string"); obufout = obuf; ofre = osiz - 1; @@ -1313,10 +1460,9 @@ pp_string(const char *in_str, size_t len, int delim) *obufout++ = '\\'; *obufout++ = delim; } else if (*str == '\0') { - chksize(4); - *obufout++ = '\\'; *obufout++ = '0'; + chksize(2); /* need 2 more chars for this case */ *obufout++ = '0'; *obufout++ = '0'; } else if ((cp = strchr(escapes, *str)) != NULL) { @@ -1326,7 +1472,7 @@ pp_string(const char *in_str, size_t len, int delim) /* NB: Deliberate use of lower-case versions. */ } else if (isascii(*str) && isprint(*str)) { *obufout++ = *str; - ofre += 1; + ofre += 1; /* used 1 less than expected */ } else { size_t len; @@ -1350,45 +1496,12 @@ pp_string(const char *in_str, size_t len, int delim) char * pp_number(NODE *n) { -#define PP_PRECISION 6 char *str; -#ifdef HAVE_MPFR - size_t count; - - if (is_mpg_float(n)) { - count = mpfr_get_prec(n->mpg_numbr) / 3; /* ~ 3.22 binary digits per decimal digit */ - emalloc(str, char *, count, "pp_number"); - /* - * 3/2015: Format string used to be "%0.*R*g". That padded - * with leading zeros. But it doesn't do that for regular - * numbers in the non-MPFR case. - */ - mpfr_sprintf(str, "%.*R*g", PP_PRECISION, ROUND_MODE, n->mpg_numbr); - } else if (is_mpg_integer(n)) { - count = mpz_sizeinbase(n->mpg_i, 10) + 2; /* +1 for sign, +1 for NUL at end */ - emalloc(str, char *, count, "pp_number"); - mpfr_sprintf(str, "%Zd", n->mpg_i); - } else -#endif - { - /* Use format_val() to get integral values printed as integers */ - NODE *s; - - getnode(s); - *s = *n; - s->flags &= ~STRCUR; - - s = r_format_val("%.6g", 0, s); - - s->stptr[s->stlen] = '\0'; - str = s->stptr; - - freenode(s); - } - + assert((n->flags & NUMCONSTSTR) != 0); + emalloc(str, char *, n->stlen + 1, "pp_number"); + strcpy(str, n->stptr); return str; -#undef PP_PRECISION } /* pp_node --- pretty format a node */ @@ -1441,7 +1554,7 @@ pp_list(int nargs, const char *paren, const char *delim) emalloc(str, char *, len + 1, "pp_list"); s = str; if (paren != NULL) - *s++ = paren[0]; + *s++ = paren[0]; if (nargs > 0) { r = pp_args[nargs]; memcpy(s, r->pp_str, r->pp_len); @@ -1461,7 +1574,7 @@ pp_list(int nargs, const char *paren, const char *delim) if (paren != NULL) *s++ = paren[1]; *s = '\0'; - return str; + return str; } /* is_unary_minus --- return true if string starts with unary minus */ @@ -1536,7 +1649,7 @@ pp_concat(int nargs) *s++ = ' '; } } - + pl_l = prec_level(pp_args[nargs-1]->type); pl_r = prec_level(pp_args[nargs]->type); r = pp_args[nargs]; @@ -1552,7 +1665,7 @@ pp_concat(int nargs) pp_free(r); *s = '\0'; - return str; + return str; } /* pp_group3 --- string together up to 3 strings */ @@ -1566,7 +1679,7 @@ pp_group3(const char *s1, const char *s2, const char *s3) len1 = strlen(s1); len2 = strlen(s2); len3 = strlen(s3); - l = len1 + len2 + len3 + 2; + l = len1 + len2 + len3 + 1; emalloc(str, char *, l, "pp_group3"); s = str; if (len1 > 0) { @@ -1594,14 +1707,24 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED) static bool first = true; NODE *func; int pcount; + INSTRUCTION *fp; if (first) { first = false; - fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n")); + 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; @@ -1611,11 +1734,21 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED) if (j < pcount - 1) fprintf(prof_fp, ", "); } - fprintf(prof_fp, ")\n\t{\n"); + if (fp->opcode == Op_comment + && fp->memory->comment_type == EOL_COMMENT) { + fprintf(prof_fp, ")"); + fp = end_line(fp); + } else + fprintf(prof_fp, ")\n"); + if (do_profile) + indent(0); + fprintf(prof_fp, "{\n"); indent_in(); - pprint(pc->nexti->nexti, NULL, NO_PPRINT_FLAGS); /* function body */ + pprint(fp, NULL, NO_PPRINT_FLAGS); /* function body */ indent_out(); - fprintf(prof_fp, "\t}\n"); + if (do_profile) + indent(0); + fprintf(prof_fp, "}\n"); return 0; } |