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