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