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