Blame interpret.h

Packit 575503
/*
Packit 575503
 * interpret.h ---  run a list of instructions.
Packit 575503
 */
Packit 575503
Packit 575503
/* 
Packit 575503
 * Copyright (C) 1986, 1988, 1989, 1991-2018 the Free Software Foundation, Inc.
Packit 575503
 * 
Packit 575503
 * This file is part of GAWK, the GNU implementation of the
Packit 575503
 * AWK Programming Language.
Packit 575503
 *
Packit 575503
 * GAWK is free software; you can redistribute it and/or modify
Packit 575503
 * it under the terms of the GNU General Public License as published by
Packit 575503
 * the Free Software Foundation; either version 3 of the License, or
Packit 575503
 * (at your option) any later version.
Packit 575503
 *
Packit 575503
 * GAWK is distributed in the hope that it will be useful,
Packit 575503
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 575503
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 575503
 * GNU General Public License for more details.
Packit 575503
 *
Packit 575503
 * You should have received a copy of the GNU General Public License
Packit 575503
 * along with this program; if not, write to the Free Software
Packit 575503
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit 575503
 */
Packit 575503
Packit 575503
/*
Packit 575503
 * If "r" is a field, valref should normally be > 1, because the field is
Packit 575503
 * created initially with valref 1, and valref should be bumped when it is
Packit 575503
 * pushed onto the stack by Op_field_spec. On the other hand, if we are
Packit 575503
 * assigning to $n, then Op_store_field calls unref(*lhs) before assigning
Packit 575503
 * the new value, so that decrements valref. So if the RHS is a field with
Packit 575503
 * valref 1, that effectively means that this is an assignment like "$n = $n",
Packit 575503
 * so a no-op, other than triggering $0 reconstitution.
Packit 575503
 */
