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