Blame profile.c

Packit Service f629e6
/*
Packit Service f629e6
 * profile.c - gawk bytecode pretty-printer with counts
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 1999-2017 the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#include "awk.h"
Packit Service f629e6
Packit Service f629e6
static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags);
Packit Service f629e6
static INSTRUCTION *end_line(INSTRUCTION *ip);
Packit Service f629e6
static void pp_parenthesize(NODE *n);
Packit Service f629e6
static void parenthesize(int type, NODE *left, NODE *right);
Packit Service f629e6
static char *pp_list(int nargs, const char *paren, const char *delim);
Packit Service f629e6
static char *pp_group3(const char *s1, const char *s2, const char *s3);
Packit Service f629e6
static char *pp_concat(int nargs);
Packit Service f629e6
static char *pp_string_or_typed_regex(const char *in_str, size_t len, int delim, bool typed_regex);
Packit Service f629e6
static char *pp_typed_regex(const char *in_str, size_t len, int delim);
Packit Service f629e6
static bool is_binary(int type);
Packit Service f629e6
static bool is_scalar(int type);
Packit Service f629e6
static int prec_level(int type);
Packit Service f629e6
static void pp_push(int type, char *s, int flag);
Packit Service f629e6
static NODE *pp_pop(void);
Packit Service f629e6
static void print_comment(INSTRUCTION *pc, long in);
Packit Service f629e6
const char *redir2str(int redirtype);
Packit Service f629e6
Packit Service f629e6
#define pp_str	vname
Packit Service f629e6
#define pp_len	sub.nodep.reserved
Packit Service f629e6
#define pp_next	rnode
Packit Service f629e6
Packit Service f629e6
#define DONT_FREE 1
Packit Service f629e6
#define CAN_FREE  2
Packit Service f629e6
Packit Service f629e6
static void dump_and_exit(int signum) ATTRIBUTE_NORETURN;
Packit Service f629e6
static void just_dump(int signum);
Packit Service f629e6
Packit Service f629e6
/* pretty printing related functions and variables */
Packit Service f629e6
Packit Service f629e6
static NODE *pp_stack = NULL;
Packit Service f629e6
static NODE *func_params;	/* function parameters */
Packit Service f629e6
static FILE *prof_fp;	/* where to send the profile */
Packit Service f629e6
Packit Service f629e6
static long indent_level = 0;
Packit Service f629e6
Packit Service f629e6
#define SPACEOVER	0
Packit Service f629e6
Packit Service f629e6
#define NO_PPRINT_FLAGS	0
Packit Service f629e6
#define IN_FOR_HEADER	1
Packit Service f629e6
#define IN_ELSE_IF	2
Packit Service f629e6
Packit Service f629e6
/* set_prof_file --- set the output file for profiling or pretty-printing */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
set_prof_file(const char *file)
Packit Service f629e6
{
Packit Service f629e6
	int fd;
Packit Service f629e6
Packit Service f629e6
	assert(file != NULL);
Packit Service f629e6
	fd = devopen_simple(file, "w", true);
Packit Service f629e6
	if (fd == INVALID_HANDLE)
Packit Service f629e6
		prof_fp = NULL;
Packit Service f629e6
	else if (fd == fileno(stdout))
Packit Service f629e6
		prof_fp = stdout;
Packit Service f629e6
	else if (fd == fileno(stderr))
Packit Service f629e6
		prof_fp = stderr;
Packit Service f629e6
	else
Packit Service f629e6
		prof_fp = fdopen(fd, "w");
Packit Service f629e6
Packit Service f629e6
	if (prof_fp == NULL) {
Packit Service f629e6
		/* don't leak file descriptors */
Packit Service f629e6
		int e = errno;
Packit Service f629e6
Packit Service f629e6
		if (   fd != INVALID_HANDLE
Packit Service f629e6
		    && fd != fileno(stdout)
Packit Service f629e6
		    && fd != fileno(stderr))
Packit Service f629e6
			(void) close(fd);
Packit Service f629e6
Packit Service f629e6
		errno = e;
Packit Service f629e6
		warning(_("could not open `%s' for writing: %s"),
Packit Service f629e6
				file, strerror(errno));
Packit Service f629e6
		warning(_("sending profile to standard error"));
Packit Service f629e6
		prof_fp = stderr;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* init_profiling_signals --- set up signal handling for gawk --profile */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
init_profiling_signals()
Packit Service f629e6
{
Packit Service f629e6
#ifdef __DJGPP__
Packit Service f629e6
	signal(SIGINT, dump_and_exit);
Packit Service f629e6
	signal(SIGQUIT, just_dump);
Packit Service f629e6
#else  /* !__DJGPP__ */
Packit Service f629e6
#ifdef SIGHUP
Packit Service f629e6
	signal(SIGHUP, dump_and_exit);
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef SIGUSR1
Packit Service f629e6
	signal(SIGUSR1, just_dump);
Packit Service f629e6
#endif
Packit Service f629e6
#endif /* !__DJGPP__ */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* indent --- print out enough tabs */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
indent(long count)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	if (do_profile) {
Packit Service f629e6
		if (count == 0)
Packit Service f629e6
			fprintf(prof_fp, "\t");
Packit Service f629e6
		else
Packit Service f629e6
			fprintf(prof_fp, "%6ld  ", count);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	assert(indent_level >= 0);
Packit Service f629e6
	for (i = 0; i < indent_level; i++)
Packit Service f629e6
		fprintf(prof_fp, "\t");
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* indent_in --- increase the level, with error checking */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
indent_in(void)
Packit Service f629e6
{
Packit Service f629e6
	assert(indent_level >= 0);
Packit Service f629e6
	indent_level++;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* indent_out --- decrease the level, with error checking */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
indent_out(void)
Packit Service f629e6
{
Packit Service f629e6
	indent_level--;
Packit Service f629e6
	assert(indent_level >= 0);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_push --- push a pretty printed string onto the stack */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
pp_push(int type, char *s, int flag)
Packit Service f629e6
{
Packit Service f629e6
	NODE *n;
Packit Service f629e6
	getnode(n);
Packit Service f629e6
	n->pp_str = s;
Packit Service f629e6
	n->pp_len = strlen(s);
Packit Service f629e6
	n->flags = flag;
Packit Service f629e6
	n->type = type;
Packit Service f629e6
	n->pp_next = pp_stack;
Packit Service f629e6
	pp_stack = n;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_pop --- pop a pretty printed string off the stack */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
pp_pop()
Packit Service f629e6
{
Packit Service f629e6
	NODE *n;
Packit Service f629e6
	n = pp_stack;
Packit Service f629e6
	pp_stack = n->pp_next;
Packit Service f629e6
	return n;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_free --- release a pretty printed node */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
pp_free(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	if ((n->flags & CAN_FREE) != 0)
Packit Service f629e6
		efree(n->pp_str);
Packit Service f629e6
	freenode(n);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pprint --- pretty print a program segment */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags)
Packit Service f629e6
{
Packit Service f629e6
	INSTRUCTION *pc;
Packit Service f629e6
	NODE *t1;
Packit Service f629e6
	char *str;
Packit Service f629e6
	NODE *t2;
Packit Service f629e6
	INSTRUCTION *ip1;
Packit Service f629e6
	INSTRUCTION *ip2;
Packit Service f629e6
	NODE *m;
Packit Service f629e6
	char *tmp;
Packit Service f629e6
	int rule;
Packit Service f629e6
	static int rule_count[MAXRULE];
Packit Service f629e6
	static bool skip_comment = false;
Packit Service f629e6
Packit Service f629e6
	for (pc = startp; pc != endp; pc = pc->nexti) {
Packit Service f629e6
		if (pc->source_line > 0)
Packit Service f629e6
			sourceline = pc->source_line;
Packit Service f629e6
Packit Service f629e6
		/* skip leading EOL comment as it has already been printed  */
Packit Service f629e6
		if (pc->opcode == Op_comment
Packit Service f629e6
		    && pc->memory->comment_type == EOL_COMMENT
Packit Service f629e6
		    && skip_comment) {
Packit Service f629e6
			skip_comment = false;
Packit Service f629e6
			continue;
Packit Service f629e6
		}
Packit Service f629e6
		skip_comment = false;
Packit Service f629e6
Packit Service f629e6
		switch (pc->opcode) {
Packit Service f629e6
		case Op_rule:
Packit Service f629e6
			/*
Packit Service f629e6
			 * Rules are three instructions long.
Packit Service f629e6
			 * See append_rule in awkgram.y.
Packit Service f629e6
			 * The first has the Rule Op Code, nexti etc.
Packit Service f629e6
			 * The second, (pc + 1) has firsti and lasti:
Packit Service f629e6
			 * 	the first/last ACTION instructions for this rule.
Packit Service f629e6
			 * The third has first_line and last_line:
Packit Service f629e6
			 * 	the first and last source line numbers.
Packit Service f629e6
			 */
Packit Service f629e6
			source = pc->source_file;
Packit Service f629e6
			rule = pc->in_rule;
Packit Service f629e6
Packit Service f629e6
			if (rule != Rule) {
Packit Service f629e6
				/* Allow for pre-non-rule-block comment  */
Packit Service f629e6
				if (pc->nexti != (pc +1)->firsti
Packit Service f629e6
				    && pc->nexti->opcode == Op_comment
Packit Service f629e6
				    && pc->nexti->memory->comment_type == FULL_COMMENT)
Packit Service f629e6
					print_comment(pc->nexti, -1);
Packit Service f629e6
				ip1 = (pc + 1)->firsti;
Packit Service f629e6
				ip2 = (pc + 1)->lasti;
Packit Service f629e6
Packit Service f629e6
				if (do_profile) {
Packit Service f629e6
					if (! rule_count[rule]++)
Packit Service f629e6
						fprintf(prof_fp, _("\t# %s rule(s)\n\n"), ruletab[rule]);
Packit Service f629e6
					indent(0);
Packit Service f629e6
				}
Packit Service f629e6
				fprintf(prof_fp, "%s {", ruletab[rule]);
Packit Service f629e6
				end_line(pc);
Packit Service f629e6
				skip_comment = true;
Packit Service f629e6
			} else {
Packit Service f629e6
				if (do_profile && ! rule_count[rule]++)
Packit Service f629e6
					fprintf(prof_fp, _("\t# Rule(s)\n\n"));
Packit Service f629e6
				ip1 = pc->nexti;
Packit Service f629e6
				indent(ip1->exec_count);
Packit Service f629e6
				if (ip1 != (pc + 1)->firsti) {		/* non-empty pattern */
Packit Service f629e6
					pprint(ip1->nexti, (pc + 1)->firsti, NO_PPRINT_FLAGS);
Packit Service f629e6
					/* Allow for case where the "pattern" is just a comment  */
Packit Service f629e6
					if (ip1->nexti->nexti->nexti != (pc +1)->firsti
Packit Service f629e6
					    || ip1->nexti->opcode != Op_comment) {
Packit Service f629e6
						t1 = pp_pop();
Packit Service f629e6
						fprintf(prof_fp, "%s {", t1->pp_str);
Packit Service f629e6
						pp_free(t1);
Packit Service f629e6
					} else
Packit Service f629e6
						fprintf(prof_fp, "{");
Packit Service f629e6
					ip1 = (pc + 1)->firsti;
Packit Service f629e6
					ip2 = (pc + 1)->lasti;
Packit Service f629e6
Packit Service f629e6
					if (do_profile && ip1->exec_count > 0)
Packit Service f629e6
						fprintf(prof_fp, " # %ld", ip1->exec_count);
Packit Service f629e6
Packit Service f629e6
					end_line(ip1);
Packit Service f629e6
					skip_comment = true;
Packit Service f629e6
				} else {
Packit Service f629e6
					fprintf(prof_fp, "{\n");
Packit Service f629e6
					ip1 = (pc + 1)->firsti;
Packit Service f629e6
					ip2 = (pc + 1)->lasti;
Packit Service f629e6
				}
Packit Service f629e6
				ip1 = ip1->nexti;
Packit Service f629e6
			}
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pprint(ip1, ip2, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			if (do_profile)
Packit Service f629e6
				indent(0);
Packit Service f629e6
			fprintf(prof_fp, "}\n\n");
Packit Service f629e6
			pc = (pc + 1)->lasti;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_atexit:
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_stop:
Packit Service f629e6
			memset(rule_count, 0, MAXRULE * sizeof(int));
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_push_i:
Packit Service f629e6
			m = pc->memory;
Packit Service f629e6
			if (m == Nnull_string)	/* optional return or exit value; don't print 0 or "" */
Packit Service f629e6
				pp_push(pc->opcode, m->stptr, DONT_FREE);
Packit Service f629e6
			else if ((m->flags & NUMBER) != 0)
Packit Service f629e6
				pp_push(pc->opcode, pp_number(m), CAN_FREE);
Packit Service f629e6
			else {
Packit Service f629e6
				str = pp_string(m->stptr, m->stlen, '"');
Packit Service f629e6
				if ((m->flags & INTLSTR) != 0) {
Packit Service f629e6
					char *tmp = str;
Packit Service f629e6
					str = pp_group3("_", tmp, "");
Packit Service f629e6
					efree(tmp);
Packit Service f629e6
				}
Packit Service f629e6
				pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_store_var:
Packit Service f629e6
			if (pc->initval != NULL)
Packit Service f629e6
				pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE);
Packit Service f629e6
			/* fall through */
Packit Service f629e6
		case Op_store_sub:
Packit Service f629e6
		case Op_assign_concat:
Packit Service f629e6
		case Op_push_lhs:
Packit Service f629e6
		case Op_push_param:
Packit Service f629e6
		case Op_push_array:
Packit Service f629e6
		case Op_push:
Packit Service f629e6
		case Op_push_arg:
Packit Service f629e6
		case Op_push_arg_untyped:
Packit Service f629e6
			m = pc->memory;
Packit Service f629e6
			switch (m->type) {
Packit Service f629e6
			case Node_param_list:
Packit Service f629e6
				pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE);
Packit Service f629e6
				break;
Packit Service f629e6
Packit Service f629e6
			case Node_var:
Packit Service f629e6
			case Node_var_new:
Packit Service f629e6
			case Node_var_array:
Packit Service f629e6
				if (m->vname != NULL)
Packit Service f629e6
					pp_push(pc->opcode, m->vname, DONT_FREE);
Packit Service f629e6
 				else
Packit Service f629e6
					fatal(_("internal error: %s with null vname"),
Packit Service f629e6
							nodetype2str(m->type));
Packit Service f629e6
				break;
Packit Service f629e6
Packit Service f629e6
			default:
Packit Service f629e6
				cant_happen();
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			switch (pc->opcode) {
Packit Service f629e6
			case Op_store_var:
Packit Service f629e6
				t2 = pp_pop(); /* l.h.s. */
Packit Service f629e6
				t1 = pp_pop(); /* r.h.s. */
Packit Service f629e6
				fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(pc->opcode), t1->pp_str);
Packit Service f629e6
				goto cleanup;
Packit Service f629e6
Packit Service f629e6
			case Op_store_sub:
Packit Service f629e6
				t1 = pp_pop();	/* array */
Packit Service f629e6
				tmp = pp_list(pc->expr_count, op2str(Op_subscript), ", "); /*subscript*/
Packit Service f629e6
				t2 = pp_pop(); /* r.h.s. */
Packit Service f629e6
				fprintf(prof_fp, "%s%s%s%s", t1->pp_str, tmp,
Packit Service f629e6
									op2str(pc->opcode), t2->pp_str);
Packit Service f629e6
				efree(tmp);
Packit Service f629e6
				goto cleanup;
Packit Service f629e6
Packit Service f629e6
			case Op_assign_concat:
Packit Service f629e6
				t2 = pp_pop(); /* l.h.s. */
Packit Service f629e6
				t1 = pp_pop();
Packit Service f629e6
				tmp = pp_group3(t2->pp_str, op2str(Op_concat), t1->pp_str);
Packit Service f629e6
				fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(Op_assign), tmp);
Packit Service f629e6
				efree(tmp);
Packit Service f629e6
cleanup:
Packit Service f629e6
				pp_free(t2);
Packit Service f629e6
				pp_free(t1);
Packit Service f629e6
				if ((flags & IN_FOR_HEADER) == 0)
Packit Service f629e6
					pc = end_line(pc);
Packit Service f629e6
				break;
Packit Service f629e6
Packit Service f629e6
			default:
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_sub_array:
Packit Service f629e6
		case Op_subscript_lhs:
Packit Service f629e6
		case Op_subscript:
Packit Service f629e6
			tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			str = pp_group3(t1->pp_str, tmp, "");
Packit Service f629e6
			efree(tmp);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_and:
Packit Service f629e6
		case Op_or:
Packit Service f629e6
			pprint(pc->nexti, pc->target_jmp, flags);
Packit Service f629e6
			t2 = pp_pop();
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			parenthesize(pc->opcode, t1, t2);
Packit Service f629e6
			str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_free(t2);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			pc = pc->target_jmp;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_plus_i:
Packit Service f629e6
		case Op_minus_i:
Packit Service f629e6
		case Op_times_i:
Packit Service f629e6
		case Op_exp_i:
Packit Service f629e6
		case Op_quotient_i:
Packit Service f629e6
		case Op_mod_i:
Packit Service f629e6
			m = pc->memory;
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			if (prec_level(pc->opcode) > prec_level(t1->type)
Packit Service f629e6
					&& is_binary(t1->type))  /* (a - b) * 1 */
Packit Service f629e6
				pp_parenthesize(t1);
Packit Service f629e6
			if ((m->flags & NUMBER) != 0)
Packit Service f629e6
				tmp = pp_number(m);
Packit Service f629e6
			else
Packit Service f629e6
				tmp = pp_string(m->stptr, m->stlen, '"');
Packit Service f629e6
			str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp);
Packit Service f629e6
			efree(tmp);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_parens:
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			str = pp_group3("(", t1->pp_str, ")");
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_plus:
Packit Service f629e6
		case Op_minus:
Packit Service f629e6
		case Op_times:
Packit Service f629e6
		case Op_exp:
Packit Service f629e6
		case Op_quotient:
Packit Service f629e6
		case Op_mod:
Packit Service f629e6
		case Op_equal:
Packit Service f629e6
		case Op_notequal:
Packit Service f629e6
		case Op_less:
Packit Service f629e6
		case Op_greater:
Packit Service f629e6
		case Op_leq:
Packit Service f629e6
		case Op_geq:
Packit Service f629e6
			t2 = pp_pop();
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			parenthesize(pc->opcode, t1, t2);
Packit Service f629e6
			str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_free(t2);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_preincrement:
Packit Service f629e6
		case Op_predecrement:
Packit Service f629e6
		case Op_postincrement:
Packit Service f629e6
		case Op_postdecrement:
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
Packit Service f629e6
				str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
Packit Service f629e6
			else
Packit Service f629e6
				str = pp_group3(t1->pp_str, op2str(pc->opcode), "");
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_field_spec:
Packit Service f629e6
		case Op_field_spec_lhs:
Packit Service f629e6
		case Op_unary_minus:
Packit Service f629e6
		case Op_unary_plus:
Packit Service f629e6
		case Op_not:
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			if (is_binary(t1->type)
Packit Service f629e6
			    || (((OPCODE) t1->type) == pc->opcode
Packit Service f629e6
				    && (pc->opcode == Op_unary_minus
Packit Service f629e6
					    || pc->opcode == Op_unary_plus)))
Packit Service f629e6
				pp_parenthesize(t1);
Packit Service f629e6
Packit Service f629e6
			/* optypes table (eval.c) includes space after ! */
Packit Service f629e6
			str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_assign:
Packit Service f629e6
		case Op_assign_plus:
Packit Service f629e6
		case Op_assign_minus:
Packit Service f629e6
		case Op_assign_times:
Packit Service f629e6
		case Op_assign_quotient:
Packit Service f629e6
		case Op_assign_mod:
Packit Service f629e6
		case Op_assign_exp:
Packit Service f629e6
			t2 = pp_pop(); /* l.h.s. */
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			str = pp_group3(t2->pp_str, op2str(pc->opcode), t1->pp_str);
Packit Service f629e6
			pp_free(t2);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_store_field:
Packit Service f629e6
			t1 = pp_pop(); /* field num */
Packit Service f629e6
			if (is_binary(t1->type))
Packit Service f629e6
				pp_parenthesize(t1);
Packit Service f629e6
			t2 = pp_pop(); /* r.h.s. */
Packit Service f629e6
			fprintf(prof_fp, "$%s%s%s", t1->pp_str, op2str(pc->opcode), t2->pp_str);
Packit Service f629e6
			pp_free(t2);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			if ((flags & IN_FOR_HEADER) == 0)
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_concat:
Packit Service f629e6
			str = pp_concat(pc->expr_count);
Packit Service f629e6
			pp_push(Op_concat, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_delete:
Packit Service f629e6
		{
Packit Service f629e6
			char *array;
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			array = t1->pp_str;
Packit Service f629e6
			if (pc->expr_count > 0) {
Packit Service f629e6
				char *sub;
Packit Service f629e6
				sub = pp_list(pc->expr_count, NULL, pc->expr_count > 1 ? "][" : ", ");
Packit Service f629e6
				fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
Packit Service f629e6
				efree(sub);
Packit Service f629e6
			} else
Packit Service f629e6
				fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
Packit Service f629e6
			if ((flags & IN_FOR_HEADER) == 0)
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_delete_loop:
Packit Service f629e6
			/* Efficency hack not in effect because of exec_count instruction */
Packit Service f629e6
			cant_happen();
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_in_array:
Packit Service f629e6
		{
Packit Service f629e6
			char *array, *sub;
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			array = t1->pp_str;
Packit Service f629e6
			if (pc->expr_count > 1) {
Packit Service f629e6
				sub = pp_list(pc->expr_count, "()", ", ");
Packit Service f629e6
				str = pp_group3(sub, op2str(Op_in_array), array);
Packit Service f629e6
				efree(sub);
Packit Service f629e6
			} else {
Packit Service f629e6
				t2 = pp_pop();
Packit Service f629e6
				if (prec_level(t2->type) < prec_level(Op_in_array)) {
Packit Service f629e6
					pp_parenthesize(t2);
Packit Service f629e6
				}
Packit Service f629e6
				sub = t2->pp_str;
Packit Service f629e6
				str = pp_group3(sub, op2str(Op_in_array), array);
Packit Service f629e6
				pp_free(t2);
Packit Service f629e6
			}
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(Op_in_array, str, CAN_FREE);
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_var_update:
Packit Service f629e6
		case Op_var_assign:
Packit Service f629e6
		case Op_field_assign:
Packit Service f629e6
		case Op_subscript_assign:
Packit Service f629e6
		case Op_arrayfor_init:
Packit Service f629e6
		case Op_arrayfor_incr:
Packit Service f629e6
		case Op_arrayfor_final:
Packit Service f629e6
		case Op_newfile:
Packit Service f629e6
		case Op_get_record:
Packit Service f629e6
		case Op_lint:
Packit Service f629e6
		case Op_jmp:
Packit Service f629e6
		case Op_jmp_false:
Packit Service f629e6
		case Op_jmp_true:
Packit Service f629e6
		case Op_no_op:
Packit Service f629e6
		case Op_and_final:
Packit Service f629e6
		case Op_or_final:
Packit Service f629e6
		case Op_cond_pair:
Packit Service f629e6
		case Op_after_beginfile:
Packit Service f629e6
		case Op_after_endfile:
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_sub_builtin:
Packit Service f629e6
		{
Packit Service f629e6
			const char *fname = "sub";
Packit Service f629e6
			if ((pc->sub_flags & GSUB) != 0)
Packit Service f629e6
				fname = "gsub";
Packit Service f629e6
			else if ((pc->sub_flags & GENSUB) != 0)
Packit Service f629e6
				fname = "gensub";
Packit Service f629e6
			tmp = pp_list(pc->expr_count, "()", ", ");
Packit Service f629e6
			str = pp_group3(fname, tmp, "");
Packit Service f629e6
			efree(tmp);
Packit Service f629e6
			pp_push(Op_sub_builtin, str, CAN_FREE);
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_builtin:
Packit Service f629e6
		case Op_ext_builtin:
Packit Service f629e6
		{
Packit Service f629e6
			const char *fname;
Packit Service f629e6
			if (pc->opcode == Op_builtin)
Packit Service f629e6
				fname = getfname(pc->builtin);
Packit Service f629e6
			else
Packit Service f629e6
				fname = (pc + 1)->func_name;
Packit Service f629e6
			if (fname != NULL) {
Packit Service f629e6
				if (pc->expr_count > 0) {
Packit Service f629e6
					tmp = pp_list(pc->expr_count, "()", ", ");
Packit Service f629e6
					str = pp_group3(fname, tmp, "");
Packit Service f629e6
					efree(tmp);
Packit Service f629e6
				} else
Packit Service f629e6
					str = pp_group3(fname, "()", "");
Packit Service f629e6
				pp_push(Op_builtin, str, CAN_FREE);
Packit Service f629e6
			} else
Packit Service f629e6
				fatal(_("internal error: builtin with null fname"));
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_print:
Packit Service f629e6
		case Op_K_printf:
Packit Service f629e6
		case Op_K_print_rec:
Packit Service f629e6
			if (pc->opcode == Op_K_print_rec)
Packit Service f629e6
				tmp = pp_group3(" ", op2str(Op_field_spec), "0");
Packit Service f629e6
			else if (pc->redir_type != 0)
Packit Service f629e6
				tmp = pp_list(pc->expr_count, "()", ", ");
Packit Service f629e6
			else {
Packit Service f629e6
				tmp = pp_list(pc->expr_count, "  ", ", ");
Packit Service f629e6
				tmp[strlen(tmp) - 1] = '\0';	/* remove trailing space */
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			if (pc->redir_type != 0) {
Packit Service f629e6
				t1 = pp_pop();
Packit Service f629e6
				if (is_binary(t1->type))
Packit Service f629e6
					pp_parenthesize(t1);
Packit Service f629e6
				fprintf(prof_fp, "%s%s%s%s", op2str(pc->opcode),
Packit Service f629e6
							tmp, redir2str(pc->redir_type), t1->pp_str);
Packit Service f629e6
				pp_free(t1);
Packit Service f629e6
			} else
Packit Service f629e6
				fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
Packit Service f629e6
			efree(tmp);
Packit Service f629e6
			if ((flags & IN_FOR_HEADER) == 0)
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_push_re:
Packit Service f629e6
			if (pc->memory->type != Node_regex && (pc->memory->flags & REGEX) == 0)
Packit Service f629e6
				break;
Packit Service f629e6
			/* else
Packit Service f629e6
				fall through */
Packit Service f629e6
		case Op_match_rec:
Packit Service f629e6
		{
Packit Service f629e6
			if (pc->memory->type == Node_regex) {
Packit Service f629e6
				NODE *re = pc->memory->re_exp;
Packit Service f629e6
				str = pp_string(re->stptr, re->stlen, '/');
Packit Service f629e6
			} else {
Packit Service f629e6
				assert((pc->memory->flags & REGEX) != 0);
Packit Service f629e6
				str = pp_typed_regex(pc->memory->stptr, pc->memory->stlen, '/');
Packit Service f629e6
			}
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_nomatch:
Packit Service f629e6
		case Op_match:
Packit Service f629e6
		{
Packit Service f629e6
			char *restr, *txt;
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			if (is_binary(t1->type))
Packit Service f629e6
				pp_parenthesize(t1);
Packit Service f629e6
			txt = t1->pp_str;
Packit Service f629e6
			m = pc->memory;
Packit Service f629e6
			if (m->type == Node_dynregex) {
Packit Service f629e6
				restr = txt;
Packit Service f629e6
				t2 = pp_pop();
Packit Service f629e6
				if (is_binary(t2->type))
Packit Service f629e6
					pp_parenthesize(t2);
Packit Service f629e6
				txt = t2->pp_str;
Packit Service f629e6
				str = pp_group3(txt, op2str(pc->opcode), restr);
Packit Service f629e6
				pp_free(t2);
Packit Service f629e6
			} else if (m->type == Node_val && (m->flags & REGEX) != 0) {
Packit Service f629e6
				restr = pp_typed_regex(m->stptr, m->stlen, '/');
Packit Service f629e6
				str = pp_group3(txt, op2str(pc->opcode), restr);
Packit Service f629e6
				efree(restr);
Packit Service f629e6
			} else {
Packit Service f629e6
				NODE *re = m->re_exp;
Packit Service f629e6
				restr = pp_string(re->stptr, re->stlen, '/');
Packit Service f629e6
				str = pp_group3(txt, op2str(pc->opcode), restr);
Packit Service f629e6
				efree(restr);
Packit Service f629e6
			}
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_getline:
Packit Service f629e6
		case Op_K_getline_redir:
Packit Service f629e6
			if (pc->into_var) {
Packit Service f629e6
				t1 = pp_pop();
Packit Service f629e6
				tmp = pp_group3(op2str(Op_K_getline), " ", t1->pp_str);
Packit Service f629e6
				pp_free(t1);
Packit Service f629e6
			} else
Packit Service f629e6
				tmp = pp_group3(op2str(Op_K_getline), "", "");
Packit Service f629e6
Packit Service f629e6
			if (pc->redir_type != 0) {
Packit Service f629e6
				int before = (pc->redir_type == redirect_pipein
Packit Service f629e6
							|| pc->redir_type == redirect_twoway);
Packit Service f629e6
Packit Service f629e6
				t2 = pp_pop();
Packit Service f629e6
				if (is_binary(t2->type))
Packit Service f629e6
					pp_parenthesize(t2);
Packit Service f629e6
				if (before)
Packit Service f629e6
					str = pp_group3(t2->pp_str, redir2str(pc->redir_type), tmp);
Packit Service f629e6
				else
Packit Service f629e6
					str = pp_group3(tmp, redir2str(pc->redir_type), t2->pp_str);
Packit Service f629e6
				efree(tmp);
Packit Service f629e6
				pp_free(t2);
Packit Service f629e6
			} else
Packit Service f629e6
				str = tmp;
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_indirect_func_call:
Packit Service f629e6
		case Op_func_call:
Packit Service f629e6
		{
Packit Service f629e6
			char *fname = pc->func_name;
Packit Service f629e6
			char *pre;
Packit Service f629e6
 			int pcount;
Packit Service f629e6
Packit Service f629e6
			if (pc->opcode == Op_indirect_func_call)
Packit Service f629e6
				pre = "@";
Packit Service f629e6
			else
Packit Service f629e6
				pre = "";
Packit Service f629e6
			pcount = (pc + 1)->expr_count;
Packit Service f629e6
			if (pcount > 0) {
Packit Service f629e6
				tmp = pp_list(pcount, "()", ", ");
Packit Service f629e6
				str = pp_group3(pre, fname, tmp);
Packit Service f629e6
				efree(tmp);
Packit Service f629e6
			} else
Packit Service f629e6
				str = pp_group3(pre, fname, "()");
Packit Service f629e6
			if (pc->opcode == Op_indirect_func_call) {
Packit Service f629e6
				t1 = pp_pop();	/* indirect var */
Packit Service f629e6
				pp_free(t1);
Packit Service f629e6
			}
Packit Service f629e6
			pp_push(pc->opcode, str, CAN_FREE);
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_continue:
Packit Service f629e6
		case Op_K_break:
Packit Service f629e6
		case Op_K_nextfile:
Packit Service f629e6
		case Op_K_next:
Packit Service f629e6
			fprintf(prof_fp, "%s", op2str(pc->opcode));
Packit Service f629e6
			pc = end_line(pc);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_return:
Packit Service f629e6
		case Op_K_exit:
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			if (is_binary(t1->type))
Packit Service f629e6
				pp_parenthesize(t1);
Packit Service f629e6
			if (pc->source_line > 0) {	/* don't print implicit 'return' at end of function */
Packit Service f629e6
				fprintf(prof_fp, "%s %s", op2str(pc->opcode), t1->pp_str);
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
			}
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_pop:
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			fprintf(prof_fp, "%s", t1->pp_str);
Packit Service f629e6
			if ((flags & IN_FOR_HEADER) == 0)
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_line_range:
Packit Service f629e6
			ip1 = pc + 1;
Packit Service f629e6
			pprint(pc->nexti, ip1->condpair_left, NO_PPRINT_FLAGS);
Packit Service f629e6
			pprint(ip1->condpair_left->nexti, ip1->condpair_right, NO_PPRINT_FLAGS);
Packit Service f629e6
			t2 = pp_pop();
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			str = pp_group3(t1->pp_str, ", ", t2->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pp_free(t2);
Packit Service f629e6
			pp_push(Op_line_range, str, CAN_FREE);
Packit Service f629e6
			pc = ip1->condpair_right;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_while:
Packit Service f629e6
			ip1 = pc + 1;
Packit Service f629e6
			indent(ip1->while_body->exec_count);
Packit Service f629e6
			fprintf(prof_fp, "%s (", op2str(pc->opcode));
Packit Service f629e6
			pprint(pc->nexti, ip1->while_body, NO_PPRINT_FLAGS);
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			fprintf(prof_fp, "%s) {", t1->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			ip1->while_body = end_line(ip1->while_body);
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pprint(ip1->while_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			indent(SPACEOVER);
Packit Service f629e6
			fprintf(prof_fp, "}");
Packit Service f629e6
			pc = end_line(pc->target_break);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_do:
Packit Service f629e6
			ip1 = pc + 1;
Packit Service f629e6
			indent(pc->nexti->exec_count);
Packit Service f629e6
			fprintf(prof_fp, "%s {", op2str(pc->opcode));
Packit Service f629e6
			end_line(pc->nexti);
Packit Service f629e6
			skip_comment = true;
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pprint(pc->nexti->nexti, ip1->doloop_cond, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			pprint(ip1->doloop_cond, pc->target_break, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent(SPACEOVER);
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			fprintf(prof_fp, "} %s (%s)", op2str(Op_K_while), t1->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			end_line(pc->target_break);
Packit Service f629e6
			skip_comment = true;
Packit Service f629e6
			pc = pc->target_break;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_for:
Packit Service f629e6
			ip1 = pc + 1;
Packit Service f629e6
			indent(ip1->forloop_body->exec_count);
Packit Service f629e6
			fprintf(prof_fp, "%s (", op2str(pc->opcode));
Packit Service f629e6
Packit Service f629e6
			/* If empty for looop header, print it a little more nicely. */
Packit Service f629e6
			if (   pc->nexti->opcode == Op_no_op
Packit Service f629e6
			    && ip1->forloop_cond == pc->nexti
Packit Service f629e6
			    && pc->target_continue->opcode == Op_jmp) {
Packit Service f629e6
				fprintf(prof_fp, ";;");
Packit Service f629e6
			} else {
Packit Service f629e6
				pprint(pc->nexti, ip1->forloop_cond, IN_FOR_HEADER);
Packit Service f629e6
				fprintf(prof_fp, "; ");
Packit Service f629e6
Packit Service f629e6
				if (ip1->forloop_cond->opcode == Op_no_op &&
Packit Service f629e6
						ip1->forloop_cond->nexti == ip1->forloop_body)
Packit Service f629e6
					fprintf(prof_fp, "; ");
Packit Service f629e6
				else {
Packit Service f629e6
					pprint(ip1->forloop_cond, ip1->forloop_body, IN_FOR_HEADER);
Packit Service f629e6
					t1 = pp_pop();
Packit Service f629e6
					fprintf(prof_fp, "%s; ", t1->pp_str);
Packit Service f629e6
					pp_free(t1);
Packit Service f629e6
				}
Packit Service f629e6
Packit Service f629e6
				pprint(pc->target_continue, pc->target_break, IN_FOR_HEADER);
Packit Service f629e6
			}
Packit Service f629e6
			fprintf(prof_fp, ") {");
Packit Service f629e6
			end_line(ip1->forloop_body);
Packit Service f629e6
			skip_comment = true;
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pprint(ip1->forloop_body->nexti, pc->target_continue, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			indent(SPACEOVER);
Packit Service f629e6
			fprintf(prof_fp, "}");
Packit Service f629e6
			end_line(pc->target_break);
Packit Service f629e6
			skip_comment = true;
Packit Service f629e6
			pc = pc->target_break;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_arrayfor:
Packit Service f629e6
		{
Packit Service f629e6
			char *array;
Packit Service f629e6
			const char *item;
Packit Service f629e6
Packit Service f629e6
			ip1 = pc + 1;
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			array = t1->pp_str;
Packit Service f629e6
			m = ip1->forloop_cond->array_var;
Packit Service f629e6
			if (m->type == Node_param_list)
Packit Service f629e6
				item = func_params[m->param_cnt].param;
Packit Service f629e6
			else
Packit Service f629e6
				item = m->vname;
Packit Service f629e6
			indent(ip1->forloop_body->exec_count);
Packit Service f629e6
			fprintf(prof_fp, "%s (%s%s%s) {", op2str(Op_K_arrayfor),
Packit Service f629e6
						item, op2str(Op_in_array), array);
Packit Service f629e6
			end_line(ip1->forloop_body);
Packit Service f629e6
			skip_comment = true;
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pprint(ip1->forloop_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			indent(SPACEOVER);
Packit Service f629e6
			fprintf(prof_fp, "}");
Packit Service f629e6
			end_line(pc->target_break);
Packit Service f629e6
			skip_comment = true;
Packit Service f629e6
			pc = pc->target_break;
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_switch:
Packit Service f629e6
			ip1 = pc + 1;
Packit Service f629e6
			fprintf(prof_fp, "%s (", op2str(pc->opcode));
Packit Service f629e6
			pprint(pc->nexti, ip1->switch_start, NO_PPRINT_FLAGS);
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			fprintf(prof_fp, "%s) {\n", t1->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
			pprint(ip1->switch_start, ip1->switch_end, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent(SPACEOVER);
Packit Service f629e6
			fprintf(prof_fp, "}\n");
Packit Service f629e6
			pc = pc->target_break;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_case:
Packit Service f629e6
		case Op_K_default:
Packit Service f629e6
			indent(pc->stmt_start->exec_count);
Packit Service f629e6
			if (pc->opcode == Op_K_case) {
Packit Service f629e6
				t1 = pp_pop();
Packit Service f629e6
				fprintf(prof_fp, "%s %s:", op2str(pc->opcode), t1->pp_str);
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
				pp_free(t1);
Packit Service f629e6
			} else {
Packit Service f629e6
				fprintf(prof_fp, "%s:", op2str(pc->opcode));
Packit Service f629e6
				pc = end_line(pc);
Packit Service f629e6
			}
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_if:
Packit Service f629e6
			fprintf(prof_fp, "%s (", op2str(pc->opcode));
Packit Service f629e6
			pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS);
Packit Service f629e6
			t1 = pp_pop();
Packit Service f629e6
			fprintf(prof_fp, "%s) {", t1->pp_str);
Packit Service f629e6
			pp_free(t1);
Packit Service f629e6
Packit Service f629e6
			ip1 = pc->branch_if;
Packit Service f629e6
			if (ip1->exec_count > 0)
Packit Service f629e6
				fprintf(prof_fp, " # %ld", ip1->exec_count);
Packit Service f629e6
			ip1 = end_line(ip1);
Packit Service f629e6
			indent_in();
Packit Service f629e6
			pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS);
Packit Service f629e6
			indent_out();
Packit Service f629e6
			pc = pc->branch_else;
Packit Service f629e6
			if (pc->nexti->opcode == Op_no_op) {	/* no following else */
Packit Service f629e6
				indent(SPACEOVER);
Packit Service f629e6
				fprintf(prof_fp, "}");
Packit Service f629e6
				if (pc->nexti->nexti->opcode != Op_comment
Packit Service f629e6
				    || pc->nexti->nexti->memory->comment_type == FULL_COMMENT)
Packit Service f629e6
					fprintf(prof_fp, "\n");
Packit Service f629e6
				/* else
Packit Service f629e6
				 	It will be printed at the top. */
Packit Service f629e6
			}
Packit Service f629e6
			/*
Packit Service f629e6
			 * See next case; turn off the flag so that the
Packit Service f629e6
			 * following else is correctly indented.
Packit Service f629e6
			 */
Packit Service f629e6
			flags &= ~IN_ELSE_IF;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_K_else:
Packit Service f629e6
			/*
Packit Service f629e6
			 * If possible, chain else-if's together on the
Packit Service f629e6
			 * same line.
Packit Service f629e6
			 *
Packit Service f629e6
			 * See awkgram.y:mk_condition to understand
Packit Service f629e6
			 * what is being checked here.
Packit Service f629e6
			 *
Packit Service f629e6
			 * Op_exec_count follows Op_K_else, check the
Packit Service f629e6
			 * opcode of the following instruction.
Packit Service f629e6
			 * Additionally, check that the subsequent if
Packit Service f629e6
			 * terminates where this else does; in that case
Packit Service f629e6
			 * it's ok to compact the if to follow the else.
Packit Service f629e6
			 */
Packit Service f629e6
Packit Service f629e6
			fprintf(prof_fp, "} %s ", op2str(pc->opcode));
Packit Service f629e6
			if (pc->nexti->nexti->opcode == Op_K_if
Packit Service f629e6
			    && pc->branch_end == pc->nexti->nexti->branch_else->lasti) {
Packit Service f629e6
				pprint(pc->nexti, pc->branch_end, IN_ELSE_IF);
Packit Service f629e6
			} else {
Packit Service f629e6
				fprintf(prof_fp, "{");
Packit Service f629e6
				end_line(pc);
Packit Service f629e6
				skip_comment = true;
Packit Service f629e6
				indent_in();
Packit Service f629e6
				pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
Packit Service f629e6
				indent_out();
Packit Service f629e6
				indent(SPACEOVER);
Packit Service f629e6
				fprintf(prof_fp, "}");
Packit Service f629e6
				end_line(pc->branch_end);
Packit Service f629e6
				skip_comment = true;
Packit Service f629e6
			}
Packit Service f629e6
			/*
Packit Service f629e6
			 * Don't do end_line() here, we get multiple blank lines after
Packit Service f629e6
			 * the final else in a chain of else-ifs since they all point
Packit Service f629e6
			 * to the same branch_end.
Packit Service f629e6
			 */
Packit Service f629e6
			pc = pc->branch_end;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_cond_exp:
Packit Service f629e6
		{
Packit Service f629e6
			NODE *f, *t, *cond;
Packit Service f629e6
			size_t len;
Packit Service f629e6
Packit Service f629e6
			pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS);
Packit Service f629e6
			ip1 = pc->branch_if;
Packit Service f629e6
			pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS);
Packit Service f629e6
			ip1 = pc->branch_else->nexti;
Packit Service f629e6
Packit Service f629e6
			pc = ip1->nexti;
Packit Service f629e6
			assert(pc->opcode == Op_cond_exp);
Packit Service f629e6
			pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
Packit Service f629e6
Packit Service f629e6
			f = pp_pop();
Packit Service f629e6
			t = pp_pop();
Packit Service f629e6
			cond = pp_pop();
Packit Service f629e6
Packit Service f629e6
			len =  f->pp_len + t->pp_len + cond->pp_len + 12;
Packit Service f629e6
			emalloc(str, char *, len, "pprint");
Packit Service f629e6
			sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str);
Packit Service f629e6
Packit Service f629e6
			pp_free(cond);
Packit Service f629e6
			pp_free(t);
Packit Service f629e6
			pp_free(f);
Packit Service f629e6
			pp_push(Op_cond_exp, str, CAN_FREE);
Packit Service f629e6
			pc = pc->branch_end;
Packit Service f629e6
		}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_exec_count:
Packit Service f629e6
			if (flags == NO_PPRINT_FLAGS)
Packit Service f629e6
				indent(pc->exec_count);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_comment:
Packit Service f629e6
			print_comment(pc, 0);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case Op_list:
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		default:
Packit Service f629e6
			cant_happen();
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		if (pc == endp)
Packit Service f629e6
			break;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* end_line --- end pretty print line with new line or on-line comment  */
Packit Service f629e6
Packit Service f629e6
INSTRUCTION *
Packit Service f629e6
end_line(INSTRUCTION *ip)
Packit Service f629e6
{
Packit Service f629e6
	INSTRUCTION *ret = ip;
Packit Service f629e6
Packit Service f629e6
	if (ip->nexti->opcode == Op_comment
Packit Service f629e6
	    && ip->nexti->memory->comment_type == EOL_COMMENT) {
Packit Service f629e6
		fprintf(prof_fp, "\t");
Packit Service f629e6
		print_comment(ip->nexti, -1);
Packit Service f629e6
		ret = ip->nexti;
Packit Service f629e6
	}
Packit Service f629e6
	else
Packit Service f629e6
		fprintf(prof_fp, "\n");
Packit Service f629e6
Packit Service f629e6
	return ret;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_string_fp --- printy print a string to the fp */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * This routine concentrates string pretty printing in one place,
Packit Service f629e6
 * so that it can be called from multiple places within gawk.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
Packit Service f629e6
		size_t len, int delim, bool breaklines)
Packit Service f629e6
{
Packit Service f629e6
	char *s = pp_string(in_str, len, delim);
Packit Service f629e6
	int count;
Packit Service f629e6
	size_t slen;
Packit Service f629e6
	const char *str = (const char *) s;
Packit Service f629e6
#define BREAKPOINT	70 /* arbitrary */
Packit Service f629e6
Packit Service f629e6
	slen = strlen(str);
Packit Service f629e6
	for (count = 0; slen > 0; slen--, str++) {
Packit Service f629e6
		print_func(fp, "%c", *str);
Packit Service f629e6
		if (++count >= BREAKPOINT && breaklines) {
Packit Service f629e6
			print_func(fp, "%c\n%c", delim, delim);
Packit Service f629e6
			count = 0;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	efree(s);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* just_dump --- dump the profile and function stack and keep going */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
just_dump(int signum)
Packit Service f629e6
{
Packit Service f629e6
	extern INSTRUCTION *code_block;
Packit Service f629e6
Packit Service f629e6
	dump_prog(code_block);
Packit Service f629e6
	dump_funcs();
Packit Service f629e6
	dump_fcall_stack(prof_fp);
Packit Service f629e6
	fflush(prof_fp);
Packit Service f629e6
	signal(signum, just_dump);	/* for OLD Unix systems ... */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* dump_and_exit --- dump the profile, the function stack, and exit */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
dump_and_exit(int signum)
Packit Service f629e6
{
Packit Service f629e6
	just_dump(signum);
Packit Service f629e6
	final_exit(EXIT_FAILURE);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* print_lib_list --- print a list of all libraries loaded */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
print_lib_list(FILE *prof_fp)
Packit Service f629e6
{
Packit Service f629e6
	SRCFILE *s;
Packit Service f629e6
	static bool printed_header = false;
Packit Service f629e6
Packit Service f629e6
	for (s = srcfiles->next; s != srcfiles; s = s->next) {
Packit Service f629e6
		if (s->stype == SRC_EXTLIB) {
Packit Service f629e6
			if (! printed_header) {
Packit Service f629e6
				printed_header = true;
Packit Service f629e6
				fprintf(prof_fp, _("\t# Loaded extensions (-l and/or @load)\n\n"));
Packit Service f629e6
			}
Packit Service f629e6
			fprintf(prof_fp, "\t@load \"%s\"\n", s->src);
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	if (printed_header)	/* we found some */
Packit Service f629e6
		fprintf(prof_fp, "\n");
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* print_comment --- print comment text with proper indentation */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
print_comment(INSTRUCTION* pc, long in)
Packit Service f629e6
{
Packit Service f629e6
	char *text;
Packit Service f629e6
	size_t count;
Packit Service f629e6
	bool after_newline = false;
Packit Service f629e6
Packit Service f629e6
	count = pc->memory->stlen;
Packit Service f629e6
	text = pc->memory->stptr;
Packit Service f629e6
Packit Service f629e6
	if (in >= 0)
Packit Service f629e6
		indent(in);    /* is this correct? Where should comments go?  */
Packit Service f629e6
	for (; count > 0; count--, text++) {
Packit Service f629e6
		if (after_newline) {
Packit Service f629e6
			indent(in);
Packit Service f629e6
			after_newline = false;
Packit Service f629e6
		}
Packit Service f629e6
		putc(*text, prof_fp);
Packit Service f629e6
		if (*text == '\n')
Packit Service f629e6
			after_newline = true;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* dump_prog --- dump the program */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * XXX: I am not sure it is right to have the strings in the dump
Packit Service f629e6
 * be translated, but I'll leave it alone for now.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
dump_prog(INSTRUCTION *code)
Packit Service f629e6
{
Packit Service f629e6
	time_t now;
Packit Service f629e6
Packit Service f629e6
	(void) time(& now);
Packit Service f629e6
	/* \n on purpose, with \n in ctime() output */
Packit Service f629e6
	if (do_profile)
Packit Service f629e6
		fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
Packit Service f629e6
	print_lib_list(prof_fp);
Packit Service f629e6
	pprint(code, NULL, NO_PPRINT_FLAGS);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* prec_level --- return the precedence of an operator, for paren tests */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
prec_level(int type)
Packit Service f629e6
{
Packit Service f629e6
	switch (type) {
Packit Service f629e6
	case Op_push_lhs:
Packit Service f629e6
	case Op_push_param:
Packit Service f629e6
	case Op_push_array:
Packit Service f629e6
	case Op_push:
Packit Service f629e6
	case Op_push_i:
Packit Service f629e6
	case Op_push_re:
Packit Service f629e6
	case Op_match_rec:
Packit Service f629e6
	case Op_subscript:
Packit Service f629e6
	case Op_subscript_lhs:
Packit Service f629e6
	case Op_func_call:
Packit Service f629e6
	case Op_K_delete_loop:
Packit Service f629e6
	case Op_builtin:
Packit Service f629e6
		return 16;
Packit Service f629e6
Packit Service f629e6
	case Op_field_spec:
Packit Service f629e6
	case Op_field_spec_lhs:
Packit Service f629e6
		return 15;
Packit Service f629e6
Packit Service f629e6
	case Op_preincrement:
Packit Service f629e6
	case Op_predecrement:
Packit Service f629e6
	case Op_postincrement:
Packit Service f629e6
	case Op_postdecrement:
Packit Service f629e6
		return 14;
Packit Service f629e6
Packit Service f629e6
	case Op_exp:
Packit Service f629e6
	case Op_exp_i:
Packit Service f629e6
		return 13;
Packit Service f629e6
Packit Service f629e6
	case Op_unary_minus:
Packit Service f629e6
	case Op_unary_plus:
Packit Service f629e6
	case Op_not:
Packit Service f629e6
		return 12;
Packit Service f629e6
Packit Service f629e6
	case Op_times:
Packit Service f629e6
	case Op_times_i:
Packit Service f629e6
	case Op_quotient:
Packit Service f629e6
	case Op_quotient_i:
Packit Service f629e6
	case Op_mod:
Packit Service f629e6
	case Op_mod_i:
Packit Service f629e6
		return 11;
Packit Service f629e6
Packit Service f629e6
	case Op_plus:
Packit Service f629e6
	case Op_plus_i:
Packit Service f629e6
	case Op_minus:
Packit Service f629e6
	case Op_minus_i:
Packit Service f629e6
		return 10;
Packit Service f629e6
Packit Service f629e6
	case Op_concat:
Packit Service f629e6
	case Op_assign_concat:
Packit Service f629e6
		return 9;
Packit Service f629e6
Packit Service f629e6
	case Op_equal:
Packit Service f629e6
	case Op_notequal:
Packit Service f629e6
	case Op_greater:
Packit Service f629e6
	case Op_less:
Packit Service f629e6
	case Op_leq:
Packit Service f629e6
	case Op_geq:
Packit Service f629e6
		return 8;
Packit Service f629e6
Packit Service f629e6
	case Op_match:
Packit Service f629e6
	case Op_nomatch:
Packit Service f629e6
		return 7;
Packit Service f629e6
Packit Service f629e6
	case Op_K_getline:
Packit Service f629e6
	case Op_K_getline_redir:
Packit Service f629e6
		return 6;
Packit Service f629e6
Packit Service f629e6
	case Op_in_array:
Packit Service f629e6
		return 5;
Packit Service f629e6
Packit Service f629e6
	case Op_and:
Packit Service f629e6
		return 4;
Packit Service f629e6
Packit Service f629e6
	case Op_or:
Packit Service f629e6
		return 3;
Packit Service f629e6
Packit Service f629e6
	case Op_cond_exp:
Packit Service f629e6
		return 2;
Packit Service f629e6
Packit Service f629e6
	case Op_assign:
Packit Service f629e6
	case Op_assign_times:
Packit Service f629e6
	case Op_assign_quotient:
Packit Service f629e6
	case Op_assign_mod:
Packit Service f629e6
	case Op_assign_plus:
Packit Service f629e6
	case Op_assign_minus:
Packit Service f629e6
	case Op_assign_exp:
Packit Service f629e6
		return 1;
Packit Service f629e6
Packit Service f629e6
	default:
Packit Service f629e6
		return 0;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* is_scalar --- return true if scalar, false otherwise */
Packit Service f629e6
Packit Service f629e6
static bool
Packit Service f629e6
is_scalar(int type)
Packit Service f629e6
{
Packit Service f629e6
	switch (type) {
Packit Service f629e6
	case Op_push_lhs:
Packit Service f629e6
	case Op_push_param:
Packit Service f629e6
	case Op_push_array:
Packit Service f629e6
	case Op_push:
Packit Service f629e6
	case Op_push_i:
Packit Service f629e6
	case Op_push_re:
Packit Service f629e6
	case Op_subscript:
Packit Service f629e6
	case Op_subscript_lhs:
Packit Service f629e6
	case Op_func_call:
Packit Service f629e6
	case Op_builtin:
Packit Service f629e6
	case Op_field_spec:
Packit Service f629e6
	case Op_field_spec_lhs:
Packit Service f629e6
	case Op_preincrement:
Packit Service f629e6
	case Op_predecrement:
Packit Service f629e6
	case Op_postincrement:
Packit Service f629e6
	case Op_postdecrement:
Packit Service f629e6
	case Op_unary_minus:
Packit Service f629e6
	case Op_unary_plus:
Packit Service f629e6
	case Op_not:
Packit Service f629e6
		return true;
Packit Service f629e6
Packit Service f629e6
	default:
Packit Service f629e6
		return false;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* is_binary --- return true if type represents a binary operator */
Packit Service f629e6
Packit Service f629e6
static bool
Packit Service f629e6
is_binary(int type)
Packit Service f629e6
{
Packit Service f629e6
	switch (type) {
Packit Service f629e6
	case Op_geq:
Packit Service f629e6
	case Op_leq:
Packit Service f629e6
	case Op_greater:
Packit Service f629e6
	case Op_less:
Packit Service f629e6
	case Op_notequal:
Packit Service f629e6
	case Op_equal:
Packit Service f629e6
	case Op_exp:
Packit Service f629e6
	case Op_times:
Packit Service f629e6
	case Op_quotient:
Packit Service f629e6
	case Op_mod:
Packit Service f629e6
	case Op_plus:
Packit Service f629e6
	case Op_minus:
Packit Service f629e6
	case Op_exp_i:
Packit Service f629e6
	case Op_times_i:
Packit Service f629e6
	case Op_quotient_i:
Packit Service f629e6
	case Op_mod_i:
Packit Service f629e6
	case Op_plus_i:
Packit Service f629e6
	case Op_minus_i:
Packit Service f629e6
	case Op_concat:
Packit Service f629e6
	case Op_assign_concat:
Packit Service f629e6
	case Op_match:
Packit Service f629e6
	case Op_nomatch:
Packit Service f629e6
	case Op_assign:
Packit Service f629e6
	case Op_assign_times:
Packit Service f629e6
	case Op_assign_quotient:
Packit Service f629e6
	case Op_assign_mod:
Packit Service f629e6
	case Op_assign_plus:
Packit Service f629e6
	case Op_assign_minus:
Packit Service f629e6
	case Op_assign_exp:
Packit Service f629e6
	case Op_cond_exp:
Packit Service f629e6
	case Op_and:
Packit Service f629e6
	case Op_or:
Packit Service f629e6
	case Op_in_array:
Packit Service f629e6
	case Op_K_getline_redir:	/* sometimes */
Packit Service f629e6
	case Op_K_getline:
Packit Service f629e6
		return true;
Packit Service f629e6
Packit Service f629e6
	default:
Packit Service f629e6
		return false;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_parenthesize --- parenthesize an expression in stack */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
pp_parenthesize(NODE *sp)
Packit Service f629e6
{
Packit Service f629e6
	char *p = sp->pp_str;
Packit Service f629e6
	size_t len = sp->pp_len;
Packit Service f629e6
Packit Service f629e6
	if (p[0] == '(')	// already parenthesized
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	emalloc(p, char *, len + 3, "pp_parenthesize");
Packit Service f629e6
	*p = '(';
Packit Service f629e6
	memcpy(p + 1, sp->pp_str, len);
Packit Service f629e6
	p[len + 1] = ')';
Packit Service f629e6
	p[len + 2] = '\0';
Packit Service f629e6
	if ((sp->flags & CAN_FREE) != 0)
Packit Service f629e6
		efree(sp->pp_str);
Packit Service f629e6
	sp->pp_str = p;
Packit Service f629e6
	sp->pp_len += 2;
Packit Service f629e6
	sp->flags |= CAN_FREE;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* parenthesize --- parenthesize two nodes relative to parent node type */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
parenthesize(int type, NODE *left, NODE *right)
Packit Service f629e6
{
Packit Service f629e6
	int rprec = prec_level(right->type);
Packit Service f629e6
	int lprec = prec_level(left->type);
Packit Service f629e6
	int prec = prec_level(type);
Packit Service f629e6
Packit Service f629e6
	if (lprec < prec)
Packit Service f629e6
		pp_parenthesize(left);
Packit Service f629e6
	if (rprec < prec)
Packit Service f629e6
		pp_parenthesize(right);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_string --- pretty format a string or regular regex constant */
Packit Service f629e6
Packit Service f629e6
char *
Packit Service f629e6
pp_string(const char *in_str, size_t len, int delim)
Packit Service f629e6
{
Packit Service f629e6
	return pp_string_or_typed_regex(in_str, len, delim, false);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_typed_regex --- pretty format a hard regex constant */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
pp_typed_regex(const char *in_str, size_t len, int delim)
Packit Service f629e6
{
Packit Service f629e6
	return pp_string_or_typed_regex(in_str, len, delim, true);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_string_or_typed_regex --- pretty format a string, regex, or typed regex constant */
Packit Service f629e6
Packit Service f629e6
char *
Packit Service f629e6
pp_string_or_typed_regex(const char *in_str, size_t len, int delim, bool typed_regex)
Packit Service f629e6
{
Packit Service f629e6
	static char str_escapes[] = "\a\b\f\n\r\t\v\\";
Packit Service f629e6
	static char str_printables[] = "abfnrtv\\";
Packit Service f629e6
	static char re_escapes[] = "\a\b\f\n\r\t\v";
Packit Service f629e6
	static char re_printables[] = "abfnrtv";
Packit Service f629e6
	char *escapes;
Packit Service f629e6
	char *printables;
Packit Service f629e6
	char *cp;
Packit Service f629e6
	int i;
Packit Service f629e6
	const unsigned char *str = (const unsigned char *) in_str;
Packit Service f629e6
	size_t ofre, osiz;
Packit Service f629e6
	char *obuf, *obufout;
Packit Service f629e6
Packit Service f629e6
	assert(delim == '"' || delim == '/');
Packit Service f629e6
Packit Service f629e6
	if (delim == '/') {
Packit Service f629e6
		escapes = re_escapes;
Packit Service f629e6
		printables = re_printables;
Packit Service f629e6
	} else {
Packit Service f629e6
		escapes = str_escapes;
Packit Service f629e6
		printables = str_printables;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
/* make space for something l big in the buffer */
Packit Service f629e6
#define chksize(l)  if ((l) > ofre) { \
Packit Service f629e6
		long olen = obufout - obuf; \
Packit Service f629e6
		erealloc(obuf, char *, osiz * 2, "pp_string"); \
Packit Service f629e6
		obufout = obuf + olen; \
Packit Service f629e6
		ofre += osiz; \
Packit Service f629e6
		osiz *= 2; \
Packit Service f629e6
	} ofre -= (l)
Packit Service f629e6
Packit Service f629e6
	/* initial size; 3 for delim + terminating null, 1 for @ */
Packit Service f629e6
	osiz = len + 3 + 1 + (typed_regex == true);
Packit Service f629e6
	emalloc(obuf, char *, osiz, "pp_string");
Packit Service f629e6
	obufout = obuf;
Packit Service f629e6
	ofre = osiz - 1;
Packit Service f629e6
Packit Service f629e6
	if (typed_regex)
Packit Service f629e6
		*obufout++ = '@';
Packit Service f629e6
Packit Service f629e6
	*obufout++ = delim;
Packit Service f629e6
	for (; len > 0; len--, str++) {
Packit Service f629e6
		chksize(2);		/* make space for 2 chars */
Packit Service f629e6
		if (delim != '/' && *str == delim) {
Packit Service f629e6
			*obufout++ = '\\';
Packit Service f629e6
			*obufout++ = delim;
Packit Service f629e6
		} else if (*str == '\0') {
Packit Service f629e6
			*obufout++ = '\\';
Packit Service f629e6
			*obufout++ = '0';
Packit Service f629e6
			chksize(2);	/* need 2 more chars for this case */
Packit Service f629e6
			*obufout++ = '0';
Packit Service f629e6
			*obufout++ = '0';
Packit Service f629e6
		} else if ((cp = strchr(escapes, *str)) != NULL) {
Packit Service f629e6
			i = cp - escapes;
Packit Service f629e6
			*obufout++ = '\\';
Packit Service f629e6
			*obufout++ = printables[i];
Packit Service f629e6
		/* NB: Deliberate use of lower-case versions. */
Packit Service f629e6
		} else if (isascii(*str) && isprint(*str)) {
Packit Service f629e6
			*obufout++ = *str;
Packit Service f629e6
			ofre += 1;	/* used 1 less than expected */
Packit Service f629e6
		} else {
Packit Service f629e6
			size_t len;
Packit Service f629e6
Packit Service f629e6
			chksize(8);		/* total available space is 10 */
Packit Service f629e6
Packit Service f629e6
			sprintf(obufout, "\\%03o", *str & 0xff);
Packit Service f629e6
			len = strlen(obufout);
Packit Service f629e6
			ofre += (10 - len);	 /* adjust free space count */
Packit Service f629e6
			obufout += len;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	chksize(2);
Packit Service f629e6
	*obufout++ = delim;
Packit Service f629e6
	*obufout = '\0';
Packit Service f629e6
	return obuf;
Packit Service f629e6
#undef chksize
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_number --- pretty format a number */
Packit Service f629e6
Packit Service f629e6
char *
Packit Service f629e6
pp_number(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	char *str;
Packit Service f629e6
Packit Service f629e6
	assert((n->flags & NUMCONSTSTR) != 0);
Packit Service f629e6
	emalloc(str, char *, n->stlen + 1, "pp_number");
Packit Service f629e6
	strcpy(str, n->stptr);
Packit Service f629e6
	return str;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_node --- pretty format a node */
Packit Service f629e6
Packit Service f629e6
char *
Packit Service f629e6
pp_node(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	if ((n->flags & NUMBER) != 0)
Packit Service f629e6
		return pp_number(n);
Packit Service f629e6
	return pp_string(n->stptr, n->stlen, '"');
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_list --- pretty print a list, with surrounding characters and separator */
Packit Service f629e6
Packit Service f629e6
static NODE **pp_args = NULL;
Packit Service f629e6
static int npp_args;
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
pp_list(int nargs, const char *paren, const char *delim)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
 	char *str, *s;
Packit Service f629e6
	size_t len;
Packit Service f629e6
	size_t delimlen;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	if (pp_args == NULL) {
Packit Service f629e6
		npp_args = nargs;
Packit Service f629e6
		emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
Packit Service f629e6
	} else if (nargs > npp_args) {
Packit Service f629e6
		npp_args = nargs;
Packit Service f629e6
		erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	delimlen = strlen(delim);
Packit Service f629e6
	if (nargs == 0)
Packit Service f629e6
		len = 2;
Packit Service f629e6
	else {
Packit Service f629e6
		len = -delimlen;
Packit Service f629e6
		for (i = 1; i <= nargs; i++) {
Packit Service f629e6
			r = pp_args[i] = pp_pop();
Packit Service f629e6
			len += r->pp_len + delimlen;
Packit Service f629e6
		}
Packit Service f629e6
		if (paren != NULL) {
Packit Service f629e6
			assert(strlen(paren) == 2);
Packit Service f629e6
			len += 2;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	emalloc(str, char *, len + 1, "pp_list");
Packit Service f629e6
	s = str;
Packit Service f629e6
	if (paren != NULL)
Packit Service f629e6
		*s++ = paren[0];
Packit Service f629e6
	if (nargs > 0) {
Packit Service f629e6
		r = pp_args[nargs];
Packit Service f629e6
		memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
		s += r->pp_len;
Packit Service f629e6
		pp_free(r);
Packit Service f629e6
		for (i = nargs - 1; i > 0; i--) {
Packit Service f629e6
			if (delimlen > 0) {
Packit Service f629e6
				memcpy(s, delim, delimlen);
Packit Service f629e6
				s += delimlen;
Packit Service f629e6
			}
Packit Service f629e6
			r = pp_args[i];
Packit Service f629e6
			memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
			s += r->pp_len;
Packit Service f629e6
			pp_free(r);
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	if (paren != NULL)
Packit Service f629e6
		*s++ = paren[1];
Packit Service f629e6
	*s = '\0';
Packit Service f629e6
	return str;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* is_unary_minus --- return true if string starts with unary minus */
Packit Service f629e6
Packit Service f629e6
static bool
Packit Service f629e6
is_unary_minus(const char *str)
Packit Service f629e6
{
Packit Service f629e6
	return str[0] == '-' && str[1] != '-';
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_concat --- handle concatenation and correct parenthesizing of expressions */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
pp_concat(int nargs)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
 	char *str, *s;
Packit Service f629e6
	size_t len;
Packit Service f629e6
	static const size_t delimlen = 1;	/* " " */
Packit Service f629e6
	int i;
Packit Service f629e6
	int pl_l, pl_r;
Packit Service f629e6
Packit Service f629e6
	if (pp_args == NULL) {
Packit Service f629e6
		npp_args = nargs;
Packit Service f629e6
		emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
Packit Service f629e6
	} else if (nargs > npp_args) {
Packit Service f629e6
		npp_args = nargs;
Packit Service f629e6
		erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * items are on the stack in reverse order that they
Packit Service f629e6
	 * will be printed to pop them off backwards.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	len = -delimlen;
Packit Service f629e6
	for (i = nargs; i >= 1; i--) {
Packit Service f629e6
		r = pp_args[i] = pp_pop();
Packit Service f629e6
		len += r->pp_len + delimlen + 2;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	emalloc(str, char *, len + 1, "pp_concat");
Packit Service f629e6
	s = str;
Packit Service f629e6
Packit Service f629e6
	/* now copy in */
Packit Service f629e6
	for (i = 1; i < nargs; i++) {
Packit Service f629e6
		r = pp_args[i];
Packit Service f629e6
Packit Service f629e6
		if (r->pp_str[0] != '(') {
Packit Service f629e6
			pl_l = prec_level(pp_args[i]->type);
Packit Service f629e6
			pl_r = prec_level(pp_args[i+1]->type);
Packit Service f629e6
Packit Service f629e6
			if (i >= 2 && is_unary_minus(r->pp_str)) {
Packit Service f629e6
				*s++ = '(';
Packit Service f629e6
				memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
				s += r->pp_len;
Packit Service f629e6
				*s++ = ')';
Packit Service f629e6
			} else if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) {
Packit Service f629e6
				memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
				s += r->pp_len;
Packit Service f629e6
			} else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) {
Packit Service f629e6
				*s++ = '(';
Packit Service f629e6
				memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
				s += r->pp_len;
Packit Service f629e6
				*s++ = ')';
Packit Service f629e6
			} else {
Packit Service f629e6
				memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
				s += r->pp_len;
Packit Service f629e6
			}
Packit Service f629e6
		} else {
Packit Service f629e6
			memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
			s += r->pp_len;
Packit Service f629e6
		}
Packit Service f629e6
		pp_free(r);
Packit Service f629e6
Packit Service f629e6
		if (i < nargs) {
Packit Service f629e6
			*s++ = ' ';
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	pl_l = prec_level(pp_args[nargs-1]->type);
Packit Service f629e6
	pl_r = prec_level(pp_args[nargs]->type);
Packit Service f629e6
	r = pp_args[nargs];
Packit Service f629e6
	if (r->pp_str[0] == '(') {
Packit Service f629e6
		memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
		s += r->pp_len;
Packit Service f629e6
	} else if (is_unary_minus(r->pp_str) || ((pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)))) {
Packit Service f629e6
		*s++ = '(';
Packit Service f629e6
		memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
		s += r->pp_len;
Packit Service f629e6
		*s++ = ')';
Packit Service f629e6
	} else {
Packit Service f629e6
		memcpy(s, r->pp_str, r->pp_len);
Packit Service f629e6
		s += r->pp_len;
Packit Service f629e6
	}
Packit Service f629e6
	pp_free(r);
Packit Service f629e6
Packit Service f629e6
	*s = '\0';
Packit Service f629e6
	return str;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_group3 --- string together up to 3 strings */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
pp_group3(const char *s1, const char *s2, const char *s3)
Packit Service f629e6
{
Packit Service f629e6
	size_t len1, len2, len3, l;
Packit Service f629e6
	char *str, *s;
Packit Service f629e6
Packit Service f629e6
	len1 = strlen(s1);
Packit Service f629e6
	len2 = strlen(s2);
Packit Service f629e6
	len3 = strlen(s3);
Packit Service f629e6
	l = len1 + len2 + len3 + 1;
Packit Service f629e6
	emalloc(str, char *, l, "pp_group3");
Packit Service f629e6
	s = str;
Packit Service f629e6
	if (len1 > 0) {
Packit Service f629e6
		memcpy(s, s1, len1);
Packit Service f629e6
		s += len1;
Packit Service f629e6
	}
Packit Service f629e6
	if (len2 > 0) {
Packit Service f629e6
		memcpy(s, s2, len2);
Packit Service f629e6
		s += len2;
Packit Service f629e6
	}
Packit Service f629e6
	if (len3 > 0) {
Packit Service f629e6
		memcpy(s, s3, len3);
Packit Service f629e6
		s += len3;
Packit Service f629e6
	}
Packit Service f629e6
	*s = '\0';
Packit Service f629e6
	return str;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pp_func --- pretty print a function */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
Packit Service f629e6
{
Packit Service f629e6
	int j;
Packit Service f629e6
	static bool first = true;
Packit Service f629e6
	NODE *func;
Packit Service f629e6
	int pcount;
Packit Service f629e6
	INSTRUCTION *fp;
Packit Service f629e6
Packit Service f629e6
	if (first) {
Packit Service f629e6
		first = false;
Packit Service f629e6
		if (do_profile)
Packit Service f629e6
			fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	fp = pc->nexti->nexti;
Packit Service f629e6
	func = pc->func_body;
Packit Service f629e6
	fprintf(prof_fp, "\n");
Packit Service f629e6
Packit Service f629e6
	/* print any function comment */
Packit Service f629e6
	if (fp->opcode == Op_comment && fp->source_line == 0) {
Packit Service f629e6
		print_comment(fp, -1);	/* -1 ==> don't indent */
Packit Service f629e6
		fp = fp->nexti;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	indent(pc->nexti->exec_count);
Packit Service f629e6
	fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname);
Packit Service f629e6
	pcount = func->param_cnt;
Packit Service f629e6
	func_params = func->fparms;
Packit Service f629e6
	for (j = 0; j < pcount; j++) {
Packit Service f629e6
		fprintf(prof_fp, "%s", func_params[j].param);
Packit Service f629e6
		if (j < pcount - 1)
Packit Service f629e6
			fprintf(prof_fp, ", ");
Packit Service f629e6
	}
Packit Service f629e6
	if (fp->opcode == Op_comment
Packit Service f629e6
		&& fp->memory->comment_type == EOL_COMMENT) {
Packit Service f629e6
		fprintf(prof_fp, ")");
Packit Service f629e6
		fp = end_line(fp);
Packit Service f629e6
	} else
Packit Service f629e6
		fprintf(prof_fp, ")\n");
Packit Service f629e6
	if (do_profile)
Packit Service f629e6
		indent(0);
Packit Service f629e6
	fprintf(prof_fp, "{\n");
Packit Service f629e6
	indent_in();
Packit Service f629e6
	pprint(fp, NULL, NO_PPRINT_FLAGS);	/* function body */
Packit Service f629e6
	indent_out();
Packit Service f629e6
	if (do_profile)
Packit Service f629e6
		indent(0);
Packit Service f629e6
	fprintf(prof_fp, "}\n");
Packit Service f629e6
	return 0;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* redir2str --- convert a redirection type into a printable value */
Packit Service f629e6
Packit Service f629e6
const char *
Packit Service f629e6
redir2str(int redirtype)
Packit Service f629e6
{
Packit Service f629e6
	static const char *const redirtab[] = {
Packit Service f629e6
		"",
Packit Service f629e6
		" > ",	/* redirect_output */
Packit Service f629e6
		" >> ",	/* redirect_append */
Packit Service f629e6
		" | ",	/* redirect_pipe */
Packit Service f629e6
		" | ",	/* redirect_pipein */
Packit Service f629e6
		" < ",	/* redirect_input */
Packit Service f629e6
		" |& ",	/* redirect_twoway */
Packit Service f629e6
	};
Packit Service f629e6
Packit Service f629e6
	if (redirtype < 0 || redirtype > redirect_twoway)
Packit Service f629e6
		fatal(_("redir2str: unknown redirection type %d"), redirtype);
Packit Service f629e6
	return redirtab[redirtype];
Packit Service f629e6
}