Home | History | Annotate | Download | only in awk_xpg4
      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 			 *