xref: /titanic_51/usr/src/cmd/awk_xpg4/awk3.c (revision 79777a7dd0179283917bda2ba98999c382d31c2c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*79777a7dSnakanon  * Common Development and Distribution License (the "License").
6*79777a7dSnakanon  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * awk -- executor
237c478bd9Sstevel@tonic-gate  *
24*79777a7dSnakanon  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * Copyright 1985, 1994 by Mortice Kern Systems Inc.  All rights reserved.
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include "awk.h"
357c478bd9Sstevel@tonic-gate #include "y.tab.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate static int	dohash(wchar_t *name);
387c478bd9Sstevel@tonic-gate static NODE	*arithmetic(NODE *np);
397c478bd9Sstevel@tonic-gate static NODE	*comparison(NODE *np);
401c53dae2Smike_s static int	type_of(NODE *np);
417c478bd9Sstevel@tonic-gate static NODE	*lfield(INT fieldno, NODE *value);
427c478bd9Sstevel@tonic-gate static NODE	*rfield(INT fieldno);
437c478bd9Sstevel@tonic-gate static NODE	*userfunc(NODE *np);
447c478bd9Sstevel@tonic-gate static wchar_t	*lltoa(long long l);
457c478bd9Sstevel@tonic-gate static NODE	*exprconcat(NODE *np, int len);
467c478bd9Sstevel@tonic-gate static int	s_if(NODE *np);
477c478bd9Sstevel@tonic-gate static int	s_while(NODE *np);
487c478bd9Sstevel@tonic-gate static int	s_for(NODE *np);
497c478bd9Sstevel@tonic-gate static int	s_forin(NODE *np);
507c478bd9Sstevel@tonic-gate static void	setrefield(NODE *value);
517c478bd9Sstevel@tonic-gate static void	freetemps(void);
527c478bd9Sstevel@tonic-gate static int	action(NODE *np);
537c478bd9Sstevel@tonic-gate static wchar_t	*makeindex(NODE *np, wchar_t *array, int tag);
547c478bd9Sstevel@tonic-gate static int	exprtest(NODE *np);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	regmatch(rp, s) REGWEXEC(rp, s, 0, (REGWMATCH_T*)NULL, 0)
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * This code allows for integers to be stored in longs (type INT) and
607c478bd9Sstevel@tonic-gate  * only promoted to double precision floating point numbers (type REAL)
617c478bd9Sstevel@tonic-gate  * when overflow occurs during +, -, or * operations.  This is very
627c478bd9Sstevel@tonic-gate  * non-portable if you desire such a speed optimisation.  You may wish
637c478bd9Sstevel@tonic-gate  * to put something here for your system.  This "something" would likely
647c478bd9Sstevel@tonic-gate  * include either an assembler "jump on overflow" instruction or a
657c478bd9Sstevel@tonic-gate  * method to get traps on overflows from the hardware.
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * This portable method works for ones and twos complement integer
687c478bd9Sstevel@tonic-gate  * representations (which is, realistically) almost all machines.
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate #if	__TURBOC__
717c478bd9Sstevel@tonic-gate #define	addoverflow()	asm	jo	overflow
727c478bd9Sstevel@tonic-gate #define	suboverflow()	asm	jo	overflow
737c478bd9Sstevel@tonic-gate #else
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * These are portable to two's complement integer machines
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate #define	addoverflow()	if ((i1^i2) >= 0 && (iresult^i1) < 0) goto overflow
787c478bd9Sstevel@tonic-gate #define	suboverflow()	if ((i1^i2) < 0 && (iresult^i2) >= 0) goto overflow
797c478bd9Sstevel@tonic-gate #endif
80*79777a7dSnakanon #define	muloverflow()	if (((short)i1 != i1 || (short)i2 != i2) &&	\
81*79777a7dSnakanon 			    ((i2 != 0 && iresult/i2 != i1) ||		\
82*79777a7dSnakanon 			    (i1 == LONG_MIN && i2 == -1)))	  goto overflow
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static char	notarray[] = "scalar \"%s\" cannot be used as array";
857c478bd9Sstevel@tonic-gate static char	badarray[] = "array \"%s\" cannot be used as a scalar";
867c478bd9Sstevel@tonic-gate static char	varnotfunc[] = "variable \"%s\" cannot be used as a function";
877c478bd9Sstevel@tonic-gate static char	tmfld[] = "Too many fields (LIMIT: %d)";
887c478bd9Sstevel@tonic-gate static char	toolong[] = "Record too long (LIMIT: %d bytes)";
897c478bd9Sstevel@tonic-gate static char	divzero[] =  "division (/ or %%) by zero";
907c478bd9Sstevel@tonic-gate static char	toodeep[] = "too deeply nested for in loop (LIMIT: %d)";
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static wchar_t	numbuf[NUMSIZE];	/* Used to convert INTs to strings */
937c478bd9Sstevel@tonic-gate static wchar_t	*fields[NFIELD];	/* Cache of pointers into fieldbuf */
947c478bd9Sstevel@tonic-gate static wchar_t	*fieldbuf;		/* '\0' separated copy of linebuf */
957c478bd9Sstevel@tonic-gate static NODE	nodes[NSNODE];		/* Cache of quick access nodes */
967c478bd9Sstevel@tonic-gate static NODE	*fnodep = &nodes[0];
977c478bd9Sstevel@tonic-gate #define	NINDEXBUF	50
987c478bd9Sstevel@tonic-gate static wchar_t	indexbuf[NINDEXBUF];	/* Used for simple array indices */
997c478bd9Sstevel@tonic-gate static int	concflag;		/* In CONCAT operation (no frees) */
1007c478bd9Sstevel@tonic-gate static NODE	*retval;		/* Last return value of a function */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * The following stack is used to store the next pointers for all nested
1047c478bd9Sstevel@tonic-gate  * for-in loops. This needs to be global so that delete can check to see
1057c478bd9Sstevel@tonic-gate  * if it is deleting the next node to be used by a loop.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate #define	NFORINLOOP	10
1087c478bd9Sstevel@tonic-gate static NODE*	forindex[NFORINLOOP];
1097c478bd9Sstevel@tonic-gate static NODE**	next_forin = forindex;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Assign a string directly to a NODE without creating an intermediate
1137c478bd9Sstevel@tonic-gate  * NODE.  This can handle either FALLOC, FSTATIC, FNOALLOC or FSENSE for
1147c478bd9Sstevel@tonic-gate  * "flags" argument.  Also the NODE "np" must be reduced to an lvalue
1157c478bd9Sstevel@tonic-gate  * (PARM nodes are not acceptable).
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate void
1187c478bd9Sstevel@tonic-gate strassign(NODE *np, STRING string, int flags, size_t length)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	if (np->n_type == FUNC)
1217c478bd9Sstevel@tonic-gate 		awkerr(gettext("attempt to redefine builtin function"));
1227c478bd9Sstevel@tonic-gate 	else if (np->n_type == GETLINE || np->n_type == KEYWORD)
1237c478bd9Sstevel@tonic-gate 		awkerr(gettext("inadmissible use of reserved keyword"));
1247c478bd9Sstevel@tonic-gate 	if (np->n_flags & FSPECIAL) {
1257c478bd9Sstevel@tonic-gate 		(void) nassign(np, stringnode(string, flags, length));
1267c478bd9Sstevel@tonic-gate 		return;
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 	if (isastring(np->n_flags))
1297c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_string);
1307c478bd9Sstevel@tonic-gate 	np->n_strlen = length++;
1317c478bd9Sstevel@tonic-gate 	if (flags & FALLOC) {
1327c478bd9Sstevel@tonic-gate 		length *= sizeof (wchar_t);
1337c478bd9Sstevel@tonic-gate 		np->n_string = (STRING) emalloc(length);
1347c478bd9Sstevel@tonic-gate 		(void) memcpy((void *)np->n_string, string, length);
1357c478bd9Sstevel@tonic-gate 	} else {
1367c478bd9Sstevel@tonic-gate 		np->n_string = string;
1377c478bd9Sstevel@tonic-gate 		if (flags & FNOALLOC) {
1387c478bd9Sstevel@tonic-gate 			flags &= ~FNOALLOC;
1397c478bd9Sstevel@tonic-gate 			flags |= FALLOC;
1407c478bd9Sstevel@tonic-gate 		}
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 	np->n_flags &= FSAVE;
1437c478bd9Sstevel@tonic-gate 	if (flags & FSENSE) {
1447c478bd9Sstevel@tonic-gate 		flags &= ~FSENSE;
1451c53dae2Smike_s 		flags |= type_of(np);
1467c478bd9Sstevel@tonic-gate 	} else
1477c478bd9Sstevel@tonic-gate 		flags |= FSTRING;
1487c478bd9Sstevel@tonic-gate 	np->n_flags |= flags;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Assign to a variable node.
1537c478bd9Sstevel@tonic-gate  * LHS must be a VAR type and RHS must be reduced by now.
1547c478bd9Sstevel@tonic-gate  * To speed certain operations up, check for
1557c478bd9Sstevel@tonic-gate  * certain things here and do special assignments.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate NODE *
1587c478bd9Sstevel@tonic-gate nassign(NODE *np, NODE *value)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
1617c478bd9Sstevel@tonic-gate 	register int len;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/* short circuit assignment of a node to itself */
1647c478bd9Sstevel@tonic-gate 	if (np == value)
1657c478bd9Sstevel@tonic-gate 		return (np);
1667c478bd9Sstevel@tonic-gate 	if (np->n_flags & FSPECIAL) {
1677c478bd9Sstevel@tonic-gate 		if (np == varRS || np == varFS) {
1687c478bd9Sstevel@tonic-gate 			if (isastring(np->n_flags))
1697c478bd9Sstevel@tonic-gate 				free((void *)np->n_string);
1707c478bd9Sstevel@tonic-gate 			len = sizeof (wchar_t) * ((np->n_strlen =
1717c478bd9Sstevel@tonic-gate 				wcslen(cp = exprstring(value)))+1);
1727c478bd9Sstevel@tonic-gate 			np->n_string = emalloc(len);
1737c478bd9Sstevel@tonic-gate 			(void) memcpy((wchar_t *)np->n_string, cp, len);
1747c478bd9Sstevel@tonic-gate 			np->n_flags = FALLOC|FSTRING|FSPECIAL;
1757c478bd9Sstevel@tonic-gate 			if (np == varRS) {
1767c478bd9Sstevel@tonic-gate 				if (np->n_string[0] == '\n')
1777c478bd9Sstevel@tonic-gate 					awkrecord = defrecord;
1787c478bd9Sstevel@tonic-gate 				else if (np->n_string[0] == '\0')
1797c478bd9Sstevel@tonic-gate 					awkrecord = multirecord;
1807c478bd9Sstevel@tonic-gate 				else
1817c478bd9Sstevel@tonic-gate 					awkrecord = charrecord;
1827c478bd9Sstevel@tonic-gate 			} else if (np == varFS) {
1837c478bd9Sstevel@tonic-gate 				if (resep != (REGEXP)NULL) {
184*79777a7dSnakanon 					REGWFREE(resep);
1857c478bd9Sstevel@tonic-gate 					resep = (REGEXP)NULL;
1867c478bd9Sstevel@tonic-gate 				}
1877c478bd9Sstevel@tonic-gate 				if (wcslen((wchar_t *)np->n_string) > 1)
1887c478bd9Sstevel@tonic-gate 					setrefield(np);
1897c478bd9Sstevel@tonic-gate 				else if (np->n_string[0] == ' ')
1907c478bd9Sstevel@tonic-gate 					awkfield = whitefield;
1917c478bd9Sstevel@tonic-gate 				else
1927c478bd9Sstevel@tonic-gate 					awkfield = blackfield;
1937c478bd9Sstevel@tonic-gate 			}
1947c478bd9Sstevel@tonic-gate 			return (np);
1957c478bd9Sstevel@tonic-gate 		}
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	if (isastring(np->n_flags))
1987c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_string);
1997c478bd9Sstevel@tonic-gate 	if (isstring(value->n_flags)) {
2007c478bd9Sstevel@tonic-gate 		np->n_strlen = value->n_strlen;
2017c478bd9Sstevel@tonic-gate 		if (value->n_flags&FALLOC || value->n_string != _null) {
2027c478bd9Sstevel@tonic-gate 			len = (np->n_strlen+1) * sizeof (wchar_t);
2037c478bd9Sstevel@tonic-gate 			np->n_string = emalloc(len);
2047c478bd9Sstevel@tonic-gate 			(void) memcpy(np->n_string, value->n_string, len);
2057c478bd9Sstevel@tonic-gate 			np->n_flags &= FSAVE;
2067c478bd9Sstevel@tonic-gate 			np->n_flags |= value->n_flags & ~FSAVE;
2077c478bd9Sstevel@tonic-gate 			np->n_flags |= FALLOC;
2087c478bd9Sstevel@tonic-gate 			return (np);
2097c478bd9Sstevel@tonic-gate 		} else
2107c478bd9Sstevel@tonic-gate 			np->n_string = value->n_string;
2117c478bd9Sstevel@tonic-gate 	} else if (value->n_flags & FINT)
2127c478bd9Sstevel@tonic-gate 		np->n_int = value->n_int;
2137c478bd9Sstevel@tonic-gate 	else
2147c478bd9Sstevel@tonic-gate 		np->n_real = value->n_real;
2157c478bd9Sstevel@tonic-gate 	np->n_flags &= FSAVE;
2167c478bd9Sstevel@tonic-gate 	np->n_flags |= value->n_flags & ~FSAVE;
2177c478bd9Sstevel@tonic-gate 	return (np);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate  * Set regular expression FS value.
2227c478bd9Sstevel@tonic-gate  */
2237c478bd9Sstevel@tonic-gate static void
2247c478bd9Sstevel@tonic-gate setrefield(NODE *np)
2257c478bd9Sstevel@tonic-gate {
226*79777a7dSnakanon 	static REGEXP re;
2277c478bd9Sstevel@tonic-gate 	int n;
2287c478bd9Sstevel@tonic-gate 
229*79777a7dSnakanon 	if ((n = REGWCOMP(&re, np->n_string)) != REG_OK) {
230*79777a7dSnakanon 		REGWERROR(n, &re, (char *)linebuf, sizeof (linebuf));
2317c478bd9Sstevel@tonic-gate 		awkerr(gettext("syntax error \"%s\" in /%s/\n"),
2327c478bd9Sstevel@tonic-gate 			(char *)linebuf, np->n_string);
2337c478bd9Sstevel@tonic-gate 	}
234*79777a7dSnakanon 	resep = re;
2357c478bd9Sstevel@tonic-gate 	awkfield = refield;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * Assign to an l-value node.
2407c478bd9Sstevel@tonic-gate  */
2417c478bd9Sstevel@tonic-gate NODE *
2427c478bd9Sstevel@tonic-gate assign(NODE *left, NODE *right)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	if (isleaf(right->n_flags)) {
2457c478bd9Sstevel@tonic-gate 		if (right->n_type == PARM)
2467c478bd9Sstevel@tonic-gate 			right = right->n_next;
2477c478bd9Sstevel@tonic-gate 	} else
2487c478bd9Sstevel@tonic-gate 		right = exprreduce(right);
2497c478bd9Sstevel@tonic-gate top:
2507c478bd9Sstevel@tonic-gate 	switch (left->n_type) {
2517c478bd9Sstevel@tonic-gate 	case INDEX:
2527c478bd9Sstevel@tonic-gate 		left = exprreduce(left);
253*79777a7dSnakanon 	/*FALLTHRU*/
2547c478bd9Sstevel@tonic-gate 	case VAR:
2557c478bd9Sstevel@tonic-gate 		return (nassign(left, right));
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	case PARM:
2587c478bd9Sstevel@tonic-gate 		/*
2597c478bd9Sstevel@tonic-gate 		 * If it's a parameter then link to the actual value node and
2607c478bd9Sstevel@tonic-gate 		 * do the checks again.
2617c478bd9Sstevel@tonic-gate 		 */
2627c478bd9Sstevel@tonic-gate 		left = left->n_next;
2637c478bd9Sstevel@tonic-gate 		goto top;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	case FIELD:
2667c478bd9Sstevel@tonic-gate 		return (lfield(exprint(left->n_left), right));
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	case CALLUFUNC:
2697c478bd9Sstevel@tonic-gate 	case UFUNC:
2707c478bd9Sstevel@tonic-gate 		awkerr(gettext("cannot assign to function \"%s\""),
2717c478bd9Sstevel@tonic-gate 		    left->n_name);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	default:
2747c478bd9Sstevel@tonic-gate 		awkerr(gettext("lvalue required in assignment"));
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
27788f3d729Sakaplan 	return (0);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * Compiled tree non-terminal node.
2827c478bd9Sstevel@tonic-gate  */
2837c478bd9Sstevel@tonic-gate NODE *
2847c478bd9Sstevel@tonic-gate node(int type, NODE *left, NODE *right)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	register NODE *np;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	np = emptynode(type, 0);
2897c478bd9Sstevel@tonic-gate 	np->n_left = left;
2907c478bd9Sstevel@tonic-gate 	np->n_right = right;
2917c478bd9Sstevel@tonic-gate 	np->n_lineno = lineno;
2927c478bd9Sstevel@tonic-gate 	return (np);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate  * Create an integer node.
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate NODE *
2997c478bd9Sstevel@tonic-gate intnode(INT i)
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	register NODE *np;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	np = emptynode(CONSTANT, 0);
3047c478bd9Sstevel@tonic-gate 	np->n_flags = FINT|FVINT;
3057c478bd9Sstevel@tonic-gate 	np->n_int = i;
3067c478bd9Sstevel@tonic-gate 	return (np);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * Create a real number node.
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate NODE *
3137c478bd9Sstevel@tonic-gate realnode(REAL real)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	register NODE *np;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	np = emptynode(CONSTANT, 0);
3187c478bd9Sstevel@tonic-gate 	np->n_flags = FREAL|FVREAL;
3197c478bd9Sstevel@tonic-gate 	np->n_real = real;
3207c478bd9Sstevel@tonic-gate 	return (np);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate  * Make a node for a string.
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate NODE *
3277c478bd9Sstevel@tonic-gate stringnode(STRING s, int how, size_t length)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	register NODE *np;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	np = emptynode(CONSTANT, 0);
3327c478bd9Sstevel@tonic-gate 	np->n_strlen = length;
3337c478bd9Sstevel@tonic-gate 	if (how & FALLOC) {
3347c478bd9Sstevel@tonic-gate 		np->n_string = emalloc(length = (length+1) * sizeof (wchar_t));
3357c478bd9Sstevel@tonic-gate 		(void) memcpy(np->n_string, s, length);
3367c478bd9Sstevel@tonic-gate 	} else {
3377c478bd9Sstevel@tonic-gate 		np->n_string = s;
3387c478bd9Sstevel@tonic-gate 		if (how & FNOALLOC) {
3397c478bd9Sstevel@tonic-gate 			how &= ~FNOALLOC;
3407c478bd9Sstevel@tonic-gate 			how |= FALLOC;
3417c478bd9Sstevel@tonic-gate 		}
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 	if (how & FSENSE) {
3441c53dae2Smike_s 		np->n_flags = type_of(np);
3457c478bd9Sstevel@tonic-gate 		how &= ~FSENSE;
3467c478bd9Sstevel@tonic-gate 	} else
3477c478bd9Sstevel@tonic-gate 		np->n_flags = FSTRING;
3487c478bd9Sstevel@tonic-gate 	np->n_flags |= how;
3497c478bd9Sstevel@tonic-gate 	return (np);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * Save a copy of a string.
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate STRING
3567c478bd9Sstevel@tonic-gate strsave(wchar_t *old)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	STRING new;
3597c478bd9Sstevel@tonic-gate 	register size_t len;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	new = (STRING)emalloc(len = (wcslen(old)+1) * sizeof (wchar_t));
3627c478bd9Sstevel@tonic-gate 	(void) memcpy(new, old, len);
3637c478bd9Sstevel@tonic-gate 	return (new);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * Allocate an empty node of given type.
3687c478bd9Sstevel@tonic-gate  * String space for the node is given by `length'.
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate NODE *
3717c478bd9Sstevel@tonic-gate emptynode(int type, size_t length)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	register NODE *np;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	if (length == 0 && running && fnodep < &nodes[NSNODE]) {
3767c478bd9Sstevel@tonic-gate 		np = fnodep++;
3777c478bd9Sstevel@tonic-gate 	} else {
378*79777a7dSnakanon 		np = (NODE *)emalloc(sizeof (NODE) +
379*79777a7dSnakanon 		    (length * sizeof (wchar_t)));
3807c478bd9Sstevel@tonic-gate 		if (running && type != VAR && type != ARRAY) {
3817c478bd9Sstevel@tonic-gate 			np->n_next = freelist;
3827c478bd9Sstevel@tonic-gate 			freelist = np;
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 	np->n_flags = FNONTOK;
3867c478bd9Sstevel@tonic-gate 	np->n_type = type;
3877c478bd9Sstevel@tonic-gate 	np->n_alink = NNULL;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	return (np);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  * Free a node.
3947c478bd9Sstevel@tonic-gate  */
3957c478bd9Sstevel@tonic-gate void
3967c478bd9Sstevel@tonic-gate freenode(NODE *np)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	if (isastring(np->n_flags))
3997c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_string);
4007c478bd9Sstevel@tonic-gate 	else if (np->n_type == RE) {
401*79777a7dSnakanon 		REGWFREE(np->n_regexp);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 	free((wchar_t *)np);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate  * Install a keyword of given `type'.
4087c478bd9Sstevel@tonic-gate  */
4097c478bd9Sstevel@tonic-gate void
4107c478bd9Sstevel@tonic-gate kinstall(LOCCHARP name, int type)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	register NODE *np;
4137c478bd9Sstevel@tonic-gate 	register size_t l;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	l = wcslen(name);
4167c478bd9Sstevel@tonic-gate 	np = emptynode(KEYWORD, l);
4177c478bd9Sstevel@tonic-gate 	np->n_keywtype = type;
4187c478bd9Sstevel@tonic-gate 	(void) memcpy(np->n_name, name, (l+1) * sizeof (wchar_t));
4197c478bd9Sstevel@tonic-gate 	addsymtab(np);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate  * Install built-in function.
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate NODE *
4267c478bd9Sstevel@tonic-gate finstall(LOCCHARP name, FUNCTION func, int type)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	register NODE *np;
4297c478bd9Sstevel@tonic-gate 	register size_t l;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	l = wcslen(name);
4327c478bd9Sstevel@tonic-gate 	np = emptynode(type, l);
4337c478bd9Sstevel@tonic-gate 	np->n_function = func;
4347c478bd9Sstevel@tonic-gate 	(void) memcpy(np->n_name, name, (l+1) * sizeof (wchar_t));
4357c478bd9Sstevel@tonic-gate 	addsymtab(np);
436*79777a7dSnakanon 	return (np);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*
4407c478bd9Sstevel@tonic-gate  * Lookup an identifier.
4417c478bd9Sstevel@tonic-gate  * nocreate contains the following flag values:
4427c478bd9Sstevel@tonic-gate  *	1 if no creation of a new NODE,
4437c478bd9Sstevel@tonic-gate  *	0 if ok to create new NODE
4447c478bd9Sstevel@tonic-gate  */
4457c478bd9Sstevel@tonic-gate NODE *
4467c478bd9Sstevel@tonic-gate vlookup(wchar_t *name, int nocreate)
4477c478bd9Sstevel@tonic-gate {
448*79777a7dSnakanon 	register ushort_t hash;
4497c478bd9Sstevel@tonic-gate 	register NODE *np;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	np = symtab[hashbuck(hash = dohash((wchar_t *)name))];
4527c478bd9Sstevel@tonic-gate 	while (np != NNULL) {
4537c478bd9Sstevel@tonic-gate 		if (np->n_hash == hash && wcscmp(name, np->n_name) == 0)
4547c478bd9Sstevel@tonic-gate 			return (np);
4557c478bd9Sstevel@tonic-gate 		np = np->n_next;
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	if (nocreate) {
4587c478bd9Sstevel@tonic-gate 		np = NNULL;
4597c478bd9Sstevel@tonic-gate 	} else {
4607c478bd9Sstevel@tonic-gate 		np = emptynode(VAR, hash = wcslen(name));
4617c478bd9Sstevel@tonic-gate 		np->n_flags = FSTRING|FVINT;
4627c478bd9Sstevel@tonic-gate 		np->n_strlen = 0;
4637c478bd9Sstevel@tonic-gate 		np->n_string = _null;
4647c478bd9Sstevel@tonic-gate 		(void) memcpy(np->n_name, name,
4657c478bd9Sstevel@tonic-gate 			(hash+1) * sizeof (wchar_t));
4667c478bd9Sstevel@tonic-gate 		addsymtab(np);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	return (np);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate /*
4727c478bd9Sstevel@tonic-gate  * Add a symbol to the table.
4737c478bd9Sstevel@tonic-gate  */
4747c478bd9Sstevel@tonic-gate void
4757c478bd9Sstevel@tonic-gate addsymtab(NODE *np)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	register NODE **spp;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	np->n_hash = dohash((wchar_t *)np->n_name);
4807c478bd9Sstevel@tonic-gate 	spp = &symtab[hashbuck(np->n_hash)];
4817c478bd9Sstevel@tonic-gate 	np->n_next = *spp;
4827c478bd9Sstevel@tonic-gate 	*spp = np;
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * Delete the given node from the symbol table.
4877c478bd9Sstevel@tonic-gate  * If fflag is non-zero, also free the node space.
4887c478bd9Sstevel@tonic-gate  * This routine must also check the stack of forin loop pointers. If
4897c478bd9Sstevel@tonic-gate  * we are deleting the next item to be used, then the pointer must be
4907c478bd9Sstevel@tonic-gate  * advanced.
4917c478bd9Sstevel@tonic-gate  */
4927c478bd9Sstevel@tonic-gate void
4937c478bd9Sstevel@tonic-gate delsymtab(NODE *np, int fflag)
4947c478bd9Sstevel@tonic-gate {
4957c478bd9Sstevel@tonic-gate 	register NODE *rnp;
4967c478bd9Sstevel@tonic-gate 	register NODE *prevp;
4977c478bd9Sstevel@tonic-gate 	register NODE **sptr;
498*79777a7dSnakanon 	register ushort_t h;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	h = hashbuck(np->n_hash);
5057c478bd9Sstevel@tonic-gate 	prevp = NNULL;
5067c478bd9Sstevel@tonic-gate 	for (rnp = symtab[h]; rnp != NNULL; rnp = rnp->n_next) {
5077c478bd9Sstevel@tonic-gate 		if (rnp == np) {
5087c478bd9Sstevel@tonic-gate 			/*
5097c478bd9Sstevel@tonic-gate 			 * check all of the for-in loop pointers
5107c478bd9Sstevel@tonic-gate 			 * to see if any need to be advanced because
5117c478bd9Sstevel@tonic-gate 			 * this element is being deleted.
5127c478bd9Sstevel@tonic-gate 			 */
5137c478bd9Sstevel@tonic-gate 			if (next_forin != forindex) {
5147c478bd9Sstevel@tonic-gate 				sptr = next_forin;
5157c478bd9Sstevel@tonic-gate 				do {
5167c478bd9Sstevel@tonic-gate 					if (*--sptr == rnp) {
5177c478bd9Sstevel@tonic-gate 						*sptr = rnp->n_next;
5187c478bd9Sstevel@tonic-gate 						break;
5197c478bd9Sstevel@tonic-gate 					}
5207c478bd9Sstevel@tonic-gate 				} while (sptr != forindex);
5217c478bd9Sstevel@tonic-gate 			}
5227c478bd9Sstevel@tonic-gate 			if (prevp == NNULL)
5237c478bd9Sstevel@tonic-gate 				symtab[h] = rnp->n_next; else
5247c478bd9Sstevel@tonic-gate 				prevp->n_next = rnp->n_next;
5257c478bd9Sstevel@tonic-gate 			if (fflag)
5267c478bd9Sstevel@tonic-gate 				freenode(rnp);
5277c478bd9Sstevel@tonic-gate 			break;
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 		prevp = rnp;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate  * Hashing function.
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate static int
5377c478bd9Sstevel@tonic-gate dohash(wchar_t *name)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	register int hash = 0;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	while (*name != '\0')
5427c478bd9Sstevel@tonic-gate 		hash += *name++;
5437c478bd9Sstevel@tonic-gate 	return (hash);
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate  * Top level executor for an awk programme.
5487c478bd9Sstevel@tonic-gate  * This will be passed: pattern, action or a list of these.
5497c478bd9Sstevel@tonic-gate  * The former function to evaluate a pattern has been
5507c478bd9Sstevel@tonic-gate  * subsumed into this function for speed.
5517c478bd9Sstevel@tonic-gate  * Patterns are:
5527c478bd9Sstevel@tonic-gate  *	BEGIN,
5537c478bd9Sstevel@tonic-gate  *	END,
5547c478bd9Sstevel@tonic-gate  *	other expressions (including regular expressions)
5557c478bd9Sstevel@tonic-gate  */
5567c478bd9Sstevel@tonic-gate void
5577c478bd9Sstevel@tonic-gate execute(NODE *wp)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	register NODE *np;
5607c478bd9Sstevel@tonic-gate 	register int type;
5617c478bd9Sstevel@tonic-gate 	register NODE *tnp;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	curnode = wp;
5647c478bd9Sstevel@tonic-gate 	if (phase != 0) {
5657c478bd9Sstevel@tonic-gate 		linebuf[0] = '\0';
5667c478bd9Sstevel@tonic-gate 		lbuflen = 0;
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 	while (wp != NNULL) {
5697c478bd9Sstevel@tonic-gate 		if (wp->n_type == COMMA) {
5707c478bd9Sstevel@tonic-gate 			np = wp->n_left;
5717c478bd9Sstevel@tonic-gate 			wp = wp->n_right;
5727c478bd9Sstevel@tonic-gate 		} else {
5737c478bd9Sstevel@tonic-gate 			np = wp;
5747c478bd9Sstevel@tonic-gate 			wp = NNULL;
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 		if (np->n_type != PACT)
5777c478bd9Sstevel@tonic-gate 			awkerr(interr, "PACT");
5787c478bd9Sstevel@tonic-gate 		/*
5797c478bd9Sstevel@tonic-gate 		 * Save the parent node and evaluate the pattern.
5807c478bd9Sstevel@tonic-gate 		 * If it evaluates to false (0) just continue
5817c478bd9Sstevel@tonic-gate 		 * to the next pattern/action (PACT) pair.
5827c478bd9Sstevel@tonic-gate 		 */
5837c478bd9Sstevel@tonic-gate 		tnp = np;
5847c478bd9Sstevel@tonic-gate 		np = np->n_left;
5857c478bd9Sstevel@tonic-gate 		if (np == NNULL) {
5867c478bd9Sstevel@tonic-gate 			if (phase != 0)
5877c478bd9Sstevel@tonic-gate 				continue;
5887c478bd9Sstevel@tonic-gate 		} else if (phase != 0) {
5897c478bd9Sstevel@tonic-gate 			if (np->n_type != phase)
5907c478bd9Sstevel@tonic-gate 				continue;
5917c478bd9Sstevel@tonic-gate 		} else if ((type = np->n_type) == BEGIN || type == END) {
5927c478bd9Sstevel@tonic-gate 			continue;
5937c478bd9Sstevel@tonic-gate 		} else if (type == COMMA) {
5947c478bd9Sstevel@tonic-gate 			/*
5957c478bd9Sstevel@tonic-gate 			 * The grammar only allows expressions
5967c478bd9Sstevel@tonic-gate 			 * to be separated by the ',' operator
5977c478bd9Sstevel@tonic-gate 			 * for range patterns.
5987c478bd9Sstevel@tonic-gate 			 */
5997c478bd9Sstevel@tonic-gate 			if (np->n_flags & FMATCH) {
6007c478bd9Sstevel@tonic-gate 				if (exprint(np->n_right) != 0)
6017c478bd9Sstevel@tonic-gate 					np->n_flags &= ~FMATCH;
6027c478bd9Sstevel@tonic-gate 			} else if (exprint(np->n_left) != 0) {
6037c478bd9Sstevel@tonic-gate 				if (exprint(np->n_right) == 0)
6047c478bd9Sstevel@tonic-gate 					np->n_flags |= FMATCH;
6057c478bd9Sstevel@tonic-gate 			} else
6067c478bd9Sstevel@tonic-gate 				continue;
6077c478bd9Sstevel@tonic-gate 		} else if (exprint(np) == 0)
6087c478bd9Sstevel@tonic-gate 			continue;
6097c478bd9Sstevel@tonic-gate 		np = tnp;
6107c478bd9Sstevel@tonic-gate 		if (action(np->n_right)) {
6117c478bd9Sstevel@tonic-gate 			loopexit = 0;
6127c478bd9Sstevel@tonic-gate 			break;
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 	if (freelist != NNULL)
6167c478bd9Sstevel@tonic-gate 		freetemps();
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  * Free all temporary nodes.
6217c478bd9Sstevel@tonic-gate  */
6227c478bd9Sstevel@tonic-gate static void
6237c478bd9Sstevel@tonic-gate freetemps()
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	register NODE *np, *nnp;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (concflag)
6287c478bd9Sstevel@tonic-gate 		return;
6297c478bd9Sstevel@tonic-gate 	for (np = &nodes[0]; np < fnodep; np++) {
6307c478bd9Sstevel@tonic-gate 		if (isastring(np->n_flags)) {
6317c478bd9Sstevel@tonic-gate 			free((wchar_t *)np->n_string);
6327c478bd9Sstevel@tonic-gate 		} else if (np->n_type == RE) {
633*79777a7dSnakanon 			REGWFREE(np->n_regexp);
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 	fnodep = &nodes[0];
6377c478bd9Sstevel@tonic-gate 	for (np = freelist; np != NNULL; np = nnp) {
6387c478bd9Sstevel@tonic-gate 		nnp = np->n_next;
6397c478bd9Sstevel@tonic-gate 		freenode(np);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 	freelist = NNULL;
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate  * Do the given action.
6467c478bd9Sstevel@tonic-gate  * Actions are statements or expressions.
6477c478bd9Sstevel@tonic-gate  */
6487c478bd9Sstevel@tonic-gate static int
6497c478bd9Sstevel@tonic-gate action(NODE *wp)
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate 	register NODE *np;
6527c478bd9Sstevel@tonic-gate 	register int act = 0;
6537c478bd9Sstevel@tonic-gate 	register NODE *l;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	while (wp != NNULL) {
6567c478bd9Sstevel@tonic-gate 		if (wp->n_type == COMMA) {
6577c478bd9Sstevel@tonic-gate 			np = wp->n_left;
6587c478bd9Sstevel@tonic-gate 			wp = wp->n_right;
6597c478bd9Sstevel@tonic-gate 		} else {
6607c478bd9Sstevel@tonic-gate 			np = wp;
6617c478bd9Sstevel@tonic-gate 			wp = NNULL;
6627c478bd9Sstevel@tonic-gate 		}
6637c478bd9Sstevel@tonic-gate 		if (freelist != NNULL)
6647c478bd9Sstevel@tonic-gate 			freetemps();
6657c478bd9Sstevel@tonic-gate 		curnode = np;
6667c478bd9Sstevel@tonic-gate 		/*
6677c478bd9Sstevel@tonic-gate 		 * Don't change order of these cases without
6687c478bd9Sstevel@tonic-gate 		 * changing order in awk.y declarations.
6697c478bd9Sstevel@tonic-gate 		 * The order is optimised.
6707c478bd9Sstevel@tonic-gate 		 */
6717c478bd9Sstevel@tonic-gate 		switch (np->n_type) {
6727c478bd9Sstevel@tonic-gate 		case ASG:
6737c478bd9Sstevel@tonic-gate 			(void) assign(np->n_left, np->n_right);
6747c478bd9Sstevel@tonic-gate 			continue;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		case PRINT:
6777c478bd9Sstevel@tonic-gate 			s_print(np);
6787c478bd9Sstevel@tonic-gate 			continue;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		case PRINTF:
6817c478bd9Sstevel@tonic-gate 			s_prf(np);
6827c478bd9Sstevel@tonic-gate 			continue;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		case EXIT:
6857c478bd9Sstevel@tonic-gate 			if (np->n_left != NNULL)
6867c478bd9Sstevel@tonic-gate 				act = (int)exprint(np->n_left); else
6877c478bd9Sstevel@tonic-gate 				act = 0;
6887c478bd9Sstevel@tonic-gate 			doend(act);
6897c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		case RETURN:
6927c478bd9Sstevel@tonic-gate 			if (slevel == 0)
6937c478bd9Sstevel@tonic-gate 				awkerr(gettext("return outside of a function"));
6947c478bd9Sstevel@tonic-gate 			np = np->n_left != NNULL
6957c478bd9Sstevel@tonic-gate 			    ? exprreduce(np->n_left)
6967c478bd9Sstevel@tonic-gate 			    : const0;
6977c478bd9Sstevel@tonic-gate 			retval = emptynode(CONSTANT, 0);
6987c478bd9Sstevel@tonic-gate 			retval->n_flags = FINT;
6997c478bd9Sstevel@tonic-gate 			(void) nassign(retval, np);
7007c478bd9Sstevel@tonic-gate 			return (RETURN);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		case NEXT:
7037c478bd9Sstevel@tonic-gate 			loopexit = NEXT;
704*79777a7dSnakanon 		/*FALLTHRU*/
7057c478bd9Sstevel@tonic-gate 		case BREAK:
7067c478bd9Sstevel@tonic-gate 		case CONTINUE:
7077c478bd9Sstevel@tonic-gate 			return (np->n_type);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 		case DELETE:
7107c478bd9Sstevel@tonic-gate 			if ((l = np->n_left)->n_type == PARM) {
7117c478bd9Sstevel@tonic-gate 				l = l->n_next;
7127c478bd9Sstevel@tonic-gate 				if (!(l->n_flags & FLARRAY))
7137c478bd9Sstevel@tonic-gate 					l = l->n_alink;
7147c478bd9Sstevel@tonic-gate 			}
7157c478bd9Sstevel@tonic-gate 			switch (l->n_type) {
7167c478bd9Sstevel@tonic-gate 			case ARRAY:
7177c478bd9Sstevel@tonic-gate 				delarray(l);
7187c478bd9Sstevel@tonic-gate 				break;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 			case INDEX:
7217c478bd9Sstevel@tonic-gate 				if ((np = l->n_left)->n_type == PARM) {
7227c478bd9Sstevel@tonic-gate 					np = np->n_next;
7237c478bd9Sstevel@tonic-gate 					if (!(np->n_flags & FLARRAY))
7247c478bd9Sstevel@tonic-gate 						np = np->n_alink;
7257c478bd9Sstevel@tonic-gate 				}
7267c478bd9Sstevel@tonic-gate 				/*
7277c478bd9Sstevel@tonic-gate 				 * get pointer to the node for this array
7287c478bd9Sstevel@tonic-gate 				 * element using the hash key.
7297c478bd9Sstevel@tonic-gate 				 */
7307c478bd9Sstevel@tonic-gate 				l = exprreduce(l);
7317c478bd9Sstevel@tonic-gate 				/*
7327c478bd9Sstevel@tonic-gate 				 * now search linearly from the beginning of
7337c478bd9Sstevel@tonic-gate 				 * the list to find the element before the
7347c478bd9Sstevel@tonic-gate 				 * one being deleted. This must be done
7357c478bd9Sstevel@tonic-gate 				 * because arrays are singley-linked.
7367c478bd9Sstevel@tonic-gate 				 */
7377c478bd9Sstevel@tonic-gate 				while (np != NNULL) {
7387c478bd9Sstevel@tonic-gate 					if (np->n_alink == l) {
7397c478bd9Sstevel@tonic-gate 						np->n_alink = l->n_alink;
7407c478bd9Sstevel@tonic-gate 						break;
7417c478bd9Sstevel@tonic-gate 					}
7427c478bd9Sstevel@tonic-gate 					np = np->n_alink;
7437c478bd9Sstevel@tonic-gate 				}
7447c478bd9Sstevel@tonic-gate 				delsymtab(l, 1);
7457c478bd9Sstevel@tonic-gate 				break;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 			case VAR:
748*79777a7dSnakanon 				if (isstring(l->n_flags) &&
749*79777a7dSnakanon 				    l->n_string == _null)
7507c478bd9Sstevel@tonic-gate 					break;
7517c478bd9Sstevel@tonic-gate 			default:
7527c478bd9Sstevel@tonic-gate 				awkerr(gettext(
7537c478bd9Sstevel@tonic-gate 				    "may delete only array element or array"));
7547c478bd9Sstevel@tonic-gate 				break;
7557c478bd9Sstevel@tonic-gate 			}
7567c478bd9Sstevel@tonic-gate 			continue;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		case WHILE:
7597c478bd9Sstevel@tonic-gate 		case DO:
7607c478bd9Sstevel@tonic-gate 			if ((act = s_while(np)) != 0)
7617c478bd9Sstevel@tonic-gate 				break;
7627c478bd9Sstevel@tonic-gate 			continue;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		case FOR:
7657c478bd9Sstevel@tonic-gate 			if ((act = s_for(np)) != 0)
7667c478bd9Sstevel@tonic-gate 				break;
7677c478bd9Sstevel@tonic-gate 			continue;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 		case FORIN:
7707c478bd9Sstevel@tonic-gate 			if ((act = s_forin(np)) != 0)
7717c478bd9Sstevel@tonic-gate 				break;
7727c478bd9Sstevel@tonic-gate 			continue;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		case IF:
7757c478bd9Sstevel@tonic-gate 			if ((act = s_if(np)) != 0)
7767c478bd9Sstevel@tonic-gate 				break;
7777c478bd9Sstevel@tonic-gate 			continue;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 		default:
7807c478bd9Sstevel@tonic-gate 			(void) exprreduce(np);
7817c478bd9Sstevel@tonic-gate 			if (loopexit != 0) {
7827c478bd9Sstevel@tonic-gate 				act = loopexit;
7837c478bd9Sstevel@tonic-gate 				break;
7847c478bd9Sstevel@tonic-gate 			}
7857c478bd9Sstevel@tonic-gate 			continue;
7867c478bd9Sstevel@tonic-gate 		}
7877c478bd9Sstevel@tonic-gate 		return (act);
7887c478bd9Sstevel@tonic-gate 	}
7897c478bd9Sstevel@tonic-gate 	return (0);
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate /*
7937c478bd9Sstevel@tonic-gate  * Delete an entire array
7947c478bd9Sstevel@tonic-gate  */
7957c478bd9Sstevel@tonic-gate void
7967c478bd9Sstevel@tonic-gate delarray(NODE *np)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate 	register NODE *nnp;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	nnp = np->n_alink;
8017c478bd9Sstevel@tonic-gate 	np->n_alink = NNULL;
8027c478bd9Sstevel@tonic-gate 	while (nnp != NNULL) {
8037c478bd9Sstevel@tonic-gate 		np = nnp->n_alink;
8047c478bd9Sstevel@tonic-gate 		delsymtab(nnp, 1);
8057c478bd9Sstevel@tonic-gate 		nnp = np;
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate  * Return the INT value of an expression.
8117c478bd9Sstevel@tonic-gate  */
8127c478bd9Sstevel@tonic-gate INT
8137c478bd9Sstevel@tonic-gate exprint(NODE *np)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate 	if (isleaf(np->n_flags)) {
8167c478bd9Sstevel@tonic-gate 		if (np->n_type == PARM)
8177c478bd9Sstevel@tonic-gate 			np = np->n_next;
8187c478bd9Sstevel@tonic-gate 		goto leaf;
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
8217c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
8227c478bd9Sstevel@tonic-gate 	case CONSTANT:
8237c478bd9Sstevel@tonic-gate 	case VAR:
8247c478bd9Sstevel@tonic-gate 	leaf:
8257c478bd9Sstevel@tonic-gate 		if (np->n_flags & FINT)
8267c478bd9Sstevel@tonic-gate 			return (np->n_int);
8277c478bd9Sstevel@tonic-gate 		if (np->n_flags & FREAL)
8287c478bd9Sstevel@tonic-gate 			return ((INT)np->n_real);
829*79777a7dSnakanon 		return ((INT)wcstoll(np->n_string, NULL, 10));
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	default:
8327c478bd9Sstevel@tonic-gate 		awkerr(interr, "exprint");
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
83588f3d729Sakaplan 	return (0);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate  * Return a real number from an expression tree.
8407c478bd9Sstevel@tonic-gate  */
8417c478bd9Sstevel@tonic-gate REAL
8427c478bd9Sstevel@tonic-gate exprreal(NODE *np)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate 	if (loopexit)
845*79777a7dSnakanon 		return ((REAL)loopexit);
8467c478bd9Sstevel@tonic-gate 	if (isleaf(np->n_flags)) {
8477c478bd9Sstevel@tonic-gate 		if (np->n_type == PARM)
8487c478bd9Sstevel@tonic-gate 			np = np->n_next;
8497c478bd9Sstevel@tonic-gate 		goto leaf;
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
8527c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
8537c478bd9Sstevel@tonic-gate 	case CONSTANT:
8547c478bd9Sstevel@tonic-gate 	case VAR:
8557c478bd9Sstevel@tonic-gate 	leaf:
8567c478bd9Sstevel@tonic-gate 		if (np->n_flags & FREAL)
8577c478bd9Sstevel@tonic-gate 			return (np->n_real);
8587c478bd9Sstevel@tonic-gate 		if (np->n_flags & FINT)
8597c478bd9Sstevel@tonic-gate 			return ((REAL)np->n_int);
8607c478bd9Sstevel@tonic-gate 		return ((REAL)wcstod((wchar_t *)np->n_string, (wchar_t **)0));
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	default:
8637c478bd9Sstevel@tonic-gate 		awkerr(interr, "exprreal");
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
866*79777a7dSnakanon 	return ((REAL)0);
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate /*
8707c478bd9Sstevel@tonic-gate  * Return a string from an expression tree.
8717c478bd9Sstevel@tonic-gate  */
8727c478bd9Sstevel@tonic-gate STRING
8737c478bd9Sstevel@tonic-gate exprstring(NODE *np)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	if (isleaf(np->n_flags)) {
8767c478bd9Sstevel@tonic-gate 		if (np->n_type == PARM)
8777c478bd9Sstevel@tonic-gate 			np = np->n_next;
8787c478bd9Sstevel@tonic-gate 		goto leaf;
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
8817c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
8827c478bd9Sstevel@tonic-gate 	case CONSTANT:
8837c478bd9Sstevel@tonic-gate 	case VAR:
8847c478bd9Sstevel@tonic-gate 	leaf:
8857c478bd9Sstevel@tonic-gate 		if (isstring(np->n_flags))
8867c478bd9Sstevel@tonic-gate 			return (np->n_string);
8877c478bd9Sstevel@tonic-gate 		if (np->n_flags & FINT)
8887c478bd9Sstevel@tonic-gate 			return (STRING)lltoa((long long)np->n_int);
8897c478bd9Sstevel@tonic-gate 		{
8907c478bd9Sstevel@tonic-gate 			char *tmp;
8917c478bd9Sstevel@tonic-gate 			(void) wsprintf(numbuf,
8927c478bd9Sstevel@tonic-gate 		(const char *) (tmp = wcstombsdup(exprstring(varCONVFMT))),
8937c478bd9Sstevel@tonic-gate 				(double)np->n_real);
8947c478bd9Sstevel@tonic-gate 			if (tmp != NULL)
8957c478bd9Sstevel@tonic-gate 				free(tmp);
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 		return ((STRING)numbuf);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	default:
9007c478bd9Sstevel@tonic-gate 		awkerr(interr, "exprstring");
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
90388f3d729Sakaplan 	return (0);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate /*
9077c478bd9Sstevel@tonic-gate  * Convert number to string.
9087c478bd9Sstevel@tonic-gate  */
9097c478bd9Sstevel@tonic-gate static wchar_t *
9107c478bd9Sstevel@tonic-gate lltoa(long long l)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 	register wchar_t *p = &numbuf[NUMSIZE];
9137c478bd9Sstevel@tonic-gate 	register int s;
9147c478bd9Sstevel@tonic-gate 	register int neg;
9157c478bd9Sstevel@tonic-gate 	static wchar_t zero[] = M_MB_L("0");
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (l == 0)
9187c478bd9Sstevel@tonic-gate 		return (zero);
9197c478bd9Sstevel@tonic-gate 	*--p = '\0';
9207c478bd9Sstevel@tonic-gate 	if (l < 0)
9217c478bd9Sstevel@tonic-gate 		neg = 1, l = -l; else
9227c478bd9Sstevel@tonic-gate 		neg = 0;
9237c478bd9Sstevel@tonic-gate 	if ((s = (short)l) == l) {
9247c478bd9Sstevel@tonic-gate 		while (s != 0) {
9257c478bd9Sstevel@tonic-gate 			*--p = s%10 + '0';
9267c478bd9Sstevel@tonic-gate 			s /= 10;
9277c478bd9Sstevel@tonic-gate 		}
9287c478bd9Sstevel@tonic-gate 	} else {
9297c478bd9Sstevel@tonic-gate 		while (l != 0) {
9307c478bd9Sstevel@tonic-gate 			*--p = l%10 + '0';
9317c478bd9Sstevel@tonic-gate 			l /= 10;
9327c478bd9Sstevel@tonic-gate 		}
9337c478bd9Sstevel@tonic-gate 	}
9347c478bd9Sstevel@tonic-gate 	if (neg)
9357c478bd9Sstevel@tonic-gate 		*--p = '-';
9367c478bd9Sstevel@tonic-gate 	return (wcscpy(numbuf, p));
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate /*
9407c478bd9Sstevel@tonic-gate  * Return pointer to node with concatenation of operands of CONCAT node.
9417c478bd9Sstevel@tonic-gate  * In the interest of speed, a left recursive tree of CONCAT nodes
9427c478bd9Sstevel@tonic-gate  * is handled with a single malloc.  The accumulated lengths of the
9437c478bd9Sstevel@tonic-gate  * right operands are passed down recursive invocations of this
9447c478bd9Sstevel@tonic-gate  * routine, which allocates a large enough string when the left
9457c478bd9Sstevel@tonic-gate  * operand is not a CONCAT node.
9467c478bd9Sstevel@tonic-gate  */
9477c478bd9Sstevel@tonic-gate static NODE *
9487c478bd9Sstevel@tonic-gate exprconcat(NODE *np, int len)
9497c478bd9Sstevel@tonic-gate {
9507c478bd9Sstevel@tonic-gate 	/* we KNOW (np->n_type==CONCAT) */
9517c478bd9Sstevel@tonic-gate 	register NODE *lnp = np->n_left;
9527c478bd9Sstevel@tonic-gate 	register NODE *rnp = np->n_right;
9537c478bd9Sstevel@tonic-gate 	register STRING	rsp;
9547c478bd9Sstevel@tonic-gate 	int rlen;
9557c478bd9Sstevel@tonic-gate 	size_t llen;
9567c478bd9Sstevel@tonic-gate 	wchar_t *cp;
9577c478bd9Sstevel@tonic-gate 	wchar_t rnumbuf[NUMSIZE];
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if (isleaf(rnp->n_flags) && rnp->n_type == PARM)
9607c478bd9Sstevel@tonic-gate 		rnp = rnp->n_next;
9617c478bd9Sstevel@tonic-gate 	if (isstring(rnp->n_flags)) {
9627c478bd9Sstevel@tonic-gate 		rsp = rnp->n_string;
9637c478bd9Sstevel@tonic-gate 		rlen = rnp->n_strlen;
9647c478bd9Sstevel@tonic-gate 	} else
9657c478bd9Sstevel@tonic-gate 		rlen = wcslen((wchar_t *)(rsp = exprstring(rnp)));
9667c478bd9Sstevel@tonic-gate 	if (rsp == numbuf) {	/* static, so save a copy */
9677c478bd9Sstevel@tonic-gate 		(void) memcpy(rnumbuf, (wchar_t *)rsp,
9687c478bd9Sstevel@tonic-gate 			(rlen+1) * sizeof (wchar_t));
9697c478bd9Sstevel@tonic-gate 		rsp = rnumbuf;
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 	len += rlen;
9727c478bd9Sstevel@tonic-gate 	if (lnp->n_type == CONCAT) {
9737c478bd9Sstevel@tonic-gate 		lnp = exprconcat(lnp, len);
9747c478bd9Sstevel@tonic-gate 		cp = lnp->n_string;
9757c478bd9Sstevel@tonic-gate 		llen = lnp->n_strlen;
9767c478bd9Sstevel@tonic-gate 	} else {
9777c478bd9Sstevel@tonic-gate 		register STRING	lsp;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 		if (isleaf(lnp->n_flags) && lnp->n_type == PARM)
9807c478bd9Sstevel@tonic-gate 			lnp = lnp->n_next;
9817c478bd9Sstevel@tonic-gate 		if (isstring(lnp->n_flags)) {
9827c478bd9Sstevel@tonic-gate 			lsp = lnp->n_string;
9837c478bd9Sstevel@tonic-gate 			llen = lnp->n_strlen;
9847c478bd9Sstevel@tonic-gate 		} else
9857c478bd9Sstevel@tonic-gate 			llen = wcslen((wchar_t *)(lsp = exprstring(lnp)));
9867c478bd9Sstevel@tonic-gate 		cp = emalloc((llen+len+1) * sizeof (wchar_t));
9877c478bd9Sstevel@tonic-gate 		(void) memcpy(cp, (wchar_t *)lsp, llen * sizeof (wchar_t));
9887c478bd9Sstevel@tonic-gate 		lnp = stringnode(cp, FNOALLOC, llen);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 	(void) memcpy(cp+llen, (wchar_t *)rsp, (rlen+1) * sizeof (wchar_t));
9917c478bd9Sstevel@tonic-gate 	lnp->n_strlen += rlen;
9927c478bd9Sstevel@tonic-gate 	return (lnp);
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate /*
9967c478bd9Sstevel@tonic-gate  * Reduce an expression to a terminal node.
9977c478bd9Sstevel@tonic-gate  */
9987c478bd9Sstevel@tonic-gate NODE *
9997c478bd9Sstevel@tonic-gate exprreduce(NODE *np)
10007c478bd9Sstevel@tonic-gate {
10017c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
10027c478bd9Sstevel@tonic-gate 	NODE *tnp;
10037c478bd9Sstevel@tonic-gate 	register int temp;
10047c478bd9Sstevel@tonic-gate 	register int t;
10057c478bd9Sstevel@tonic-gate 	register int  tag;
10067c478bd9Sstevel@tonic-gate 	register wchar_t *fname;
10077c478bd9Sstevel@tonic-gate 	register wchar_t *aname;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/*
10107c478bd9Sstevel@tonic-gate 	 * a var or constant is a leaf-node (no further reduction required)
10117c478bd9Sstevel@tonic-gate 	 * so return immediately.
10127c478bd9Sstevel@tonic-gate 	 */
10137c478bd9Sstevel@tonic-gate 	if ((t = np->n_type) == VAR || t == CONSTANT)
10147c478bd9Sstevel@tonic-gate 		return (np);
10157c478bd9Sstevel@tonic-gate 	/*
10167c478bd9Sstevel@tonic-gate 	 * If it's a parameter then it is probably a leaf node but it
10177c478bd9Sstevel@tonic-gate 	 * might be an array so we check.. If it is an array, then signal
10187c478bd9Sstevel@tonic-gate 	 * an error as an array by itself cannot be used in this context.
10197c478bd9Sstevel@tonic-gate 	 */
10207c478bd9Sstevel@tonic-gate 	if (t == PARM)
10217c478bd9Sstevel@tonic-gate 		if ((np = np->n_next)->n_type == ARRAY)
10227c478bd9Sstevel@tonic-gate 			awkerr(badarray, np->n_name);
10237c478bd9Sstevel@tonic-gate 		else
10247c478bd9Sstevel@tonic-gate 			return (np);
10257c478bd9Sstevel@tonic-gate 	/*
10267c478bd9Sstevel@tonic-gate 	 * All the rest are non-leaf nodes.
10277c478bd9Sstevel@tonic-gate 	 */
10287c478bd9Sstevel@tonic-gate 	curnode = np;
10297c478bd9Sstevel@tonic-gate 	switch (t) {
10307c478bd9Sstevel@tonic-gate 	case CALLUFUNC:
10317c478bd9Sstevel@tonic-gate 		return (userfunc(np));
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	case FIELD:
10347c478bd9Sstevel@tonic-gate 		return (rfield(exprint(np->n_left)));
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	case IN:
10377c478bd9Sstevel@tonic-gate 	case INDEX:
10387c478bd9Sstevel@tonic-gate 		tag = 0;
10397c478bd9Sstevel@tonic-gate 		temp = np->n_type;
10407c478bd9Sstevel@tonic-gate 		tnp = np->n_left;
10417c478bd9Sstevel@tonic-gate 		np = np->n_right;
10427c478bd9Sstevel@tonic-gate 		/* initially formal var name and array key name are the same */
10437c478bd9Sstevel@tonic-gate 		fname = aname = tnp->n_name;
10447c478bd9Sstevel@tonic-gate 		if (tnp->n_type == PARM) {
10457c478bd9Sstevel@tonic-gate 			tnp = tnp->n_next;
10467c478bd9Sstevel@tonic-gate 			tag = tnp->n_scope;
10477c478bd9Sstevel@tonic-gate 			if (!(tnp->n_flags & FLARRAY)) {
10487c478bd9Sstevel@tonic-gate 				tnp = tnp->n_alink;
10497c478bd9Sstevel@tonic-gate 			}
10507c478bd9Sstevel@tonic-gate 			aname = tnp->n_name;
10517c478bd9Sstevel@tonic-gate 		}
10527c478bd9Sstevel@tonic-gate 		if (tnp->n_type != ARRAY) {
10537c478bd9Sstevel@tonic-gate 			if (!isstring(tnp->n_flags) || tnp->n_string != _null)
10547c478bd9Sstevel@tonic-gate 				awkerr(notarray, fname);
10557c478bd9Sstevel@tonic-gate 			else {
10567c478bd9Sstevel@tonic-gate 				/* promotion to array */
10577c478bd9Sstevel@tonic-gate 				promote(tnp);
10587c478bd9Sstevel@tonic-gate 				if (tnp->n_alink != NNULL) {
10597c478bd9Sstevel@tonic-gate 					tag = tnp->n_scope;
10607c478bd9Sstevel@tonic-gate 					if (!(tnp->n_flags & FLARRAY))
10617c478bd9Sstevel@tonic-gate 						tnp = tnp->n_alink;
10627c478bd9Sstevel@tonic-gate 					aname = tnp->n_name;
10637c478bd9Sstevel@tonic-gate 				} else {
10647c478bd9Sstevel@tonic-gate 					tag = 0;
10657c478bd9Sstevel@tonic-gate 					if (tnp->n_flags & FLARRAY)
10667c478bd9Sstevel@tonic-gate 						tag = tnp->n_scope;
10677c478bd9Sstevel@tonic-gate 				}
10687c478bd9Sstevel@tonic-gate 			}
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 		if (tnp == varSYMTAB) {
10717c478bd9Sstevel@tonic-gate 			if (np == NNULL || np->n_type == COMMA)
10727c478bd9Sstevel@tonic-gate 				awkerr(gettext(
10737c478bd9Sstevel@tonic-gate 				    "SYMTAB must have exactly one index"));
10747c478bd9Sstevel@tonic-gate 			np = vlook(exprstring(np));
10757c478bd9Sstevel@tonic-gate 			return (np);
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate 		cp = makeindex(np, aname, tag);
10787c478bd9Sstevel@tonic-gate 		if (temp == INDEX) {
10797c478bd9Sstevel@tonic-gate 			np = vlook(cp);
10807c478bd9Sstevel@tonic-gate 			if (!(np->n_flags & FINARRAY)) {
10817c478bd9Sstevel@tonic-gate 				np->n_alink = tnp->n_alink;
10827c478bd9Sstevel@tonic-gate 				tnp->n_alink = np;
10837c478bd9Sstevel@tonic-gate 				np->n_flags |= FINARRAY;
10847c478bd9Sstevel@tonic-gate 			}
10857c478bd9Sstevel@tonic-gate 		} else
10867c478bd9Sstevel@tonic-gate 			np = vlookup(cp, 1) == NNULL ? const0 : const1;
10877c478bd9Sstevel@tonic-gate 		if (cp != indexbuf)
10887c478bd9Sstevel@tonic-gate 			free(cp);
10897c478bd9Sstevel@tonic-gate 		return (np);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	case CONCAT:
10927c478bd9Sstevel@tonic-gate 		++concflag;
10937c478bd9Sstevel@tonic-gate 		np = exprconcat(np, 0);
10947c478bd9Sstevel@tonic-gate 		--concflag;
10957c478bd9Sstevel@tonic-gate 		return (np);
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	case NOT:
10987c478bd9Sstevel@tonic-gate 		return (intnode(exprtest(np->n_left) == 0 ? (INT)1 : (INT)0));
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	case AND:
1101*79777a7dSnakanon 		return ((exprtest(np->n_left) != 0 &&
1102*79777a7dSnakanon 		    exprtest(np->n_right) != 0) ? const1 : const0);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	case OR:
1105*79777a7dSnakanon 		return ((exprtest(np->n_left) != 0 ||
1106*79777a7dSnakanon 		    exprtest(np->n_right) != 0) ? const1 : const0);
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	case EXP:
11097c478bd9Sstevel@tonic-gate 		{
11107c478bd9Sstevel@tonic-gate 			double f1, f2;
11117c478bd9Sstevel@tonic-gate 
1112*79777a7dSnakanon 			/*
1113*79777a7dSnakanon 			 * evaluate expressions in proper order before
11147c478bd9Sstevel@tonic-gate 			 * calling pow().
11157c478bd9Sstevel@tonic-gate 			 * Can't guarantee that compiler will do this
11167c478bd9Sstevel@tonic-gate 			 * correctly for us if we put them inline.
11177c478bd9Sstevel@tonic-gate 			 */
11187c478bd9Sstevel@tonic-gate 			f1 = (double)exprreal(np->n_left);
11197c478bd9Sstevel@tonic-gate 			f2 = (double)exprreal(np->n_right);
11207c478bd9Sstevel@tonic-gate 			return (realnode((REAL)pow(f1, f2)));
11217c478bd9Sstevel@tonic-gate 		}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	case QUEST:
11247c478bd9Sstevel@tonic-gate 		if (np->n_right->n_type != COLON)
11257c478bd9Sstevel@tonic-gate 			awkerr(interr, "?:");
11267c478bd9Sstevel@tonic-gate 		if (exprtest(np->n_left))
11277c478bd9Sstevel@tonic-gate 			np = np->n_right->n_left; else
11287c478bd9Sstevel@tonic-gate 			np = np->n_right->n_right;
11297c478bd9Sstevel@tonic-gate 		return (exprreduce(np));
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	case EQ:
11327c478bd9Sstevel@tonic-gate 	case NE:
11337c478bd9Sstevel@tonic-gate 	case GE:
11347c478bd9Sstevel@tonic-gate 	case LE:
11357c478bd9Sstevel@tonic-gate 	case GT:
11367c478bd9Sstevel@tonic-gate 	case LT:
11377c478bd9Sstevel@tonic-gate 		return (comparison(np));
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	case ADD:
11407c478bd9Sstevel@tonic-gate 	case SUB:
11417c478bd9Sstevel@tonic-gate 	case MUL:
11427c478bd9Sstevel@tonic-gate 	case DIV:
11437c478bd9Sstevel@tonic-gate 	case REM:
11447c478bd9Sstevel@tonic-gate 		return (arithmetic(np));
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	case DEC:
11477c478bd9Sstevel@tonic-gate 		inc_oper->n_type = SUB;
11487c478bd9Sstevel@tonic-gate 		goto do_inc_op;
11497c478bd9Sstevel@tonic-gate 	case INC:
11507c478bd9Sstevel@tonic-gate 		inc_oper->n_type = ADD;
11517c478bd9Sstevel@tonic-gate do_inc_op:
11527c478bd9Sstevel@tonic-gate 		if ((np = np->n_left)->n_type == INDEX)
11537c478bd9Sstevel@tonic-gate 			np = exprreduce(np);
11547c478bd9Sstevel@tonic-gate 		if (np->n_flags & FREAL)
11557c478bd9Sstevel@tonic-gate 			tnp = realnode(np->n_real);
11567c478bd9Sstevel@tonic-gate 		else
11577c478bd9Sstevel@tonic-gate 			tnp = intnode(exprint(np));
11587c478bd9Sstevel@tonic-gate 		inc_oper->n_left = np;
11597c478bd9Sstevel@tonic-gate 		(void) assign(np, inc_oper);
11607c478bd9Sstevel@tonic-gate 		return (tnp);
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	case PRE_DEC:
11637c478bd9Sstevel@tonic-gate 		inc_oper->n_type = SUB;
11647c478bd9Sstevel@tonic-gate 		goto do_pinc_op;
11657c478bd9Sstevel@tonic-gate 	case PRE_INC:
11667c478bd9Sstevel@tonic-gate 		inc_oper->n_type = ADD;
11677c478bd9Sstevel@tonic-gate do_pinc_op:
11687c478bd9Sstevel@tonic-gate 		if ((np = np->n_left)->n_type == INDEX)
11697c478bd9Sstevel@tonic-gate 			np = exprreduce(np);
11707c478bd9Sstevel@tonic-gate 		inc_oper->n_left = np;
11717c478bd9Sstevel@tonic-gate 		return (assign(np, inc_oper));
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	case AADD:
11747c478bd9Sstevel@tonic-gate 		asn_oper->n_type = ADD;
11757c478bd9Sstevel@tonic-gate 		goto do_asn_op;
11767c478bd9Sstevel@tonic-gate 	case ASUB:
11777c478bd9Sstevel@tonic-gate 		asn_oper->n_type = SUB;
11787c478bd9Sstevel@tonic-gate 		goto do_asn_op;
11797c478bd9Sstevel@tonic-gate 	case AMUL:
11807c478bd9Sstevel@tonic-gate 		asn_oper->n_type = MUL;
11817c478bd9Sstevel@tonic-gate 		goto do_asn_op;
11827c478bd9Sstevel@tonic-gate 	case ADIV:
11837c478bd9Sstevel@tonic-gate 		asn_oper->n_type = DIV;
11847c478bd9Sstevel@tonic-gate 		goto do_asn_op;
11857c478bd9Sstevel@tonic-gate 	case AREM:
11867c478bd9Sstevel@tonic-gate 		asn_oper->n_type = REM;
11877c478bd9Sstevel@tonic-gate 		goto do_asn_op;
11887c478bd9Sstevel@tonic-gate 	case AEXP:
11897c478bd9Sstevel@tonic-gate 		asn_oper->n_type = EXP;
11907c478bd9Sstevel@tonic-gate do_asn_op:
11917c478bd9Sstevel@tonic-gate 		asn_oper->n_right = np->n_right;
11927c478bd9Sstevel@tonic-gate 		if ((np = np->n_left)->n_type == INDEX)
11937c478bd9Sstevel@tonic-gate 			np = exprreduce(np);
11947c478bd9Sstevel@tonic-gate 		asn_oper->n_left = np;
11957c478bd9Sstevel@tonic-gate 		return (assign(np, asn_oper));
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	case GETLINE:
11997c478bd9Sstevel@tonic-gate 		return (f_getline(np));
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	case CALLFUNC:
12027c478bd9Sstevel@tonic-gate 		return ((*np->n_left->n_function)(np->n_right));
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	case RE:
12057c478bd9Sstevel@tonic-gate 		if (regmatch(np->n_regexp, linebuf) == REG_OK)
12067c478bd9Sstevel@tonic-gate 			return (const1);
12077c478bd9Sstevel@tonic-gate 		return (const0);
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	case TILDE:
12107c478bd9Sstevel@tonic-gate 		cp = exprstring(np->n_left);
12117c478bd9Sstevel@tonic-gate 		if (regmatch(getregexp(np->n_right), cp) == REG_OK)
12127c478bd9Sstevel@tonic-gate 			return (const1);
12137c478bd9Sstevel@tonic-gate 		return (const0);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	case NRE:
12167c478bd9Sstevel@tonic-gate 		cp = exprstring(np->n_left);
12177c478bd9Sstevel@tonic-gate 		if (regmatch(getregexp(np->n_right), cp) != REG_OK)
12187c478bd9Sstevel@tonic-gate 			return (const1);
12197c478bd9Sstevel@tonic-gate 		return (const0);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	case ASG:
12227c478bd9Sstevel@tonic-gate 		return (assign(np->n_left, np->n_right));
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	case ARRAY:
12257c478bd9Sstevel@tonic-gate 		awkerr(badarray, np->n_name);
12267c478bd9Sstevel@tonic-gate 
1227*79777a7dSnakanon 	/*FALLTHRU*/
12287c478bd9Sstevel@tonic-gate 	case UFUNC:
12297c478bd9Sstevel@tonic-gate 		awkerr(varnotfunc, np->n_name);
12307c478bd9Sstevel@tonic-gate 
1231*79777a7dSnakanon 	/*FALLTHRU*/
12327c478bd9Sstevel@tonic-gate 	default:
12337c478bd9Sstevel@tonic-gate 		awkerr(gettext("panic: exprreduce(%d)"), t);
12347c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
12357c478bd9Sstevel@tonic-gate 	}
123688f3d729Sakaplan 	return (0);
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate  * Do arithmetic operators.
12417c478bd9Sstevel@tonic-gate  */
12427c478bd9Sstevel@tonic-gate static NODE *
12437c478bd9Sstevel@tonic-gate arithmetic(NODE *np)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate 	register NODE *left, *right;
12467c478bd9Sstevel@tonic-gate 	int type;
12477c478bd9Sstevel@tonic-gate 	register INT i1, i2;
12487c478bd9Sstevel@tonic-gate 	register INT iresult;
12497c478bd9Sstevel@tonic-gate 	register REAL r1, r2;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	left = exprreduce(np->n_left);
1252*79777a7dSnakanon 	if (isreal(left->n_flags) ||
1253*79777a7dSnakanon 	    (isstring(left->n_flags) && (type_of(left)&FVREAL))) {
12547c478bd9Sstevel@tonic-gate 		type = FREAL;
12557c478bd9Sstevel@tonic-gate 		r1 = exprreal(left);
12567c478bd9Sstevel@tonic-gate 		r2 = exprreal(np->n_right);
12577c478bd9Sstevel@tonic-gate 	} else {
12587c478bd9Sstevel@tonic-gate 		i1 = exprint(left);
12597c478bd9Sstevel@tonic-gate 		right = exprreduce(np->n_right);
1260*79777a7dSnakanon 		if (isreal(right->n_flags) ||
1261*79777a7dSnakanon 		    (isstring(right->n_flags) && (type_of(right)&FVREAL))) {
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 			type = FREAL;
12647c478bd9Sstevel@tonic-gate 			r1 = i1;
12657c478bd9Sstevel@tonic-gate 			r2 = exprreal(right);
12667c478bd9Sstevel@tonic-gate 		} else {
12677c478bd9Sstevel@tonic-gate 			type = FINT;
12687c478bd9Sstevel@tonic-gate 			i2 = exprint(right);
12697c478bd9Sstevel@tonic-gate 		}
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate reswitch:
12727c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
12737c478bd9Sstevel@tonic-gate 	case ADD:
12747c478bd9Sstevel@tonic-gate 		if (type == FINT) {
12757c478bd9Sstevel@tonic-gate 			iresult = i1 + i2;
12767c478bd9Sstevel@tonic-gate 			addoverflow();
12777c478bd9Sstevel@tonic-gate 		} else
12787c478bd9Sstevel@tonic-gate 			r1 += r2;
12797c478bd9Sstevel@tonic-gate 		break;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	/*
12827c478bd9Sstevel@tonic-gate 	 * Strategically placed between ADD and SUB
12837c478bd9Sstevel@tonic-gate 	 * so "jo" branches will reach on 80*86
12847c478bd9Sstevel@tonic-gate 	 */
12857c478bd9Sstevel@tonic-gate 	overflow:
12867c478bd9Sstevel@tonic-gate 		r1 = i1;
12877c478bd9Sstevel@tonic-gate 		r2 = i2;
12887c478bd9Sstevel@tonic-gate 		type = FREAL;
12897c478bd9Sstevel@tonic-gate 		goto reswitch;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	case SUB:
12927c478bd9Sstevel@tonic-gate 		if (type == FINT) {
12937c478bd9Sstevel@tonic-gate 			iresult = i1 - i2;
12947c478bd9Sstevel@tonic-gate 			suboverflow();
12957c478bd9Sstevel@tonic-gate 		} else
12967c478bd9Sstevel@tonic-gate 			r1 -= r2;
12977c478bd9Sstevel@tonic-gate 		break;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	case MUL:
13007c478bd9Sstevel@tonic-gate 		if (type == FINT) {
13017c478bd9Sstevel@tonic-gate 			iresult = i1 * i2;
13027c478bd9Sstevel@tonic-gate 			muloverflow();
13037c478bd9Sstevel@tonic-gate 		} else
13047c478bd9Sstevel@tonic-gate 			r1 *= r2;
13057c478bd9Sstevel@tonic-gate 		break;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	case DIV:
13087c478bd9Sstevel@tonic-gate 		if (type == FINT) {
13097c478bd9Sstevel@tonic-gate 			r1 = i1;
13107c478bd9Sstevel@tonic-gate 			r2 = i2;
13117c478bd9Sstevel@tonic-gate 			type = FREAL;
13127c478bd9Sstevel@tonic-gate 		}
13137c478bd9Sstevel@tonic-gate 		if (r2 == 0.0)
13147c478bd9Sstevel@tonic-gate 			awkerr(divzero);
13157c478bd9Sstevel@tonic-gate 		r1 /= r2;
13167c478bd9Sstevel@tonic-gate 		break;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	case REM:
13197c478bd9Sstevel@tonic-gate 		if (type == FINT) {
13207c478bd9Sstevel@tonic-gate 			if (i2 == 0)
13217c478bd9Sstevel@tonic-gate 				awkerr(divzero);
13227c478bd9Sstevel@tonic-gate 			iresult = i1 % i2;
13237c478bd9Sstevel@tonic-gate 		} else {
13247c478bd9Sstevel@tonic-gate 			double fmod(double x, double y);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 			errno = 0;
13277c478bd9Sstevel@tonic-gate 			r1 = fmod(r1, r2);
13287c478bd9Sstevel@tonic-gate 			if (errno == EDOM)
13297c478bd9Sstevel@tonic-gate 				awkerr(divzero);
13307c478bd9Sstevel@tonic-gate 		}
13317c478bd9Sstevel@tonic-gate 		break;
13327c478bd9Sstevel@tonic-gate 	}
13337c478bd9Sstevel@tonic-gate 	return (type == FINT ? intnode(iresult) : realnode(r1));
13347c478bd9Sstevel@tonic-gate }
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate /*
13377c478bd9Sstevel@tonic-gate  * Do comparison operators.
13387c478bd9Sstevel@tonic-gate  */
13397c478bd9Sstevel@tonic-gate static NODE *
13407c478bd9Sstevel@tonic-gate comparison(NODE *np)
13417c478bd9Sstevel@tonic-gate {
13427c478bd9Sstevel@tonic-gate 	register NODE *left, *right;
13437c478bd9Sstevel@tonic-gate 	register int cmp;
13447c478bd9Sstevel@tonic-gate 	int tl, tr;
13457c478bd9Sstevel@tonic-gate 	register REAL r1, r2;
13467c478bd9Sstevel@tonic-gate 	register INT i1, i2;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	left = np->n_left;
13497c478bd9Sstevel@tonic-gate 	if (isleaf(left->n_flags)) {
13507c478bd9Sstevel@tonic-gate 		if (left->n_type == PARM)
13517c478bd9Sstevel@tonic-gate 			left = left->n_next;
13527c478bd9Sstevel@tonic-gate 	} else
13537c478bd9Sstevel@tonic-gate 		left = exprreduce(left);
13547c478bd9Sstevel@tonic-gate 	tl = left->n_flags;
13557c478bd9Sstevel@tonic-gate 	right = np->n_right;
13567c478bd9Sstevel@tonic-gate 	if (isleaf(right->n_flags)) {
13577c478bd9Sstevel@tonic-gate 		if (right->n_type == PARM)
13587c478bd9Sstevel@tonic-gate 			right = right->n_next;
13597c478bd9Sstevel@tonic-gate 	} else {
13607c478bd9Sstevel@tonic-gate 		++concflag;
13617c478bd9Sstevel@tonic-gate 		right = exprreduce(right);
13627c478bd9Sstevel@tonic-gate 		--concflag;
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 	tr = right->n_flags;
13657c478bd9Sstevel@tonic-gate 	/*
13667c478bd9Sstevel@tonic-gate 	 * Posix mandates semantics for the comparison operators that
13677c478bd9Sstevel@tonic-gate 	 * are incompatible with traditional AWK behaviour. If the following
13687c478bd9Sstevel@tonic-gate 	 * define is true then awk will use the traditional behaviour.
13697c478bd9Sstevel@tonic-gate 	 * if it's false, then AWK will use the POSIX-mandated behaviour.
13707c478bd9Sstevel@tonic-gate 	 */
13717c478bd9Sstevel@tonic-gate #define	TRADITIONAL 0
13727c478bd9Sstevel@tonic-gate #if TRADITIONAL
13737c478bd9Sstevel@tonic-gate 	if (!isnumber(tl) || !isnumber(tr)) {
13747c478bd9Sstevel@tonic-gate 		cmp = wcscoll((wchar_t *)exprstring(left),
13757c478bd9Sstevel@tonic-gate 		    (wchar_t *)exprstring(right));
13767c478bd9Sstevel@tonic-gate 	} else if (isreal(tl) || isreal(tr)) {
13777c478bd9Sstevel@tonic-gate 		r1 = exprreal(left);
13787c478bd9Sstevel@tonic-gate 		r2 = exprreal(right);
13797c478bd9Sstevel@tonic-gate 		if (r1 < r2)
13807c478bd9Sstevel@tonic-gate 			cmp = -1;
13817c478bd9Sstevel@tonic-gate 		else if (r1 > r2)
13827c478bd9Sstevel@tonic-gate 			cmp = 1;
13837c478bd9Sstevel@tonic-gate 		else
13847c478bd9Sstevel@tonic-gate 			cmp = 0;
13857c478bd9Sstevel@tonic-gate 	} else {
13867c478bd9Sstevel@tonic-gate 		i1 = exprint(left);
13877c478bd9Sstevel@tonic-gate 		i2 = exprint(right);
13887c478bd9Sstevel@tonic-gate 		if (i1 < i2)
13897c478bd9Sstevel@tonic-gate 			cmp = -1;
13907c478bd9Sstevel@tonic-gate 		else if (i1 > i2)
13917c478bd9Sstevel@tonic-gate 			cmp = 1;
13927c478bd9Sstevel@tonic-gate 		else
13937c478bd9Sstevel@tonic-gate 			cmp = 0;
13947c478bd9Sstevel@tonic-gate 	}
13957c478bd9Sstevel@tonic-gate #else
13967c478bd9Sstevel@tonic-gate 	if (!isnumber(tl) && !isnumber(tr)) {
13977c478bd9Sstevel@tonic-gate do_strcmp:
13987c478bd9Sstevel@tonic-gate 		cmp = wcscoll((wchar_t *)exprstring(left),
13997c478bd9Sstevel@tonic-gate 		    (wchar_t *)exprstring(right));
14007c478bd9Sstevel@tonic-gate 	} else {
14017c478bd9Sstevel@tonic-gate 		if (isstring(tl))
14021c53dae2Smike_s 			tl = type_of(left);
14037c478bd9Sstevel@tonic-gate 		if (isstring(tr))
14041c53dae2Smike_s 			tr = type_of(right);
14057c478bd9Sstevel@tonic-gate 		if (!isnumber(tl) || !isnumber(tr))
14067c478bd9Sstevel@tonic-gate 			goto do_strcmp;
14077c478bd9Sstevel@tonic-gate 		if (isreal(tl) || isreal(tr)) {
14087c478bd9Sstevel@tonic-gate 			r1 = exprreal(left);
14097c478bd9Sstevel@tonic-gate 			r2 = exprreal(right);
14107c478bd9Sstevel@tonic-gate 			if (r1 < r2)
14117c478bd9Sstevel@tonic-gate 				cmp = -1;
14127c478bd9Sstevel@tonic-gate 			else if (r1 > r2)
14137c478bd9Sstevel@tonic-gate 				cmp = 1;
14147c478bd9Sstevel@tonic-gate 			else
14157c478bd9Sstevel@tonic-gate 				cmp = 0;
14167c478bd9Sstevel@tonic-gate 		} else {
14177c478bd9Sstevel@tonic-gate 			i1 = exprint(left);
14187c478bd9Sstevel@tonic-gate 			i2 = exprint(right);
14197c478bd9Sstevel@tonic-gate 			if (i1 < i2)
14207c478bd9Sstevel@tonic-gate 				cmp = -1;
14217c478bd9Sstevel@tonic-gate 			else if (i1 > i2)
14227c478bd9Sstevel@tonic-gate 				cmp = 1;
14237c478bd9Sstevel@tonic-gate 			else
14247c478bd9Sstevel@tonic-gate 				cmp = 0;
14257c478bd9Sstevel@tonic-gate 		}
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate #endif
14287c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
14297c478bd9Sstevel@tonic-gate 	case EQ:
14307c478bd9Sstevel@tonic-gate 		return (cmp == 0 ? const1 : const0);
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	case  NE:
14337c478bd9Sstevel@tonic-gate 		return (cmp != 0 ? const1 : const0);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	case GE:
14367c478bd9Sstevel@tonic-gate 		return (cmp >= 0 ? const1 : const0);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 	case LE:
14397c478bd9Sstevel@tonic-gate 		return (cmp <= 0 ? const1 : const0);
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	case GT:
14427c478bd9Sstevel@tonic-gate 		return (cmp > 0 ? const1 : const0);
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	case LT:
14457c478bd9Sstevel@tonic-gate 		return (cmp < 0 ? const1 : const0);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	default:
14487c478bd9Sstevel@tonic-gate 		awkerr(interr, "comparison");
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
145188f3d729Sakaplan 	return (0);
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate /*
14557c478bd9Sstevel@tonic-gate  * Return the type of a constant that is a string.
14567c478bd9Sstevel@tonic-gate  * The node must be a FSTRING type and the return value
14577c478bd9Sstevel@tonic-gate  * will possibly have FVINT or FVREAL or'ed in.
14587c478bd9Sstevel@tonic-gate  */
14597c478bd9Sstevel@tonic-gate static int
14601c53dae2Smike_s type_of(NODE *np)
14617c478bd9Sstevel@tonic-gate {
14627c478bd9Sstevel@tonic-gate 	wchar_t *cp;
14637c478bd9Sstevel@tonic-gate 	int somedigits = 0;
14647c478bd9Sstevel@tonic-gate 	int seene = 0;
14657c478bd9Sstevel@tonic-gate 	int seenradix = 0;
14667c478bd9Sstevel@tonic-gate 	int seensign = 0;
14677c478bd9Sstevel@tonic-gate 	int digitsaftere = 0;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	cp = (wchar_t *)np->n_string;
14707c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
14717c478bd9Sstevel@tonic-gate 		return (FSTRING|FVINT);
14727c478bd9Sstevel@tonic-gate 	while (iswspace(*cp))
14737c478bd9Sstevel@tonic-gate 		cp++;
14747c478bd9Sstevel@tonic-gate 	if (*cp == '-' || *cp == '+')
14757c478bd9Sstevel@tonic-gate 		cp++;
14767c478bd9Sstevel@tonic-gate 	while (*cp != '\0') {
14777c478bd9Sstevel@tonic-gate 		switch (*cp) {
14787c478bd9Sstevel@tonic-gate 		case '0':
14797c478bd9Sstevel@tonic-gate 		case '1':
14807c478bd9Sstevel@tonic-gate 		case '2':
14817c478bd9Sstevel@tonic-gate 		case '3':
14827c478bd9Sstevel@tonic-gate 		case '4':
14837c478bd9Sstevel@tonic-gate 		case '5':
14847c478bd9Sstevel@tonic-gate 		case '6':
14857c478bd9Sstevel@tonic-gate 		case '7':
14867c478bd9Sstevel@tonic-gate 		case '8':
14877c478bd9Sstevel@tonic-gate 		case '9':
14887c478bd9Sstevel@tonic-gate 			if (seene)
14897c478bd9Sstevel@tonic-gate 				digitsaftere = 1;
14907c478bd9Sstevel@tonic-gate 			somedigits++;
14917c478bd9Sstevel@tonic-gate 			break;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 		case 'E':
14947c478bd9Sstevel@tonic-gate 		case 'e':
14957c478bd9Sstevel@tonic-gate 			if (seene || !somedigits)
14967c478bd9Sstevel@tonic-gate 				return (FSTRING);
14977c478bd9Sstevel@tonic-gate 			seene = 1;
14987c478bd9Sstevel@tonic-gate 			break;
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 		case '+':
15017c478bd9Sstevel@tonic-gate 		case '-':
15027c478bd9Sstevel@tonic-gate 			if (seensign || !seene || digitsaftere)
15037c478bd9Sstevel@tonic-gate 				return (FSTRING);
15047c478bd9Sstevel@tonic-gate 			seensign = 1;
15057c478bd9Sstevel@tonic-gate 			break;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		default:
15087c478bd9Sstevel@tonic-gate 			if (*cp == radixpoint) {
15097c478bd9Sstevel@tonic-gate 				if (seenradix || seene || (!somedigits &&
15107c478bd9Sstevel@tonic-gate 				    !iswdigit(*++cp)))
15117c478bd9Sstevel@tonic-gate 					return (FSTRING);
15127c478bd9Sstevel@tonic-gate 			} else
15137c478bd9Sstevel@tonic-gate 				return (FSTRING);
15147c478bd9Sstevel@tonic-gate 			seenradix = 1;
15157c478bd9Sstevel@tonic-gate 		}
15167c478bd9Sstevel@tonic-gate 		cp++;
15177c478bd9Sstevel@tonic-gate 	}
15187c478bd9Sstevel@tonic-gate 	if (somedigits == 0)
15197c478bd9Sstevel@tonic-gate 		return (FSTRING);
15207c478bd9Sstevel@tonic-gate 	if (somedigits >= MAXDIGINT || seenradix || seene) {
15217c478bd9Sstevel@tonic-gate 		if (seensign && !digitsaftere)
15227c478bd9Sstevel@tonic-gate 			return (FSTRING);
15237c478bd9Sstevel@tonic-gate 		else
15247c478bd9Sstevel@tonic-gate 			return (FSTRING|FVREAL);
15257c478bd9Sstevel@tonic-gate 	} else
15267c478bd9Sstevel@tonic-gate 		return (FSTRING|FVINT);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate /*
15307c478bd9Sstevel@tonic-gate  * Return a field rvalue.
15317c478bd9Sstevel@tonic-gate  */
15327c478bd9Sstevel@tonic-gate static NODE *
15337c478bd9Sstevel@tonic-gate rfield(INT fieldno)
15347c478bd9Sstevel@tonic-gate {
15357c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	if (fieldno == 0)
15387c478bd9Sstevel@tonic-gate 		return (stringnode(linebuf, FSTATIC|FSENSE, lbuflen));
15397c478bd9Sstevel@tonic-gate 	if (!splitdone)
15407c478bd9Sstevel@tonic-gate 		fieldsplit();
15417c478bd9Sstevel@tonic-gate 	if (fieldno > nfield || fieldno < 0)
15427c478bd9Sstevel@tonic-gate 		return (stringnode(_null, FSTATIC, 0));
15437c478bd9Sstevel@tonic-gate 	cp = fields[fieldno-1];
15447c478bd9Sstevel@tonic-gate 	return (stringnode(cp, FSTATIC|FSENSE, wcslen(cp)));
15457c478bd9Sstevel@tonic-gate }
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate /*
15487c478bd9Sstevel@tonic-gate  * Split linebuf into fields.  Done only once
15497c478bd9Sstevel@tonic-gate  * per input record (maximum).
15507c478bd9Sstevel@tonic-gate  */
15517c478bd9Sstevel@tonic-gate void
15527c478bd9Sstevel@tonic-gate fieldsplit()
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate 	register wchar_t *ip, *op;
15557c478bd9Sstevel@tonic-gate 	register int n;
15567c478bd9Sstevel@tonic-gate 	wchar_t *ep;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	if (fieldbuf == NULL)
15597c478bd9Sstevel@tonic-gate 		fieldbuf = emalloc(NLINE * sizeof (wchar_t));
15607c478bd9Sstevel@tonic-gate 	fcount = 0;
15617c478bd9Sstevel@tonic-gate 	ep = linebuf;
15627c478bd9Sstevel@tonic-gate 	op = fieldbuf;
15637c478bd9Sstevel@tonic-gate 	while ((ip = (*awkfield)(&ep)) != NULL) {
15647c478bd9Sstevel@tonic-gate 		fields[fcount++] = op;
15657c478bd9Sstevel@tonic-gate 		if (fcount > NFIELD)
15667c478bd9Sstevel@tonic-gate 			awkerr(tmfld, NFIELD);
15677c478bd9Sstevel@tonic-gate 		n = ep-ip;
15687c478bd9Sstevel@tonic-gate 		(void) memcpy(op, ip, n * sizeof (wchar_t));
15697c478bd9Sstevel@tonic-gate 		op += n;
15707c478bd9Sstevel@tonic-gate 		*op++ = '\0';
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 	if (varNF->n_flags & FINT)
15737c478bd9Sstevel@tonic-gate 		varNF->n_int = fcount;
15747c478bd9Sstevel@tonic-gate 	else {
15757c478bd9Sstevel@tonic-gate 		constant->n_int = fcount;
15767c478bd9Sstevel@tonic-gate 		(void) nassign(varNF, constant);
15777c478bd9Sstevel@tonic-gate 	}
15787c478bd9Sstevel@tonic-gate 	nfield = fcount;
15797c478bd9Sstevel@tonic-gate 	splitdone++;
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate /*
15837c478bd9Sstevel@tonic-gate  * Assign to a field as an lvalue.
15847c478bd9Sstevel@tonic-gate  * Return the unevaluated node as one doesn't always need it
15857c478bd9Sstevel@tonic-gate  * evaluated in an assignment.
15867c478bd9Sstevel@tonic-gate  */
15877c478bd9Sstevel@tonic-gate static NODE *
15887c478bd9Sstevel@tonic-gate lfield(INT fieldno, NODE *np)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
15917c478bd9Sstevel@tonic-gate 	register wchar_t *op;
15927c478bd9Sstevel@tonic-gate 	register wchar_t *sep;
15937c478bd9Sstevel@tonic-gate 	register int i;
15947c478bd9Sstevel@tonic-gate 	register wchar_t *newval;
15957c478bd9Sstevel@tonic-gate 	register int seplen;
15967c478bd9Sstevel@tonic-gate 	register int newlen;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	newlen = wcslen(newval = (wchar_t *)exprstring(np));
15997c478bd9Sstevel@tonic-gate 	if (fieldno == 0) {
16007c478bd9Sstevel@tonic-gate 		splitdone = 0;
16017c478bd9Sstevel@tonic-gate 		(void) memcpy(linebuf, newval, (newlen+1) * sizeof (wchar_t));
16027c478bd9Sstevel@tonic-gate 		lbuflen = newlen;
16037c478bd9Sstevel@tonic-gate 		fieldsplit();
16047c478bd9Sstevel@tonic-gate 	} else {
16057c478bd9Sstevel@tonic-gate 		seplen = wcslen(sep = (wchar_t *)exprstring(varOFS));
16067c478bd9Sstevel@tonic-gate 		if (!splitdone)
16077c478bd9Sstevel@tonic-gate 			fieldsplit();
1608*79777a7dSnakanon 		if (--fieldno < nfield &&
1609*79777a7dSnakanon 		    (newlen <= wcslen(fields[fieldno]))) {
16107c478bd9Sstevel@tonic-gate 			(void) memcpy(fields[fieldno], newval,
16117c478bd9Sstevel@tonic-gate 				(newlen+1) * sizeof (wchar_t));
16127c478bd9Sstevel@tonic-gate 		} else {
16137c478bd9Sstevel@tonic-gate 			register wchar_t *buf;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 			buf = fieldbuf;
16167c478bd9Sstevel@tonic-gate 			fieldbuf = emalloc(NLINE * sizeof (wchar_t));
16177c478bd9Sstevel@tonic-gate 			if (fieldno >= nfield) {
16187c478bd9Sstevel@tonic-gate 				if (fieldno >= NFIELD)
16197c478bd9Sstevel@tonic-gate 					awkerr(tmfld, NFIELD);
16207c478bd9Sstevel@tonic-gate 				while (nfield < fieldno)
16217c478bd9Sstevel@tonic-gate 					fields[nfield++] = _null;
16227c478bd9Sstevel@tonic-gate 				++nfield;
16237c478bd9Sstevel@tonic-gate 			}
16247c478bd9Sstevel@tonic-gate 			fields[fieldno] = newval;
16257c478bd9Sstevel@tonic-gate 			op = fieldbuf;
16267c478bd9Sstevel@tonic-gate 			for (i = 0; i < nfield; i++) {
16277c478bd9Sstevel@tonic-gate 				newlen = wcslen(cp = fields[i])+1;
16287c478bd9Sstevel@tonic-gate 				fields[i] = op;
16297c478bd9Sstevel@tonic-gate 				if (op+newlen >= fieldbuf+NLINE)
16307c478bd9Sstevel@tonic-gate 					awkerr(toolong, NLINE);
1631*79777a7dSnakanon 				(void) memcpy(op, cp,
1632*79777a7dSnakanon 				    newlen * sizeof (wchar_t));
16337c478bd9Sstevel@tonic-gate 				op += newlen;
16347c478bd9Sstevel@tonic-gate 			}
16357c478bd9Sstevel@tonic-gate 			free(buf);
16367c478bd9Sstevel@tonic-gate 		}
16377c478bd9Sstevel@tonic-gate 		/*
16387c478bd9Sstevel@tonic-gate 		 * Reconstruct $0
16397c478bd9Sstevel@tonic-gate 		 */
16407c478bd9Sstevel@tonic-gate 		op = linebuf;
16417c478bd9Sstevel@tonic-gate 		i = 0;
16427c478bd9Sstevel@tonic-gate 		while (i < nfield) {
16437c478bd9Sstevel@tonic-gate 			newlen = wcslen(cp = fields[i++]);
16447c478bd9Sstevel@tonic-gate 			(void) memcpy(op, cp, newlen * sizeof (wchar_t));
16457c478bd9Sstevel@tonic-gate 			op += newlen;
16467c478bd9Sstevel@tonic-gate 			if (i < nfield) {
16477c478bd9Sstevel@tonic-gate 				(void) memcpy(op, sep,
16487c478bd9Sstevel@tonic-gate 					seplen * sizeof (wchar_t));
16497c478bd9Sstevel@tonic-gate 				op += seplen;
16507c478bd9Sstevel@tonic-gate 			}
16517c478bd9Sstevel@tonic-gate 			if (op >= &linebuf[NLINE])
16527c478bd9Sstevel@tonic-gate 				awkerr(toolong, NLINE);
16537c478bd9Sstevel@tonic-gate 		}
16547c478bd9Sstevel@tonic-gate 		*op = '\0';
16557c478bd9Sstevel@tonic-gate 		lbuflen = op-linebuf;
16567c478bd9Sstevel@tonic-gate 		if (varNF->n_flags & FINT)
16577c478bd9Sstevel@tonic-gate 			varNF->n_int = nfield;
16587c478bd9Sstevel@tonic-gate 		else {
16597c478bd9Sstevel@tonic-gate 			constant->n_int = nfield;
16607c478bd9Sstevel@tonic-gate 			(void) nassign(varNF, constant);
16617c478bd9Sstevel@tonic-gate 		}
16627c478bd9Sstevel@tonic-gate 	}
16637c478bd9Sstevel@tonic-gate 	return (np);
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate /*
16677c478bd9Sstevel@tonic-gate  * Do a user function.
16687c478bd9Sstevel@tonic-gate  * Each formal parameter must:
16697c478bd9Sstevel@tonic-gate  *	have the actual parameter assigned to it (call by value),
16707c478bd9Sstevel@tonic-gate  *	have a pointer to an array put into it (call by reference),
16717c478bd9Sstevel@tonic-gate  *	and be made undefined (extra formal parameters)
16727c478bd9Sstevel@tonic-gate  */
16737c478bd9Sstevel@tonic-gate static NODE *
16747c478bd9Sstevel@tonic-gate userfunc(NODE *np)
16757c478bd9Sstevel@tonic-gate {
16767c478bd9Sstevel@tonic-gate 	register NODE *temp;
16777c478bd9Sstevel@tonic-gate 	NODE *fnp;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	if ((fnp = np->n_left) == NNULL)
16807c478bd9Sstevel@tonic-gate 		awkerr(gettext("impossible function call"));
16817c478bd9Sstevel@tonic-gate 	if (fnp->n_type != UFUNC)
16827c478bd9Sstevel@tonic-gate 		awkerr(varnotfunc, fnp->n_name);
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate #ifndef M_STKCHK
16857c478bd9Sstevel@tonic-gate 	if (slevel >= NRECUR)
16867c478bd9Sstevel@tonic-gate 		awkerr(gettext("function \"%S\" nesting level > %u"),
16877c478bd9Sstevel@tonic-gate 		    fnp->n_name, NRECUR);
16887c478bd9Sstevel@tonic-gate #else
16897c478bd9Sstevel@tonic-gate 	if (!M_STKCHK)
16907c478bd9Sstevel@tonic-gate 		awkerr(gettext("function \"%s\" nesting level too deep"),
16917c478bd9Sstevel@tonic-gate 		    fnp->n_name);
16927c478bd9Sstevel@tonic-gate #endif
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	fnp = fnp->n_ufunc;
16957c478bd9Sstevel@tonic-gate 	{
16967c478bd9Sstevel@tonic-gate 		register NODE *formal;
16977c478bd9Sstevel@tonic-gate 		register NODE *actual;
16987c478bd9Sstevel@tonic-gate 		NODE *formlist, *actlist, *templist, *temptail;
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 		templist = temptail = NNULL;
17017c478bd9Sstevel@tonic-gate 		actlist = np->n_right;
17027c478bd9Sstevel@tonic-gate 		formlist = fnp->n_left;
1703*79777a7dSnakanon 		/*
1704*79777a7dSnakanon 		 * pass through formal list, setting up a list
17057c478bd9Sstevel@tonic-gate 		 * (on templist) containing temps for the values
17067c478bd9Sstevel@tonic-gate 		 * of the actuals.
17077c478bd9Sstevel@tonic-gate 		 * If the actual list runs out before the formal
17087c478bd9Sstevel@tonic-gate 		 * list, assign 'constundef' as the value
17097c478bd9Sstevel@tonic-gate 		 */
17107c478bd9Sstevel@tonic-gate 		while ((formal = getlist(&formlist)) != NNULL) {
17117c478bd9Sstevel@tonic-gate 			register NODE *array;
17127c478bd9Sstevel@tonic-gate 			register int t;
17137c478bd9Sstevel@tonic-gate 			register size_t len;
17147c478bd9Sstevel@tonic-gate 			register int scope_tag;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 			actual = getlist(&actlist);
17177c478bd9Sstevel@tonic-gate 			if (actual == NNULL) {
17187c478bd9Sstevel@tonic-gate 				actual = constundef;
17197c478bd9Sstevel@tonic-gate 				scope_tag = slevel+1;
17207c478bd9Sstevel@tonic-gate 			} else
17217c478bd9Sstevel@tonic-gate 				scope_tag = 0;
17227c478bd9Sstevel@tonic-gate 			array = actual;
17237c478bd9Sstevel@tonic-gate 			switch (actual->n_type) {
17247c478bd9Sstevel@tonic-gate 			case ARRAY:
17257c478bd9Sstevel@tonic-gate 				t = ARRAY;
17267c478bd9Sstevel@tonic-gate 				scope_tag = 0;
17277c478bd9Sstevel@tonic-gate 				break;
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 			case PARM:
17307c478bd9Sstevel@tonic-gate 				array = actual = actual->n_next;
17317c478bd9Sstevel@tonic-gate 				t = actual->n_type;
17327c478bd9Sstevel@tonic-gate 				scope_tag = actual->n_scope;
17337c478bd9Sstevel@tonic-gate 				if (!(actual->n_flags & FLARRAY))
17347c478bd9Sstevel@tonic-gate 					array = actual->n_alink;
17357c478bd9Sstevel@tonic-gate 				break;
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 			default:
17387c478bd9Sstevel@tonic-gate 				t = VAR;
17397c478bd9Sstevel@tonic-gate 				break;
17407c478bd9Sstevel@tonic-gate 			}
17417c478bd9Sstevel@tonic-gate 			temp = emptynode(t, len = wcslen(formal->n_name));
17427c478bd9Sstevel@tonic-gate 			(void) memcpy(temp->n_name, formal->n_name,
17437c478bd9Sstevel@tonic-gate 			    (len+1) * sizeof (wchar_t));
17447c478bd9Sstevel@tonic-gate 			temp->n_flags = FSTRING|FVINT;
17457c478bd9Sstevel@tonic-gate 			temp->n_string = _null;
17467c478bd9Sstevel@tonic-gate 			temp->n_strlen = 0;
17477c478bd9Sstevel@tonic-gate 			if (t == VAR)
17487c478bd9Sstevel@tonic-gate 				(void) assign(temp, actual);
17497c478bd9Sstevel@tonic-gate 			if (t != ARRAY)
17507c478bd9Sstevel@tonic-gate 				temp->n_flags |= FLARRAY;
17517c478bd9Sstevel@tonic-gate 			temp->n_scope = scope_tag;
17527c478bd9Sstevel@tonic-gate 			/*
17537c478bd9Sstevel@tonic-gate 			 * link to actual parameter in case of promotion to
17547c478bd9Sstevel@tonic-gate 			 * array
17557c478bd9Sstevel@tonic-gate 			 */
17567c478bd9Sstevel@tonic-gate 			if (actual != constundef)
17577c478bd9Sstevel@tonic-gate 				temp->n_alink = actual;
17587c478bd9Sstevel@tonic-gate 			/*
17597c478bd9Sstevel@tonic-gate 			 * Build the templist
17607c478bd9Sstevel@tonic-gate 			 */
17617c478bd9Sstevel@tonic-gate 			if (templist != NNULL) {
17627c478bd9Sstevel@tonic-gate 				temptail->n_next = temp;
17637c478bd9Sstevel@tonic-gate 				temptail = temp;
17647c478bd9Sstevel@tonic-gate 			} else
17657c478bd9Sstevel@tonic-gate 				templist = temptail = temp;
17667c478bd9Sstevel@tonic-gate 			temp->n_next = NNULL;
17677c478bd9Sstevel@tonic-gate 			if (actual->n_type == CONSTANT)
17687c478bd9Sstevel@tonic-gate 				temp->n_alink = temp;
17697c478bd9Sstevel@tonic-gate 			else
17707c478bd9Sstevel@tonic-gate 				temp->n_alink = array;
17717c478bd9Sstevel@tonic-gate 		}
17727c478bd9Sstevel@tonic-gate 		/*
17737c478bd9Sstevel@tonic-gate 		 * Bind results of the evaluation of actuals to formals.
17747c478bd9Sstevel@tonic-gate 		 */
17757c478bd9Sstevel@tonic-gate 		formlist = fnp->n_left;
17767c478bd9Sstevel@tonic-gate 		while (templist != NNULL) {
17777c478bd9Sstevel@tonic-gate 			temp = templist;
17787c478bd9Sstevel@tonic-gate 			templist = temp->n_next;
17797c478bd9Sstevel@tonic-gate 			formal = getlist(&formlist);
17807c478bd9Sstevel@tonic-gate 			temp->n_next = formal->n_next;
17817c478bd9Sstevel@tonic-gate 			formal->n_next = temp;
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 		}
17917c478bd9Sstevel@tonic-gate 	}
17927c478bd9Sstevel@tonic-gate 	{
17937c478bd9Sstevel@tonic-gate 		register NODE *savenode = curnode;
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 		++slevel;
17967c478bd9Sstevel@tonic-gate 		if (action(fnp->n_right) == RETURN)
17977c478bd9Sstevel@tonic-gate 			np = retval; else
17987c478bd9Sstevel@tonic-gate 			np = const0;
17997c478bd9Sstevel@tonic-gate 		curnode = savenode;
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 	{
18027c478bd9Sstevel@tonic-gate 		register NODE *formal;
18037c478bd9Sstevel@tonic-gate 		NODE *formlist;
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 		formlist = fnp->n_left;
18067c478bd9Sstevel@tonic-gate 		while ((formal = getlist(&formlist)) != NNULL) {
18077c478bd9Sstevel@tonic-gate 			temp = formal->n_next;
18087c478bd9Sstevel@tonic-gate 			formal->n_next = temp->n_next;
18097c478bd9Sstevel@tonic-gate 			/* if node is a local array, free the elements */
18107c478bd9Sstevel@tonic-gate 			if (temp->n_type == ARRAY && (temp->n_scope == slevel))
18117c478bd9Sstevel@tonic-gate 				delarray(temp);
18127c478bd9Sstevel@tonic-gate 			freenode(temp);
18137c478bd9Sstevel@tonic-gate 		}
18147c478bd9Sstevel@tonic-gate 	}
18157c478bd9Sstevel@tonic-gate 	--slevel;
18167c478bd9Sstevel@tonic-gate 	return (np);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate /*
18207c478bd9Sstevel@tonic-gate  * Get the regular expression from an expression tree.
18217c478bd9Sstevel@tonic-gate  */
18227c478bd9Sstevel@tonic-gate REGEXP
18237c478bd9Sstevel@tonic-gate getregexp(NODE *np)
18247c478bd9Sstevel@tonic-gate {
18257c478bd9Sstevel@tonic-gate 	if (np->n_type == RE)
18267c478bd9Sstevel@tonic-gate 		return (np->n_regexp);
18277c478bd9Sstevel@tonic-gate 	np = renode((wchar_t *)exprstring(np));
18287c478bd9Sstevel@tonic-gate 	return (np->n_regexp);
18297c478bd9Sstevel@tonic-gate }
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate /*
18327c478bd9Sstevel@tonic-gate  * Get the next element from a list.
18337c478bd9Sstevel@tonic-gate  */
18347c478bd9Sstevel@tonic-gate NODE *
18357c478bd9Sstevel@tonic-gate getlist(NODE **npp)
18367c478bd9Sstevel@tonic-gate {
18377c478bd9Sstevel@tonic-gate 	register NODE *np;
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	if ((np = *npp) == NNULL)
18407c478bd9Sstevel@tonic-gate 		return (np);
18417c478bd9Sstevel@tonic-gate 	if (np->n_type == COMMA) {
18427c478bd9Sstevel@tonic-gate 		*npp = np->n_right;
18437c478bd9Sstevel@tonic-gate 		return (np->n_left);
18447c478bd9Sstevel@tonic-gate 	} else {
18457c478bd9Sstevel@tonic-gate 		*npp = NNULL;
18467c478bd9Sstevel@tonic-gate 		return (np);
18477c478bd9Sstevel@tonic-gate 	}
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate /*
18517c478bd9Sstevel@tonic-gate  * if statement.
18527c478bd9Sstevel@tonic-gate  */
18537c478bd9Sstevel@tonic-gate static int
18547c478bd9Sstevel@tonic-gate s_if(NODE *np)
18557c478bd9Sstevel@tonic-gate {
18567c478bd9Sstevel@tonic-gate 	register NODE *xp;
18577c478bd9Sstevel@tonic-gate 	register int test;
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	test = exprtest(np->n_left);
18607c478bd9Sstevel@tonic-gate 	xp = np->n_right;
18617c478bd9Sstevel@tonic-gate 	if (xp->n_type != ELSE)
18627c478bd9Sstevel@tonic-gate 		awkerr(interr, "if/else");
18637c478bd9Sstevel@tonic-gate 	if (test)
18647c478bd9Sstevel@tonic-gate 		xp = xp->n_left;
18657c478bd9Sstevel@tonic-gate 	else
18667c478bd9Sstevel@tonic-gate 		xp = xp->n_right;
18677c478bd9Sstevel@tonic-gate 	return (action(xp));
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate /*
18717c478bd9Sstevel@tonic-gate  * while and do{}while statements.
18727c478bd9Sstevel@tonic-gate  */
18737c478bd9Sstevel@tonic-gate static int
18747c478bd9Sstevel@tonic-gate s_while(NODE *np)
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate 	register int act = 0;
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 	if (np->n_type == DO)
18797c478bd9Sstevel@tonic-gate 		goto dowhile;
18807c478bd9Sstevel@tonic-gate 	for (;;) {
18817c478bd9Sstevel@tonic-gate 		if (exprtest(np->n_left) == 0)
18827c478bd9Sstevel@tonic-gate 			break;
18837c478bd9Sstevel@tonic-gate 	dowhile:
18847c478bd9Sstevel@tonic-gate 		if ((act = action(np->n_right)) != 0) {
18857c478bd9Sstevel@tonic-gate 			switch (act) {
18867c478bd9Sstevel@tonic-gate 			case BREAK:
18877c478bd9Sstevel@tonic-gate 				act = 0;
18887c478bd9Sstevel@tonic-gate 				break;
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 			case CONTINUE:
18917c478bd9Sstevel@tonic-gate 				act = 0;
18927c478bd9Sstevel@tonic-gate 				continue;
18937c478bd9Sstevel@tonic-gate 			}
18947c478bd9Sstevel@tonic-gate 			break;
18957c478bd9Sstevel@tonic-gate 		}
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 	return (act);
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate /*
19017c478bd9Sstevel@tonic-gate  * for statement.
19027c478bd9Sstevel@tonic-gate  */
19037c478bd9Sstevel@tonic-gate static int
19047c478bd9Sstevel@tonic-gate s_for(NODE *np)
19057c478bd9Sstevel@tonic-gate {
19067c478bd9Sstevel@tonic-gate 	register NODE *testnp, *incnp, *initnp;
19077c478bd9Sstevel@tonic-gate 	register int act = 0;
19087c478bd9Sstevel@tonic-gate 	NODE *listp;
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	listp = np->n_left;
19117c478bd9Sstevel@tonic-gate 	initnp = getlist(&listp);
19127c478bd9Sstevel@tonic-gate 	testnp = getlist(&listp);
19137c478bd9Sstevel@tonic-gate 	incnp = getlist(&listp);
19147c478bd9Sstevel@tonic-gate 	if (initnp != NNULL)
19157c478bd9Sstevel@tonic-gate 		(void) exprreduce(initnp);
19167c478bd9Sstevel@tonic-gate 	for (;;) {
19177c478bd9Sstevel@tonic-gate 		if (exprtest(testnp) == 0)
19187c478bd9Sstevel@tonic-gate 			break;
19197c478bd9Sstevel@tonic-gate 		if ((act = action(np->n_right)) != 0) {
19207c478bd9Sstevel@tonic-gate 			switch (act) {
19217c478bd9Sstevel@tonic-gate 			case BREAK:
19227c478bd9Sstevel@tonic-gate 				act = 0;
19237c478bd9Sstevel@tonic-gate 				break;
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 			case CONTINUE:
19267c478bd9Sstevel@tonic-gate 				act = 0;
19277c478bd9Sstevel@tonic-gate 				goto clabel;
19287c478bd9Sstevel@tonic-gate 			}
19297c478bd9Sstevel@tonic-gate 			break;
19307c478bd9Sstevel@tonic-gate 		}
19317c478bd9Sstevel@tonic-gate 	clabel:
19327c478bd9Sstevel@tonic-gate 		if (incnp != NNULL)
19337c478bd9Sstevel@tonic-gate 			(void) exprreduce(incnp);
19347c478bd9Sstevel@tonic-gate 	}
19357c478bd9Sstevel@tonic-gate 	return (act);
19367c478bd9Sstevel@tonic-gate }
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate /*
19397c478bd9Sstevel@tonic-gate  * for variable in array statement.
19407c478bd9Sstevel@tonic-gate  */
19417c478bd9Sstevel@tonic-gate static int
19427c478bd9Sstevel@tonic-gate s_forin(NODE *np)
19437c478bd9Sstevel@tonic-gate {
19447c478bd9Sstevel@tonic-gate 	register NODE *left;
19457c478bd9Sstevel@tonic-gate 	register int act = 0;
19467c478bd9Sstevel@tonic-gate 	register NODE *var;
19477c478bd9Sstevel@tonic-gate 	register NODE **nnp;
19487c478bd9Sstevel@tonic-gate 	register NODE *statement;
19497c478bd9Sstevel@tonic-gate 	register int issymtab = 0;
19507c478bd9Sstevel@tonic-gate 	wchar_t *index;
19517c478bd9Sstevel@tonic-gate 	register int alen;
19527c478bd9Sstevel@tonic-gate 	int nbuck;
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	left = np->n_left;
19557c478bd9Sstevel@tonic-gate 	statement = np->n_right;
19567c478bd9Sstevel@tonic-gate 	if (left->n_type != IN)
19577c478bd9Sstevel@tonic-gate 		awkerr(interr, "for (var in array)");
19587c478bd9Sstevel@tonic-gate 	if ((var = left->n_left)->n_type == PARM)
19597c478bd9Sstevel@tonic-gate 		var = var->n_next;
19607c478bd9Sstevel@tonic-gate 	np = left->n_right;
19617c478bd9Sstevel@tonic-gate 	if (np->n_type == PARM) {
19627c478bd9Sstevel@tonic-gate 		np = np->n_next;
19637c478bd9Sstevel@tonic-gate 		if (!(np->n_flags & FLARRAY))
19647c478bd9Sstevel@tonic-gate 			np = np->n_alink;
19657c478bd9Sstevel@tonic-gate 	}
19667c478bd9Sstevel@tonic-gate 	if (np == varSYMTAB) {
19677c478bd9Sstevel@tonic-gate 		issymtab++;
19687c478bd9Sstevel@tonic-gate 		np = NNULL;
19697c478bd9Sstevel@tonic-gate 		nbuck = 0;
19707c478bd9Sstevel@tonic-gate 	} else {
1971*79777a7dSnakanon 		/*
19727c478bd9Sstevel@tonic-gate 		 * At this point if the node is not actually an array
19737c478bd9Sstevel@tonic-gate 		 * check to see if it has already been established as
19747c478bd9Sstevel@tonic-gate 		 * a scalar. If it is a scalar then flag an error. If
19757c478bd9Sstevel@tonic-gate 		 * not then promote the object to an array type.
19767c478bd9Sstevel@tonic-gate 		 */
19777c478bd9Sstevel@tonic-gate 		if (np->n_type != ARRAY) {
19787c478bd9Sstevel@tonic-gate 			if (!isstring(np->n_flags) || np->n_string != _null)
19797c478bd9Sstevel@tonic-gate 				awkerr(notarray, np->n_name);
19807c478bd9Sstevel@tonic-gate 			else {
19817c478bd9Sstevel@tonic-gate 				/* promotion to array */
19827c478bd9Sstevel@tonic-gate 				promote(np);
19837c478bd9Sstevel@tonic-gate 				if (np->n_alink != NNULL)
19847c478bd9Sstevel@tonic-gate 					if (!(np->n_flags & FLARRAY))
19857c478bd9Sstevel@tonic-gate 						np = np->n_alink;
19867c478bd9Sstevel@tonic-gate 			}
19877c478bd9Sstevel@tonic-gate 		}
19887c478bd9Sstevel@tonic-gate 		/*
19897c478bd9Sstevel@tonic-gate 		 * Set up a pointer to the first node in the array list.
19907c478bd9Sstevel@tonic-gate 		 * Save this pointer on the delete stack. This information
19917c478bd9Sstevel@tonic-gate 		 * is used by the delete function to advance any pointers
19927c478bd9Sstevel@tonic-gate 		 * that might be pointing at a node which has been deleted.
19937c478bd9Sstevel@tonic-gate 		 * See the delsymtab() function for more information. Note
19947c478bd9Sstevel@tonic-gate 		 * that if the a_link field is nil, then just return 0 since
19957c478bd9Sstevel@tonic-gate 		 * this array has no elements yet.
19967c478bd9Sstevel@tonic-gate 		 */
19977c478bd9Sstevel@tonic-gate 		if ((*(nnp = next_forin) = np->n_alink) == 0)
19987c478bd9Sstevel@tonic-gate 			return (0);
19997c478bd9Sstevel@tonic-gate 		if (++next_forin > &forindex[NFORINLOOP])
20007c478bd9Sstevel@tonic-gate 			awkerr(toodeep, NFORINLOOP);
20017c478bd9Sstevel@tonic-gate 		/*
20027c478bd9Sstevel@tonic-gate 		 * array elements have names of the form
20037c478bd9Sstevel@tonic-gate 		 *	<name>]<index> (global arrays)
20047c478bd9Sstevel@tonic-gate 		 * or
20057c478bd9Sstevel@tonic-gate 		 *	<name>[<scope>]<index> (local arrays)
20067c478bd9Sstevel@tonic-gate 		 * We need to know the offset of the index portion of the
20077c478bd9Sstevel@tonic-gate 		 * name string in order to place it in the index variable so
20087c478bd9Sstevel@tonic-gate 		 * we look for the ']'. This is calculated here and then
20097c478bd9Sstevel@tonic-gate 		 * used below.
20107c478bd9Sstevel@tonic-gate 		 */
20117c478bd9Sstevel@tonic-gate 		for (alen = 0; (*nnp)->n_name[alen++] != ']'; )
20127c478bd9Sstevel@tonic-gate 			if ((*nnp)->n_name[alen] == '\0')
20137c478bd9Sstevel@tonic-gate 				awkerr(interr, "for: invalid array");
20147c478bd9Sstevel@tonic-gate 	}
20157c478bd9Sstevel@tonic-gate 	for (;;) {
20167c478bd9Sstevel@tonic-gate 		if (issymtab) {
20177c478bd9Sstevel@tonic-gate 			if ((left = symwalk(&nbuck, &np)) == NNULL)
20187c478bd9Sstevel@tonic-gate 				break;
20197c478bd9Sstevel@tonic-gate 			index = left->n_name;
20207c478bd9Sstevel@tonic-gate 		} else {
20217c478bd9Sstevel@tonic-gate 			if ((np = *nnp) == NNULL)
20227c478bd9Sstevel@tonic-gate 				break;
20237c478bd9Sstevel@tonic-gate 			index = np->n_name+alen;
20247c478bd9Sstevel@tonic-gate 			*nnp = np->n_alink;
20257c478bd9Sstevel@tonic-gate 		}
20267c478bd9Sstevel@tonic-gate 		strassign(var, index, FSTATIC, wcslen(index));
20277c478bd9Sstevel@tonic-gate 		if ((act = action(statement)) != 0) {
20287c478bd9Sstevel@tonic-gate 			switch (act) {
20297c478bd9Sstevel@tonic-gate 			case BREAK:
20307c478bd9Sstevel@tonic-gate 				act = 0;
20317c478bd9Sstevel@tonic-gate 				break;
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 			case CONTINUE:
20347c478bd9Sstevel@tonic-gate 				act = 0;
20357c478bd9Sstevel@tonic-gate 				continue;
20367c478bd9Sstevel@tonic-gate 			}
20377c478bd9Sstevel@tonic-gate 			break;
20387c478bd9Sstevel@tonic-gate 		}
20397c478bd9Sstevel@tonic-gate 	}
20407c478bd9Sstevel@tonic-gate 	next_forin--;
20417c478bd9Sstevel@tonic-gate 	return (act);
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate /*
20457c478bd9Sstevel@tonic-gate  * Walk the symbol table using the same algorithm as arraynode.
20467c478bd9Sstevel@tonic-gate  */
20477c478bd9Sstevel@tonic-gate NODE *
20487c478bd9Sstevel@tonic-gate symwalk(int *buckp, NODE **npp)
20497c478bd9Sstevel@tonic-gate {
20507c478bd9Sstevel@tonic-gate 	register NODE *np;
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	np = *npp;
20537c478bd9Sstevel@tonic-gate 	for (;;) {
20547c478bd9Sstevel@tonic-gate 		while (np == NNULL) {
20557c478bd9Sstevel@tonic-gate 			if (*buckp >= NBUCKET)
20567c478bd9Sstevel@tonic-gate 				return (*npp = NNULL);
20577c478bd9Sstevel@tonic-gate 			np = symtab[(*buckp)++];
20587c478bd9Sstevel@tonic-gate 		}
2059*79777a7dSnakanon 		if (np->n_type == VAR &&
2060*79777a7dSnakanon 		    (!isstring(np->n_flags) || np->n_string != _null)) {
20617c478bd9Sstevel@tonic-gate 			*npp = np->n_next;
20627c478bd9Sstevel@tonic-gate 			return (np);
20637c478bd9Sstevel@tonic-gate 		}
20647c478bd9Sstevel@tonic-gate 		np = np->n_next;
20657c478bd9Sstevel@tonic-gate 	}
20667c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate /*
20707c478bd9Sstevel@tonic-gate  * Test the result of an expression.
20717c478bd9Sstevel@tonic-gate  */
20727c478bd9Sstevel@tonic-gate static int
20737c478bd9Sstevel@tonic-gate exprtest(NODE *np)
20747c478bd9Sstevel@tonic-gate {
20757c478bd9Sstevel@tonic-gate 	register int t;
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	if (np == NNULL)
20787c478bd9Sstevel@tonic-gate 		return (1);
20797c478bd9Sstevel@tonic-gate 	if (freelist != NNULL)
20807c478bd9Sstevel@tonic-gate 		freetemps();
20817c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
20827c478bd9Sstevel@tonic-gate 	if (isint(t = np->n_flags)) {
20837c478bd9Sstevel@tonic-gate 		if (isstring(t))
20847c478bd9Sstevel@tonic-gate 			return (exprint(np) != 0);
20857c478bd9Sstevel@tonic-gate 		return (np->n_int != 0);
20867c478bd9Sstevel@tonic-gate 	}
20877c478bd9Sstevel@tonic-gate 	if (isreal(t)) {
20887c478bd9Sstevel@tonic-gate 		REAL rval;
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 		rval = isstring(t) ? exprreal(np) : np->n_real;
20917c478bd9Sstevel@tonic-gate 		return (rval != 0.0);
20927c478bd9Sstevel@tonic-gate 	}
20937c478bd9Sstevel@tonic-gate 	return (*(wchar_t *)exprstring(np) != '\0');
20947c478bd9Sstevel@tonic-gate }
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate /*
20977c478bd9Sstevel@tonic-gate  * Return malloc'ed space that holds the given name "[" scope "]" index ...
20987c478bd9Sstevel@tonic-gate  * concatenated string.
20997c478bd9Sstevel@tonic-gate  * The node (np) is the list of indices and 'array' is the array name.
21007c478bd9Sstevel@tonic-gate  */
21017c478bd9Sstevel@tonic-gate static wchar_t *
21027c478bd9Sstevel@tonic-gate makeindex(NODE *np, wchar_t *array, int tag)
21037c478bd9Sstevel@tonic-gate {
21047c478bd9Sstevel@tonic-gate 	static wchar_t tags[sizeof (int)];
21057c478bd9Sstevel@tonic-gate 	static wchar_t tag_chars[] = M_MB_L("0123456789ABCDEF");
21067c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
21077c478bd9Sstevel@tonic-gate 	register NODE *index;
2108*79777a7dSnakanon 	register uint_t n;
21097c478bd9Sstevel@tonic-gate 	register int len;
21107c478bd9Sstevel@tonic-gate 	register wchar_t *indstr;
21117c478bd9Sstevel@tonic-gate 	register wchar_t *sep;
21127c478bd9Sstevel@tonic-gate 	register int seplen;
21137c478bd9Sstevel@tonic-gate 	register int taglen;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	/*
21177c478bd9Sstevel@tonic-gate 	 * calculate and create the tag string
21187c478bd9Sstevel@tonic-gate 	 */
21197c478bd9Sstevel@tonic-gate 	for (taglen = 0; tag; tag >>= 4)
21207c478bd9Sstevel@tonic-gate 		tags[taglen++] = tag_chars[tag & 0xf];
21217c478bd9Sstevel@tonic-gate 	/*
21227c478bd9Sstevel@tonic-gate 	 * Special (normal) case: only one index.
21237c478bd9Sstevel@tonic-gate 	 */
21247c478bd9Sstevel@tonic-gate 	if (np->n_type != COMMA) {
21257c478bd9Sstevel@tonic-gate 		wchar_t *ocp;
21267c478bd9Sstevel@tonic-gate 		size_t i;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 		if (isleaf(np->n_flags) && np->n_type == PARM)
21297c478bd9Sstevel@tonic-gate 			np = np->n_next;
21307c478bd9Sstevel@tonic-gate 		if (isstring(np->n_flags)) {
21317c478bd9Sstevel@tonic-gate 			indstr = np->n_string;
21327c478bd9Sstevel@tonic-gate 			len = np->n_strlen;
21337c478bd9Sstevel@tonic-gate 		} else {
21347c478bd9Sstevel@tonic-gate 			indstr = exprstring(np);
21357c478bd9Sstevel@tonic-gate 			len = wcslen(indstr);
21367c478bd9Sstevel@tonic-gate 		}
21377c478bd9Sstevel@tonic-gate 		i = (n = wcslen(array)) + len + 3 + taglen;
21387c478bd9Sstevel@tonic-gate 		if (i < NINDEXBUF)
21397c478bd9Sstevel@tonic-gate 			ocp = indexbuf;
21407c478bd9Sstevel@tonic-gate 		else
21417c478bd9Sstevel@tonic-gate 			ocp = emalloc(i * sizeof (wchar_t));
21427c478bd9Sstevel@tonic-gate 		(void) memcpy(ocp, array, n * sizeof (wchar_t));
21437c478bd9Sstevel@tonic-gate 		cp = ocp+n;
21447c478bd9Sstevel@tonic-gate 		if (taglen) {
21457c478bd9Sstevel@tonic-gate 			*cp++ = '[';
21467c478bd9Sstevel@tonic-gate 			while (taglen)
21477c478bd9Sstevel@tonic-gate 				*cp++ = tags[--taglen];
21487c478bd9Sstevel@tonic-gate 		}
21497c478bd9Sstevel@tonic-gate 		*cp++ = ']';
21507c478bd9Sstevel@tonic-gate 		(void) memcpy(cp, indstr, (len+1) * sizeof (wchar_t));
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 		return (ocp);
21537c478bd9Sstevel@tonic-gate 	}
21547c478bd9Sstevel@tonic-gate 	n = 0;
21557c478bd9Sstevel@tonic-gate 	seplen = wcslen(sep = (wchar_t *)exprstring(varSUBSEP));
21567c478bd9Sstevel@tonic-gate 	while ((index = getlist(&np)) != NNULL) {
21577c478bd9Sstevel@tonic-gate 		indstr = exprstring(index);
21587c478bd9Sstevel@tonic-gate 		len = wcslen(indstr);
21597c478bd9Sstevel@tonic-gate 		if (n == 0) {
21607c478bd9Sstevel@tonic-gate 			cp = emalloc(sizeof (wchar_t) * ((n = wcslen(array)) +
21617c478bd9Sstevel@tonic-gate 				len + 3 + taglen));
21627c478bd9Sstevel@tonic-gate 			(void) memcpy(cp, array, n * sizeof (wchar_t));
21637c478bd9Sstevel@tonic-gate 			if (taglen) {
21647c478bd9Sstevel@tonic-gate 				cp[n++] = '[';
21657c478bd9Sstevel@tonic-gate 				while (taglen)
21667c478bd9Sstevel@tonic-gate 					cp[n++] = tags[--taglen];
21677c478bd9Sstevel@tonic-gate 			}
21687c478bd9Sstevel@tonic-gate 			cp[n++] = ']';
21697c478bd9Sstevel@tonic-gate 		} else {
21707c478bd9Sstevel@tonic-gate 			cp = erealloc(cp, (n+len+seplen+1) * sizeof (wchar_t));
21717c478bd9Sstevel@tonic-gate 			(void) memcpy(cp+n, sep, seplen * sizeof (wchar_t));
21727c478bd9Sstevel@tonic-gate 			n += seplen;
21737c478bd9Sstevel@tonic-gate 		}
21747c478bd9Sstevel@tonic-gate 		(void) memcpy(cp+n, indstr, (len+1) * sizeof (wchar_t));
21757c478bd9Sstevel@tonic-gate 		n += len;
21767c478bd9Sstevel@tonic-gate 	}
21777c478bd9Sstevel@tonic-gate 	return (cp);
21787c478bd9Sstevel@tonic-gate }
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate /*
21827c478bd9Sstevel@tonic-gate  * Promote a node to an array. In the simplest case, just set the
21837c478bd9Sstevel@tonic-gate  * node type field to ARRAY. The more complicated case involves walking
21847c478bd9Sstevel@tonic-gate  * a list of variables that haven't been determined yet as scalar or array.
21857c478bd9Sstevel@tonic-gate  * This routine plays with the pointers to avoid recursion.
21867c478bd9Sstevel@tonic-gate  */
21877c478bd9Sstevel@tonic-gate void
21887c478bd9Sstevel@tonic-gate promote(NODE *n)
21897c478bd9Sstevel@tonic-gate {
21907c478bd9Sstevel@tonic-gate 	register NODE *prev = NNULL;
21917c478bd9Sstevel@tonic-gate 	register NODE *next;
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	/*
21947c478bd9Sstevel@tonic-gate 	 * walk down the variable chain, reversing the pointers and
21957c478bd9Sstevel@tonic-gate 	 * setting each node to type array.
21967c478bd9Sstevel@tonic-gate 	 */
21977c478bd9Sstevel@tonic-gate 	while ((n->n_flags & FLARRAY) && (n->n_alink != n)) {
21987c478bd9Sstevel@tonic-gate 		n->n_type = ARRAY;
21997c478bd9Sstevel@tonic-gate 		next = n->n_alink;
22007c478bd9Sstevel@tonic-gate 		n->n_alink = prev;
22017c478bd9Sstevel@tonic-gate 		prev = n;
22027c478bd9Sstevel@tonic-gate 		n = next;
22037c478bd9Sstevel@tonic-gate 	}
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 	/*
22067c478bd9Sstevel@tonic-gate 	 * If the final entity on the chain is a local variable, then
22077c478bd9Sstevel@tonic-gate 	 * reset it's alink field to NNULL - normally it points back
22087c478bd9Sstevel@tonic-gate 	 * to itself - this is used in other parts of the code to
22097c478bd9Sstevel@tonic-gate 	 * reduce the number of conditionals when handling locals.
22107c478bd9Sstevel@tonic-gate 	 */
22117c478bd9Sstevel@tonic-gate 	n->n_type = ARRAY;
22127c478bd9Sstevel@tonic-gate 	if (n->n_flags & FLARRAY)
22137c478bd9Sstevel@tonic-gate 		n->n_alink = NNULL;
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	/*
22167c478bd9Sstevel@tonic-gate 	 * Now walk back up the list setting the alink to point to
22177c478bd9Sstevel@tonic-gate 	 * the last entry in the chain and clear the 'local array'
22187c478bd9Sstevel@tonic-gate 	 * flag.
22197c478bd9Sstevel@tonic-gate 	 */
22207c478bd9Sstevel@tonic-gate 	while (prev != NNULL) {
22217c478bd9Sstevel@tonic-gate 		prev->n_flags &= ~FLARRAY;
22227c478bd9Sstevel@tonic-gate 		next = prev->n_alink;
22237c478bd9Sstevel@tonic-gate 		prev->n_alink = n;
22247c478bd9Sstevel@tonic-gate 		prev = next;
22257c478bd9Sstevel@tonic-gate 	}
22267c478bd9Sstevel@tonic-gate }
2227