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