Packit 575503
#define UNFIELD(l, r) \
Packit 575503
{ \
Packit 575503
	/* if was a field, turn it into a var */ \
Packit 575503
	if ((r->flags & MALLOC) != 0 || r->valref == 1) { \
Packit 575503
		l = r; \
Packit 575503
	} else { \
Packit 575503
		l = dupnode(r); \
Packit 575503
		DEREF(r); \
Packit 575503
	} \
Packit 575503
}
Packit 575503
int
Packit 575503
r_interpret(INSTRUCTION *code)
Packit 575503
{
Packit 575503
	INSTRUCTION *pc;   /* current instruction */
Packit 575503
	OPCODE op;	/* current opcode */
Packit 575503
	NODE *r = NULL;
Packit 575503
	NODE *m;
Packit 575503
	INSTRUCTION *ni;
Packit 575503
	NODE *t1, *t2;
Packit 575503
	NODE **lhs;
Packit 575503
	AWKNUM x, x2;
Packit 575503
	int di;
Packit 575503
	Regexp *rp;
Packit 575503
	NODE *set_array = NULL;	/* array with a post-assignment routine */
Packit 575503
	NODE *set_idx = NULL;	/* the index of the array element */
Packit 575503
Packit 575503
Packit 575503
/* array subscript */
Packit 575503
#define mk_sub(n)  	(n == 1 ? POP_SCALAR() : concat_exp(n, true))
Packit 575503
Packit 575503
#ifdef EXEC_HOOK
Packit 575503
#define JUMPTO(x)	do { if (post_execute) post_execute(pc); pc = (x); goto top; } while (false)
Packit 575503
#else
Packit 575503
#define JUMPTO(x)	do { pc = (x); goto top; } while (false)
Packit 575503
#endif
Packit 575503
Packit 575503
	pc = code;
Packit 575503
Packit 575503
	/* N.B.: always use JUMPTO for next instruction, otherwise bad things
Packit 575503
	 * may happen. DO NOT add a real loop (for/while) below to
Packit 575503
	 * replace ' forever {'; this catches failure to use JUMPTO to execute
Packit 575503
	 * next instruction (e.g. continue statement).
Packit 575503
	 */
Packit 575503
Packit 575503
	/* loop until hit Op_stop instruction */
Packit 575503
Packit 575503
	/* forever {  */
Packit 575503
top:
Packit 575503
		if (pc->source_line > 0)
Packit 575503
			sourceline = pc->source_line;
Packit 575503
Packit 575503
#ifdef EXEC_HOOK
Packit 575503
		for (di = 0; di < num_exec_hook; di++) {
Packit 575503
			if (! pre_execute[di](& pc))
Packit 575503
				goto top;
Packit 575503
		}
Packit 575503
#endif
Packit 575503
Packit 575503
		switch ((op = pc->opcode)) {
Packit 575503
		case Op_rule:
Packit 575503
			currule = pc->in_rule;   /* for sole use in Op_K_next, Op_K_nextfile, Op_K_getline */
Packit 575503
			/* fall through */
Packit 575503
		case Op_func:
Packit 575503
			source = pc->source_file;
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_atexit:
Packit 575503
		{
Packit 575503
			bool stdio_problem = false;
Packit 575503
Packit 575503
			/* avoid false source indications */
Packit 575503
			source = NULL;
Packit 575503
			sourceline = 0;
Packit 575503
			(void) nextfile(& curfile, true);	/* close input data file */
Packit 575503
			/*
Packit 575503
			 * This used to be:
Packit 575503
			 *
Packit 575503
			 * if (close_io() != 0 && ! exiting && exit_val == 0)
Packit 575503
			 *      exit_val = 1;
Packit 575503
			 *
Packit 575503
			 * Other awks don't care about problems closing open files
Packit 575503
			 * and pipes, in that it doesn't affect their exit status.
Packit 575503
			 * So we no longer do either.
Packit 575503
			 */
Packit 575503
			(void) close_io(& stdio_problem);
Packit 575503
			/*
Packit 575503
			 * However, we do want to exit non-zero if there was a problem
Packit 575503
			 * with stdout/stderr, so we reinstate a slightly different
Packit 575503
			 * version of the above:
Packit 575503
			 */
Packit 575503
			if (stdio_problem && ! exiting && exit_val == 0)
Packit 575503
				exit_val = 1;
Packit 575503
Packit 575503
			close_extensions();
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_stop:
Packit 575503
			return 0;
Packit 575503
Packit 575503
		case Op_push_i:
Packit 575503
			m = pc->memory;
Packit 575503
			if (! do_traditional && (m->flags & INTLSTR) != 0) {
Packit 575503
				char *orig, *trans, save;
Packit 575503
Packit 575503
				save = m->stptr[m->stlen];
Packit 575503
				m->stptr[m->stlen] = '\0';
Packit 575503
				orig = m->stptr;
Packit 575503
				trans = dgettext(TEXTDOMAIN, orig);
Packit 575503
				m->stptr[m->stlen] = save;
Packit 575503
				m = make_string(trans, strlen(trans));
Packit 575503
			} else
Packit 575503
				UPREF(m);
Packit 575503
			PUSH(m);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_push:
Packit 575503
		case Op_push_arg:
Packit 575503
		case Op_push_arg_untyped:
Packit 575503
		{
Packit 575503
			NODE *save_symbol;
Packit 575503
			bool isparam = false;
Packit 575503
Packit 575503
			save_symbol = m = pc->memory;
Packit 575503
			if (m->type == Node_param_list) {
Packit 575503
				isparam = true;
Packit 575503
				save_symbol = m = GET_PARAM(m->param_cnt);
Packit 575503
				if (m->type == Node_array_ref) {
Packit 575503
					if (m->orig_array->type == Node_var) {
Packit 575503
						/* gawk 'func f(x) { a = 10; print x; } BEGIN{ f(a) }' */
Packit 575503
						goto uninitialized_scalar;
Packit 575503
					}
Packit 575503
					m = m->orig_array;
Packit 575503
				}
Packit 575503
			}
Packit 575503
Packit 575503
			switch (m->type) {
Packit 575503
			case Node_var:
Packit 575503
				if (do_lint && var_uninitialized(m))
Packit 575503
					lintwarn(isparam ?
Packit 575503
						_("reference to uninitialized argument `%s'") :
Packit 575503
						_("reference to uninitialized variable `%s'"),
Packit 575503
								save_symbol->vname);
Packit 575503
				m = m->var_value;
Packit 575503
				UPREF(m);
Packit 575503
				PUSH(m);
Packit 575503
				break;
Packit 575503
Packit 575503
			case Node_var_new:
Packit 575503
uninitialized_scalar:
Packit 575503
				if (op != Op_push_arg_untyped) {
Packit 575503
					/* convert untyped to scalar */
Packit 575503
					m->type = Node_var;
Packit 575503
					m->var_value = dupnode(Nnull_string);
Packit 575503
				}
Packit 575503
				if (do_lint)
Packit 575503
					lintwarn(isparam ?
Packit 575503
						_("reference to uninitialized argument `%s'") :
Packit 575503
						_("reference to uninitialized variable `%s'"),
Packit 575503
								save_symbol->vname);
Packit 575503
				if (op != Op_push_arg_untyped)
Packit 575503
					m = dupnode(Nnull_string);
Packit 575503
				PUSH(m);
Packit 575503
				break;
Packit 575503
Packit 575503
			case Node_var_array:
Packit 575503
				if (op == Op_push_arg || op == Op_push_arg_untyped)
Packit 575503
					PUSH(m);
Packit 575503
				else
Packit 575503
					fatal(_("attempt to use array `%s' in a scalar context"),
Packit 575503
							array_vname(save_symbol));
Packit 575503
				break;
Packit 575503
Packit 575503
			default:
Packit 575503
				cant_happen();
Packit 575503
			}
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_push_param:		/* function argument */
Packit 575503
			m = pc->memory;
Packit 575503
			if (m->type == Node_param_list)
Packit 575503
				m = GET_PARAM(m->param_cnt);
Packit 575503
			if (m->type == Node_var) {
Packit 575503
				m = m->var_value;
Packit 575503
				UPREF(m);
Packit 575503
				PUSH(m);
Packit 575503
		 		break;
Packit 575503
			}
Packit 575503
 			/* else
Packit 575503
				fall through */
Packit 575503
		case Op_push_array:
Packit 575503
			PUSH(pc->memory);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_push_lhs:
Packit 575503
			lhs = get_lhs(pc->memory, pc->do_reference);
Packit 575503
			PUSH_ADDRESS(lhs);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_subscript:
Packit 575503
			t2 = mk_sub(pc->sub_count);
Packit 575503
			t1 = POP_ARRAY();
Packit 575503
Packit 575503
			if (do_lint && in_array(t1, t2) == NULL) {
Packit 575503
				t2 = force_string(t2);
Packit 575503
				lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
Packit 575503
					array_vname(t1), (int) t2->stlen, t2->stptr);
Packit 575503
				if (t2->stlen == 0)
Packit 575503
					lintwarn(_("subscript of array `%s' is null string"), array_vname(t1));
Packit 575503
			}
Packit 575503
Packit 575503
			/* for FUNCTAB, get the name as the element value */
Packit 575503
			if (t1 == func_table) {
Packit 575503
				static bool warned = false;
Packit 575503
Packit 575503
				if (do_lint && ! warned) {
Packit 575503
					warned = true;
Packit 575503
					lintwarn(_("FUNCTAB is a gawk extension"));
Packit 575503
				}
Packit 575503
				r = t2;
Packit 575503
			} else {
Packit 575503
				/* make sure stuff like NF, NR, are up to date */
Packit 575503
				if (t1 == symbol_table)
Packit 575503
					update_global_values();
Packit 575503
Packit 575503
				r = *assoc_lookup(t1, t2);
Packit 575503
			}
Packit 575503
			DEREF(t2);
Packit 575503
Packit 575503
			/* for SYMTAB, step through to the actual variable */
Packit 575503
			if (t1 == symbol_table) {
Packit 575503
				static bool warned = false;
Packit 575503
Packit 575503
				if (do_lint && ! warned) {
Packit 575503
					warned = true;
Packit 575503
					lintwarn(_("SYMTAB is a gawk extension"));
Packit 575503
				}
Packit 575503
				if (r->type == Node_var)
Packit 575503
					r = r->var_value;
Packit 575503
			}
Packit 575503
Packit 575503
			if (r->type == Node_val)
Packit 575503
				UPREF(r);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_sub_array:
Packit 575503
			t2 = mk_sub(pc->sub_count);
Packit 575503
			t1 = POP_ARRAY();
Packit 575503
			r = in_array(t1, t2);
Packit 575503
			if (r == NULL) {
Packit 575503
				r = make_array();
Packit 575503
				r->parent_array = t1;
Packit 575503
				lhs = assoc_lookup(t1, t2);
Packit 575503
				unref(*lhs);
Packit 575503
				*lhs = r;
Packit 575503
				t2 = force_string(t2);
Packit 575503
				r->vname = estrdup(t2->stptr, t2->stlen);	/* the subscript in parent array */
Packit 575503
Packit 575503
				/* execute post-assignment routine if any */
Packit 575503
				if (t1->astore != NULL)
Packit 575503
					(*t1->astore)(t1, t2);
Packit 575503
			} else if (r->type != Node_var_array) {
Packit 575503
				t2 = force_string(t2);
Packit 575503
				fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"),
Packit 575503
						array_vname(t1), (int) t2->stlen, t2->stptr);
Packit 575503
			}
Packit 575503
Packit 575503
			DEREF(t2);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_subscript_lhs:
Packit 575503
			t2 = mk_sub(pc->sub_count);
Packit 575503
			t1 = POP_ARRAY();
Packit 575503
			if (do_lint && in_array(t1, t2) == NULL) {
Packit 575503
				t2 = force_string(t2);
Packit 575503
				if (pc->do_reference)
Packit 575503
					lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
Packit 575503
						array_vname(t1), (int) t2->stlen, t2->stptr);
Packit 575503
				if (t2->stlen == 0)
Packit 575503
					lintwarn(_("subscript of array `%s' is null string"), array_vname(t1));
Packit 575503
			}
Packit 575503
Packit 575503
			lhs = assoc_lookup(t1, t2);
Packit 575503
			if ((*lhs)->type == Node_var_array) {
Packit 575503
				t2 = force_string(t2);
Packit 575503
				fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
Packit 575503
						array_vname(t1), (int) t2->stlen, t2->stptr);
Packit 575503
			}
Packit 575503
Packit 575503
			/*
Packit 575503
			 * Changing something in FUNCTAB is not allowed.
Packit 575503
			 *
Packit 575503
			 * SYMTAB is a little more messy.  Three kinds of values may
Packit 575503
			 * be stored in SYMTAB:
Packit 575503
			 * 	1. Variables that don"t yet have a value (Node_var_new)
Packit 575503
			 * 	2. Variables that have a value (Node_var)
Packit 575503
			 * 	3. Values that awk code stuck into SYMTAB not related to variables (Node_value)
Packit 575503
			 * For 1, since we are giving it a value, we have to change the type to Node_var.
Packit 575503
			 * For 1 and 2, we have to step through the Node_var to get to the value.
Packit 575503
			 * For 3, we just us the value we got from assoc_lookup(), above.
Packit 575503
			 */
