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