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