Packit 575503
			if (t1 == func_table)
Packit 575503
				fatal(_("cannot assign to elements of FUNCTAB"));
Packit 575503
			else if (   t1 == symbol_table
Packit 575503
				 && (   (*lhs)->type == Node_var
Packit 575503
				     || (*lhs)->type == Node_var_new)) {
Packit 575503
				update_global_values();		/* make sure stuff like NF, NR, are up to date */
Packit 575503
				(*lhs)->type = Node_var;	/* in case was Node_var_new */
Packit 575503
				lhs = & ((*lhs)->var_value);	/* extra level of indirection */
Packit 575503
			}
Packit 575503
Packit 575503
			assert(set_idx == NULL);
Packit 575503
Packit 575503
			if (t1->astore) {
Packit 575503
				/* array has post-assignment routine */
Packit 575503
				set_array = t1;
Packit 575503
				set_idx = t2;
Packit 575503
			} else
Packit 575503
				DEREF(t2);
Packit 575503
Packit 575503
			PUSH_ADDRESS(lhs);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_field_spec:
Packit 575503
			t1 = TOP_SCALAR();
Packit 575503
			lhs = r_get_field(t1, (Func_ptr *) 0, true);
Packit 575503
			decr_sp();
Packit 575503
			DEREF(t1);
Packit 575503
			r = *lhs;
Packit 575503
			UPREF(r);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_field_spec_lhs:
Packit 575503
			t1 = TOP_SCALAR();
Packit 575503
			lhs = r_get_field(t1, &pc->target_assign->field_assign, pc->do_reference);
Packit 575503
			decr_sp();
Packit 575503
			DEREF(t1);
Packit 575503
			PUSH_ADDRESS(lhs);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_lint:
Packit 575503
			if (do_lint) {
Packit 575503
				switch (pc->lint_type) {
Packit 575503
				case LINT_assign_in_cond:
Packit 575503
					lintwarn(_("assignment used in conditional context"));
Packit 575503
					break;
Packit 575503
Packit 575503
				case LINT_no_effect:
Packit 575503
					lintwarn(_("statement has no effect"));
Packit 575503
					break;
Packit 575503
Packit 575503
				default:
Packit 575503
					cant_happen();
Packit 575503
				}
Packit 575503
			}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_break:
Packit 575503
		case Op_K_continue:
Packit 575503
		case Op_jmp:
Packit 575503
			assert(pc->target_jmp != NULL);
Packit 575503
			JUMPTO(pc->target_jmp);
Packit 575503
Packit 575503
		case Op_jmp_false:
Packit 575503
			r = POP_SCALAR();
Packit 575503
			di = eval_condition(r);
Packit 575503
			DEREF(r);
Packit 575503
			if (! di)
Packit 575503
				JUMPTO(pc->target_jmp);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_jmp_true:
Packit 575503
			r = POP_SCALAR();
Packit 575503
			di = eval_condition(r);
Packit 575503
			DEREF(r);
Packit 575503
			if (di)
Packit 575503
				JUMPTO(pc->target_jmp);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_and:
Packit 575503
		case Op_or:
Packit 575503
			t1 = POP_SCALAR();
Packit 575503
			di = eval_condition(t1);
Packit 575503
			DEREF(t1);
Packit 575503
			if ((op == Op_and && di) || (op == Op_or && ! di))
Packit 575503
				break;
Packit 575503
			r = node_Boolean[di];
Packit 575503
			UPREF(r);
Packit 575503
			PUSH(r);
Packit 575503
			ni = pc->target_jmp;
Packit 575503
			JUMPTO(ni->nexti);
Packit 575503
Packit 575503
		case Op_and_final:
Packit 575503
		case Op_or_final:
Packit 575503
			t1 = TOP_SCALAR();
Packit 575503
			r = node_Boolean[eval_condition(t1)];
Packit 575503
			DEREF(t1);
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_not:
Packit 575503
			t1 = TOP_SCALAR();
Packit 575503
			r = node_Boolean[! eval_condition(t1)];
Packit 575503
			DEREF(t1);
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_equal:
Packit 575503
			r = node_Boolean[cmp_scalars(SCALAR_EQ_NEQ) == 0];
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_notequal:
Packit 575503
			r = node_Boolean[cmp_scalars(SCALAR_EQ_NEQ) != 0];
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_less:
Packit 575503
			r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) < 0];
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_greater:
Packit 575503
			r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) > 0];
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_leq:
Packit 575503
			r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) <= 0];
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_geq:
Packit 575503
			r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) >= 0];
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_plus_i:
Packit 575503
			x2 = force_number(pc->memory)->numbr;
Packit 575503
			goto plus;
Packit 575503
		case Op_plus:
Packit 575503
			t2 = POP_NUMBER();
Packit 575503
			x2 = t2->numbr;
Packit 575503
			DEREF(t2);
Packit 575503
plus:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			r = make_number(t1->numbr + x2);
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_minus_i:
Packit 575503
			x2 = force_number(pc->memory)->numbr;
Packit 575503
			goto minus;
Packit 575503
		case Op_minus:
Packit 575503
			t2 = POP_NUMBER();
Packit 575503
			x2 = t2->numbr;
Packit 575503
			DEREF(t2);
Packit 575503
minus:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			r = make_number(t1->numbr - x2);
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_times_i:
Packit 575503
			x2 = force_number(pc->memory)->numbr;
Packit 575503
			goto times;
Packit 575503
		case Op_times:
Packit 575503
			t2 = POP_NUMBER();
Packit 575503
			x2 = t2->numbr;
Packit 575503
			DEREF(t2);
Packit 575503
times:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			r = make_number(t1->numbr * x2);
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_exp_i:
Packit 575503
			x2 = force_number(pc->memory)->numbr;
Packit 575503
			goto exp;
Packit 575503
		case Op_exp:
Packit 575503
			t2 = POP_NUMBER();
Packit 575503
			x2 = t2->numbr;
Packit 575503
			DEREF(t2);
Packit 575503
exp:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			r = make_number(calc_exp(t1->numbr, x2));
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_quotient_i:
Packit 575503
			x2 = force_number(pc->memory)->numbr;
Packit 575503
			goto quotient;
Packit 575503
		case Op_quotient:
Packit 575503
			t2 = POP_NUMBER();
Packit 575503
			x2 = t2->numbr;
Packit 575503
			DEREF(t2);
Packit 575503
quotient:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			if (x2 == 0)
Packit 575503
				fatal(_("division by zero attempted"));
Packit 575503
			r = make_number(t1->numbr / x2);
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_mod_i:
Packit 575503
			x2 = force_number(pc->memory)->numbr;
Packit 575503
			goto mod;
Packit 575503
		case Op_mod:
Packit 575503
			t2 = POP_NUMBER();
Packit 575503
			x2 = t2->numbr;
Packit 575503
			DEREF(t2);
Packit 575503
mod:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			if (x2 == 0)
Packit 575503
				fatal(_("division by zero attempted in `%%'"));
Packit 575503
#ifdef HAVE_FMOD
Packit 575503
			x = fmod(t1->numbr, x2);
Packit 575503
#else	/* ! HAVE_FMOD */
Packit 575503
			(void) modf(t1->numbr / x2, &x);
Packit 575503
			x = t1->numbr - x * x2;
Packit 575503
#endif	/* ! HAVE_FMOD */
Packit 575503
			r = make_number(x);
Packit 575503
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_preincrement:
Packit 575503
		case Op_predecrement:
Packit 575503
			x = op == Op_preincrement ? 1.0 : -1.0;
