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