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