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