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 *