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