Packit 575503
			lhs = TOP_ADDRESS();
Packit 575503
			t1 = *lhs;
Packit 575503
			force_number(t1);
Packit 575503
			if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
Packit 575503
				/* optimization */
Packit 575503
				t1->numbr += x;
Packit 575503
				r = t1;
Packit 575503
			} else {
Packit 575503
				r = *lhs = make_number(t1->numbr + x);
Packit 575503
				unref(t1);
Packit 575503
			}
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_postincrement:
Packit 575503
		case Op_postdecrement:
Packit 575503
			x = op == Op_postincrement ? 1.0 : -1.0;
Packit 575503
			lhs = TOP_ADDRESS();
Packit 575503
			t1 = *lhs;
Packit 575503
			force_number(t1);
Packit 575503
			r = make_number(t1->numbr);
Packit 575503
			if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
Packit 575503
 				/* optimization */
Packit 575503
				t1->numbr += x;
Packit 575503
			} else {
Packit 575503
				*lhs = make_number(t1->numbr + x);
Packit 575503
				unref(t1);
Packit 575503
			}
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_unary_minus:
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			r = make_number(-t1->numbr);
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_unary_plus:
Packit 575503
			// Force argument to be numeric
Packit 575503
			t1 = TOP_NUMBER();
Packit 575503
			r = make_number(t1->numbr);
Packit 575503
			DEREF(t1);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_store_sub:
Packit 575503
			/*
Packit 575503
			 * array[sub] assignment optimization,
Packit 575503
			 * see awkgram.y (optimize_assignment)
Packit 575503
			 */
Packit 575503
			t1 = force_array(pc->memory, true);	/* array */
Packit 575503
			t2 = mk_sub(pc->expr_count);	/* subscript */
Packit 575503
 			lhs = assoc_lookup(t1, t2);
Packit 575503
			if ((*lhs)->type == Node_var_array) {
Packit 575503
				t2 = force_string(t2);
Packit 575503
				fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
Packit 575503
						array_vname(t1), (int) t2->stlen, t2->stptr);
Packit 575503
			}
Packit 575503
			DEREF(t2);
Packit 575503
Packit 575503
			/*
Packit 575503
			 * Changing something in FUNCTAB is not allowed.
Packit 575503
			 *
Packit 575503
			 * SYMTAB is a little more messy.  Three kinds of values may
Packit 575503
			 * be stored in SYMTAB:
Packit 575503
			 * 	1. Variables that don"t yet have a value (Node_var_new)
Packit 575503
			 * 	2. Variables that have a value (Node_var)
Packit 575503
			 * 	3. Values that awk code stuck into SYMTAB not related to variables (Node_value)
Packit 575503
			 * For 1, since we are giving it a value, we have to change the type to Node_var.
Packit 575503
			 * For 1 and 2, we have to step through the Node_var to get to the value.
Packit 575503
			 * For 3, we just us the value we got from assoc_lookup(), above.
Packit 575503
			 */
Packit 575503
			if (t1 == func_table)
Packit 575503
				fatal(_("cannot assign to elements of FUNCTAB"));
Packit 575503
			else if (   t1 == symbol_table
Packit 575503
				 && (   (*lhs)->type == Node_var
Packit 575503
				     || (*lhs)->type == Node_var_new)) {
Packit 575503
				(*lhs)->type = Node_var;	/* in case was Node_var_new */
Packit 575503
				lhs = & ((*lhs)->var_value);	/* extra level of indirection */
Packit 575503
			}
Packit 575503
Packit 575503
			unref(*lhs);
Packit 575503
			r = POP_SCALAR();
Packit 575503
			UNFIELD(*lhs, r);
Packit 575503
Packit 575503
			/* execute post-assignment routine if any */
Packit 575503
			if (t1->astore != NULL)
Packit 575503
				(*t1->astore)(t1, t2);
Packit 575503
Packit 575503
			DEREF(t2);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_store_var:
Packit 575503
			/*
Packit 575503
			 * simple variable assignment optimization,
Packit 575503
			 * see awkgram.y (optimize_assignment)
Packit 575503
			 */
Packit 575503
Packit 575503
			lhs = get_lhs(pc->memory, false);
Packit 575503
			unref(*lhs);
Packit 575503
			r = pc->initval;	/* constant initializer */
Packit 575503
			if (r != NULL) {
Packit 575503
				UPREF(r);
Packit 575503
				*lhs = r;
Packit 575503
			} else {
Packit 575503
				r = POP_SCALAR();
Packit 575503
				UNFIELD(*lhs, r);
Packit 575503
			}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_store_field:
Packit 575503
		{
Packit 575503
			/* field assignment optimization,
Packit 575503
			 * see awkgram.y (optimize_assignment)
Packit 575503
			 */
Packit 575503
Packit 575503
			Func_ptr assign;
Packit 575503
			t1 = TOP_SCALAR();
Packit 575503
			lhs = r_get_field(t1, & assign, false);
Packit 575503
			decr_sp();
Packit 575503
			DEREF(t1);
Packit 575503
			/*
Packit 575503
			 * N.B. We must call assign() before unref, since
Packit 575503
			 * we may need to copy $n values before freeing the
Packit 575503
			 * $0 buffer.
Packit 575503
			 */
Packit 575503
			assert(assign != NULL);
Packit 575503
			assign();
Packit 575503
			unref(*lhs);
Packit 575503
			r = POP_SCALAR();
Packit 575503
			UNFIELD(*lhs, r);
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_assign_concat:
Packit 575503
			/* x = x ... string concatenation optimization */
Packit 575503
			lhs = get_lhs(pc->memory, false);
Packit 575503
			t1 = force_string(*lhs);
Packit 575503
			t2 = POP_STRING();
Packit 575503
Packit 575503
			if (t1 != *lhs) {
Packit 575503
				unref(*lhs);
Packit 575503
				*lhs = dupnode(t1);
Packit 575503
			}
Packit 575503
Packit 575503
			if (t1 != t2 && t1->valref == 1 && (t1->flags & (MALLOC|MPFN|MPZN)) == MALLOC) {
Packit 575503
				size_t nlen = t1->stlen + t2->stlen;
Packit 575503
Packit 575503
				erealloc(t1->stptr, char *, nlen + 1, "r_interpret");
Packit 575503
				memcpy(t1->stptr + t1->stlen, t2->stptr, t2->stlen);
Packit 575503
				t1->stlen = nlen;
Packit 575503
				t1->stptr[nlen] = '\0';
Packit 575503
				/* clear flags except WSTRCUR (used below) */
Packit 575503
				t1->flags &= WSTRCUR;
Packit 575503
				/* configure as a string as in make_str_node */
Packit 575503
				t1->flags |= (MALLOC|STRING|STRCUR);
Packit 575503
				t1->stfmt = STFMT_UNUSED;
Packit 575503
#ifdef HAVE_MPFR
Packit 575503
				t1->strndmode = MPFR_round_mode;
Packit 575503
#endif
Packit 575503
Packit 575503
				if ((t1->flags & WSTRCUR) != 0 && (t2->flags & WSTRCUR) != 0) {
Packit 575503
					size_t wlen = t1->wstlen + t2->wstlen;
Packit 575503
Packit 575503
					erealloc(t1->wstptr, wchar_t *,
Packit 575503
							sizeof(wchar_t) * (wlen + 1), "r_interpret");
Packit 575503
					memcpy(t1->wstptr + t1->wstlen, t2->wstptr, t2->wstlen * sizeof(wchar_t));
Packit 575503
					t1->wstlen = wlen;
Packit 575503
					t1->wstptr[wlen] = L'\0';
Packit 575503
				} else
Packit 575503
					free_wstr(*lhs);
Packit 575503
			} else {
Packit 575503
				size_t nlen = t1->stlen + t2->stlen;
Packit 575503
				char *p;
Packit 575503
Packit 575503
				emalloc(p, char *, nlen + 1, "r_interpret");
Packit 575503
				memcpy(p, t1->stptr, t1->stlen);
Packit 575503
				memcpy(p + t1->stlen, t2->stptr, t2->stlen);
Packit 575503
				/* N.B. No NUL-termination required, since make_str_node will do it. */
Packit 575503
				unref(*lhs);
Packit 575503
				t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED);
Packit 575503
			}
