xref: /titanic_52/usr/src/cmd/awk_xpg4/awk3.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * awk -- executor
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * Copyright 1985, 1994 by Mortice Kern Systems Inc.  All rights reserved.
29*7c478bd9Sstevel@tonic-gate  *
30*7c478bd9Sstevel@tonic-gate  * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "awk.h"
36*7c478bd9Sstevel@tonic-gate #include "y.tab.h"
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate static int	dohash(wchar_t *name);
39*7c478bd9Sstevel@tonic-gate static NODE	*arithmetic(NODE *np);
40*7c478bd9Sstevel@tonic-gate static NODE	*comparison(NODE *np);
41*7c478bd9Sstevel@tonic-gate static int	typeof(NODE *np);
42*7c478bd9Sstevel@tonic-gate static NODE	*lfield(INT fieldno, NODE *value);
43*7c478bd9Sstevel@tonic-gate static NODE	*rfield(INT fieldno);
44*7c478bd9Sstevel@tonic-gate static NODE	*userfunc(NODE *np);
45*7c478bd9Sstevel@tonic-gate static wchar_t	*lltoa(long long l);
46*7c478bd9Sstevel@tonic-gate static NODE	*exprconcat(NODE *np, int len);
47*7c478bd9Sstevel@tonic-gate static int	s_if(NODE *np);
48*7c478bd9Sstevel@tonic-gate static int	s_while(NODE *np);
49*7c478bd9Sstevel@tonic-gate static int	s_for(NODE *np);
50*7c478bd9Sstevel@tonic-gate static int	s_forin(NODE *np);
51*7c478bd9Sstevel@tonic-gate static void	setrefield(NODE *value);
52*7c478bd9Sstevel@tonic-gate static void	freetemps(void);
53*7c478bd9Sstevel@tonic-gate static int	action(NODE *np);
54*7c478bd9Sstevel@tonic-gate static wchar_t	*makeindex(NODE *np, wchar_t *array, int tag);
55*7c478bd9Sstevel@tonic-gate static int	exprtest(NODE *np);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #define	regmatch(rp, s) REGWEXEC(rp, s, 0, (REGWMATCH_T*)NULL, 0)
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate /*
60*7c478bd9Sstevel@tonic-gate  * This code allows for integers to be stored in longs (type INT) and
61*7c478bd9Sstevel@tonic-gate  * only promoted to double precision floating point numbers (type REAL)
62*7c478bd9Sstevel@tonic-gate  * when overflow occurs during +, -, or * operations.  This is very
63*7c478bd9Sstevel@tonic-gate  * non-portable if you desire such a speed optimisation.  You may wish
64*7c478bd9Sstevel@tonic-gate  * to put something here for your system.  This "something" would likely
65*7c478bd9Sstevel@tonic-gate  * include either an assembler "jump on overflow" instruction or a
66*7c478bd9Sstevel@tonic-gate  * method to get traps on overflows from the hardware.
67*7c478bd9Sstevel@tonic-gate  *
68*7c478bd9Sstevel@tonic-gate  * This portable method works for ones and twos complement integer
69*7c478bd9Sstevel@tonic-gate  * representations (which is, realistically) almost all machines.
70*7c478bd9Sstevel@tonic-gate  */
71*7c478bd9Sstevel@tonic-gate #if	__TURBOC__
72*7c478bd9Sstevel@tonic-gate #define	addoverflow()	asm	jo	overflow
73*7c478bd9Sstevel@tonic-gate #define	suboverflow()	asm	jo	overflow
74*7c478bd9Sstevel@tonic-gate #else
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate  * These are portable to two's complement integer machines
77*7c478bd9Sstevel@tonic-gate  */
78*7c478bd9Sstevel@tonic-gate #define	addoverflow()	if ((i1^i2)>=0 && (iresult^i1)<0) goto overflow
79*7c478bd9Sstevel@tonic-gate #define	suboverflow()	if ((i1^i2)<0 && (iresult^i2)>=0) goto overflow
80*7c478bd9Sstevel@tonic-gate #endif
81*7c478bd9Sstevel@tonic-gate #define	muloverflow()	if (((short)i1!=i1 || (short)i2!=i2)	\
82*7c478bd9Sstevel@tonic-gate 			 && ((i2!=0 && iresult/i2!=i1)		\
83*7c478bd9Sstevel@tonic-gate 			  || (i1==LONG_MIN && i2==-1)))	  goto overflow
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate static char	notarray[] = "scalar \"%s\" cannot be used as array";
86*7c478bd9Sstevel@tonic-gate static char	badarray[] = "array \"%s\" cannot be used as a scalar";
87*7c478bd9Sstevel@tonic-gate static char	varnotfunc[] = "variable \"%s\" cannot be used as a function";
88*7c478bd9Sstevel@tonic-gate static char	tmfld[] = "Too many fields (LIMIT: %d)";
89*7c478bd9Sstevel@tonic-gate static char	toolong[] = "Record too long (LIMIT: %d bytes)";
90*7c478bd9Sstevel@tonic-gate static char	divzero[] =  "division (/ or %%) by zero";
91*7c478bd9Sstevel@tonic-gate static char	toodeep[] = "too deeply nested for in loop (LIMIT: %d)";
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate static wchar_t	numbuf[NUMSIZE];	/* Used to convert INTs to strings */
94*7c478bd9Sstevel@tonic-gate static wchar_t	*fields[NFIELD];	/* Cache of pointers into fieldbuf */
95*7c478bd9Sstevel@tonic-gate static wchar_t	*fieldbuf;		/* '\0' separated copy of linebuf */
96*7c478bd9Sstevel@tonic-gate static NODE	nodes[NSNODE];		/* Cache of quick access nodes */
97*7c478bd9Sstevel@tonic-gate static NODE	*fnodep = &nodes[0];
98*7c478bd9Sstevel@tonic-gate #define	NINDEXBUF	50
99*7c478bd9Sstevel@tonic-gate static wchar_t	indexbuf[NINDEXBUF];	/* Used for simple array indices */
100*7c478bd9Sstevel@tonic-gate static int	concflag;		/* In CONCAT operation (no frees) */
101*7c478bd9Sstevel@tonic-gate static NODE	*retval;		/* Last return value of a function */
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate  * The following stack is used to store the next pointers for all nested
105*7c478bd9Sstevel@tonic-gate  * for-in loops. This needs to be global so that delete can check to see
106*7c478bd9Sstevel@tonic-gate  * if it is deleting the next node to be used by a loop.
107*7c478bd9Sstevel@tonic-gate  */
108*7c478bd9Sstevel@tonic-gate #define NFORINLOOP	10
109*7c478bd9Sstevel@tonic-gate static NODE*	forindex[NFORINLOOP];
110*7c478bd9Sstevel@tonic-gate static NODE**	next_forin = forindex;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /*
113*7c478bd9Sstevel@tonic-gate  * Assign a string directly to a NODE without creating an intermediate
114*7c478bd9Sstevel@tonic-gate  * NODE.  This can handle either FALLOC, FSTATIC, FNOALLOC or FSENSE for
115*7c478bd9Sstevel@tonic-gate  * "flags" argument.  Also the NODE "np" must be reduced to an lvalue
116*7c478bd9Sstevel@tonic-gate  * (PARM nodes are not acceptable).
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate void
119*7c478bd9Sstevel@tonic-gate strassign(NODE *np, STRING string, int flags, size_t length)
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	if (np->n_type == FUNC)
122*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("attempt to redefine builtin function"));
123*7c478bd9Sstevel@tonic-gate 	else if (np->n_type == GETLINE || np->n_type == KEYWORD)
124*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("inadmissible use of reserved keyword"));
125*7c478bd9Sstevel@tonic-gate 	if (np->n_flags & FSPECIAL) {
126*7c478bd9Sstevel@tonic-gate 		(void)nassign(np, stringnode(string, flags, length));
127*7c478bd9Sstevel@tonic-gate 		return;
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 	if (isastring(np->n_flags))
130*7c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_string);
131*7c478bd9Sstevel@tonic-gate 	np->n_strlen = length++;
132*7c478bd9Sstevel@tonic-gate 	if (flags & FALLOC) {
133*7c478bd9Sstevel@tonic-gate 		length *= sizeof(wchar_t);
134*7c478bd9Sstevel@tonic-gate 		np->n_string = (STRING) emalloc(length);
135*7c478bd9Sstevel@tonic-gate 		(void) memcpy((void *)np->n_string, string, length);
136*7c478bd9Sstevel@tonic-gate 	} else {
137*7c478bd9Sstevel@tonic-gate 		np->n_string = string;
138*7c478bd9Sstevel@tonic-gate 		if (flags & FNOALLOC) {
139*7c478bd9Sstevel@tonic-gate 			flags &= ~FNOALLOC;
140*7c478bd9Sstevel@tonic-gate 			flags |= FALLOC;
141*7c478bd9Sstevel@tonic-gate 		}
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 	np->n_flags &= FSAVE;
144*7c478bd9Sstevel@tonic-gate 	if (flags & FSENSE) {
145*7c478bd9Sstevel@tonic-gate 		flags &= ~FSENSE;
146*7c478bd9Sstevel@tonic-gate 		flags |= typeof(np);
147*7c478bd9Sstevel@tonic-gate 	} else
148*7c478bd9Sstevel@tonic-gate 		flags |= FSTRING;
149*7c478bd9Sstevel@tonic-gate 	np->n_flags |= flags;
150*7c478bd9Sstevel@tonic-gate }
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate /*
153*7c478bd9Sstevel@tonic-gate  * Assign to a variable node.
154*7c478bd9Sstevel@tonic-gate  * LHS must be a VAR type and RHS must be reduced by now.
155*7c478bd9Sstevel@tonic-gate  * To speed certain operations up, check for
156*7c478bd9Sstevel@tonic-gate  * certain things here and do special assignments.
157*7c478bd9Sstevel@tonic-gate  */
158*7c478bd9Sstevel@tonic-gate NODE *
159*7c478bd9Sstevel@tonic-gate nassign(NODE *np, NODE *value)
160*7c478bd9Sstevel@tonic-gate {
161*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
162*7c478bd9Sstevel@tonic-gate 	register int len;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	/* short circuit assignment of a node to itself */
165*7c478bd9Sstevel@tonic-gate 	if (np == value)
166*7c478bd9Sstevel@tonic-gate 		return (np);
167*7c478bd9Sstevel@tonic-gate 	if (np->n_flags & FSPECIAL) {
168*7c478bd9Sstevel@tonic-gate 		if (np == varRS || np == varFS) {
169*7c478bd9Sstevel@tonic-gate 			if (isastring(np->n_flags))
170*7c478bd9Sstevel@tonic-gate 				free((void *)np->n_string);
171*7c478bd9Sstevel@tonic-gate 			len = sizeof(wchar_t) * ((np->n_strlen =
172*7c478bd9Sstevel@tonic-gate 				wcslen(cp = exprstring(value)))+1);
173*7c478bd9Sstevel@tonic-gate 			np->n_string = emalloc(len);
174*7c478bd9Sstevel@tonic-gate 			(void) memcpy((wchar_t *)np->n_string, cp, len);
175*7c478bd9Sstevel@tonic-gate 			np->n_flags = FALLOC|FSTRING|FSPECIAL;
176*7c478bd9Sstevel@tonic-gate 			if (np == varRS) {
177*7c478bd9Sstevel@tonic-gate 				if (np->n_string[0] == '\n')
178*7c478bd9Sstevel@tonic-gate 					awkrecord = defrecord;
179*7c478bd9Sstevel@tonic-gate 				else if (np->n_string[0] == '\0')
180*7c478bd9Sstevel@tonic-gate 					awkrecord = multirecord;
181*7c478bd9Sstevel@tonic-gate 				else
182*7c478bd9Sstevel@tonic-gate 					awkrecord = charrecord;
183*7c478bd9Sstevel@tonic-gate 			} else if (np == varFS) {
184*7c478bd9Sstevel@tonic-gate 				if (resep != (REGEXP)NULL) {
185*7c478bd9Sstevel@tonic-gate 					regfree(resep);
186*7c478bd9Sstevel@tonic-gate 					resep = (REGEXP)NULL;
187*7c478bd9Sstevel@tonic-gate 				}
188*7c478bd9Sstevel@tonic-gate 				if (wcslen((wchar_t *)np->n_string) > 1)
189*7c478bd9Sstevel@tonic-gate 					setrefield(np);
190*7c478bd9Sstevel@tonic-gate 				else if (np->n_string[0] == ' ')
191*7c478bd9Sstevel@tonic-gate 					awkfield = whitefield;
192*7c478bd9Sstevel@tonic-gate 				else
193*7c478bd9Sstevel@tonic-gate 					awkfield = blackfield;
194*7c478bd9Sstevel@tonic-gate 			}
195*7c478bd9Sstevel@tonic-gate 			return (np);
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate 	}
198*7c478bd9Sstevel@tonic-gate 	if (isastring(np->n_flags))
199*7c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_string);
200*7c478bd9Sstevel@tonic-gate 	if (isstring(value->n_flags)) {
201*7c478bd9Sstevel@tonic-gate 		np->n_strlen = value->n_strlen;
202*7c478bd9Sstevel@tonic-gate 		if (value->n_flags&FALLOC || value->n_string!=_null) {
203*7c478bd9Sstevel@tonic-gate 			len = (np->n_strlen+1) * sizeof(wchar_t);
204*7c478bd9Sstevel@tonic-gate 			np->n_string = emalloc(len);
205*7c478bd9Sstevel@tonic-gate 			(void) memcpy(np->n_string, value->n_string, len);
206*7c478bd9Sstevel@tonic-gate 			np->n_flags &= FSAVE;
207*7c478bd9Sstevel@tonic-gate 			np->n_flags |= value->n_flags & ~FSAVE;
208*7c478bd9Sstevel@tonic-gate 			np->n_flags |= FALLOC;
209*7c478bd9Sstevel@tonic-gate 			return (np);
210*7c478bd9Sstevel@tonic-gate 		} else
211*7c478bd9Sstevel@tonic-gate 			np->n_string = value->n_string;
212*7c478bd9Sstevel@tonic-gate 	} else if (value->n_flags & FINT)
213*7c478bd9Sstevel@tonic-gate 		np->n_int = value->n_int;
214*7c478bd9Sstevel@tonic-gate 	else
215*7c478bd9Sstevel@tonic-gate 		np->n_real = value->n_real;
216*7c478bd9Sstevel@tonic-gate 	np->n_flags &= FSAVE;
217*7c478bd9Sstevel@tonic-gate 	np->n_flags |= value->n_flags & ~FSAVE;
218*7c478bd9Sstevel@tonic-gate 	return (np);
219*7c478bd9Sstevel@tonic-gate }
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate /*
222*7c478bd9Sstevel@tonic-gate  * Set regular expression FS value.
223*7c478bd9Sstevel@tonic-gate  */
224*7c478bd9Sstevel@tonic-gate static void
225*7c478bd9Sstevel@tonic-gate setrefield(NODE *np)
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	static regex_t re;
228*7c478bd9Sstevel@tonic-gate 	int n;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	if ((n = REGWCOMP(&re, np->n_string, REG_EXTENDED)) != REG_OK) {
231*7c478bd9Sstevel@tonic-gate 		regerror(n, &re, (char *)linebuf, sizeof(linebuf));
232*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("syntax error \"%s\" in /%s/\n"),
233*7c478bd9Sstevel@tonic-gate 			(char *)linebuf, np->n_string);
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 	resep = &re;
236*7c478bd9Sstevel@tonic-gate 	awkfield = refield;
237*7c478bd9Sstevel@tonic-gate }
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate /*
240*7c478bd9Sstevel@tonic-gate  * Assign to an l-value node.
241*7c478bd9Sstevel@tonic-gate  */
242*7c478bd9Sstevel@tonic-gate NODE *
243*7c478bd9Sstevel@tonic-gate assign(NODE *left, NODE *right)
244*7c478bd9Sstevel@tonic-gate {
245*7c478bd9Sstevel@tonic-gate 	if (isleaf(right->n_flags)) {
246*7c478bd9Sstevel@tonic-gate 		if (right->n_type == PARM)
247*7c478bd9Sstevel@tonic-gate 			right = right->n_next;
248*7c478bd9Sstevel@tonic-gate 	} else
249*7c478bd9Sstevel@tonic-gate 		right = exprreduce(right);
250*7c478bd9Sstevel@tonic-gate top:
251*7c478bd9Sstevel@tonic-gate 	switch (left->n_type) {
252*7c478bd9Sstevel@tonic-gate 	case INDEX:
253*7c478bd9Sstevel@tonic-gate 		left = exprreduce(left);
254*7c478bd9Sstevel@tonic-gate 	case VAR:
255*7c478bd9Sstevel@tonic-gate 		return (nassign(left, right));
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	case PARM:
258*7c478bd9Sstevel@tonic-gate 		/*
259*7c478bd9Sstevel@tonic-gate 		 * If it's a parameter then link to the actual value node and
260*7c478bd9Sstevel@tonic-gate 		 * do the checks again.
261*7c478bd9Sstevel@tonic-gate 		 */
262*7c478bd9Sstevel@tonic-gate 		left = left->n_next;
263*7c478bd9Sstevel@tonic-gate 		goto top;
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	case FIELD:
266*7c478bd9Sstevel@tonic-gate 		return (lfield(exprint(left->n_left), right));
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	case CALLUFUNC:
269*7c478bd9Sstevel@tonic-gate 	case UFUNC:
270*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("cannot assign to function \"%s\""),
271*7c478bd9Sstevel@tonic-gate 		    left->n_name);
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	default:
274*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("lvalue required in assignment"));
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * Compiled tree non-terminal node.
281*7c478bd9Sstevel@tonic-gate  */
282*7c478bd9Sstevel@tonic-gate NODE *
283*7c478bd9Sstevel@tonic-gate node(int type, NODE *left, NODE *right)
284*7c478bd9Sstevel@tonic-gate {
285*7c478bd9Sstevel@tonic-gate 	register NODE *np;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	np = emptynode(type, 0);
288*7c478bd9Sstevel@tonic-gate 	np->n_left = left;
289*7c478bd9Sstevel@tonic-gate 	np->n_right = right;
290*7c478bd9Sstevel@tonic-gate 	np->n_lineno = lineno;
291*7c478bd9Sstevel@tonic-gate 	return (np);
292*7c478bd9Sstevel@tonic-gate }
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate /*
295*7c478bd9Sstevel@tonic-gate  * Create an integer node.
296*7c478bd9Sstevel@tonic-gate  */
297*7c478bd9Sstevel@tonic-gate NODE *
298*7c478bd9Sstevel@tonic-gate intnode(INT i)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	register NODE *np;
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	np = emptynode(CONSTANT, 0);
303*7c478bd9Sstevel@tonic-gate 	np->n_flags = FINT|FVINT;
304*7c478bd9Sstevel@tonic-gate 	np->n_int = i;
305*7c478bd9Sstevel@tonic-gate 	return (np);
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate /*
309*7c478bd9Sstevel@tonic-gate  * Create a real number node.
310*7c478bd9Sstevel@tonic-gate  */
311*7c478bd9Sstevel@tonic-gate NODE *
312*7c478bd9Sstevel@tonic-gate realnode(REAL real)
313*7c478bd9Sstevel@tonic-gate {
314*7c478bd9Sstevel@tonic-gate 	register NODE *np;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	np = emptynode(CONSTANT, 0);
317*7c478bd9Sstevel@tonic-gate 	np->n_flags = FREAL|FVREAL;
318*7c478bd9Sstevel@tonic-gate 	np->n_real = real;
319*7c478bd9Sstevel@tonic-gate 	return (np);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate  * Make a node for a string.
324*7c478bd9Sstevel@tonic-gate  */
325*7c478bd9Sstevel@tonic-gate NODE *
326*7c478bd9Sstevel@tonic-gate stringnode(STRING s, int how, size_t length)
327*7c478bd9Sstevel@tonic-gate {
328*7c478bd9Sstevel@tonic-gate 	register NODE *np;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	np = emptynode(CONSTANT, 0);
331*7c478bd9Sstevel@tonic-gate 	np->n_strlen = length;
332*7c478bd9Sstevel@tonic-gate 	if (how & FALLOC) {
333*7c478bd9Sstevel@tonic-gate 		np->n_string = emalloc(length = (length+1) * sizeof(wchar_t));
334*7c478bd9Sstevel@tonic-gate 		(void) memcpy(np->n_string, s, length);
335*7c478bd9Sstevel@tonic-gate 	} else {
336*7c478bd9Sstevel@tonic-gate 		np->n_string = s;
337*7c478bd9Sstevel@tonic-gate 		if (how & FNOALLOC) {
338*7c478bd9Sstevel@tonic-gate 			how &= ~FNOALLOC;
339*7c478bd9Sstevel@tonic-gate 			how |= FALLOC;
340*7c478bd9Sstevel@tonic-gate 		}
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 	if (how & FSENSE) {
343*7c478bd9Sstevel@tonic-gate 		np->n_flags = typeof(np);
344*7c478bd9Sstevel@tonic-gate 		how &= ~FSENSE;
345*7c478bd9Sstevel@tonic-gate 	} else
346*7c478bd9Sstevel@tonic-gate 		np->n_flags = FSTRING;
347*7c478bd9Sstevel@tonic-gate 	np->n_flags |= how;
348*7c478bd9Sstevel@tonic-gate 	return (np);
349*7c478bd9Sstevel@tonic-gate }
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate /*
352*7c478bd9Sstevel@tonic-gate  * Save a copy of a string.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate STRING
355*7c478bd9Sstevel@tonic-gate strsave(wchar_t *old)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	STRING new;
358*7c478bd9Sstevel@tonic-gate 	register size_t len;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	new = (STRING)emalloc(len = (wcslen(old)+1) * sizeof(wchar_t));
361*7c478bd9Sstevel@tonic-gate 	(void) memcpy(new, old, len);
362*7c478bd9Sstevel@tonic-gate 	return (new);
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate /*
366*7c478bd9Sstevel@tonic-gate  * Allocate an empty node of given type.
367*7c478bd9Sstevel@tonic-gate  * String space for the node is given by `length'.
368*7c478bd9Sstevel@tonic-gate  */
369*7c478bd9Sstevel@tonic-gate NODE *
370*7c478bd9Sstevel@tonic-gate emptynode(int type, size_t length)
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	register NODE *np;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	if (length==0 && running && fnodep < &nodes[NSNODE]) {
375*7c478bd9Sstevel@tonic-gate 		np = fnodep++;
376*7c478bd9Sstevel@tonic-gate 	} else {
377*7c478bd9Sstevel@tonic-gate 		np = (NODE *) emalloc(sizeof(NODE)+(length * sizeof(wchar_t)));
378*7c478bd9Sstevel@tonic-gate 		if (running && type!=VAR && type!=ARRAY) {
379*7c478bd9Sstevel@tonic-gate 			np->n_next = freelist;
380*7c478bd9Sstevel@tonic-gate 			freelist = np;
381*7c478bd9Sstevel@tonic-gate 		}
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 	np->n_flags = FNONTOK;
384*7c478bd9Sstevel@tonic-gate 	np->n_type = type;
385*7c478bd9Sstevel@tonic-gate 	np->n_alink = NNULL;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	return (np);
388*7c478bd9Sstevel@tonic-gate }
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate /*
391*7c478bd9Sstevel@tonic-gate  * Free a node.
392*7c478bd9Sstevel@tonic-gate  */
393*7c478bd9Sstevel@tonic-gate void
394*7c478bd9Sstevel@tonic-gate freenode(NODE *np)
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate 	if (isastring(np->n_flags))
397*7c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_string);
398*7c478bd9Sstevel@tonic-gate 	else if (np->n_type == RE) {
399*7c478bd9Sstevel@tonic-gate 		regfree(np->n_regexp);
400*7c478bd9Sstevel@tonic-gate 		free((wchar_t *)np->n_regexp);
401*7c478bd9Sstevel@tonic-gate 	}
402*7c478bd9Sstevel@tonic-gate 	free((wchar_t *)np);
403*7c478bd9Sstevel@tonic-gate }
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate /*
406*7c478bd9Sstevel@tonic-gate  * Install a keyword of given `type'.
407*7c478bd9Sstevel@tonic-gate  */
408*7c478bd9Sstevel@tonic-gate void
409*7c478bd9Sstevel@tonic-gate kinstall(LOCCHARP name, int type)
410*7c478bd9Sstevel@tonic-gate {
411*7c478bd9Sstevel@tonic-gate 	register NODE *np;
412*7c478bd9Sstevel@tonic-gate 	register size_t l;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	l = wcslen(name);
415*7c478bd9Sstevel@tonic-gate 	np = emptynode(KEYWORD, l);
416*7c478bd9Sstevel@tonic-gate 	np->n_keywtype = type;
417*7c478bd9Sstevel@tonic-gate 	(void) memcpy(np->n_name, name, (l+1) * sizeof(wchar_t));
418*7c478bd9Sstevel@tonic-gate 	addsymtab(np);
419*7c478bd9Sstevel@tonic-gate }
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate /*
422*7c478bd9Sstevel@tonic-gate  * Install built-in function.
423*7c478bd9Sstevel@tonic-gate  */
424*7c478bd9Sstevel@tonic-gate NODE *
425*7c478bd9Sstevel@tonic-gate finstall(LOCCHARP name, FUNCTION func, int type)
426*7c478bd9Sstevel@tonic-gate {
427*7c478bd9Sstevel@tonic-gate 	register NODE *np;
428*7c478bd9Sstevel@tonic-gate 	register size_t l;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	l = wcslen(name);
431*7c478bd9Sstevel@tonic-gate 	np = emptynode(type, l);
432*7c478bd9Sstevel@tonic-gate 	np->n_function = func;
433*7c478bd9Sstevel@tonic-gate 	(void) memcpy(np->n_name, name, (l+1) * sizeof(wchar_t));
434*7c478bd9Sstevel@tonic-gate 	addsymtab(np);
435*7c478bd9Sstevel@tonic-gate 	return np;
436*7c478bd9Sstevel@tonic-gate }
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate /*
439*7c478bd9Sstevel@tonic-gate  * Lookup an identifier.
440*7c478bd9Sstevel@tonic-gate  * nocreate contains the following flag values:
441*7c478bd9Sstevel@tonic-gate  *	1 if no creation of a new NODE,
442*7c478bd9Sstevel@tonic-gate  *	0 if ok to create new NODE
443*7c478bd9Sstevel@tonic-gate  */
444*7c478bd9Sstevel@tonic-gate NODE *
445*7c478bd9Sstevel@tonic-gate vlookup(wchar_t *name, int nocreate)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	register ushort hash;
448*7c478bd9Sstevel@tonic-gate 	register NODE *np;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	np = symtab[hashbuck(hash = dohash((wchar_t*)name))];
451*7c478bd9Sstevel@tonic-gate 	while (np != NNULL) {
452*7c478bd9Sstevel@tonic-gate 		if (np->n_hash==hash && wcscmp(name, np->n_name)==0)
453*7c478bd9Sstevel@tonic-gate 			return (np);
454*7c478bd9Sstevel@tonic-gate 		np = np->n_next;
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 	if (nocreate) {
457*7c478bd9Sstevel@tonic-gate 		np = NNULL;
458*7c478bd9Sstevel@tonic-gate 	} else {
459*7c478bd9Sstevel@tonic-gate 		np = emptynode(VAR, hash = wcslen(name));
460*7c478bd9Sstevel@tonic-gate 		np->n_flags = FSTRING|FVINT;
461*7c478bd9Sstevel@tonic-gate 		np->n_strlen = 0;
462*7c478bd9Sstevel@tonic-gate 		np->n_string = _null;
463*7c478bd9Sstevel@tonic-gate 		(void) memcpy(np->n_name, name,
464*7c478bd9Sstevel@tonic-gate 			(hash+1) * sizeof(wchar_t));
465*7c478bd9Sstevel@tonic-gate 		addsymtab(np);
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate 	return (np);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate /*
471*7c478bd9Sstevel@tonic-gate  * Add a symbol to the table.
472*7c478bd9Sstevel@tonic-gate  */
473*7c478bd9Sstevel@tonic-gate void
474*7c478bd9Sstevel@tonic-gate addsymtab(NODE *np)
475*7c478bd9Sstevel@tonic-gate {
476*7c478bd9Sstevel@tonic-gate 	register NODE **spp;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	np->n_hash = dohash((wchar_t *)np->n_name);
479*7c478bd9Sstevel@tonic-gate 	spp = &symtab[hashbuck(np->n_hash)];
480*7c478bd9Sstevel@tonic-gate 	np->n_next = *spp;
481*7c478bd9Sstevel@tonic-gate 	*spp = np;
482*7c478bd9Sstevel@tonic-gate }
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate /*
485*7c478bd9Sstevel@tonic-gate  * Delete the given node from the symbol table.
486*7c478bd9Sstevel@tonic-gate  * If fflag is non-zero, also free the node space.
487*7c478bd9Sstevel@tonic-gate  * This routine must also check the stack of forin loop pointers. If
488*7c478bd9Sstevel@tonic-gate  * we are deleting the next item to be used, then the pointer must be
489*7c478bd9Sstevel@tonic-gate  * advanced.
490*7c478bd9Sstevel@tonic-gate  */
491*7c478bd9Sstevel@tonic-gate void
492*7c478bd9Sstevel@tonic-gate delsymtab(NODE *np, int fflag)
493*7c478bd9Sstevel@tonic-gate {
494*7c478bd9Sstevel@tonic-gate 	register NODE *rnp;
495*7c478bd9Sstevel@tonic-gate 	register NODE *prevp;
496*7c478bd9Sstevel@tonic-gate 	register NODE **sptr;
497*7c478bd9Sstevel@tonic-gate 	register ushort h;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	h = hashbuck(np->n_hash);
504*7c478bd9Sstevel@tonic-gate 	prevp = NNULL;
505*7c478bd9Sstevel@tonic-gate 	for (rnp = symtab[h]; rnp != NNULL; rnp = rnp->n_next) {
506*7c478bd9Sstevel@tonic-gate 		if (rnp == np) {
507*7c478bd9Sstevel@tonic-gate 			/*
508*7c478bd9Sstevel@tonic-gate 			 * check all of the for-in loop pointers
509*7c478bd9Sstevel@tonic-gate 			 * to see if any need to be advanced because
510*7c478bd9Sstevel@tonic-gate 			 * this element is being deleted.
511*7c478bd9Sstevel@tonic-gate 			 */
512*7c478bd9Sstevel@tonic-gate 			if (next_forin != forindex) {
513*7c478bd9Sstevel@tonic-gate 				sptr = next_forin;
514*7c478bd9Sstevel@tonic-gate 				do {
515*7c478bd9Sstevel@tonic-gate 					if (*--sptr == rnp) {
516*7c478bd9Sstevel@tonic-gate 						*sptr = rnp->n_next;
517*7c478bd9Sstevel@tonic-gate 						break;
518*7c478bd9Sstevel@tonic-gate 					}
519*7c478bd9Sstevel@tonic-gate 				} while (sptr != forindex);
520*7c478bd9Sstevel@tonic-gate 			}
521*7c478bd9Sstevel@tonic-gate 			if (prevp == NNULL)
522*7c478bd9Sstevel@tonic-gate 				symtab[h] = rnp->n_next; else
523*7c478bd9Sstevel@tonic-gate 				prevp->n_next = rnp->n_next;
524*7c478bd9Sstevel@tonic-gate 			if (fflag)
525*7c478bd9Sstevel@tonic-gate 				freenode(rnp);
526*7c478bd9Sstevel@tonic-gate 			break;
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		prevp = rnp;
529*7c478bd9Sstevel@tonic-gate 	}
530*7c478bd9Sstevel@tonic-gate }
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate /*
533*7c478bd9Sstevel@tonic-gate  * Hashing function.
534*7c478bd9Sstevel@tonic-gate  */
535*7c478bd9Sstevel@tonic-gate static int
536*7c478bd9Sstevel@tonic-gate dohash(wchar_t *name)
537*7c478bd9Sstevel@tonic-gate {
538*7c478bd9Sstevel@tonic-gate 	register int hash = 0;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	while (*name != '\0')
541*7c478bd9Sstevel@tonic-gate 		hash += *name++;
542*7c478bd9Sstevel@tonic-gate 	return (hash);
543*7c478bd9Sstevel@tonic-gate }
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate /*
546*7c478bd9Sstevel@tonic-gate  * Top level executor for an awk programme.
547*7c478bd9Sstevel@tonic-gate  * This will be passed: pattern, action or a list of these.
548*7c478bd9Sstevel@tonic-gate  * The former function to evaluate a pattern has been
549*7c478bd9Sstevel@tonic-gate  * subsumed into this function for speed.
550*7c478bd9Sstevel@tonic-gate  * Patterns are:
551*7c478bd9Sstevel@tonic-gate  *	BEGIN,
552*7c478bd9Sstevel@tonic-gate  *	END,
553*7c478bd9Sstevel@tonic-gate  *	other expressions (including regular expressions)
554*7c478bd9Sstevel@tonic-gate  */
555*7c478bd9Sstevel@tonic-gate void
556*7c478bd9Sstevel@tonic-gate execute(NODE *wp)
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	register NODE *np;
559*7c478bd9Sstevel@tonic-gate 	register int type;
560*7c478bd9Sstevel@tonic-gate 	register NODE *tnp;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	curnode = wp;
563*7c478bd9Sstevel@tonic-gate 	if (phase != 0) {
564*7c478bd9Sstevel@tonic-gate 		linebuf[0] = '\0';
565*7c478bd9Sstevel@tonic-gate 		lbuflen = 0;
566*7c478bd9Sstevel@tonic-gate 	}
567*7c478bd9Sstevel@tonic-gate 	while (wp != NNULL) {
568*7c478bd9Sstevel@tonic-gate 		if (wp->n_type == COMMA) {
569*7c478bd9Sstevel@tonic-gate 			np = wp->n_left;
570*7c478bd9Sstevel@tonic-gate 			wp = wp->n_right;
571*7c478bd9Sstevel@tonic-gate 		} else {
572*7c478bd9Sstevel@tonic-gate 			np = wp;
573*7c478bd9Sstevel@tonic-gate 			wp = NNULL;
574*7c478bd9Sstevel@tonic-gate 		}
575*7c478bd9Sstevel@tonic-gate 		if (np->n_type != PACT)
576*7c478bd9Sstevel@tonic-gate 			awkerr(interr, "PACT");
577*7c478bd9Sstevel@tonic-gate 		/*
578*7c478bd9Sstevel@tonic-gate 		 * Save the parent node and evaluate the pattern.
579*7c478bd9Sstevel@tonic-gate 		 * If it evaluates to false (0) just continue
580*7c478bd9Sstevel@tonic-gate 		 * to the next pattern/action (PACT) pair.
581*7c478bd9Sstevel@tonic-gate 		 */
582*7c478bd9Sstevel@tonic-gate 		tnp = np;
583*7c478bd9Sstevel@tonic-gate 		np = np->n_left;
584*7c478bd9Sstevel@tonic-gate 		if (np == NNULL) {
585*7c478bd9Sstevel@tonic-gate 			if (phase != 0)
586*7c478bd9Sstevel@tonic-gate 				continue;
587*7c478bd9Sstevel@tonic-gate 		} else if (phase != 0) {
588*7c478bd9Sstevel@tonic-gate 			if (np->n_type != phase)
589*7c478bd9Sstevel@tonic-gate 				continue;
590*7c478bd9Sstevel@tonic-gate 		} else if ((type = np->n_type)==BEGIN || type==END) {
591*7c478bd9Sstevel@tonic-gate 			continue;
592*7c478bd9Sstevel@tonic-gate 		} else if (type == COMMA) {
593*7c478bd9Sstevel@tonic-gate 			/*
594*7c478bd9Sstevel@tonic-gate 			 * The grammar only allows expressions
595*7c478bd9Sstevel@tonic-gate 			 * to be separated by the ',' operator
596*7c478bd9Sstevel@tonic-gate 			 * for range patterns.
597*7c478bd9Sstevel@tonic-gate 			 */
598*7c478bd9Sstevel@tonic-gate 			if (np->n_flags & FMATCH) {
599*7c478bd9Sstevel@tonic-gate 				if (exprint(np->n_right) != 0)
600*7c478bd9Sstevel@tonic-gate 					np->n_flags &= ~FMATCH;
601*7c478bd9Sstevel@tonic-gate 			} else if (exprint(np->n_left) != 0) {
602*7c478bd9Sstevel@tonic-gate 				if (exprint(np->n_right) == 0)
603*7c478bd9Sstevel@tonic-gate 					np->n_flags |= FMATCH;
604*7c478bd9Sstevel@tonic-gate 			} else
605*7c478bd9Sstevel@tonic-gate 				continue;
606*7c478bd9Sstevel@tonic-gate 		} else if (exprint(np) == 0)
607*7c478bd9Sstevel@tonic-gate 			continue;
608*7c478bd9Sstevel@tonic-gate 		np = tnp;
609*7c478bd9Sstevel@tonic-gate 		if (action(np->n_right)) {
610*7c478bd9Sstevel@tonic-gate 			loopexit = 0;
611*7c478bd9Sstevel@tonic-gate 			break;
612*7c478bd9Sstevel@tonic-gate 		}
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate 	if (freelist != NNULL)
615*7c478bd9Sstevel@tonic-gate 		freetemps();
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate /*
619*7c478bd9Sstevel@tonic-gate  * Free all temporary nodes.
620*7c478bd9Sstevel@tonic-gate  */
621*7c478bd9Sstevel@tonic-gate static void
622*7c478bd9Sstevel@tonic-gate freetemps()
623*7c478bd9Sstevel@tonic-gate {
624*7c478bd9Sstevel@tonic-gate 	register NODE *np, *nnp;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	if (concflag)
627*7c478bd9Sstevel@tonic-gate 		return;
628*7c478bd9Sstevel@tonic-gate 	for (np = &nodes[0]; np < fnodep; np++) {
629*7c478bd9Sstevel@tonic-gate 		if (isastring(np->n_flags)) {
630*7c478bd9Sstevel@tonic-gate 			free((wchar_t *)np->n_string);
631*7c478bd9Sstevel@tonic-gate 		} else if (np->n_type == RE) {
632*7c478bd9Sstevel@tonic-gate 			regfree(np->n_regexp);
633*7c478bd9Sstevel@tonic-gate 			free((wchar_t *)np->n_regexp);
634*7c478bd9Sstevel@tonic-gate 		}
635*7c478bd9Sstevel@tonic-gate 	}
636*7c478bd9Sstevel@tonic-gate 	fnodep = &nodes[0];
637*7c478bd9Sstevel@tonic-gate 	for (np = freelist; np != NNULL; np = nnp) {
638*7c478bd9Sstevel@tonic-gate 		nnp = np->n_next;
639*7c478bd9Sstevel@tonic-gate 		freenode(np);
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate 	freelist = NNULL;
642*7c478bd9Sstevel@tonic-gate }
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate /*
645*7c478bd9Sstevel@tonic-gate  * Do the given action.
646*7c478bd9Sstevel@tonic-gate  * Actions are statements or expressions.
647*7c478bd9Sstevel@tonic-gate  */
648*7c478bd9Sstevel@tonic-gate static int
649*7c478bd9Sstevel@tonic-gate action(NODE *wp)
650*7c478bd9Sstevel@tonic-gate {
651*7c478bd9Sstevel@tonic-gate 	register NODE *np;
652*7c478bd9Sstevel@tonic-gate 	register int act = 0;
653*7c478bd9Sstevel@tonic-gate 	register NODE *l;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	while (wp != NNULL) {
656*7c478bd9Sstevel@tonic-gate 		if (wp->n_type == COMMA) {
657*7c478bd9Sstevel@tonic-gate 			np = wp->n_left;
658*7c478bd9Sstevel@tonic-gate 			wp = wp->n_right;
659*7c478bd9Sstevel@tonic-gate 		} else {
660*7c478bd9Sstevel@tonic-gate 			np = wp;
661*7c478bd9Sstevel@tonic-gate 			wp = NNULL;
662*7c478bd9Sstevel@tonic-gate 		}
663*7c478bd9Sstevel@tonic-gate 		if (freelist != NNULL)
664*7c478bd9Sstevel@tonic-gate 			freetemps();
665*7c478bd9Sstevel@tonic-gate 		curnode = np;
666*7c478bd9Sstevel@tonic-gate 		/*
667*7c478bd9Sstevel@tonic-gate 		 * Don't change order of these cases without
668*7c478bd9Sstevel@tonic-gate 		 * changing order in awk.y declarations.
669*7c478bd9Sstevel@tonic-gate 		 * The order is optimised.
670*7c478bd9Sstevel@tonic-gate 		 */
671*7c478bd9Sstevel@tonic-gate 		switch (np->n_type) {
672*7c478bd9Sstevel@tonic-gate 		case ASG:
673*7c478bd9Sstevel@tonic-gate 			(void)assign(np->n_left, np->n_right);
674*7c478bd9Sstevel@tonic-gate 			continue;
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 		case PRINT:
677*7c478bd9Sstevel@tonic-gate 			s_print(np);
678*7c478bd9Sstevel@tonic-gate 			continue;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 		case PRINTF:
681*7c478bd9Sstevel@tonic-gate 			s_prf(np);
682*7c478bd9Sstevel@tonic-gate 			continue;
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		case EXIT:
685*7c478bd9Sstevel@tonic-gate 			if (np->n_left != NNULL)
686*7c478bd9Sstevel@tonic-gate 				act = (int)exprint(np->n_left); else
687*7c478bd9Sstevel@tonic-gate 				act = 0;
688*7c478bd9Sstevel@tonic-gate 			doend(act);
689*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 		case RETURN:
692*7c478bd9Sstevel@tonic-gate 			if (slevel == 0)
693*7c478bd9Sstevel@tonic-gate 				awkerr(gettext("return outside of a function"));
694*7c478bd9Sstevel@tonic-gate 			np = np->n_left!=NNULL
695*7c478bd9Sstevel@tonic-gate 			    ? exprreduce(np->n_left)
696*7c478bd9Sstevel@tonic-gate 			    : const0;
697*7c478bd9Sstevel@tonic-gate 			retval = emptynode(CONSTANT, 0);
698*7c478bd9Sstevel@tonic-gate 			retval->n_flags = FINT;
699*7c478bd9Sstevel@tonic-gate 			(void)nassign(retval, np);
700*7c478bd9Sstevel@tonic-gate 			return (RETURN);
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 		case NEXT:
703*7c478bd9Sstevel@tonic-gate 			loopexit = NEXT;
704*7c478bd9Sstevel@tonic-gate 		case BREAK:
705*7c478bd9Sstevel@tonic-gate 		case CONTINUE:
706*7c478bd9Sstevel@tonic-gate 			return (np->n_type);
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 		case DELETE:
709*7c478bd9Sstevel@tonic-gate 			if ((l = np->n_left)->n_type == PARM) {
710*7c478bd9Sstevel@tonic-gate 				l = l->n_next;
711*7c478bd9Sstevel@tonic-gate 				if (!(l->n_flags & FLARRAY))
712*7c478bd9Sstevel@tonic-gate 					l = l->n_alink;
713*7c478bd9Sstevel@tonic-gate 			}
714*7c478bd9Sstevel@tonic-gate 			switch (l->n_type) {
715*7c478bd9Sstevel@tonic-gate 			case ARRAY:
716*7c478bd9Sstevel@tonic-gate 				delarray(l);
717*7c478bd9Sstevel@tonic-gate 				break;
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 			case INDEX:
720*7c478bd9Sstevel@tonic-gate 				if ((np = l->n_left)->n_type == PARM) {
721*7c478bd9Sstevel@tonic-gate 	 				np = np->n_next;
722*7c478bd9Sstevel@tonic-gate 					if (!(np->n_flags & FLARRAY))
723*7c478bd9Sstevel@tonic-gate 						np = np->n_alink;
724*7c478bd9Sstevel@tonic-gate 				}
725*7c478bd9Sstevel@tonic-gate 				/*
726*7c478bd9Sstevel@tonic-gate 				 * get pointer to the node for this array
727*7c478bd9Sstevel@tonic-gate 				 * element using the hash key.
728*7c478bd9Sstevel@tonic-gate 				 */
729*7c478bd9Sstevel@tonic-gate 				l = exprreduce(l);
730*7c478bd9Sstevel@tonic-gate 				/*
731*7c478bd9Sstevel@tonic-gate 				 * now search linearly from the beginning of
732*7c478bd9Sstevel@tonic-gate 				 * the list to find the element before the
733*7c478bd9Sstevel@tonic-gate 				 * one being deleted. This must be done
734*7c478bd9Sstevel@tonic-gate 				 * because arrays are singley-linked.
735*7c478bd9Sstevel@tonic-gate 				 */
736*7c478bd9Sstevel@tonic-gate 				while (np != NNULL) {
737*7c478bd9Sstevel@tonic-gate 					if (np->n_alink == l) {
738*7c478bd9Sstevel@tonic-gate 						np->n_alink = l->n_alink;
739*7c478bd9Sstevel@tonic-gate 						break;
740*7c478bd9Sstevel@tonic-gate 					}
741*7c478bd9Sstevel@tonic-gate 					np = np->n_alink;
742*7c478bd9Sstevel@tonic-gate 				}
743*7c478bd9Sstevel@tonic-gate 				delsymtab(l, 1);
744*7c478bd9Sstevel@tonic-gate 				break;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 			case VAR:
747*7c478bd9Sstevel@tonic-gate 				if (isstring(l->n_flags) && l->n_string==_null)
748*7c478bd9Sstevel@tonic-gate 					break;
749*7c478bd9Sstevel@tonic-gate 			default:
750*7c478bd9Sstevel@tonic-gate 				awkerr(gettext(
751*7c478bd9Sstevel@tonic-gate 				    "may delete only array element or array"));
752*7c478bd9Sstevel@tonic-gate 				break;
753*7c478bd9Sstevel@tonic-gate 			}
754*7c478bd9Sstevel@tonic-gate 			continue;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 		case WHILE:
757*7c478bd9Sstevel@tonic-gate 		case DO:
758*7c478bd9Sstevel@tonic-gate 			if ((act = s_while(np)) != 0)
759*7c478bd9Sstevel@tonic-gate 				break;
760*7c478bd9Sstevel@tonic-gate 			continue;
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 		case FOR:
763*7c478bd9Sstevel@tonic-gate 			if ((act = s_for(np)) != 0)
764*7c478bd9Sstevel@tonic-gate 				break;
765*7c478bd9Sstevel@tonic-gate 			continue;
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 		case FORIN:
768*7c478bd9Sstevel@tonic-gate 			if ((act = s_forin(np)) != 0)
769*7c478bd9Sstevel@tonic-gate 				break;
770*7c478bd9Sstevel@tonic-gate 			continue;
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 		case IF:
773*7c478bd9Sstevel@tonic-gate 			if ((act = s_if(np)) != 0)
774*7c478bd9Sstevel@tonic-gate 				break;
775*7c478bd9Sstevel@tonic-gate 			continue;
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 		default:
778*7c478bd9Sstevel@tonic-gate 			(void)exprreduce(np);
779*7c478bd9Sstevel@tonic-gate 			if (loopexit != 0) {
780*7c478bd9Sstevel@tonic-gate 				act = loopexit;
781*7c478bd9Sstevel@tonic-gate 				break;
782*7c478bd9Sstevel@tonic-gate 			}
783*7c478bd9Sstevel@tonic-gate 			continue;
784*7c478bd9Sstevel@tonic-gate 		}
785*7c478bd9Sstevel@tonic-gate 		return (act);
786*7c478bd9Sstevel@tonic-gate 	}
787*7c478bd9Sstevel@tonic-gate 	return (0);
788*7c478bd9Sstevel@tonic-gate }
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate /*
791*7c478bd9Sstevel@tonic-gate  * Delete an entire array
792*7c478bd9Sstevel@tonic-gate  */
793*7c478bd9Sstevel@tonic-gate void
794*7c478bd9Sstevel@tonic-gate delarray(NODE *np)
795*7c478bd9Sstevel@tonic-gate {
796*7c478bd9Sstevel@tonic-gate 	register NODE *nnp;
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	nnp = np->n_alink;
799*7c478bd9Sstevel@tonic-gate 	np->n_alink = NNULL;
800*7c478bd9Sstevel@tonic-gate 	while (nnp != NNULL) {
801*7c478bd9Sstevel@tonic-gate 		np = nnp->n_alink;
802*7c478bd9Sstevel@tonic-gate 		delsymtab(nnp, 1);
803*7c478bd9Sstevel@tonic-gate 		nnp = np;
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate }
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate /*
808*7c478bd9Sstevel@tonic-gate  * Return the INT value of an expression.
809*7c478bd9Sstevel@tonic-gate  */
810*7c478bd9Sstevel@tonic-gate INT
811*7c478bd9Sstevel@tonic-gate exprint(NODE *np)
812*7c478bd9Sstevel@tonic-gate {
813*7c478bd9Sstevel@tonic-gate 	if (isleaf(np->n_flags)) {
814*7c478bd9Sstevel@tonic-gate 		if (np->n_type == PARM)
815*7c478bd9Sstevel@tonic-gate 			np = np->n_next;
816*7c478bd9Sstevel@tonic-gate 		goto leaf;
817*7c478bd9Sstevel@tonic-gate 	}
818*7c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
819*7c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
820*7c478bd9Sstevel@tonic-gate 	case CONSTANT:
821*7c478bd9Sstevel@tonic-gate 	case VAR:
822*7c478bd9Sstevel@tonic-gate 	leaf:
823*7c478bd9Sstevel@tonic-gate 		if (np->n_flags & FINT)
824*7c478bd9Sstevel@tonic-gate 			return (np->n_int);
825*7c478bd9Sstevel@tonic-gate 		if (np->n_flags & FREAL)
826*7c478bd9Sstevel@tonic-gate 			return ((INT)np->n_real);
827*7c478bd9Sstevel@tonic-gate 		return ((INT)watoll(np->n_string));
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	default:
830*7c478bd9Sstevel@tonic-gate 		awkerr(interr, "exprint");
831*7c478bd9Sstevel@tonic-gate 	}
832*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
833*7c478bd9Sstevel@tonic-gate }
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate /*
836*7c478bd9Sstevel@tonic-gate  * Return a real number from an expression tree.
837*7c478bd9Sstevel@tonic-gate  */
838*7c478bd9Sstevel@tonic-gate REAL
839*7c478bd9Sstevel@tonic-gate exprreal(NODE *np)
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	if (loopexit)
842*7c478bd9Sstevel@tonic-gate 		return (loopexit);
843*7c478bd9Sstevel@tonic-gate 	if (isleaf(np->n_flags)) {
844*7c478bd9Sstevel@tonic-gate 		if (np->n_type == PARM)
845*7c478bd9Sstevel@tonic-gate 			np = np->n_next;
846*7c478bd9Sstevel@tonic-gate 		goto leaf;
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
849*7c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
850*7c478bd9Sstevel@tonic-gate 	case CONSTANT:
851*7c478bd9Sstevel@tonic-gate 	case VAR:
852*7c478bd9Sstevel@tonic-gate 	leaf:
853*7c478bd9Sstevel@tonic-gate 		if (np->n_flags & FREAL)
854*7c478bd9Sstevel@tonic-gate 			return (np->n_real);
855*7c478bd9Sstevel@tonic-gate 		if (np->n_flags & FINT)
856*7c478bd9Sstevel@tonic-gate 			return ((REAL)np->n_int);
857*7c478bd9Sstevel@tonic-gate 		return ((REAL)wcstod((wchar_t *)np->n_string, (wchar_t **)0));
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	default:
860*7c478bd9Sstevel@tonic-gate 		awkerr(interr, "exprreal");
861*7c478bd9Sstevel@tonic-gate 	}
862*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
863*7c478bd9Sstevel@tonic-gate }
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate /*
866*7c478bd9Sstevel@tonic-gate  * Return a string from an expression tree.
867*7c478bd9Sstevel@tonic-gate  */
868*7c478bd9Sstevel@tonic-gate STRING
869*7c478bd9Sstevel@tonic-gate exprstring(NODE *np)
870*7c478bd9Sstevel@tonic-gate {
871*7c478bd9Sstevel@tonic-gate 	if (isleaf(np->n_flags)) {
872*7c478bd9Sstevel@tonic-gate 		if (np->n_type == PARM)
873*7c478bd9Sstevel@tonic-gate 			np = np->n_next;
874*7c478bd9Sstevel@tonic-gate 		goto leaf;
875*7c478bd9Sstevel@tonic-gate 	}
876*7c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
877*7c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
878*7c478bd9Sstevel@tonic-gate 	case CONSTANT:
879*7c478bd9Sstevel@tonic-gate 	case VAR:
880*7c478bd9Sstevel@tonic-gate 	leaf:
881*7c478bd9Sstevel@tonic-gate 		if (isstring(np->n_flags))
882*7c478bd9Sstevel@tonic-gate 			return (np->n_string);
883*7c478bd9Sstevel@tonic-gate 		if (np->n_flags & FINT)
884*7c478bd9Sstevel@tonic-gate 			return (STRING)lltoa((long long)np->n_int);
885*7c478bd9Sstevel@tonic-gate 		{
886*7c478bd9Sstevel@tonic-gate 			char *tmp;
887*7c478bd9Sstevel@tonic-gate 			(void) wsprintf(numbuf,
888*7c478bd9Sstevel@tonic-gate 		(const char *) (tmp = wcstombsdup(exprstring(varCONVFMT))),
889*7c478bd9Sstevel@tonic-gate 				(double) np->n_real);
890*7c478bd9Sstevel@tonic-gate 			if (tmp != NULL)
891*7c478bd9Sstevel@tonic-gate 				free (tmp);
892*7c478bd9Sstevel@tonic-gate 		}
893*7c478bd9Sstevel@tonic-gate 		return ((STRING)numbuf);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	default:
896*7c478bd9Sstevel@tonic-gate 		awkerr(interr, "exprstring");
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
899*7c478bd9Sstevel@tonic-gate }
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate /*
902*7c478bd9Sstevel@tonic-gate  * Convert number to string.
903*7c478bd9Sstevel@tonic-gate  */
904*7c478bd9Sstevel@tonic-gate static wchar_t *
905*7c478bd9Sstevel@tonic-gate lltoa(long long l)
906*7c478bd9Sstevel@tonic-gate {
907*7c478bd9Sstevel@tonic-gate 	register wchar_t *p = &numbuf[NUMSIZE];
908*7c478bd9Sstevel@tonic-gate 	register int s;
909*7c478bd9Sstevel@tonic-gate 	register int neg;
910*7c478bd9Sstevel@tonic-gate 	static wchar_t zero[] = M_MB_L("0");
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	if (l == 0)
913*7c478bd9Sstevel@tonic-gate 		return (zero);
914*7c478bd9Sstevel@tonic-gate 	*--p = '\0';
915*7c478bd9Sstevel@tonic-gate 	if (l < 0)
916*7c478bd9Sstevel@tonic-gate 		neg = 1, l = -l; else
917*7c478bd9Sstevel@tonic-gate 		neg = 0;
918*7c478bd9Sstevel@tonic-gate 	if ((s = (short)l) == l) {
919*7c478bd9Sstevel@tonic-gate 		while (s != 0) {
920*7c478bd9Sstevel@tonic-gate 			*--p = s%10 + '0';
921*7c478bd9Sstevel@tonic-gate 			s /= 10;
922*7c478bd9Sstevel@tonic-gate 		}
923*7c478bd9Sstevel@tonic-gate 	} else {
924*7c478bd9Sstevel@tonic-gate 		while (l != 0) {
925*7c478bd9Sstevel@tonic-gate 			*--p = l%10 + '0';
926*7c478bd9Sstevel@tonic-gate 			l /= 10;
927*7c478bd9Sstevel@tonic-gate 		}
928*7c478bd9Sstevel@tonic-gate 	}
929*7c478bd9Sstevel@tonic-gate 	if (neg)
930*7c478bd9Sstevel@tonic-gate 		*--p = '-';
931*7c478bd9Sstevel@tonic-gate 	return (wcscpy(numbuf, p));
932*7c478bd9Sstevel@tonic-gate }
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate /*
935*7c478bd9Sstevel@tonic-gate  * Return pointer to node with concatenation of operands of CONCAT node.
936*7c478bd9Sstevel@tonic-gate  * In the interest of speed, a left recursive tree of CONCAT nodes
937*7c478bd9Sstevel@tonic-gate  * is handled with a single malloc.  The accumulated lengths of the
938*7c478bd9Sstevel@tonic-gate  * right operands are passed down recursive invocations of this
939*7c478bd9Sstevel@tonic-gate  * routine, which allocates a large enough string when the left
940*7c478bd9Sstevel@tonic-gate  * operand is not a CONCAT node.
941*7c478bd9Sstevel@tonic-gate  */
942*7c478bd9Sstevel@tonic-gate static NODE *
943*7c478bd9Sstevel@tonic-gate exprconcat(NODE *np, int len)
944*7c478bd9Sstevel@tonic-gate {
945*7c478bd9Sstevel@tonic-gate 	/* we KNOW (np->n_type==CONCAT) */
946*7c478bd9Sstevel@tonic-gate 	register NODE *lnp = np->n_left;
947*7c478bd9Sstevel@tonic-gate 	register NODE *rnp = np->n_right;
948*7c478bd9Sstevel@tonic-gate 	register STRING	rsp;
949*7c478bd9Sstevel@tonic-gate 	int rlen;
950*7c478bd9Sstevel@tonic-gate 	size_t llen;
951*7c478bd9Sstevel@tonic-gate 	wchar_t *cp;
952*7c478bd9Sstevel@tonic-gate 	wchar_t rnumbuf[NUMSIZE];
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	if (isleaf(rnp->n_flags) && rnp->n_type==PARM)
955*7c478bd9Sstevel@tonic-gate 		rnp = rnp->n_next;
956*7c478bd9Sstevel@tonic-gate 	if (isstring(rnp->n_flags)) {
957*7c478bd9Sstevel@tonic-gate 		rsp = rnp->n_string;
958*7c478bd9Sstevel@tonic-gate 		rlen = rnp->n_strlen;
959*7c478bd9Sstevel@tonic-gate 	} else
960*7c478bd9Sstevel@tonic-gate 		rlen = wcslen((wchar_t*)(rsp = exprstring(rnp)));
961*7c478bd9Sstevel@tonic-gate 	if (rsp == numbuf) {	/* static, so save a copy */
962*7c478bd9Sstevel@tonic-gate 		(void) memcpy(rnumbuf, (wchar_t*)rsp,
963*7c478bd9Sstevel@tonic-gate 			(rlen+1) * sizeof(wchar_t));
964*7c478bd9Sstevel@tonic-gate 		rsp=rnumbuf;
965*7c478bd9Sstevel@tonic-gate 	}
966*7c478bd9Sstevel@tonic-gate 	len += rlen;
967*7c478bd9Sstevel@tonic-gate 	if (lnp->n_type == CONCAT) {
968*7c478bd9Sstevel@tonic-gate 		lnp = exprconcat(lnp, len);
969*7c478bd9Sstevel@tonic-gate 		cp = lnp->n_string;
970*7c478bd9Sstevel@tonic-gate 		llen = lnp->n_strlen;
971*7c478bd9Sstevel@tonic-gate 	} else {
972*7c478bd9Sstevel@tonic-gate 		register STRING	lsp;
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 		if (isleaf(lnp->n_flags) && lnp->n_type==PARM)
975*7c478bd9Sstevel@tonic-gate 			lnp = lnp->n_next;
976*7c478bd9Sstevel@tonic-gate 		if (isstring(lnp->n_flags)) {
977*7c478bd9Sstevel@tonic-gate 			lsp = lnp->n_string;
978*7c478bd9Sstevel@tonic-gate 			llen = lnp->n_strlen;
979*7c478bd9Sstevel@tonic-gate 		} else
980*7c478bd9Sstevel@tonic-gate 			llen = wcslen((wchar_t*)(lsp = exprstring(lnp)));
981*7c478bd9Sstevel@tonic-gate 		cp = emalloc((llen+len+1) * sizeof(wchar_t));
982*7c478bd9Sstevel@tonic-gate 		(void) memcpy(cp, (wchar_t*)lsp, llen * sizeof(wchar_t));
983*7c478bd9Sstevel@tonic-gate 		lnp = stringnode(cp, FNOALLOC, llen);
984*7c478bd9Sstevel@tonic-gate 	}
985*7c478bd9Sstevel@tonic-gate 	(void) memcpy(cp+llen, (wchar_t*)rsp, (rlen+1) * sizeof(wchar_t));
986*7c478bd9Sstevel@tonic-gate 	lnp->n_strlen += rlen;
987*7c478bd9Sstevel@tonic-gate 	return (lnp);
988*7c478bd9Sstevel@tonic-gate }
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate /*
991*7c478bd9Sstevel@tonic-gate  * Reduce an expression to a terminal node.
992*7c478bd9Sstevel@tonic-gate  */
993*7c478bd9Sstevel@tonic-gate NODE *
994*7c478bd9Sstevel@tonic-gate exprreduce(NODE *np)
995*7c478bd9Sstevel@tonic-gate {
996*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
997*7c478bd9Sstevel@tonic-gate 	NODE *tnp;
998*7c478bd9Sstevel@tonic-gate 	register int temp;
999*7c478bd9Sstevel@tonic-gate 	register int t;
1000*7c478bd9Sstevel@tonic-gate 	register int  tag;
1001*7c478bd9Sstevel@tonic-gate 	register wchar_t *fname;
1002*7c478bd9Sstevel@tonic-gate 	register wchar_t *aname;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	/*
1005*7c478bd9Sstevel@tonic-gate 	 * a var or constant is a leaf-node (no further reduction required)
1006*7c478bd9Sstevel@tonic-gate 	 * so return immediately.
1007*7c478bd9Sstevel@tonic-gate 	 */
1008*7c478bd9Sstevel@tonic-gate 	if ((t = np->n_type)==VAR || t==CONSTANT)
1009*7c478bd9Sstevel@tonic-gate 		return (np);
1010*7c478bd9Sstevel@tonic-gate 	/*
1011*7c478bd9Sstevel@tonic-gate 	 * If it's a parameter then it is probably a leaf node but it
1012*7c478bd9Sstevel@tonic-gate 	 * might be an array so we check.. If it is an array, then signal
1013*7c478bd9Sstevel@tonic-gate 	 * an error as an array by itself cannot be used in this context.
1014*7c478bd9Sstevel@tonic-gate 	 */
1015*7c478bd9Sstevel@tonic-gate 	if (t == PARM)
1016*7c478bd9Sstevel@tonic-gate 		if ((np = np->n_next)->n_type == ARRAY)
1017*7c478bd9Sstevel@tonic-gate 			awkerr(badarray, np->n_name);
1018*7c478bd9Sstevel@tonic-gate 		else
1019*7c478bd9Sstevel@tonic-gate 			return (np);
1020*7c478bd9Sstevel@tonic-gate 	/*
1021*7c478bd9Sstevel@tonic-gate 	 * All the rest are non-leaf nodes.
1022*7c478bd9Sstevel@tonic-gate 	 */
1023*7c478bd9Sstevel@tonic-gate 	curnode = np;
1024*7c478bd9Sstevel@tonic-gate 	switch (t) {
1025*7c478bd9Sstevel@tonic-gate 	case CALLUFUNC:
1026*7c478bd9Sstevel@tonic-gate 		return (userfunc(np));
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	case FIELD:
1029*7c478bd9Sstevel@tonic-gate 		return (rfield(exprint(np->n_left)));
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	case IN:
1032*7c478bd9Sstevel@tonic-gate 	case INDEX:
1033*7c478bd9Sstevel@tonic-gate 		tag = 0;
1034*7c478bd9Sstevel@tonic-gate 		temp = np->n_type;
1035*7c478bd9Sstevel@tonic-gate 		tnp = np->n_left;
1036*7c478bd9Sstevel@tonic-gate 		np = np->n_right;
1037*7c478bd9Sstevel@tonic-gate 		/* initially formal var name and array key name are the same */
1038*7c478bd9Sstevel@tonic-gate 		fname = aname = tnp->n_name;
1039*7c478bd9Sstevel@tonic-gate 		if (tnp->n_type == PARM) {
1040*7c478bd9Sstevel@tonic-gate 			tnp = tnp->n_next;
1041*7c478bd9Sstevel@tonic-gate 			tag = tnp->n_scope;
1042*7c478bd9Sstevel@tonic-gate 			if (!(tnp->n_flags & FLARRAY)) {
1043*7c478bd9Sstevel@tonic-gate 				tnp = tnp->n_alink;
1044*7c478bd9Sstevel@tonic-gate 			}
1045*7c478bd9Sstevel@tonic-gate 			aname = tnp->n_name;
1046*7c478bd9Sstevel@tonic-gate 		}
1047*7c478bd9Sstevel@tonic-gate 		if (tnp->n_type != ARRAY) {
1048*7c478bd9Sstevel@tonic-gate 			if (!isstring(tnp->n_flags) || tnp->n_string!=_null)
1049*7c478bd9Sstevel@tonic-gate 				awkerr(notarray, fname);
1050*7c478bd9Sstevel@tonic-gate 			else {
1051*7c478bd9Sstevel@tonic-gate 				/* promotion to array */
1052*7c478bd9Sstevel@tonic-gate 				promote(tnp);
1053*7c478bd9Sstevel@tonic-gate 				if (tnp->n_alink != NNULL) {
1054*7c478bd9Sstevel@tonic-gate 					tag = tnp->n_scope;
1055*7c478bd9Sstevel@tonic-gate 					if (!(tnp->n_flags & FLARRAY))
1056*7c478bd9Sstevel@tonic-gate 						tnp = tnp->n_alink;
1057*7c478bd9Sstevel@tonic-gate 					aname = tnp->n_name;
1058*7c478bd9Sstevel@tonic-gate 				} else {
1059*7c478bd9Sstevel@tonic-gate 					tag = 0;
1060*7c478bd9Sstevel@tonic-gate 					if (tnp->n_flags & FLARRAY)
1061*7c478bd9Sstevel@tonic-gate 						tag = tnp->n_scope;
1062*7c478bd9Sstevel@tonic-gate 				}
1063*7c478bd9Sstevel@tonic-gate 			}
1064*7c478bd9Sstevel@tonic-gate 		}
1065*7c478bd9Sstevel@tonic-gate 		if (tnp == varSYMTAB) {
1066*7c478bd9Sstevel@tonic-gate 			if (np==NNULL || np->n_type==COMMA)
1067*7c478bd9Sstevel@tonic-gate 				awkerr(gettext(
1068*7c478bd9Sstevel@tonic-gate 				    "SYMTAB must have exactly one index"));
1069*7c478bd9Sstevel@tonic-gate 			np = vlook(exprstring(np));
1070*7c478bd9Sstevel@tonic-gate 			return (np);
1071*7c478bd9Sstevel@tonic-gate 		}
1072*7c478bd9Sstevel@tonic-gate 		cp = makeindex(np, aname, tag);
1073*7c478bd9Sstevel@tonic-gate 		if (temp == INDEX) {
1074*7c478bd9Sstevel@tonic-gate 			np = vlook(cp);
1075*7c478bd9Sstevel@tonic-gate 			if (!(np->n_flags & FINARRAY)) {
1076*7c478bd9Sstevel@tonic-gate 				np->n_alink = tnp->n_alink;
1077*7c478bd9Sstevel@tonic-gate 				tnp->n_alink = np;
1078*7c478bd9Sstevel@tonic-gate 				np->n_flags |= FINARRAY;
1079*7c478bd9Sstevel@tonic-gate 			}
1080*7c478bd9Sstevel@tonic-gate 		} else
1081*7c478bd9Sstevel@tonic-gate 			np = vlookup(cp, 1)==NNULL ? const0 : const1;
1082*7c478bd9Sstevel@tonic-gate 		if (cp != indexbuf)
1083*7c478bd9Sstevel@tonic-gate 			free(cp);
1084*7c478bd9Sstevel@tonic-gate 		return (np);
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	case CONCAT:
1087*7c478bd9Sstevel@tonic-gate 		++concflag;
1088*7c478bd9Sstevel@tonic-gate 		np = exprconcat(np, 0);
1089*7c478bd9Sstevel@tonic-gate 		--concflag;
1090*7c478bd9Sstevel@tonic-gate 		return (np);
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	case NOT:
1093*7c478bd9Sstevel@tonic-gate 		return (intnode(exprtest(np->n_left)==0 ? (INT)1 : (INT)0));
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	case AND:
1096*7c478bd9Sstevel@tonic-gate 		return ((exprtest(np->n_left) != 0
1097*7c478bd9Sstevel@tonic-gate 		    && exprtest(np->n_right) != 0) ? const1 : const0);
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	case OR:
1100*7c478bd9Sstevel@tonic-gate 		return ((exprtest(np->n_left) != 0
1101*7c478bd9Sstevel@tonic-gate 		    || exprtest(np->n_right) != 0) ? const1 : const0);
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	case EXP:
1104*7c478bd9Sstevel@tonic-gate 		{
1105*7c478bd9Sstevel@tonic-gate                         double f1, f2;
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 			/* evaluate expressions in proper order before
1108*7c478bd9Sstevel@tonic-gate 			 * calling pow().
1109*7c478bd9Sstevel@tonic-gate 			 * Can't guarantee that compiler will do this
1110*7c478bd9Sstevel@tonic-gate 			 * correctly for us if we put them inline.
1111*7c478bd9Sstevel@tonic-gate 			 */
1112*7c478bd9Sstevel@tonic-gate                         f1 = (double)exprreal(np->n_left);
1113*7c478bd9Sstevel@tonic-gate                         f2 = (double)exprreal(np->n_right);
1114*7c478bd9Sstevel@tonic-gate                         return (realnode((REAL)pow(f1, f2)));
1115*7c478bd9Sstevel@tonic-gate                 }
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate 	case QUEST:
1118*7c478bd9Sstevel@tonic-gate 		if (np->n_right->n_type != COLON)
1119*7c478bd9Sstevel@tonic-gate 			awkerr(interr, "?:");
1120*7c478bd9Sstevel@tonic-gate 		if (exprtest(np->n_left))
1121*7c478bd9Sstevel@tonic-gate 			np = np->n_right->n_left; else
1122*7c478bd9Sstevel@tonic-gate 			np = np->n_right->n_right;
1123*7c478bd9Sstevel@tonic-gate 		return (exprreduce(np));
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 	case EQ:
1126*7c478bd9Sstevel@tonic-gate 	case NE:
1127*7c478bd9Sstevel@tonic-gate 	case GE:
1128*7c478bd9Sstevel@tonic-gate 	case LE:
1129*7c478bd9Sstevel@tonic-gate 	case GT:
1130*7c478bd9Sstevel@tonic-gate 	case LT:
1131*7c478bd9Sstevel@tonic-gate 		return (comparison(np));
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate 	case ADD:
1134*7c478bd9Sstevel@tonic-gate 	case SUB:
1135*7c478bd9Sstevel@tonic-gate 	case MUL:
1136*7c478bd9Sstevel@tonic-gate 	case DIV:
1137*7c478bd9Sstevel@tonic-gate 	case REM:
1138*7c478bd9Sstevel@tonic-gate 		return (arithmetic(np));
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	case DEC:
1141*7c478bd9Sstevel@tonic-gate 		inc_oper->n_type = SUB;
1142*7c478bd9Sstevel@tonic-gate 		goto do_inc_op;
1143*7c478bd9Sstevel@tonic-gate 	case INC:
1144*7c478bd9Sstevel@tonic-gate 		inc_oper->n_type = ADD;
1145*7c478bd9Sstevel@tonic-gate do_inc_op:
1146*7c478bd9Sstevel@tonic-gate 		if ((np = np->n_left)->n_type == INDEX)
1147*7c478bd9Sstevel@tonic-gate 			np = exprreduce(np);
1148*7c478bd9Sstevel@tonic-gate 		if (np->n_flags & FREAL)
1149*7c478bd9Sstevel@tonic-gate 			tnp = realnode(np->n_real);
1150*7c478bd9Sstevel@tonic-gate 		else
1151*7c478bd9Sstevel@tonic-gate 			tnp = intnode(exprint(np));
1152*7c478bd9Sstevel@tonic-gate 		inc_oper->n_left = np;
1153*7c478bd9Sstevel@tonic-gate 		(void)assign(np, inc_oper);
1154*7c478bd9Sstevel@tonic-gate 		return (tnp);
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 	case PRE_DEC:
1157*7c478bd9Sstevel@tonic-gate 		inc_oper->n_type = SUB;
1158*7c478bd9Sstevel@tonic-gate 		goto do_pinc_op;
1159*7c478bd9Sstevel@tonic-gate 	case PRE_INC:
1160*7c478bd9Sstevel@tonic-gate 		inc_oper->n_type = ADD;
1161*7c478bd9Sstevel@tonic-gate do_pinc_op:
1162*7c478bd9Sstevel@tonic-gate 		if ((np = np->n_left)->n_type == INDEX)
1163*7c478bd9Sstevel@tonic-gate 			np = exprreduce(np);
1164*7c478bd9Sstevel@tonic-gate 		inc_oper->n_left = np;
1165*7c478bd9Sstevel@tonic-gate 		return (assign(np, inc_oper));
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	case AADD:
1168*7c478bd9Sstevel@tonic-gate 		asn_oper->n_type = ADD;
1169*7c478bd9Sstevel@tonic-gate 		goto do_asn_op;
1170*7c478bd9Sstevel@tonic-gate 	case ASUB:
1171*7c478bd9Sstevel@tonic-gate 		asn_oper->n_type = SUB;
1172*7c478bd9Sstevel@tonic-gate 		goto do_asn_op;
1173*7c478bd9Sstevel@tonic-gate 	case AMUL:
1174*7c478bd9Sstevel@tonic-gate 		asn_oper->n_type = MUL;
1175*7c478bd9Sstevel@tonic-gate 		goto do_asn_op;
1176*7c478bd9Sstevel@tonic-gate 	case ADIV:
1177*7c478bd9Sstevel@tonic-gate 		asn_oper->n_type = DIV;
1178*7c478bd9Sstevel@tonic-gate 		goto do_asn_op;
1179*7c478bd9Sstevel@tonic-gate 	case AREM:
1180*7c478bd9Sstevel@tonic-gate 		asn_oper->n_type = REM;
1181*7c478bd9Sstevel@tonic-gate 		goto do_asn_op;
1182*7c478bd9Sstevel@tonic-gate 	case AEXP:
1183*7c478bd9Sstevel@tonic-gate 		asn_oper->n_type = EXP;
1184*7c478bd9Sstevel@tonic-gate do_asn_op:
1185*7c478bd9Sstevel@tonic-gate 		asn_oper->n_right = np->n_right;
1186*7c478bd9Sstevel@tonic-gate 		if ((np = np->n_left)->n_type == INDEX)
1187*7c478bd9Sstevel@tonic-gate 			np = exprreduce(np);
1188*7c478bd9Sstevel@tonic-gate 		asn_oper->n_left = np;
1189*7c478bd9Sstevel@tonic-gate 		return (assign(np, asn_oper));
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate 	case GETLINE:
1193*7c478bd9Sstevel@tonic-gate 		return (f_getline(np));
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	case CALLFUNC:
1196*7c478bd9Sstevel@tonic-gate 		return ((*np->n_left->n_function)(np->n_right));
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	case RE:
1199*7c478bd9Sstevel@tonic-gate 		if (regmatch(np->n_regexp, linebuf) == REG_OK)
1200*7c478bd9Sstevel@tonic-gate 			return (const1);
1201*7c478bd9Sstevel@tonic-gate 		return (const0);
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	case TILDE:
1204*7c478bd9Sstevel@tonic-gate 		cp = exprstring(np->n_left);
1205*7c478bd9Sstevel@tonic-gate 		if (regmatch(getregexp(np->n_right), cp) == REG_OK)
1206*7c478bd9Sstevel@tonic-gate 			return (const1);
1207*7c478bd9Sstevel@tonic-gate 		return (const0);
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	case NRE:
1210*7c478bd9Sstevel@tonic-gate 		cp = exprstring(np->n_left);
1211*7c478bd9Sstevel@tonic-gate 		if (regmatch(getregexp(np->n_right), cp) != REG_OK)
1212*7c478bd9Sstevel@tonic-gate 			return (const1);
1213*7c478bd9Sstevel@tonic-gate 		return (const0);
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	case ASG:
1216*7c478bd9Sstevel@tonic-gate 		return (assign(np->n_left, np->n_right));
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	case ARRAY:
1219*7c478bd9Sstevel@tonic-gate 		awkerr(badarray, np->n_name);
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	case UFUNC:
1222*7c478bd9Sstevel@tonic-gate 		awkerr(varnotfunc, np->n_name);
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	default:
1225*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("panic: exprreduce(%d)"), t);
1226*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1227*7c478bd9Sstevel@tonic-gate 	}
1228*7c478bd9Sstevel@tonic-gate }
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate /*
1231*7c478bd9Sstevel@tonic-gate  * Do arithmetic operators.
1232*7c478bd9Sstevel@tonic-gate  */
1233*7c478bd9Sstevel@tonic-gate static NODE *
1234*7c478bd9Sstevel@tonic-gate arithmetic(NODE *np)
1235*7c478bd9Sstevel@tonic-gate {
1236*7c478bd9Sstevel@tonic-gate 	register NODE *left, *right;
1237*7c478bd9Sstevel@tonic-gate 	int type;
1238*7c478bd9Sstevel@tonic-gate 	register INT i1, i2;
1239*7c478bd9Sstevel@tonic-gate 	register INT iresult;
1240*7c478bd9Sstevel@tonic-gate 	register REAL r1, r2;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	left = exprreduce(np->n_left);
1243*7c478bd9Sstevel@tonic-gate 	if (isreal(left->n_flags)
1244*7c478bd9Sstevel@tonic-gate 	|| (isstring(left->n_flags) && (typeof(left)&FVREAL))) {
1245*7c478bd9Sstevel@tonic-gate 		type = FREAL;
1246*7c478bd9Sstevel@tonic-gate 		r1 = exprreal(left);
1247*7c478bd9Sstevel@tonic-gate 		r2 = exprreal(np->n_right);
1248*7c478bd9Sstevel@tonic-gate 	} else {
1249*7c478bd9Sstevel@tonic-gate 		i1 = exprint(left);
1250*7c478bd9Sstevel@tonic-gate 		right = exprreduce(np->n_right);
1251*7c478bd9Sstevel@tonic-gate 		if (isreal(right->n_flags)
1252*7c478bd9Sstevel@tonic-gate 		 || (isstring(right->n_flags) && (typeof(right)&FVREAL))) {
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate 			type = FREAL;
1255*7c478bd9Sstevel@tonic-gate 			r1 = i1;
1256*7c478bd9Sstevel@tonic-gate 			r2 = exprreal(right);
1257*7c478bd9Sstevel@tonic-gate 		} else {
1258*7c478bd9Sstevel@tonic-gate 			type = FINT;
1259*7c478bd9Sstevel@tonic-gate 			i2 = exprint(right);
1260*7c478bd9Sstevel@tonic-gate 		}
1261*7c478bd9Sstevel@tonic-gate 	}
1262*7c478bd9Sstevel@tonic-gate reswitch:
1263*7c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
1264*7c478bd9Sstevel@tonic-gate 	case ADD:
1265*7c478bd9Sstevel@tonic-gate 		if (type == FINT) {
1266*7c478bd9Sstevel@tonic-gate 			iresult = i1 + i2;
1267*7c478bd9Sstevel@tonic-gate 			addoverflow();
1268*7c478bd9Sstevel@tonic-gate 		} else
1269*7c478bd9Sstevel@tonic-gate 			r1 += r2;
1270*7c478bd9Sstevel@tonic-gate 		break;
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate 	/*
1273*7c478bd9Sstevel@tonic-gate 	 * Strategically placed between ADD and SUB
1274*7c478bd9Sstevel@tonic-gate 	 * so "jo" branches will reach on 80*86
1275*7c478bd9Sstevel@tonic-gate 	 */
1276*7c478bd9Sstevel@tonic-gate 	overflow:
1277*7c478bd9Sstevel@tonic-gate 		r1 = i1;
1278*7c478bd9Sstevel@tonic-gate 		r2 = i2;
1279*7c478bd9Sstevel@tonic-gate 		type = FREAL;
1280*7c478bd9Sstevel@tonic-gate 		goto reswitch;
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	case SUB:
1283*7c478bd9Sstevel@tonic-gate 		if (type == FINT) {
1284*7c478bd9Sstevel@tonic-gate 			iresult = i1 - i2;
1285*7c478bd9Sstevel@tonic-gate 			suboverflow();
1286*7c478bd9Sstevel@tonic-gate 		} else
1287*7c478bd9Sstevel@tonic-gate 			r1 -= r2;
1288*7c478bd9Sstevel@tonic-gate 		break;
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	case MUL:
1291*7c478bd9Sstevel@tonic-gate 		if (type == FINT) {
1292*7c478bd9Sstevel@tonic-gate 			iresult = i1 * i2;
1293*7c478bd9Sstevel@tonic-gate 			muloverflow();
1294*7c478bd9Sstevel@tonic-gate 		} else
1295*7c478bd9Sstevel@tonic-gate 			r1 *= r2;
1296*7c478bd9Sstevel@tonic-gate 		break;
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	case DIV:
1299*7c478bd9Sstevel@tonic-gate 		if (type == FINT) {
1300*7c478bd9Sstevel@tonic-gate 			r1 = i1;
1301*7c478bd9Sstevel@tonic-gate 			r2 = i2;
1302*7c478bd9Sstevel@tonic-gate 			type = FREAL;
1303*7c478bd9Sstevel@tonic-gate 		}
1304*7c478bd9Sstevel@tonic-gate 		if (r2 == 0.0)
1305*7c478bd9Sstevel@tonic-gate 			awkerr(divzero);
1306*7c478bd9Sstevel@tonic-gate 		r1 /= r2;
1307*7c478bd9Sstevel@tonic-gate 		break;
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate 	case REM:
1310*7c478bd9Sstevel@tonic-gate 		if (type == FINT) {
1311*7c478bd9Sstevel@tonic-gate 			if (i2 == 0)
1312*7c478bd9Sstevel@tonic-gate 				awkerr(divzero);
1313*7c478bd9Sstevel@tonic-gate 			iresult = i1 % i2;
1314*7c478bd9Sstevel@tonic-gate 		} else {
1315*7c478bd9Sstevel@tonic-gate 			double fmod(double x, double y);
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 			errno = 0;
1318*7c478bd9Sstevel@tonic-gate 			r1 = fmod(r1, r2);
1319*7c478bd9Sstevel@tonic-gate 			if (errno == EDOM)
1320*7c478bd9Sstevel@tonic-gate 				awkerr(divzero);
1321*7c478bd9Sstevel@tonic-gate 		}
1322*7c478bd9Sstevel@tonic-gate 		break;
1323*7c478bd9Sstevel@tonic-gate 	}
1324*7c478bd9Sstevel@tonic-gate 	return (type==FINT ? intnode(iresult) : realnode(r1));
1325*7c478bd9Sstevel@tonic-gate }
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate /*
1328*7c478bd9Sstevel@tonic-gate  * Do comparison operators.
1329*7c478bd9Sstevel@tonic-gate  */
1330*7c478bd9Sstevel@tonic-gate static NODE *
1331*7c478bd9Sstevel@tonic-gate comparison(NODE *np)
1332*7c478bd9Sstevel@tonic-gate {
1333*7c478bd9Sstevel@tonic-gate 	register NODE *left, *right;
1334*7c478bd9Sstevel@tonic-gate 	register int cmp;
1335*7c478bd9Sstevel@tonic-gate 	int tl, tr;
1336*7c478bd9Sstevel@tonic-gate 	register REAL r1, r2;
1337*7c478bd9Sstevel@tonic-gate 	register INT i1, i2;
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	left = np->n_left;
1340*7c478bd9Sstevel@tonic-gate 	if (isleaf(left->n_flags)) {
1341*7c478bd9Sstevel@tonic-gate 		if (left->n_type == PARM)
1342*7c478bd9Sstevel@tonic-gate 			left = left->n_next;
1343*7c478bd9Sstevel@tonic-gate 	} else
1344*7c478bd9Sstevel@tonic-gate 		left = exprreduce(left);
1345*7c478bd9Sstevel@tonic-gate 	tl = left->n_flags;
1346*7c478bd9Sstevel@tonic-gate 	right = np->n_right;
1347*7c478bd9Sstevel@tonic-gate 	if (isleaf(right->n_flags)) {
1348*7c478bd9Sstevel@tonic-gate 		if (right->n_type == PARM)
1349*7c478bd9Sstevel@tonic-gate 			right = right->n_next;
1350*7c478bd9Sstevel@tonic-gate 	} else {
1351*7c478bd9Sstevel@tonic-gate 		++concflag;
1352*7c478bd9Sstevel@tonic-gate 		right = exprreduce(right);
1353*7c478bd9Sstevel@tonic-gate 		--concflag;
1354*7c478bd9Sstevel@tonic-gate 	}
1355*7c478bd9Sstevel@tonic-gate 	tr = right->n_flags;
1356*7c478bd9Sstevel@tonic-gate 	/*
1357*7c478bd9Sstevel@tonic-gate 	 * Posix mandates semantics for the comparison operators that
1358*7c478bd9Sstevel@tonic-gate 	 * are incompatible with traditional AWK behaviour. If the following
1359*7c478bd9Sstevel@tonic-gate 	 * define is true then awk will use the traditional behaviour.
1360*7c478bd9Sstevel@tonic-gate 	 * if it's false, then AWK will use the POSIX-mandated behaviour.
1361*7c478bd9Sstevel@tonic-gate 	 */
1362*7c478bd9Sstevel@tonic-gate #define	TRADITIONAL 0
1363*7c478bd9Sstevel@tonic-gate #if TRADITIONAL
1364*7c478bd9Sstevel@tonic-gate 	if (!isnumber(tl) || !isnumber(tr)) {
1365*7c478bd9Sstevel@tonic-gate 		cmp = wcscoll((wchar_t *)exprstring(left),
1366*7c478bd9Sstevel@tonic-gate 		    (wchar_t *)exprstring(right));
1367*7c478bd9Sstevel@tonic-gate 	} else if (isreal(tl) || isreal(tr)) {
1368*7c478bd9Sstevel@tonic-gate 		r1 = exprreal(left);
1369*7c478bd9Sstevel@tonic-gate 		r2 = exprreal(right);
1370*7c478bd9Sstevel@tonic-gate 		if (r1 < r2)
1371*7c478bd9Sstevel@tonic-gate 			cmp = -1;
1372*7c478bd9Sstevel@tonic-gate 		else if (r1 > r2)
1373*7c478bd9Sstevel@tonic-gate 			cmp = 1;
1374*7c478bd9Sstevel@tonic-gate 		else
1375*7c478bd9Sstevel@tonic-gate 			cmp = 0;
1376*7c478bd9Sstevel@tonic-gate 	} else {
1377*7c478bd9Sstevel@tonic-gate 		i1 = exprint(left);
1378*7c478bd9Sstevel@tonic-gate 		i2 = exprint(right);
1379*7c478bd9Sstevel@tonic-gate 		if (i1 < i2)
1380*7c478bd9Sstevel@tonic-gate 			cmp = -1;
1381*7c478bd9Sstevel@tonic-gate 		else if (i1 > i2)
1382*7c478bd9Sstevel@tonic-gate 			cmp = 1;
1383*7c478bd9Sstevel@tonic-gate 		else
1384*7c478bd9Sstevel@tonic-gate 			cmp = 0;
1385*7c478bd9Sstevel@tonic-gate 	}
1386*7c478bd9Sstevel@tonic-gate #else
1387*7c478bd9Sstevel@tonic-gate 	if (!isnumber(tl) && !isnumber(tr)) {
1388*7c478bd9Sstevel@tonic-gate do_strcmp:
1389*7c478bd9Sstevel@tonic-gate 		cmp = wcscoll((wchar_t *)exprstring(left),
1390*7c478bd9Sstevel@tonic-gate 		    (wchar_t *)exprstring(right));
1391*7c478bd9Sstevel@tonic-gate 	} else {
1392*7c478bd9Sstevel@tonic-gate 		if (isstring(tl))
1393*7c478bd9Sstevel@tonic-gate 			tl = typeof(left);
1394*7c478bd9Sstevel@tonic-gate 		if (isstring(tr))
1395*7c478bd9Sstevel@tonic-gate 			tr = typeof(right);
1396*7c478bd9Sstevel@tonic-gate 		if (!isnumber(tl) || !isnumber(tr))
1397*7c478bd9Sstevel@tonic-gate 			goto do_strcmp;
1398*7c478bd9Sstevel@tonic-gate 		if (isreal(tl) || isreal(tr)) {
1399*7c478bd9Sstevel@tonic-gate 			r1 = exprreal(left);
1400*7c478bd9Sstevel@tonic-gate 			r2 = exprreal(right);
1401*7c478bd9Sstevel@tonic-gate 			if (r1 < r2)
1402*7c478bd9Sstevel@tonic-gate 				cmp = -1;
1403*7c478bd9Sstevel@tonic-gate 			else if (r1 > r2)
1404*7c478bd9Sstevel@tonic-gate 				cmp = 1;
1405*7c478bd9Sstevel@tonic-gate 			else
1406*7c478bd9Sstevel@tonic-gate 				cmp = 0;
1407*7c478bd9Sstevel@tonic-gate 		} else {
1408*7c478bd9Sstevel@tonic-gate 			i1 = exprint(left);
1409*7c478bd9Sstevel@tonic-gate 			i2 = exprint(right);
1410*7c478bd9Sstevel@tonic-gate 			if (i1 < i2)
1411*7c478bd9Sstevel@tonic-gate 				cmp = -1;
1412*7c478bd9Sstevel@tonic-gate 			else if (i1 > i2)
1413*7c478bd9Sstevel@tonic-gate 				cmp = 1;
1414*7c478bd9Sstevel@tonic-gate 			else
1415*7c478bd9Sstevel@tonic-gate 				cmp = 0;
1416*7c478bd9Sstevel@tonic-gate 		}
1417*7c478bd9Sstevel@tonic-gate 	}
1418*7c478bd9Sstevel@tonic-gate #endif
1419*7c478bd9Sstevel@tonic-gate 	switch (np->n_type) {
1420*7c478bd9Sstevel@tonic-gate 	case EQ:
1421*7c478bd9Sstevel@tonic-gate 		return (cmp==0 ? const1 : const0);
1422*7c478bd9Sstevel@tonic-gate 
1423*7c478bd9Sstevel@tonic-gate 	case  NE:
1424*7c478bd9Sstevel@tonic-gate 		return (cmp!=0 ? const1 : const0);
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	case GE:
1427*7c478bd9Sstevel@tonic-gate 		return (cmp>=0 ? const1 : const0);
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate 	case LE:
1430*7c478bd9Sstevel@tonic-gate 		return (cmp<=0 ? const1 : const0);
1431*7c478bd9Sstevel@tonic-gate 
1432*7c478bd9Sstevel@tonic-gate 	case GT:
1433*7c478bd9Sstevel@tonic-gate 		return (cmp>0 ? const1 : const0);
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	case LT:
1436*7c478bd9Sstevel@tonic-gate 		return (cmp<0 ? const1 : const0);
1437*7c478bd9Sstevel@tonic-gate 
1438*7c478bd9Sstevel@tonic-gate 	default:
1439*7c478bd9Sstevel@tonic-gate 		awkerr(interr, "comparison");
1440*7c478bd9Sstevel@tonic-gate 	}
1441*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1442*7c478bd9Sstevel@tonic-gate }
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate /*
1445*7c478bd9Sstevel@tonic-gate  * Return the type of a constant that is a string.
1446*7c478bd9Sstevel@tonic-gate  * The node must be a FSTRING type and the return value
1447*7c478bd9Sstevel@tonic-gate  * will possibly have FVINT or FVREAL or'ed in.
1448*7c478bd9Sstevel@tonic-gate  */
1449*7c478bd9Sstevel@tonic-gate static int
1450*7c478bd9Sstevel@tonic-gate typeof(NODE *np)
1451*7c478bd9Sstevel@tonic-gate {
1452*7c478bd9Sstevel@tonic-gate 	wchar_t *cp;
1453*7c478bd9Sstevel@tonic-gate 	int somedigits = 0;
1454*7c478bd9Sstevel@tonic-gate 	int seene = 0;
1455*7c478bd9Sstevel@tonic-gate 	int seenradix = 0;
1456*7c478bd9Sstevel@tonic-gate 	int seensign = 0;
1457*7c478bd9Sstevel@tonic-gate 	int digitsaftere = 0;
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate 	cp = (wchar_t *)np->n_string;
1460*7c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
1461*7c478bd9Sstevel@tonic-gate 		return (FSTRING|FVINT);
1462*7c478bd9Sstevel@tonic-gate 	while (iswspace(*cp))
1463*7c478bd9Sstevel@tonic-gate 		cp++;
1464*7c478bd9Sstevel@tonic-gate 	if (*cp=='-' || *cp=='+')
1465*7c478bd9Sstevel@tonic-gate 		cp++;
1466*7c478bd9Sstevel@tonic-gate 	while (*cp != '\0') {
1467*7c478bd9Sstevel@tonic-gate 		switch (*cp) {
1468*7c478bd9Sstevel@tonic-gate 		case '0':
1469*7c478bd9Sstevel@tonic-gate 		case '1':
1470*7c478bd9Sstevel@tonic-gate 		case '2':
1471*7c478bd9Sstevel@tonic-gate 		case '3':
1472*7c478bd9Sstevel@tonic-gate 		case '4':
1473*7c478bd9Sstevel@tonic-gate 		case '5':
1474*7c478bd9Sstevel@tonic-gate 		case '6':
1475*7c478bd9Sstevel@tonic-gate 		case '7':
1476*7c478bd9Sstevel@tonic-gate 		case '8':
1477*7c478bd9Sstevel@tonic-gate 		case '9':
1478*7c478bd9Sstevel@tonic-gate 			if (seene)
1479*7c478bd9Sstevel@tonic-gate 				digitsaftere = 1;
1480*7c478bd9Sstevel@tonic-gate 			somedigits++;
1481*7c478bd9Sstevel@tonic-gate 			break;
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate 		case 'E':
1484*7c478bd9Sstevel@tonic-gate 		case 'e':
1485*7c478bd9Sstevel@tonic-gate 			if (seene || !somedigits)
1486*7c478bd9Sstevel@tonic-gate 				return (FSTRING);
1487*7c478bd9Sstevel@tonic-gate 			seene = 1;
1488*7c478bd9Sstevel@tonic-gate 			break;
1489*7c478bd9Sstevel@tonic-gate 
1490*7c478bd9Sstevel@tonic-gate 		case '+':
1491*7c478bd9Sstevel@tonic-gate 		case '-':
1492*7c478bd9Sstevel@tonic-gate 			if (seensign || !seene || digitsaftere)
1493*7c478bd9Sstevel@tonic-gate 				return (FSTRING);
1494*7c478bd9Sstevel@tonic-gate 			seensign = 1;
1495*7c478bd9Sstevel@tonic-gate 			break;
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate 		default:
1498*7c478bd9Sstevel@tonic-gate 			if (*cp == radixpoint) {
1499*7c478bd9Sstevel@tonic-gate 				if (seenradix || seene || (!somedigits &&
1500*7c478bd9Sstevel@tonic-gate 				    !iswdigit(*++cp)))
1501*7c478bd9Sstevel@tonic-gate 					return (FSTRING);
1502*7c478bd9Sstevel@tonic-gate 			} else
1503*7c478bd9Sstevel@tonic-gate 				return (FSTRING);
1504*7c478bd9Sstevel@tonic-gate 			seenradix = 1;
1505*7c478bd9Sstevel@tonic-gate 		}
1506*7c478bd9Sstevel@tonic-gate 		cp++;
1507*7c478bd9Sstevel@tonic-gate 	}
1508*7c478bd9Sstevel@tonic-gate 	if (somedigits == 0)
1509*7c478bd9Sstevel@tonic-gate 		return (FSTRING);
1510*7c478bd9Sstevel@tonic-gate 	if (somedigits >= MAXDIGINT || seenradix || seene) {
1511*7c478bd9Sstevel@tonic-gate 		if (seensign && !digitsaftere)
1512*7c478bd9Sstevel@tonic-gate 			return (FSTRING);
1513*7c478bd9Sstevel@tonic-gate 		else
1514*7c478bd9Sstevel@tonic-gate 			return (FSTRING|FVREAL);
1515*7c478bd9Sstevel@tonic-gate 	} else
1516*7c478bd9Sstevel@tonic-gate 		return (FSTRING|FVINT);
1517*7c478bd9Sstevel@tonic-gate }
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate /*
1520*7c478bd9Sstevel@tonic-gate  * Return a field rvalue.
1521*7c478bd9Sstevel@tonic-gate  */
1522*7c478bd9Sstevel@tonic-gate static NODE *
1523*7c478bd9Sstevel@tonic-gate rfield(INT fieldno)
1524*7c478bd9Sstevel@tonic-gate {
1525*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate 	if (fieldno == 0)
1528*7c478bd9Sstevel@tonic-gate 		return (stringnode(linebuf, FSTATIC|FSENSE, lbuflen));
1529*7c478bd9Sstevel@tonic-gate 	if (!splitdone)
1530*7c478bd9Sstevel@tonic-gate 		fieldsplit();
1531*7c478bd9Sstevel@tonic-gate 	if (fieldno>nfield || fieldno<0)
1532*7c478bd9Sstevel@tonic-gate 		return (stringnode(_null, FSTATIC, 0));
1533*7c478bd9Sstevel@tonic-gate 	cp = fields[fieldno-1];
1534*7c478bd9Sstevel@tonic-gate 	return (stringnode(cp, FSTATIC|FSENSE, wcslen(cp)));
1535*7c478bd9Sstevel@tonic-gate }
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate /*
1538*7c478bd9Sstevel@tonic-gate  * Split linebuf into fields.  Done only once
1539*7c478bd9Sstevel@tonic-gate  * per input record (maximum).
1540*7c478bd9Sstevel@tonic-gate  */
1541*7c478bd9Sstevel@tonic-gate void
1542*7c478bd9Sstevel@tonic-gate fieldsplit()
1543*7c478bd9Sstevel@tonic-gate {
1544*7c478bd9Sstevel@tonic-gate 	register wchar_t *ip, *op;
1545*7c478bd9Sstevel@tonic-gate 	register int n;
1546*7c478bd9Sstevel@tonic-gate 	wchar_t *ep;
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate 	if (fieldbuf == NULL)
1549*7c478bd9Sstevel@tonic-gate 		fieldbuf = emalloc(NLINE * sizeof(wchar_t));
1550*7c478bd9Sstevel@tonic-gate 	fcount = 0;
1551*7c478bd9Sstevel@tonic-gate 	ep = linebuf;
1552*7c478bd9Sstevel@tonic-gate 	op = fieldbuf;
1553*7c478bd9Sstevel@tonic-gate 	while ((ip = (*awkfield)(&ep)) != NULL) {
1554*7c478bd9Sstevel@tonic-gate 		fields[fcount++] = op;
1555*7c478bd9Sstevel@tonic-gate 		if (fcount > NFIELD)
1556*7c478bd9Sstevel@tonic-gate 			awkerr(tmfld, NFIELD);
1557*7c478bd9Sstevel@tonic-gate 		n = ep-ip;
1558*7c478bd9Sstevel@tonic-gate 		(void) memcpy(op, ip, n * sizeof(wchar_t));
1559*7c478bd9Sstevel@tonic-gate 		op += n;
1560*7c478bd9Sstevel@tonic-gate 		*op++ = '\0';
1561*7c478bd9Sstevel@tonic-gate 	}
1562*7c478bd9Sstevel@tonic-gate 	if (varNF->n_flags & FINT)
1563*7c478bd9Sstevel@tonic-gate 		varNF->n_int = fcount;
1564*7c478bd9Sstevel@tonic-gate 	else {
1565*7c478bd9Sstevel@tonic-gate 		constant->n_int = fcount;
1566*7c478bd9Sstevel@tonic-gate 		(void)nassign(varNF, constant);
1567*7c478bd9Sstevel@tonic-gate 	}
1568*7c478bd9Sstevel@tonic-gate 	nfield = fcount;
1569*7c478bd9Sstevel@tonic-gate 	splitdone++;
1570*7c478bd9Sstevel@tonic-gate }
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate /*
1573*7c478bd9Sstevel@tonic-gate  * Assign to a field as an lvalue.
1574*7c478bd9Sstevel@tonic-gate  * Return the unevaluated node as one doesn't always need it
1575*7c478bd9Sstevel@tonic-gate  * evaluated in an assignment.
1576*7c478bd9Sstevel@tonic-gate  */
1577*7c478bd9Sstevel@tonic-gate static NODE *
1578*7c478bd9Sstevel@tonic-gate lfield(INT fieldno, NODE *np)
1579*7c478bd9Sstevel@tonic-gate {
1580*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
1581*7c478bd9Sstevel@tonic-gate 	register wchar_t *op;
1582*7c478bd9Sstevel@tonic-gate 	register wchar_t *sep;
1583*7c478bd9Sstevel@tonic-gate 	register int i;
1584*7c478bd9Sstevel@tonic-gate 	register wchar_t *newval;
1585*7c478bd9Sstevel@tonic-gate 	register int seplen;
1586*7c478bd9Sstevel@tonic-gate 	register int newlen;
1587*7c478bd9Sstevel@tonic-gate 
1588*7c478bd9Sstevel@tonic-gate 	newlen = wcslen(newval = (wchar_t *)exprstring(np));
1589*7c478bd9Sstevel@tonic-gate 	if (fieldno == 0) {
1590*7c478bd9Sstevel@tonic-gate 		splitdone = 0;
1591*7c478bd9Sstevel@tonic-gate 		(void) memcpy(linebuf, newval, (newlen+1) * sizeof(wchar_t));
1592*7c478bd9Sstevel@tonic-gate 		lbuflen = newlen;
1593*7c478bd9Sstevel@tonic-gate 		fieldsplit();
1594*7c478bd9Sstevel@tonic-gate 	} else {
1595*7c478bd9Sstevel@tonic-gate 		seplen = wcslen(sep = (wchar_t *)exprstring(varOFS));
1596*7c478bd9Sstevel@tonic-gate 		if (!splitdone)
1597*7c478bd9Sstevel@tonic-gate 			fieldsplit();
1598*7c478bd9Sstevel@tonic-gate 		if (--fieldno < nfield
1599*7c478bd9Sstevel@tonic-gate 		 && (newlen <= wcslen(fields[fieldno]))) {
1600*7c478bd9Sstevel@tonic-gate 			(void) memcpy(fields[fieldno], newval,
1601*7c478bd9Sstevel@tonic-gate 				(newlen+1) * sizeof(wchar_t));
1602*7c478bd9Sstevel@tonic-gate 		} else {
1603*7c478bd9Sstevel@tonic-gate 			register wchar_t *buf;
1604*7c478bd9Sstevel@tonic-gate 
1605*7c478bd9Sstevel@tonic-gate 			buf = fieldbuf;
1606*7c478bd9Sstevel@tonic-gate 			fieldbuf = emalloc(NLINE * sizeof(wchar_t));
1607*7c478bd9Sstevel@tonic-gate 			if (fieldno >= nfield) {
1608*7c478bd9Sstevel@tonic-gate 				if (fieldno >= NFIELD)
1609*7c478bd9Sstevel@tonic-gate 					awkerr(tmfld, NFIELD);
1610*7c478bd9Sstevel@tonic-gate 				while (nfield < fieldno)
1611*7c478bd9Sstevel@tonic-gate 					fields[nfield++] = _null;
1612*7c478bd9Sstevel@tonic-gate 				++nfield;
1613*7c478bd9Sstevel@tonic-gate 			}
1614*7c478bd9Sstevel@tonic-gate 			fields[fieldno] = newval;
1615*7c478bd9Sstevel@tonic-gate 			op = fieldbuf;
1616*7c478bd9Sstevel@tonic-gate 			for (i=0; i<nfield; i++) {
1617*7c478bd9Sstevel@tonic-gate 				newlen = wcslen(cp = fields[i])+1;
1618*7c478bd9Sstevel@tonic-gate 				fields[i] = op;
1619*7c478bd9Sstevel@tonic-gate 				if (op+newlen >= fieldbuf+NLINE)
1620*7c478bd9Sstevel@tonic-gate 					awkerr(toolong, NLINE);
1621*7c478bd9Sstevel@tonic-gate 				(void) memcpy(op, cp, newlen * sizeof(wchar_t));
1622*7c478bd9Sstevel@tonic-gate 				op += newlen;
1623*7c478bd9Sstevel@tonic-gate 			}
1624*7c478bd9Sstevel@tonic-gate 			free(buf);
1625*7c478bd9Sstevel@tonic-gate 		}
1626*7c478bd9Sstevel@tonic-gate 		/*
1627*7c478bd9Sstevel@tonic-gate 		 * Reconstruct $0
1628*7c478bd9Sstevel@tonic-gate 		 */
1629*7c478bd9Sstevel@tonic-gate 		op = linebuf;
1630*7c478bd9Sstevel@tonic-gate 		i = 0;
1631*7c478bd9Sstevel@tonic-gate 		while (i < nfield) {
1632*7c478bd9Sstevel@tonic-gate 			newlen = wcslen(cp = fields[i++]);
1633*7c478bd9Sstevel@tonic-gate 			(void) memcpy(op, cp, newlen * sizeof(wchar_t));
1634*7c478bd9Sstevel@tonic-gate 			op += newlen;
1635*7c478bd9Sstevel@tonic-gate 			if (i < nfield) {
1636*7c478bd9Sstevel@tonic-gate 				(void) memcpy(op, sep,
1637*7c478bd9Sstevel@tonic-gate 					seplen * sizeof(wchar_t));
1638*7c478bd9Sstevel@tonic-gate 				op += seplen;
1639*7c478bd9Sstevel@tonic-gate 			}
1640*7c478bd9Sstevel@tonic-gate 			if (op >= &linebuf[NLINE])
1641*7c478bd9Sstevel@tonic-gate 				awkerr(toolong, NLINE);
1642*7c478bd9Sstevel@tonic-gate 		}
1643*7c478bd9Sstevel@tonic-gate 		*op = '\0';
1644*7c478bd9Sstevel@tonic-gate 		lbuflen = op-linebuf;
1645*7c478bd9Sstevel@tonic-gate 		if (varNF->n_flags & FINT)
1646*7c478bd9Sstevel@tonic-gate 			varNF->n_int = nfield;
1647*7c478bd9Sstevel@tonic-gate 		else {
1648*7c478bd9Sstevel@tonic-gate 			constant->n_int = nfield;
1649*7c478bd9Sstevel@tonic-gate 			(void)nassign(varNF, constant);
1650*7c478bd9Sstevel@tonic-gate 		}
1651*7c478bd9Sstevel@tonic-gate 	}
1652*7c478bd9Sstevel@tonic-gate 	return (np);
1653*7c478bd9Sstevel@tonic-gate }
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate /*
1656*7c478bd9Sstevel@tonic-gate  * Do a user function.
1657*7c478bd9Sstevel@tonic-gate  * Each formal parameter must:
1658*7c478bd9Sstevel@tonic-gate  *	have the actual parameter assigned to it (call by value),
1659*7c478bd9Sstevel@tonic-gate  *	have a pointer to an array put into it (call by reference),
1660*7c478bd9Sstevel@tonic-gate  *	and be made undefined (extra formal parameters)
1661*7c478bd9Sstevel@tonic-gate  */
1662*7c478bd9Sstevel@tonic-gate static NODE *
1663*7c478bd9Sstevel@tonic-gate userfunc(NODE *np)
1664*7c478bd9Sstevel@tonic-gate {
1665*7c478bd9Sstevel@tonic-gate 	register NODE *temp;
1666*7c478bd9Sstevel@tonic-gate 	NODE *fnp;
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 	if ((fnp = np->n_left)==NNULL)
1669*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("impossible function call"));
1670*7c478bd9Sstevel@tonic-gate 	if (fnp->n_type!=UFUNC)
1671*7c478bd9Sstevel@tonic-gate 		awkerr(varnotfunc, fnp->n_name);
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate #ifndef M_STKCHK
1674*7c478bd9Sstevel@tonic-gate 	if (slevel >= NRECUR)
1675*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("function \"%S\" nesting level > %u"),
1676*7c478bd9Sstevel@tonic-gate 		    fnp->n_name, NRECUR);
1677*7c478bd9Sstevel@tonic-gate #else
1678*7c478bd9Sstevel@tonic-gate 	if (!M_STKCHK)
1679*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("function \"%s\" nesting level too deep"),
1680*7c478bd9Sstevel@tonic-gate 		    fnp->n_name);
1681*7c478bd9Sstevel@tonic-gate #endif
1682*7c478bd9Sstevel@tonic-gate 
1683*7c478bd9Sstevel@tonic-gate 	fnp = fnp->n_ufunc;
1684*7c478bd9Sstevel@tonic-gate 	{
1685*7c478bd9Sstevel@tonic-gate 		register NODE *formal;
1686*7c478bd9Sstevel@tonic-gate 		register NODE *actual;
1687*7c478bd9Sstevel@tonic-gate 		NODE *formlist, *actlist, *templist, *temptail;
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 		templist = temptail = NNULL;
1690*7c478bd9Sstevel@tonic-gate 		actlist = np->n_right;
1691*7c478bd9Sstevel@tonic-gate 		formlist = fnp->n_left;
1692*7c478bd9Sstevel@tonic-gate 		/* pass through formal list, setting up a list
1693*7c478bd9Sstevel@tonic-gate 		 * (on templist) containing temps for the values
1694*7c478bd9Sstevel@tonic-gate 		 * of the actuals.
1695*7c478bd9Sstevel@tonic-gate 		 * If the actual list runs out before the formal
1696*7c478bd9Sstevel@tonic-gate 		 * list, assign 'constundef' as the value
1697*7c478bd9Sstevel@tonic-gate 		 */
1698*7c478bd9Sstevel@tonic-gate 		while ((formal = getlist(&formlist)) != NNULL) {
1699*7c478bd9Sstevel@tonic-gate 			register NODE *array;
1700*7c478bd9Sstevel@tonic-gate 			register int t;
1701*7c478bd9Sstevel@tonic-gate 			register size_t len;
1702*7c478bd9Sstevel@tonic-gate 			register int scope_tag;
1703*7c478bd9Sstevel@tonic-gate 
1704*7c478bd9Sstevel@tonic-gate 			actual = getlist(&actlist);
1705*7c478bd9Sstevel@tonic-gate 			if (actual == NNULL) {
1706*7c478bd9Sstevel@tonic-gate 				actual = constundef;
1707*7c478bd9Sstevel@tonic-gate 				scope_tag = slevel+1;
1708*7c478bd9Sstevel@tonic-gate 			} else
1709*7c478bd9Sstevel@tonic-gate 				scope_tag = 0;
1710*7c478bd9Sstevel@tonic-gate 			array = actual;
1711*7c478bd9Sstevel@tonic-gate 			switch (actual->n_type) {
1712*7c478bd9Sstevel@tonic-gate 			case ARRAY:
1713*7c478bd9Sstevel@tonic-gate 				t = ARRAY;
1714*7c478bd9Sstevel@tonic-gate 				scope_tag = 0;
1715*7c478bd9Sstevel@tonic-gate 				break;
1716*7c478bd9Sstevel@tonic-gate 
1717*7c478bd9Sstevel@tonic-gate 			case PARM:
1718*7c478bd9Sstevel@tonic-gate 				array = actual = actual->n_next;
1719*7c478bd9Sstevel@tonic-gate 				t = actual->n_type;
1720*7c478bd9Sstevel@tonic-gate 				scope_tag = actual->n_scope;
1721*7c478bd9Sstevel@tonic-gate 				if (!(actual->n_flags & FLARRAY))
1722*7c478bd9Sstevel@tonic-gate 					array = actual->n_alink;
1723*7c478bd9Sstevel@tonic-gate 				break;
1724*7c478bd9Sstevel@tonic-gate 
1725*7c478bd9Sstevel@tonic-gate 			default:
1726*7c478bd9Sstevel@tonic-gate 				t = VAR;
1727*7c478bd9Sstevel@tonic-gate 				break;
1728*7c478bd9Sstevel@tonic-gate 			}
1729*7c478bd9Sstevel@tonic-gate 			temp = emptynode(t, len=wcslen(formal->n_name));
1730*7c478bd9Sstevel@tonic-gate 			(void) memcpy(temp->n_name,formal->n_name,
1731*7c478bd9Sstevel@tonic-gate 				(len+1) * sizeof(wchar_t));
1732*7c478bd9Sstevel@tonic-gate 			temp->n_flags = FSTRING|FVINT;
1733*7c478bd9Sstevel@tonic-gate 			temp->n_string = _null;
1734*7c478bd9Sstevel@tonic-gate 			temp->n_strlen = 0;
1735*7c478bd9Sstevel@tonic-gate 			if (t == VAR)
1736*7c478bd9Sstevel@tonic-gate 				(void)assign(temp, actual);
1737*7c478bd9Sstevel@tonic-gate 			if (t != ARRAY)
1738*7c478bd9Sstevel@tonic-gate 				temp->n_flags |= FLARRAY;
1739*7c478bd9Sstevel@tonic-gate 			temp->n_scope = scope_tag;
1740*7c478bd9Sstevel@tonic-gate 			/*
1741*7c478bd9Sstevel@tonic-gate 			 * link to actual parameter in case of promotion to
1742*7c478bd9Sstevel@tonic-gate 			 * array
1743*7c478bd9Sstevel@tonic-gate 			 */
1744*7c478bd9Sstevel@tonic-gate 			if (actual != constundef)
1745*7c478bd9Sstevel@tonic-gate 				temp->n_alink = actual;
1746*7c478bd9Sstevel@tonic-gate 			/*
1747*7c478bd9Sstevel@tonic-gate 			 * Build the templist
1748*7c478bd9Sstevel@tonic-gate 			 */
1749*7c478bd9Sstevel@tonic-gate 			if (templist != NNULL) {
1750*7c478bd9Sstevel@tonic-gate 				temptail->n_next = temp;
1751*7c478bd9Sstevel@tonic-gate 				temptail = temp;
1752*7c478bd9Sstevel@tonic-gate 			} else
1753*7c478bd9Sstevel@tonic-gate 				templist = temptail = temp;
1754*7c478bd9Sstevel@tonic-gate 			temp->n_next = NNULL;
1755*7c478bd9Sstevel@tonic-gate 			if (actual->n_type == CONSTANT)
1756*7c478bd9Sstevel@tonic-gate 				temp->n_alink = temp;
1757*7c478bd9Sstevel@tonic-gate 			else
1758*7c478bd9Sstevel@tonic-gate 				temp->n_alink = array;
1759*7c478bd9Sstevel@tonic-gate 		}
1760*7c478bd9Sstevel@tonic-gate 		/*
1761*7c478bd9Sstevel@tonic-gate 		 * Bind results of the evaluation of actuals to formals.
1762*7c478bd9Sstevel@tonic-gate 		 */
1763*7c478bd9Sstevel@tonic-gate 		formlist = fnp->n_left;
1764*7c478bd9Sstevel@tonic-gate 		while (templist != NNULL) {
1765*7c478bd9Sstevel@tonic-gate 			temp = templist;
1766*7c478bd9Sstevel@tonic-gate 			templist = temp->n_next;
1767*7c478bd9Sstevel@tonic-gate 			formal = getlist(&formlist);
1768*7c478bd9Sstevel@tonic-gate 			temp->n_next = formal->n_next;
1769*7c478bd9Sstevel@tonic-gate 			formal->n_next = temp;
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate 
1773*7c478bd9Sstevel@tonic-gate 
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 
1776*7c478bd9Sstevel@tonic-gate 
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 		}
1779*7c478bd9Sstevel@tonic-gate 	}
1780*7c478bd9Sstevel@tonic-gate 	{
1781*7c478bd9Sstevel@tonic-gate 		register NODE *savenode = curnode;
1782*7c478bd9Sstevel@tonic-gate 
1783*7c478bd9Sstevel@tonic-gate 		++slevel;
1784*7c478bd9Sstevel@tonic-gate 		if (action(fnp->n_right) == RETURN)
1785*7c478bd9Sstevel@tonic-gate 			np = retval; else
1786*7c478bd9Sstevel@tonic-gate 			np = const0;
1787*7c478bd9Sstevel@tonic-gate 		curnode = savenode;
1788*7c478bd9Sstevel@tonic-gate 	}
1789*7c478bd9Sstevel@tonic-gate 	{
1790*7c478bd9Sstevel@tonic-gate 		register NODE *formal;
1791*7c478bd9Sstevel@tonic-gate 		NODE *formlist;
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 		formlist = fnp->n_left;
1794*7c478bd9Sstevel@tonic-gate 		while ((formal = getlist(&formlist)) != NNULL) {
1795*7c478bd9Sstevel@tonic-gate 			temp = formal->n_next;
1796*7c478bd9Sstevel@tonic-gate 			formal->n_next = temp->n_next;
1797*7c478bd9Sstevel@tonic-gate 			/* if node is a local array, free the elements */
1798*7c478bd9Sstevel@tonic-gate 			if (temp->n_type == ARRAY && (temp->n_scope == slevel))
1799*7c478bd9Sstevel@tonic-gate 				delarray(temp);
1800*7c478bd9Sstevel@tonic-gate 			freenode(temp);
1801*7c478bd9Sstevel@tonic-gate 		}
1802*7c478bd9Sstevel@tonic-gate 	}
1803*7c478bd9Sstevel@tonic-gate 	--slevel;
1804*7c478bd9Sstevel@tonic-gate 	return (np);
1805*7c478bd9Sstevel@tonic-gate }
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate /*
1808*7c478bd9Sstevel@tonic-gate  * Get the regular expression from an expression tree.
1809*7c478bd9Sstevel@tonic-gate  */
1810*7c478bd9Sstevel@tonic-gate REGEXP
1811*7c478bd9Sstevel@tonic-gate getregexp(NODE *np)
1812*7c478bd9Sstevel@tonic-gate {
1813*7c478bd9Sstevel@tonic-gate 	if (np->n_type == RE)
1814*7c478bd9Sstevel@tonic-gate 		return (np->n_regexp);
1815*7c478bd9Sstevel@tonic-gate 	np = renode((wchar_t *)exprstring(np));
1816*7c478bd9Sstevel@tonic-gate 	return (np->n_regexp);
1817*7c478bd9Sstevel@tonic-gate }
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate /*
1820*7c478bd9Sstevel@tonic-gate  * Get the next element from a list.
1821*7c478bd9Sstevel@tonic-gate  */
1822*7c478bd9Sstevel@tonic-gate NODE *
1823*7c478bd9Sstevel@tonic-gate getlist(NODE **npp)
1824*7c478bd9Sstevel@tonic-gate {
1825*7c478bd9Sstevel@tonic-gate 	register NODE *np;
1826*7c478bd9Sstevel@tonic-gate 
1827*7c478bd9Sstevel@tonic-gate 	if ((np = *npp) == NNULL)
1828*7c478bd9Sstevel@tonic-gate 		return (np);
1829*7c478bd9Sstevel@tonic-gate 	if (np->n_type == COMMA) {
1830*7c478bd9Sstevel@tonic-gate 		*npp = np->n_right;
1831*7c478bd9Sstevel@tonic-gate 		return (np->n_left);
1832*7c478bd9Sstevel@tonic-gate 	} else {
1833*7c478bd9Sstevel@tonic-gate 		*npp = NNULL;
1834*7c478bd9Sstevel@tonic-gate 		return (np);
1835*7c478bd9Sstevel@tonic-gate 	}
1836*7c478bd9Sstevel@tonic-gate }
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate /*
1839*7c478bd9Sstevel@tonic-gate  * if statement.
1840*7c478bd9Sstevel@tonic-gate  */
1841*7c478bd9Sstevel@tonic-gate static int
1842*7c478bd9Sstevel@tonic-gate s_if(NODE *np)
1843*7c478bd9Sstevel@tonic-gate {
1844*7c478bd9Sstevel@tonic-gate 	register NODE *xp;
1845*7c478bd9Sstevel@tonic-gate 	register int test;
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 	test = exprtest(np->n_left);
1848*7c478bd9Sstevel@tonic-gate 	xp = np->n_right;
1849*7c478bd9Sstevel@tonic-gate 	if (xp->n_type != ELSE)
1850*7c478bd9Sstevel@tonic-gate 		awkerr(interr, "if/else");
1851*7c478bd9Sstevel@tonic-gate 	if (test)
1852*7c478bd9Sstevel@tonic-gate 		xp = xp->n_left;
1853*7c478bd9Sstevel@tonic-gate 	else
1854*7c478bd9Sstevel@tonic-gate 		xp = xp->n_right;
1855*7c478bd9Sstevel@tonic-gate 	return (action(xp));
1856*7c478bd9Sstevel@tonic-gate }
1857*7c478bd9Sstevel@tonic-gate 
1858*7c478bd9Sstevel@tonic-gate /*
1859*7c478bd9Sstevel@tonic-gate  * while and do{}while statements.
1860*7c478bd9Sstevel@tonic-gate  */
1861*7c478bd9Sstevel@tonic-gate static int
1862*7c478bd9Sstevel@tonic-gate s_while(NODE *np)
1863*7c478bd9Sstevel@tonic-gate {
1864*7c478bd9Sstevel@tonic-gate 	register int act = 0;
1865*7c478bd9Sstevel@tonic-gate 
1866*7c478bd9Sstevel@tonic-gate 	if (np->n_type == DO)
1867*7c478bd9Sstevel@tonic-gate 		goto dowhile;
1868*7c478bd9Sstevel@tonic-gate 	for (;;) {
1869*7c478bd9Sstevel@tonic-gate 		if (exprtest(np->n_left) == 0)
1870*7c478bd9Sstevel@tonic-gate 			break;
1871*7c478bd9Sstevel@tonic-gate 	dowhile:
1872*7c478bd9Sstevel@tonic-gate 		if ((act = action(np->n_right)) != 0) {
1873*7c478bd9Sstevel@tonic-gate 			switch (act) {
1874*7c478bd9Sstevel@tonic-gate 			case BREAK:
1875*7c478bd9Sstevel@tonic-gate 				act = 0;
1876*7c478bd9Sstevel@tonic-gate 				break;
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate 			case CONTINUE:
1879*7c478bd9Sstevel@tonic-gate 				act = 0;
1880*7c478bd9Sstevel@tonic-gate 				continue;
1881*7c478bd9Sstevel@tonic-gate 			}
1882*7c478bd9Sstevel@tonic-gate 			break;
1883*7c478bd9Sstevel@tonic-gate 		}
1884*7c478bd9Sstevel@tonic-gate 	}
1885*7c478bd9Sstevel@tonic-gate 	return (act);
1886*7c478bd9Sstevel@tonic-gate }
1887*7c478bd9Sstevel@tonic-gate 
1888*7c478bd9Sstevel@tonic-gate /*
1889*7c478bd9Sstevel@tonic-gate  * for statement.
1890*7c478bd9Sstevel@tonic-gate  */
1891*7c478bd9Sstevel@tonic-gate static int
1892*7c478bd9Sstevel@tonic-gate s_for(NODE *np)
1893*7c478bd9Sstevel@tonic-gate {
1894*7c478bd9Sstevel@tonic-gate 	register NODE *testnp, *incnp, *initnp;
1895*7c478bd9Sstevel@tonic-gate 	register int act = 0;
1896*7c478bd9Sstevel@tonic-gate 	NODE *listp;
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 	listp = np->n_left;
1899*7c478bd9Sstevel@tonic-gate 	initnp = getlist(&listp);
1900*7c478bd9Sstevel@tonic-gate 	testnp = getlist(&listp);
1901*7c478bd9Sstevel@tonic-gate 	incnp = getlist(&listp);
1902*7c478bd9Sstevel@tonic-gate 	if (initnp != NNULL)
1903*7c478bd9Sstevel@tonic-gate 		(void)exprreduce(initnp);
1904*7c478bd9Sstevel@tonic-gate 	for (;;) {
1905*7c478bd9Sstevel@tonic-gate 		if (exprtest(testnp) == 0)
1906*7c478bd9Sstevel@tonic-gate 			break;
1907*7c478bd9Sstevel@tonic-gate 		if ((act = action(np->n_right)) != 0) {
1908*7c478bd9Sstevel@tonic-gate 			switch (act) {
1909*7c478bd9Sstevel@tonic-gate 			case BREAK:
1910*7c478bd9Sstevel@tonic-gate 				act = 0;
1911*7c478bd9Sstevel@tonic-gate 				break;
1912*7c478bd9Sstevel@tonic-gate 
1913*7c478bd9Sstevel@tonic-gate 			case CONTINUE:
1914*7c478bd9Sstevel@tonic-gate 				act = 0;
1915*7c478bd9Sstevel@tonic-gate 				goto clabel;
1916*7c478bd9Sstevel@tonic-gate 			}
1917*7c478bd9Sstevel@tonic-gate 			break;
1918*7c478bd9Sstevel@tonic-gate 		}
1919*7c478bd9Sstevel@tonic-gate 	clabel:
1920*7c478bd9Sstevel@tonic-gate 		if (incnp != NNULL)
1921*7c478bd9Sstevel@tonic-gate 			(void)exprreduce(incnp);
1922*7c478bd9Sstevel@tonic-gate 	}
1923*7c478bd9Sstevel@tonic-gate 	return (act);
1924*7c478bd9Sstevel@tonic-gate }
1925*7c478bd9Sstevel@tonic-gate 
1926*7c478bd9Sstevel@tonic-gate /*
1927*7c478bd9Sstevel@tonic-gate  * for variable in array statement.
1928*7c478bd9Sstevel@tonic-gate  */
1929*7c478bd9Sstevel@tonic-gate static int
1930*7c478bd9Sstevel@tonic-gate s_forin(NODE *np)
1931*7c478bd9Sstevel@tonic-gate {
1932*7c478bd9Sstevel@tonic-gate 	register NODE *left;
1933*7c478bd9Sstevel@tonic-gate 	register int act = 0;
1934*7c478bd9Sstevel@tonic-gate 	register NODE *var;
1935*7c478bd9Sstevel@tonic-gate 	register NODE **nnp;
1936*7c478bd9Sstevel@tonic-gate 	register NODE *statement;
1937*7c478bd9Sstevel@tonic-gate 	register int issymtab = 0;
1938*7c478bd9Sstevel@tonic-gate 	wchar_t *index;
1939*7c478bd9Sstevel@tonic-gate 	register int alen;
1940*7c478bd9Sstevel@tonic-gate 	int nbuck;
1941*7c478bd9Sstevel@tonic-gate 
1942*7c478bd9Sstevel@tonic-gate 	left = np->n_left;
1943*7c478bd9Sstevel@tonic-gate 	statement = np->n_right;
1944*7c478bd9Sstevel@tonic-gate 	if (left->n_type != IN)
1945*7c478bd9Sstevel@tonic-gate 		awkerr(interr, "for (var in array)");
1946*7c478bd9Sstevel@tonic-gate 	if ((var = left->n_left)->n_type == PARM)
1947*7c478bd9Sstevel@tonic-gate 		var = var->n_next;
1948*7c478bd9Sstevel@tonic-gate 	np = left->n_right;
1949*7c478bd9Sstevel@tonic-gate 	if (np->n_type == PARM) {
1950*7c478bd9Sstevel@tonic-gate 		np = np->n_next;
1951*7c478bd9Sstevel@tonic-gate 		if (!(np->n_flags & FLARRAY))
1952*7c478bd9Sstevel@tonic-gate 			np = np->n_alink;
1953*7c478bd9Sstevel@tonic-gate 	}
1954*7c478bd9Sstevel@tonic-gate 	if (np == varSYMTAB) {
1955*7c478bd9Sstevel@tonic-gate 		issymtab++;
1956*7c478bd9Sstevel@tonic-gate 		np = NNULL;
1957*7c478bd9Sstevel@tonic-gate 		nbuck = 0;
1958*7c478bd9Sstevel@tonic-gate 	} else {
1959*7c478bd9Sstevel@tonic-gate 		/*l
1960*7c478bd9Sstevel@tonic-gate 		 * At this point if the node is not actually an array
1961*7c478bd9Sstevel@tonic-gate 		 * check to see if it has already been established as
1962*7c478bd9Sstevel@tonic-gate 		 * a scalar. If it is a scalar then flag an error. If
1963*7c478bd9Sstevel@tonic-gate 		 * not then promote the object to an array type.
1964*7c478bd9Sstevel@tonic-gate 		 */
1965*7c478bd9Sstevel@tonic-gate 		if (np->n_type != ARRAY) {
1966*7c478bd9Sstevel@tonic-gate 			if (!isstring(np->n_flags) || np->n_string!=_null)
1967*7c478bd9Sstevel@tonic-gate 				awkerr(notarray, np->n_name);
1968*7c478bd9Sstevel@tonic-gate 			else {
1969*7c478bd9Sstevel@tonic-gate 				/* promotion to array */
1970*7c478bd9Sstevel@tonic-gate 				promote(np);
1971*7c478bd9Sstevel@tonic-gate 				if (np->n_alink != NNULL)
1972*7c478bd9Sstevel@tonic-gate 					if (!(np->n_flags & FLARRAY))
1973*7c478bd9Sstevel@tonic-gate 						np = np->n_alink;
1974*7c478bd9Sstevel@tonic-gate 			}
1975*7c478bd9Sstevel@tonic-gate 		}
1976*7c478bd9Sstevel@tonic-gate 		/*
1977*7c478bd9Sstevel@tonic-gate 		 * Set up a pointer to the first node in the array list.
1978*7c478bd9Sstevel@tonic-gate 		 * Save this pointer on the delete stack. This information
1979*7c478bd9Sstevel@tonic-gate 		 * is used by the delete function to advance any pointers
1980*7c478bd9Sstevel@tonic-gate 		 * that might be pointing at a node which has been deleted.
1981*7c478bd9Sstevel@tonic-gate 		 * See the delsymtab() function for more information. Note
1982*7c478bd9Sstevel@tonic-gate 		 * that if the a_link field is nil, then just return 0 since
1983*7c478bd9Sstevel@tonic-gate 		 * this array has no elements yet.
1984*7c478bd9Sstevel@tonic-gate 		 */
1985*7c478bd9Sstevel@tonic-gate 		if ((*(nnp = next_forin) = np->n_alink) == 0)
1986*7c478bd9Sstevel@tonic-gate 			return (0);
1987*7c478bd9Sstevel@tonic-gate 		if (++next_forin > &forindex[NFORINLOOP])
1988*7c478bd9Sstevel@tonic-gate 			awkerr(toodeep, NFORINLOOP);
1989*7c478bd9Sstevel@tonic-gate 		/*
1990*7c478bd9Sstevel@tonic-gate 		 * array elements have names of the form
1991*7c478bd9Sstevel@tonic-gate 		 *	<name>]<index> (global arrays)
1992*7c478bd9Sstevel@tonic-gate 		 * or
1993*7c478bd9Sstevel@tonic-gate 		 *	<name>[<scope>]<index> (local arrays)
1994*7c478bd9Sstevel@tonic-gate 		 * We need to know the offset of the index portion of the
1995*7c478bd9Sstevel@tonic-gate 		 * name string in order to place it in the index variable so
1996*7c478bd9Sstevel@tonic-gate 		 * we look for the ']'. This is calculated here and then
1997*7c478bd9Sstevel@tonic-gate 		 * used below.
1998*7c478bd9Sstevel@tonic-gate 		 */
1999*7c478bd9Sstevel@tonic-gate 		for (alen = 0; (*nnp)->n_name[alen++] != ']'; )
2000*7c478bd9Sstevel@tonic-gate 			if ((*nnp)->n_name[alen] == '\0')
2001*7c478bd9Sstevel@tonic-gate 				awkerr(interr, "for: invalid array");
2002*7c478bd9Sstevel@tonic-gate 	}
2003*7c478bd9Sstevel@tonic-gate 	for (;;) {
2004*7c478bd9Sstevel@tonic-gate 		if (issymtab) {
2005*7c478bd9Sstevel@tonic-gate 			if ((left = symwalk(&nbuck, &np)) == NNULL)
2006*7c478bd9Sstevel@tonic-gate 				break;
2007*7c478bd9Sstevel@tonic-gate 			index = left->n_name;
2008*7c478bd9Sstevel@tonic-gate 		} else {
2009*7c478bd9Sstevel@tonic-gate 			if ((np = *nnp) == NNULL)
2010*7c478bd9Sstevel@tonic-gate 				break;
2011*7c478bd9Sstevel@tonic-gate 			index = np->n_name+alen;
2012*7c478bd9Sstevel@tonic-gate 			*nnp = np->n_alink;
2013*7c478bd9Sstevel@tonic-gate 		}
2014*7c478bd9Sstevel@tonic-gate 		strassign(var, index, FSTATIC, wcslen(index));
2015*7c478bd9Sstevel@tonic-gate 		if ((act = action(statement)) != 0) {
2016*7c478bd9Sstevel@tonic-gate 			switch (act) {
2017*7c478bd9Sstevel@tonic-gate 			case BREAK:
2018*7c478bd9Sstevel@tonic-gate 				act = 0;
2019*7c478bd9Sstevel@tonic-gate 				break;
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 			case CONTINUE:
2022*7c478bd9Sstevel@tonic-gate 				act = 0;
2023*7c478bd9Sstevel@tonic-gate 				continue;
2024*7c478bd9Sstevel@tonic-gate 			}
2025*7c478bd9Sstevel@tonic-gate 			break;
2026*7c478bd9Sstevel@tonic-gate 		}
2027*7c478bd9Sstevel@tonic-gate 	}
2028*7c478bd9Sstevel@tonic-gate 	next_forin--;
2029*7c478bd9Sstevel@tonic-gate 	return (act);
2030*7c478bd9Sstevel@tonic-gate }
2031*7c478bd9Sstevel@tonic-gate 
2032*7c478bd9Sstevel@tonic-gate /*
2033*7c478bd9Sstevel@tonic-gate  * Walk the symbol table using the same algorithm as arraynode.
2034*7c478bd9Sstevel@tonic-gate  */
2035*7c478bd9Sstevel@tonic-gate NODE *
2036*7c478bd9Sstevel@tonic-gate symwalk(int *buckp, NODE **npp)
2037*7c478bd9Sstevel@tonic-gate {
2038*7c478bd9Sstevel@tonic-gate 	register NODE *np;
2039*7c478bd9Sstevel@tonic-gate 
2040*7c478bd9Sstevel@tonic-gate 	np = *npp;
2041*7c478bd9Sstevel@tonic-gate 	for (;;) {
2042*7c478bd9Sstevel@tonic-gate 		while (np == NNULL) {
2043*7c478bd9Sstevel@tonic-gate 			if (*buckp >= NBUCKET)
2044*7c478bd9Sstevel@tonic-gate 				return (*npp = NNULL);
2045*7c478bd9Sstevel@tonic-gate 			np = symtab[(*buckp)++];
2046*7c478bd9Sstevel@tonic-gate 		}
2047*7c478bd9Sstevel@tonic-gate 		if (np->n_type == VAR
2048*7c478bd9Sstevel@tonic-gate 		 && (!isstring(np->n_flags) || np->n_string!=_null)) {
2049*7c478bd9Sstevel@tonic-gate 			*npp = np->n_next;
2050*7c478bd9Sstevel@tonic-gate 			return (np);
2051*7c478bd9Sstevel@tonic-gate 		}
2052*7c478bd9Sstevel@tonic-gate 		np = np->n_next;
2053*7c478bd9Sstevel@tonic-gate 	}
2054*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2055*7c478bd9Sstevel@tonic-gate }
2056*7c478bd9Sstevel@tonic-gate 
2057*7c478bd9Sstevel@tonic-gate /*
2058*7c478bd9Sstevel@tonic-gate  * Test the result of an expression.
2059*7c478bd9Sstevel@tonic-gate  */
2060*7c478bd9Sstevel@tonic-gate static int
2061*7c478bd9Sstevel@tonic-gate exprtest(NODE *np)
2062*7c478bd9Sstevel@tonic-gate {
2063*7c478bd9Sstevel@tonic-gate 	register int t;
2064*7c478bd9Sstevel@tonic-gate 
2065*7c478bd9Sstevel@tonic-gate 	if (np == NNULL)
2066*7c478bd9Sstevel@tonic-gate 		return (1);
2067*7c478bd9Sstevel@tonic-gate 	if (freelist != NNULL)
2068*7c478bd9Sstevel@tonic-gate 		freetemps();
2069*7c478bd9Sstevel@tonic-gate 	np = exprreduce(np);
2070*7c478bd9Sstevel@tonic-gate 	if (isint(t = np->n_flags)) {
2071*7c478bd9Sstevel@tonic-gate 		if (isstring(t))
2072*7c478bd9Sstevel@tonic-gate 			return (exprint(np) != 0);
2073*7c478bd9Sstevel@tonic-gate 		return (np->n_int != 0);
2074*7c478bd9Sstevel@tonic-gate 	}
2075*7c478bd9Sstevel@tonic-gate 	if (isreal(t)) {
2076*7c478bd9Sstevel@tonic-gate 		REAL rval;
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 		rval = isstring(t) ? exprreal(np) : np->n_real;
2079*7c478bd9Sstevel@tonic-gate 		return (rval != 0.0);
2080*7c478bd9Sstevel@tonic-gate 	}
2081*7c478bd9Sstevel@tonic-gate 	return (*(wchar_t *)exprstring(np) != '\0');
2082*7c478bd9Sstevel@tonic-gate }
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate /*
2085*7c478bd9Sstevel@tonic-gate  * Return malloc'ed space that holds the given name "[" scope "]" index ...
2086*7c478bd9Sstevel@tonic-gate  * concatenated string.
2087*7c478bd9Sstevel@tonic-gate  * The node (np) is the list of indices and 'array' is the array name.
2088*7c478bd9Sstevel@tonic-gate  */
2089*7c478bd9Sstevel@tonic-gate static wchar_t *
2090*7c478bd9Sstevel@tonic-gate makeindex(NODE *np, wchar_t *array, int tag)
2091*7c478bd9Sstevel@tonic-gate {
2092*7c478bd9Sstevel@tonic-gate 	static wchar_t tags[sizeof(int)];
2093*7c478bd9Sstevel@tonic-gate 	static wchar_t tag_chars[] = M_MB_L("0123456789ABCDEF");
2094*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
2095*7c478bd9Sstevel@tonic-gate 	register NODE *index;
2096*7c478bd9Sstevel@tonic-gate 	register uint n;
2097*7c478bd9Sstevel@tonic-gate 	register int len;
2098*7c478bd9Sstevel@tonic-gate 	register wchar_t *indstr;
2099*7c478bd9Sstevel@tonic-gate 	register wchar_t *sep;
2100*7c478bd9Sstevel@tonic-gate 	register int seplen;
2101*7c478bd9Sstevel@tonic-gate 	register int taglen;
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 
2104*7c478bd9Sstevel@tonic-gate 	/*
2105*7c478bd9Sstevel@tonic-gate 	 * calculate and create the tag string
2106*7c478bd9Sstevel@tonic-gate 	 */
2107*7c478bd9Sstevel@tonic-gate 	for (taglen = 0; tag; tag >>= 4)
2108*7c478bd9Sstevel@tonic-gate 		tags[taglen++] = tag_chars[tag & 0xf];
2109*7c478bd9Sstevel@tonic-gate 	/*
2110*7c478bd9Sstevel@tonic-gate 	 * Special (normal) case: only one index.
2111*7c478bd9Sstevel@tonic-gate 	 */
2112*7c478bd9Sstevel@tonic-gate 	if (np->n_type != COMMA) {
2113*7c478bd9Sstevel@tonic-gate 		wchar_t *ocp;
2114*7c478bd9Sstevel@tonic-gate 		size_t i;
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate 		if (isleaf(np->n_flags) && np->n_type==PARM)
2117*7c478bd9Sstevel@tonic-gate 			np = np->n_next;
2118*7c478bd9Sstevel@tonic-gate 		if (isstring(np->n_flags)) {
2119*7c478bd9Sstevel@tonic-gate 			indstr = np->n_string;
2120*7c478bd9Sstevel@tonic-gate 			len = np->n_strlen;
2121*7c478bd9Sstevel@tonic-gate 		} else {
2122*7c478bd9Sstevel@tonic-gate 			indstr = exprstring(np);
2123*7c478bd9Sstevel@tonic-gate 			len = wcslen(indstr);
2124*7c478bd9Sstevel@tonic-gate 		}
2125*7c478bd9Sstevel@tonic-gate 		i = (n = wcslen(array)) + len + 3 + taglen;
2126*7c478bd9Sstevel@tonic-gate 		if (i < NINDEXBUF)
2127*7c478bd9Sstevel@tonic-gate 			ocp = indexbuf;
2128*7c478bd9Sstevel@tonic-gate 		else
2129*7c478bd9Sstevel@tonic-gate 			ocp = emalloc(i * sizeof(wchar_t));
2130*7c478bd9Sstevel@tonic-gate 		(void) memcpy(ocp, array, n * sizeof(wchar_t));
2131*7c478bd9Sstevel@tonic-gate 		cp = ocp+n;
2132*7c478bd9Sstevel@tonic-gate 		if (taglen) {
2133*7c478bd9Sstevel@tonic-gate 			*cp++ = '[';
2134*7c478bd9Sstevel@tonic-gate 			while (taglen)
2135*7c478bd9Sstevel@tonic-gate 				*cp++ = tags[--taglen];
2136*7c478bd9Sstevel@tonic-gate 		}
2137*7c478bd9Sstevel@tonic-gate 		*cp++ = ']';
2138*7c478bd9Sstevel@tonic-gate 		(void) memcpy(cp, indstr, (len+1) * sizeof(wchar_t));
2139*7c478bd9Sstevel@tonic-gate 
2140*7c478bd9Sstevel@tonic-gate 		return (ocp);
2141*7c478bd9Sstevel@tonic-gate 	}
2142*7c478bd9Sstevel@tonic-gate 	n = 0;
2143*7c478bd9Sstevel@tonic-gate 	seplen = wcslen(sep = (wchar_t *)exprstring(varSUBSEP));
2144*7c478bd9Sstevel@tonic-gate 	while ((index = getlist(&np)) != NNULL) {
2145*7c478bd9Sstevel@tonic-gate 		indstr = exprstring(index);
2146*7c478bd9Sstevel@tonic-gate 		len = wcslen(indstr);
2147*7c478bd9Sstevel@tonic-gate 		if (n == 0) {
2148*7c478bd9Sstevel@tonic-gate 			cp = emalloc(sizeof(wchar_t) * ((n = wcslen(array)) +
2149*7c478bd9Sstevel@tonic-gate 				len + 3 + taglen));
2150*7c478bd9Sstevel@tonic-gate 			(void) memcpy(cp, array, n * sizeof(wchar_t));
2151*7c478bd9Sstevel@tonic-gate 			if (taglen) {
2152*7c478bd9Sstevel@tonic-gate 				cp[n++] = '[';
2153*7c478bd9Sstevel@tonic-gate 				while (taglen)
2154*7c478bd9Sstevel@tonic-gate 					cp[n++] = tags[--taglen];
2155*7c478bd9Sstevel@tonic-gate 			}
2156*7c478bd9Sstevel@tonic-gate 			cp[n++] = ']';
2157*7c478bd9Sstevel@tonic-gate 		} else {
2158*7c478bd9Sstevel@tonic-gate 			cp = erealloc(cp, (n+len+seplen+1) * sizeof(wchar_t));
2159*7c478bd9Sstevel@tonic-gate 			(void) memcpy(cp+n, sep, seplen * sizeof(wchar_t));
2160*7c478bd9Sstevel@tonic-gate 			n += seplen;
2161*7c478bd9Sstevel@tonic-gate 		}
2162*7c478bd9Sstevel@tonic-gate 		(void) memcpy(cp+n, indstr, (len+1) * sizeof(wchar_t));
2163*7c478bd9Sstevel@tonic-gate 		n += len;
2164*7c478bd9Sstevel@tonic-gate 	}
2165*7c478bd9Sstevel@tonic-gate 	return (cp);
2166*7c478bd9Sstevel@tonic-gate }
2167*7c478bd9Sstevel@tonic-gate 
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate /*
2170*7c478bd9Sstevel@tonic-gate  * Promote a node to an array. In the simplest case, just set the
2171*7c478bd9Sstevel@tonic-gate  * node type field to ARRAY. The more complicated case involves walking
2172*7c478bd9Sstevel@tonic-gate  * a list of variables that haven't been determined yet as scalar or array.
2173*7c478bd9Sstevel@tonic-gate  * This routine plays with the pointers to avoid recursion.
2174*7c478bd9Sstevel@tonic-gate  */
2175*7c478bd9Sstevel@tonic-gate void
2176*7c478bd9Sstevel@tonic-gate promote(NODE *n)
2177*7c478bd9Sstevel@tonic-gate {
2178*7c478bd9Sstevel@tonic-gate 	register NODE *prev = NNULL;
2179*7c478bd9Sstevel@tonic-gate 	register NODE *next;
2180*7c478bd9Sstevel@tonic-gate 
2181*7c478bd9Sstevel@tonic-gate 	/*
2182*7c478bd9Sstevel@tonic-gate 	 * walk down the variable chain, reversing the pointers and
2183*7c478bd9Sstevel@tonic-gate 	 * setting each node to type array.
2184*7c478bd9Sstevel@tonic-gate 	 */
2185*7c478bd9Sstevel@tonic-gate 	while ((n->n_flags & FLARRAY) && (n->n_alink != n)) {
2186*7c478bd9Sstevel@tonic-gate 		n->n_type = ARRAY;
2187*7c478bd9Sstevel@tonic-gate 		next = n->n_alink;
2188*7c478bd9Sstevel@tonic-gate 		n->n_alink = prev;
2189*7c478bd9Sstevel@tonic-gate 		prev = n;
2190*7c478bd9Sstevel@tonic-gate 		n = next;
2191*7c478bd9Sstevel@tonic-gate 	}
2192*7c478bd9Sstevel@tonic-gate 
2193*7c478bd9Sstevel@tonic-gate 	/*
2194*7c478bd9Sstevel@tonic-gate 	 * If the final entity on the chain is a local variable, then
2195*7c478bd9Sstevel@tonic-gate 	 * reset it's alink field to NNULL - normally it points back
2196*7c478bd9Sstevel@tonic-gate 	 * to itself - this is used in other parts of the code to
2197*7c478bd9Sstevel@tonic-gate 	 * reduce the number of conditionals when handling locals.
2198*7c478bd9Sstevel@tonic-gate 	 */
2199*7c478bd9Sstevel@tonic-gate 	n->n_type = ARRAY;
2200*7c478bd9Sstevel@tonic-gate 	if (n->n_flags & FLARRAY)
2201*7c478bd9Sstevel@tonic-gate 		n->n_alink = NNULL;
2202*7c478bd9Sstevel@tonic-gate 
2203*7c478bd9Sstevel@tonic-gate 	/*
2204*7c478bd9Sstevel@tonic-gate 	 * Now walk back up the list setting the alink to point to
2205*7c478bd9Sstevel@tonic-gate 	 * the last entry in the chain and clear the 'local array'
2206*7c478bd9Sstevel@tonic-gate 	 * flag.
2207*7c478bd9Sstevel@tonic-gate 	 */
2208*7c478bd9Sstevel@tonic-gate 	while (prev != NNULL) {
2209*7c478bd9Sstevel@tonic-gate 		prev->n_flags &= ~FLARRAY;
2210*7c478bd9Sstevel@tonic-gate 		next=prev->n_alink;
2211*7c478bd9Sstevel@tonic-gate 		prev->n_alink = n;
2212*7c478bd9Sstevel@tonic-gate 		prev=next;
2213*7c478bd9Sstevel@tonic-gate 	}
2214*7c478bd9Sstevel@tonic-gate }
2215