Packit 575503
			DEREF(t2);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_assign:
Packit 575503
			lhs = POP_ADDRESS();
Packit 575503
			r = TOP_SCALAR();
Packit 575503
			unref(*lhs);
Packit 575503
			UPREF(r);
Packit 575503
			UNFIELD(*lhs, r);
Packit 575503
			REPLACE(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_subscript_assign:
Packit 575503
			/* conditionally execute post-assignment routine for an array element */
Packit 575503
Packit 575503
			if (set_idx != NULL) {
Packit 575503
				di = true;
Packit 575503
				if (pc->assign_ctxt == Op_sub_builtin
Packit 575503
					&& (r = TOP())
Packit 575503
					&& get_number_si(r) == 0	/* no substitution performed */
Packit 575503
				)
Packit 575503
					di = false;
Packit 575503
				else if ((pc->assign_ctxt == Op_K_getline
Packit 575503
						|| pc->assign_ctxt == Op_K_getline_redir)
Packit 575503
					&& (r = TOP())
Packit 575503
					&& get_number_si(r) <= 0 	/* EOF or error */
Packit 575503
				)
Packit 575503
					di = false;
Packit 575503
Packit 575503
				if (di)
Packit 575503
					(*set_array->astore)(set_array, set_idx);
Packit 575503
				unref(set_idx);
Packit 575503
				set_idx = NULL;
Packit 575503
			}
Packit 575503
			break;
Packit 575503
Packit 575503
		/* numeric assignments */
Packit 575503
		case Op_assign_plus:
Packit 575503
		case Op_assign_minus:
Packit 575503
		case Op_assign_times:
Packit 575503
		case Op_assign_quotient:
Packit 575503
		case Op_assign_mod:
Packit 575503
		case Op_assign_exp:
Packit 575503
			op_assign(op);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_var_update:        /* update value of NR, FNR or NF */
Packit 575503
			pc->update_var();
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_var_assign:
Packit 575503
		case Op_field_assign:
Packit 575503
			r = TOP();
Packit 575503
			if (pc->assign_ctxt == Op_sub_builtin
Packit 575503
				&& get_number_si(r) == 0	/* top of stack has a number == 0 */
Packit 575503
			) {
Packit 575503
				/* There wasn't any substitutions. If the target is a FIELD,
Packit 575503
				 * this means no field re-splitting or $0 reconstruction.
Packit 575503
				 * Skip the set_FOO routine if the target is a special variable.
Packit 575503
				 */
Packit 575503
Packit 575503
				break;
Packit 575503
			} else if ((pc->assign_ctxt == Op_K_getline
Packit 575503
					|| pc->assign_ctxt == Op_K_getline_redir)
Packit 575503
				&& get_number_si(r) <= 0 	/* top of stack has a number <= 0 */
Packit 575503
			) {
Packit 575503
				/* getline returned EOF or error */
Packit 575503
Packit 575503
				break;
Packit 575503
			}
Packit 575503
Packit 575503
			if (op == Op_var_assign)
Packit 575503
				pc->assign_var();
Packit 575503
			else
Packit 575503
				pc->field_assign();
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_concat:
Packit 575503
			r = concat_exp(pc->expr_count, pc->concat_flag & CSUBSEP);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_case:
Packit 575503
			if ((pc + 1)->match_exp) {
Packit 575503
				/* match a constant regex against switch expression instead of $0. */
Packit 575503
Packit 575503
				m = POP();	/* regex */
Packit 575503
				t2 = TOP_SCALAR();	/* switch expression */
Packit 575503
				t2 = force_string(t2);
Packit 575503
				rp = re_update(m);
Packit 575503
				di = (research(rp, t2->stptr, 0, t2->stlen, RE_NO_FLAGS) >= 0);
Packit 575503
			} else {
Packit 575503
				t1 = POP_SCALAR();	/* case value */
Packit 575503
				t2 = TOP_SCALAR();	/* switch expression */
Packit 575503
				di = (cmp_nodes(t2, t1, true) == 0);
Packit 575503
				DEREF(t1);
Packit 575503
			}
Packit 575503
Packit 575503
			if (di) {
Packit 575503
				/* match found */
Packit 575503
				t2 = POP_SCALAR();
Packit 575503
				DEREF(t2);
Packit 575503
				JUMPTO(pc->target_jmp);
Packit 575503
			}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_delete:
Packit 575503
			t1 = POP_ARRAY();
Packit 575503
			do_delete(t1, pc->expr_count);
Packit 575503
			stack_adj(-pc->expr_count);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_delete_loop:
Packit 575503
			t1 = POP_ARRAY();
Packit 575503
			lhs = POP_ADDRESS();	/* item */
Packit 575503
			do_delete_loop(t1, lhs);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_in_array:
Packit 575503
			t1 = POP_ARRAY();
Packit 575503
			t2 = mk_sub(pc->expr_count);
Packit 575503
			r = node_Boolean[(in_array(t1, t2) != NULL)];
Packit 575503
			DEREF(t2);
Packit 575503
			UPREF(r);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_arrayfor_init:
Packit 575503
		{
Packit 575503
			NODE **list = NULL;
Packit 575503
			NODE *array, *sort_str;
Packit 575503
			size_t num_elems = 0;
Packit 575503
			static NODE *sorted_in = NULL;
Packit 575503
			const char *how_to_sort = "@unsorted";
Packit 575503
			char save;
Packit 575503
			bool saved_end = false;
Packit 575503
Packit 575503
			/* get the array */
Packit 575503
			array = POP_ARRAY();
Packit 575503
Packit 575503
			/* sanity: check if empty */
Packit 575503
			num_elems = assoc_length(array);
Packit 575503
			if (num_elems == 0)
Packit 575503
				goto arrayfor;
Packit 575503
Packit 575503
			if (sorted_in == NULL)		/* do this once */
Packit 575503
				sorted_in = make_string("sorted_in", 9);
Packit 575503
Packit 575503
			sort_str = NULL;
Packit 575503
			/*
Packit 575503
			 * If posix, or if there's no PROCINFO[],
Packit 575503
			 * there's no ["sorted_in"], so no sorting
Packit 575503
			 */
Packit 575503
			if (! do_posix && PROCINFO_node != NULL)
Packit 575503
				sort_str = in_array(PROCINFO_node, sorted_in);
Packit 575503
Packit 575503
			if (sort_str != NULL) {
Packit 575503
				sort_str = force_string(sort_str);
Packit 575503
				if (sort_str->stlen > 0) {
Packit 575503
					how_to_sort = sort_str->stptr;
Packit 575503
					str_terminate(sort_str, save);
Packit 575503
					saved_end = true;
Packit 575503
				}
Packit 575503
			}
Packit 575503
Packit 575503
			list = assoc_list(array, how_to_sort, SORTED_IN);
Packit 575503
			if (saved_end)
Packit 575503
				str_restore(sort_str, save);
Packit 575503
Packit 575503
arrayfor:
Packit 575503
			getnode(r);
Packit 575503
			r->type = Node_arrayfor;
Packit 575503
			r->for_list = list;
Packit 575503
			r->for_list_size = num_elems;		/* # of elements in list */
Packit 575503
			r->cur_idx = -1;			/* current index */
Packit 575503
			r->for_array = array;		/* array */
Packit 575503
			PUSH(r);
Packit 575503
Packit 575503
			if (num_elems == 0)
Packit 575503
				JUMPTO(pc->target_jmp);   /* Op_arrayfor_final */
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_arrayfor_incr:
Packit 575503
			r = TOP();	/* Node_arrayfor */
Packit 575503
			if (++r->cur_idx == r->for_list_size) {
Packit 575503
				NODE *array;
Packit 575503
				array = r->for_array;	/* actual array */
Packit 575503
				if (do_lint && array->table_size != r->for_list_size)
Packit 575503
					lintwarn(_("for loop: array `%s' changed size from %ld to %ld during loop execution"),
Packit 575503
						array_vname(array), (long) r->for_list_size, (long) array->table_size);
Packit 575503
				JUMPTO(pc->target_jmp);	/* Op_arrayfor_final */
Packit 575503
			}
Packit 575503
Packit 575503
			t1 = r->for_list[r->cur_idx];
Packit 575503
			lhs = get_lhs(pc->array_var, false);
Packit 575503
			unref(*lhs);
Packit 575503
			*lhs = dupnode(t1);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_arrayfor_final:
Packit 575503
			r = POP();
Packit 575503
			assert(r->type == Node_arrayfor);
Packit 575503
			free_arrayfor(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_builtin:
Packit 575503
			r = pc->builtin(pc->expr_count);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_ext_builtin:
Packit 575503
		{
Packit 575503
			size_t arg_count = pc->expr_count;
Packit 575503
			awk_ext_func_t *f = pc[1].c_function;
Packit 575503
			size_t min_req = f->min_required_args;
Packit 575503
			size_t max_expect = f->max_expected_args;
Packit 575503
			awk_value_t result;
Packit 575503
Packit 575503
			if (arg_count < min_req)
Packit 575503
				fatal(_("%s: called with %lu arguments, expecting at least %lu"),
Packit 575503
						pc[1].func_name,
Packit 575503
						(unsigned long) arg_count,
Packit 575503
						(unsigned long) min_req);
Packit 575503
Packit 575503
			if (do_lint && ! f->suppress_lint && arg_count > max_expect)
Packit 575503
				lintwarn(_("%s: called with %lu arguments, expecting no more than %lu"),
Packit 575503
						pc[1].func_name,
Packit 575503
						(unsigned long) arg_count,
Packit 575503
						(unsigned long) max_expect);
Packit 575503
Packit 575503
			PUSH_CODE(pc);
Packit 575503
			r = awk_value_to_node(pc->extfunc(arg_count, & result, f));
Packit 575503
			(void) POP_CODE();
Packit 575503
			while (arg_count-- > 0) {
Packit 575503
				t1 = POP();
Packit 575503
				if (t1->type == Node_val)
Packit 575503
					DEREF(t1);
Packit 575503
			}
Packit 575503
			free_api_string_copies();
Packit 575503
			PUSH(r);
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_sub_builtin:	/* sub, gsub and gensub */
Packit 575503
			r = do_sub(pc->expr_count, pc->sub_flags);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_print:
Packit 575503
			do_print(pc->expr_count, pc->redir_type);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_printf:
Packit 575503
			do_printf(pc->expr_count, pc->redir_type);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_print_rec:
Packit 575503
			do_print_rec(pc->expr_count, pc->redir_type);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_push_re:
Packit 575503
			m = pc->memory;
Packit 575503
			if (m->type == Node_dynregex) {
Packit 575503
				r = POP_STRING();
Packit 575503
				unref(m->re_exp);
Packit 575503
				m->re_exp = r;
Packit 575503
			} else if (m->type == Node_val) {
Packit 575503
				assert((m->flags & REGEX) != 0);
Packit 575503
				UPREF(m);
Packit 575503
			}
Packit 575503
			PUSH(m);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_match_rec:
Packit 575503
			m = pc->memory;
Packit 575503
			t1 = *get_field(0, (Func_ptr *) 0);
Packit 575503
match_re:
Packit 575503
			rp = re_update(m);
Packit 575503
			di = research(rp, t1->stptr, 0, t1->stlen, RE_NO_FLAGS);
Packit 575503
			di = (di == -1) ^ (op != Op_nomatch);
Packit 575503
			if (op != Op_match_rec) {
Packit 575503
				decr_sp();
Packit 575503
				DEREF(t1);
Packit 575503
			}
Packit 575503
			r = node_Boolean[di];
Packit 575503
			UPREF(r);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_nomatch:
Packit 575503
			/* fall through */
Packit 575503
		case Op_match:
Packit 575503
			m = pc->memory;
Packit 575503
			t1 = TOP_STRING();
Packit 575503
			if (m->type == Node_dynregex) {
Packit 575503
				unref(m->re_exp);
Packit 575503
				m->re_exp = t1;
Packit 575503
				decr_sp();
Packit 575503
				t1 = TOP_STRING();
Packit 575503
			}
Packit 575503
			goto match_re;
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_indirect_func_call:
Packit 575503
		{
Packit 575503
			NODE *f = NULL;
Packit 575503
			int arg_count;
Packit 575503
			char save;
Packit 575503
Packit 575503
			arg_count = (pc + 1)->expr_count;
Packit 575503
			t1 = PEEK(arg_count);	/* indirect var */
Packit 575503
Packit 575503
			if (t1->type != Node_val)	/* @a[1](p) not allowed in grammar */
Packit 575503
				fatal(_("indirect function call requires a simple scalar value"));
Packit 575503
Packit 575503
			t1 = force_string(t1);
Packit 575503
			str_terminate(t1, save);
Packit 575503
			if (t1->stlen > 0) {
Packit 575503
				/* retrieve function definition node */
Packit 575503
				f = pc->func_body;
Packit 575503
				if (f != NULL && strcmp(f->vname, t1->stptr) == 0) {
Packit 575503
					/* indirect var hasn't been reassigned */
Packit 575503
Packit 575503
					str_restore(t1, save);
Packit 575503
					ni = setup_frame(pc);
Packit 575503
					JUMPTO(ni);	/* Op_func */
Packit 575503
				}
Packit 575503
				f = lookup(t1->stptr);
Packit 575503
			}
Packit 575503
Packit 575503
			if (f == NULL) {
Packit 575503
				fatal(_("`%s' is not a function, so it cannot be called indirectly"),
Packit 575503
						t1->stptr);
Packit 575503
			} else if (f->type == Node_builtin_func) {
Packit 575503
				int arg_count = (pc + 1)->expr_count;
Packit 575503
				builtin_func_t the_func = lookup_builtin(t1->stptr);
Packit 575503
Packit 575503
				assert(the_func != NULL);
Packit 575503
Packit 575503
				/* call it */
Packit 575503
				if (the_func == (builtin_func_t) do_sub)
Packit 575503
					r = call_sub(t1->stptr, arg_count);
Packit 575503
				else if (the_func == do_match)
Packit 575503
					r = call_match(arg_count);
Packit 575503
				else if (the_func == do_split || the_func == do_patsplit)
Packit 575503
					r = call_split_func(t1->stptr, arg_count);
Packit 575503
				else
Packit 575503
					r = the_func(arg_count);
Packit 575503
				str_restore(t1, save);
Packit 575503
Packit 575503
				PUSH(r);
Packit 575503
				break;
Packit 575503
			} else if (f->type != Node_func) {
Packit 575503
				str_restore(t1, save);
Packit 575503
				if (f->type == Node_ext_func) {
Packit 575503
					/* code copied from below, keep in sync */
Packit 575503
					INSTRUCTION *bc;
Packit 575503
					char *fname = pc->func_name;
Packit 575503
					int arg_count = (pc + 1)->expr_count;
Packit 575503
					static INSTRUCTION npc[2];
Packit 575503
Packit 575503
					npc[0] = *pc;
Packit 575503
Packit 575503
					bc = f->code_ptr;
Packit 575503
					assert(bc->opcode == Op_symbol);
Packit 575503
					npc[0].opcode = Op_ext_builtin;	/* self modifying code */
Packit 575503
					npc[0].extfunc = bc->extfunc;
Packit 575503
					npc[0].expr_count = arg_count;		/* actual argument count */
Packit 575503
					npc[1] = pc[1];
Packit 575503
					npc[1].func_name = fname;	/* name of the builtin */
Packit 575503
					npc[1].c_function = bc->c_function;
Packit 575503
					ni = npc;
Packit 575503
					JUMPTO(ni);
Packit 575503
				} else
Packit 575503
					fatal(_("function called indirectly through `%s' does not exist"),
Packit 575503
							pc->func_name);
Packit 575503
			}
Packit 575503
			pc->func_body = f;     /* save for next call */
Packit 575503
			str_restore(t1, save);
Packit 575503
Packit 575503
			ni = setup_frame(pc);
Packit 575503
			JUMPTO(ni);	/* Op_func */
Packit 575503
		}
Packit 575503
Packit 575503
		case Op_func_call:
Packit 575503
		{
Packit 575503
			NODE *f;
Packit 575503
Packit 575503
			/* retrieve function definition node */
Packit 575503
			f = pc->func_body;
Packit 575503
			if (f == NULL) {
Packit 575503
				f = lookup(pc->func_name);
Packit 575503
				if (f == NULL || (f->type != Node_func && f->type != Node_ext_func))
Packit 575503
					fatal(_("function `%s' not defined"), pc->func_name);
Packit 575503
				pc->func_body = f;     /* save for next call */
Packit 575503
			}
Packit 575503
Packit 575503
			if (f->type == Node_ext_func) {
Packit 575503
				/* keep in sync with indirect call code */
Packit 575503
				INSTRUCTION *bc;
Packit 575503
				char *fname = pc->func_name;
Packit 575503
				int arg_count = (pc + 1)->expr_count;
Packit 575503
Packit 575503
				bc = f->code_ptr;
Packit 575503
				assert(bc->opcode == Op_symbol);
Packit 575503
				pc->opcode = Op_ext_builtin;	/* self modifying code */
Packit 575503
				pc->extfunc = bc->extfunc;
Packit 575503
				pc->expr_count = arg_count;	/* actual argument count */
Packit 575503
				(pc + 1)->func_name = fname;	/* name of the builtin */
Packit 575503
				(pc + 1)->c_function = bc->c_function;	/* min and max args */
Packit 575503
				ni = pc;
Packit 575503
				JUMPTO(ni);
Packit 575503
			}
Packit 575503
Packit 575503
			ni = setup_frame(pc);
Packit 575503
			JUMPTO(ni);	/* Op_func */
Packit 575503
		}
Packit 575503
Packit 575503
		case Op_K_return:
Packit 575503
			m = POP_SCALAR();       /* return value */
Packit 575503
Packit 575503
			ni = pop_fcall();
Packit 575503
Packit 575503
			/* put the return value back on stack */
Packit 575503
			PUSH(m);
Packit 575503
Packit 575503
			JUMPTO(ni);
Packit 575503
Packit 575503
		case Op_K_getline_redir:
Packit 575503
			r = do_getline_redir(pc->into_var, pc->redir_type);
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_getline:	/* no redirection */
Packit 575503
			if (! currule || currule == BEGINFILE || currule == ENDFILE)
Packit 575503
				fatal(_("non-redirected `getline' invalid inside `%s' rule"),
Packit 575503
						ruletab[currule]);
Packit 575503
Packit 575503
			do {
Packit 575503
				int ret;
Packit 575503
				ret = nextfile(& curfile, false);
Packit 575503
				if (ret <= 0)
Packit 575503
					r = do_getline(pc->into_var, curfile);
Packit 575503
				else {
Packit 575503
Packit 575503
					/* Save execution state so that we can return to it
Packit 575503
					 * from Op_after_beginfile or Op_after_endfile.
Packit 575503
					 */
Packit 575503
Packit 575503
					push_exec_state(pc, currule, source, stack_ptr);
Packit 575503
Packit 575503
					if (curfile == NULL)
Packit 575503
						JUMPTO((pc + 1)->target_endfile);
Packit 575503
					else
Packit 575503
						JUMPTO((pc + 1)->target_beginfile);
Packit 575503
				}
Packit 575503
			} while (r == NULL);	/* EOF */
Packit 575503
Packit 575503
			PUSH(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_after_endfile:
Packit 575503
			/* Find the execution state to return to */
Packit 575503
			ni = pop_exec_state(& currule, & source, NULL);
Packit 575503
Packit 575503
			assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline);
Packit 575503
			JUMPTO(ni);
Packit 575503
Packit 575503
		case Op_after_beginfile:
Packit 575503
			after_beginfile(& curfile);
Packit 575503
Packit 575503
			/* Find the execution state to return to */
Packit 575503
			ni = pop_exec_state(& currule, & source, NULL);
Packit 575503
Packit 575503
			assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline);
Packit 575503
			if (ni->opcode == Op_K_getline
Packit 575503
					|| curfile == NULL      /* skipping directory argument */
Packit 575503
			)
Packit 575503
				JUMPTO(ni);
Packit 575503
Packit 575503
			break;	/* read a record, Op_get_record */
Packit 575503
Packit 575503
		case Op_newfile:
Packit 575503
		{
Packit 575503
			int ret;
Packit 575503
Packit 575503
			ret = nextfile(& curfile, false);
Packit 575503
Packit 575503
			if (ret < 0)	/* end of input */
Packit 575503
				JUMPTO(pc->target_jmp);	/* end block or Op_atexit */
Packit 575503
Packit 575503
			if (ret == 0) /* read a record */
Packit 575503
				JUMPTO((pc + 1)->target_get_record);
Packit 575503
Packit 575503
			/* ret > 0 */
Packit 575503
			/* Save execution state for use in Op_after_beginfile or Op_after_endfile. */
Packit 575503
Packit 575503
			push_exec_state(pc, currule, source, stack_ptr);
Packit 575503
Packit 575503
			if (curfile == NULL)	/* EOF */
Packit 575503
				JUMPTO(pc->target_endfile);
Packit 575503
			/* else
Packit 575503
				execute beginfile block */
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_get_record:
Packit 575503
		{
Packit 575503
			int errcode = 0;
Packit 575503
Packit 575503
			ni = pc->target_newfile;
Packit 575503
			if (curfile == NULL) {
Packit 575503
				/* from non-redirected getline, e.g.:
Packit 575503
				 *  {
Packit 575503
				 *		while (getline > 0) ;
Packit 575503
				 *  }
Packit 575503
				 */
Packit 575503
Packit 575503
				ni = ni->target_jmp;	/* end_block or Op_atexit */
Packit 575503
				JUMPTO(ni);
Packit 575503
			}
Packit 575503
Packit 575503
			if (! inrec(curfile, & errcode)) {
Packit 575503
				if (errcode > 0) {
Packit 575503
					update_ERRNO_int(errcode);
Packit 575503
					if (do_traditional || ! pc->has_endfile)
Packit 575503
						fatal(_("error reading input file `%s': %s"),
Packit 575503
						curfile->public.name, strerror(errcode));
Packit 575503
				}
Packit 575503
Packit 575503
				JUMPTO(ni);
Packit 575503
			} /* else
Packit 575503
				prog (rule) block */
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_nextfile:
Packit 575503
		{
Packit 575503
			int ret;
Packit 575503
Packit 575503
			if (currule != Rule && currule != BEGINFILE)
Packit 575503
				fatal(_("`nextfile' cannot be called from a `%s' rule"),
Packit 575503
					ruletab[currule]);
Packit 575503
Packit 575503
			ret = nextfile(& curfile, true);	/* skip current file */
Packit 575503
Packit 575503
			if (currule == BEGINFILE) {
Packit 575503
				long stack_size = 0;
Packit 575503
Packit 575503
				ni = pop_exec_state(& currule, & source, & stack_size);
Packit 575503
Packit 575503
				assert(ni->opcode == Op_K_getline || ni->opcode == Op_newfile);
Packit 575503
Packit 575503
				/* pop stack returning to the state of Op_K_getline or Op_newfile. */
Packit 575503
				unwind_stack(stack_size);
Packit 575503
Packit 575503
				if (ret == 0) {
Packit 575503
					/* There was an error opening the file;
Packit 575503
					 * don't run ENDFILE block(s).
Packit 575503
					 */
Packit 575503
Packit 575503
					JUMPTO(ni);
Packit 575503
				} else {
Packit 575503
					/* do run ENDFILE block(s) first. */
Packit 575503
Packit 575503
					/* Execution state to return to in Op_after_endfile. */
Packit 575503
					push_exec_state(ni, currule, source, stack_ptr);
Packit 575503
Packit 575503
					JUMPTO(pc->target_endfile);
Packit 575503
				}
Packit 575503
			} /* else
Packit 575503
				Start over with the first rule. */
Packit 575503
Packit 575503
			/* empty the run-time stack to avoid memory leak */
Packit 575503
			pop_stack();
Packit 575503
Packit 575503
			/* Push an execution state for Op_after_endfile to return to */
Packit 575503
			push_exec_state(pc->target_newfile, currule, source, stack_ptr);
Packit 575503
Packit 575503
			JUMPTO(pc->target_endfile);
Packit 575503
		}
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_K_exit:
Packit 575503
			/* exit not allowed in user-defined comparison functions for "sorted_in";
Packit 575503
			 * This is done so that END blocks aren't executed more than once.
Packit 575503
			 */
Packit 575503
			if (! currule)
Packit 575503
				fatal(_("`exit' cannot be called in the current context"));
Packit 575503
Packit 575503
			exiting = true;
Packit 575503
			if ((t1 = POP_NUMBER()) != Nnull_string) {
Packit 575503
				exit_val = (int) get_number_si(t1);
Packit 575503
#ifdef VMS
Packit 575503
				if (exit_val == 0)
Packit 575503
					exit_val = EXIT_SUCCESS;
Packit 575503
				else if (exit_val == 1)
Packit 575503
					exit_val = EXIT_FAILURE;
Packit 575503
				/* else
Packit 575503
					just pass anything else on through */
Packit 575503
#endif
Packit 575503
			}
Packit 575503
			DEREF(t1);
Packit 575503
Packit 575503
			if (currule == BEGINFILE || currule == ENDFILE) {
Packit 575503
Packit 575503
				/* Find the rule of the saved execution state (Op_K_getline/Op_newfile).
Packit 575503
				 * This is needed to prevent multiple execution of any END rules:
Packit 575503
				 * 	gawk 'BEGINFILE { exit(1) } \
Packit 575503
				 *         END { while (getline > 0); }' in1 in2
Packit 575503
				 */
Packit 575503
Packit 575503
				(void) pop_exec_state(& currule, & source, NULL);
Packit 575503
			}
Packit 575503
Packit 575503
			pop_stack();	/* empty stack, don't leak memory */
Packit 575503
Packit 575503
			/* Jump to either the first END block instruction
Packit 575503
			 * or to Op_atexit.
Packit 575503
			 */
Packit 575503
Packit 575503
			if (currule == END)
Packit 575503
				ni = pc->target_atexit;
Packit 575503
			else
Packit 575503
				ni = pc->target_end;
Packit 575503
			JUMPTO(ni);
Packit 575503
Packit 575503
		case Op_K_next:
Packit 575503
			if (currule != Rule)
Packit 575503
				fatal(_("`next' cannot be called from a `%s' rule"), ruletab[currule]);
Packit 575503
Packit 575503
			pop_stack();
Packit 575503
			JUMPTO(pc->target_jmp);	/* Op_get_record, read next record */
Packit 575503
Packit 575503
		case Op_pop:
Packit 575503
			r = POP_SCALAR();
Packit 575503
			DEREF(r);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_line_range:
Packit 575503
			if (pc->triggered)		/* evaluate right expression */
Packit 575503
				JUMPTO(pc->target_jmp);
Packit 575503
			/* else
Packit 575503
				evaluate left expression */
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_cond_pair:
Packit 575503
		{
Packit 575503
			int result;
Packit 575503
			INSTRUCTION *ip;
Packit 575503
Packit 575503
			t1 = TOP_SCALAR();   /* from right hand side expression */
Packit 575503
			di = (eval_condition(t1) != 0);
Packit 575503
			DEREF(t1);
Packit 575503
Packit 575503
			ip = pc->line_range;            /* Op_line_range */
Packit 575503
Packit 575503
			if (! ip->triggered && di) {
Packit 575503
				/* not already triggered and left expression is true */
Packit 575503
				decr_sp();
Packit 575503
				ip->triggered = true;
Packit 575503
				JUMPTO(ip->target_jmp);	/* evaluate right expression */
Packit 575503
			}
Packit 575503
Packit 575503
			result = ip->triggered || di;
Packit 575503
			ip->triggered ^= di;          /* update triggered flag */
Packit 575503
			r = node_Boolean[result];      /* final value of condition pair */
Packit 575503
			UPREF(r);
Packit 575503
			REPLACE(r);
Packit 575503
			JUMPTO(pc->target_jmp);
Packit 575503
		}
Packit 575503
Packit 575503
		case Op_exec_count:
Packit 575503
			if (do_profile)
Packit 575503
				pc->exec_count++;
Packit 575503
			break;
Packit 575503
Packit 575503
		case Op_no_op:
Packit 575503
		case Op_K_do:
Packit 575503
		case Op_K_while:
Packit 575503
		case Op_K_for:
Packit 575503
		case Op_K_arrayfor:
Packit 575503
		case Op_K_switch:
Packit 575503
		case Op_K_default:
Packit 575503
		case Op_K_if:
Packit 575503
		case Op_K_else:
Packit 575503
		case Op_cond_exp:
Packit 575503
		case Op_comment:
Packit 575503
		case Op_parens:
Packit 575503
			break;
Packit 575503
Packit 575503
		default:
Packit 575503
			fatal(_("Sorry, don't know how to interpret `%s'"), opcode2str(op));
Packit 575503
		}
Packit 575503
Packit 575503
		JUMPTO(pc->nexti);
Packit 575503
Packit 575503
/*	} forever */
Packit 575503
Packit 575503
	/* not reached */
Packit 575503
	return 0;
Packit 575503
Packit 575503
#undef mk_sub
Packit 575503
#undef JUMPTO
Packit 575503
}