1 /*- 2 * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by David A. Holland. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <stdint.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 #include "array.h" 35 #include "mode.h" 36 #include "place.h" 37 #include "macro.h" 38 #include "output.h" 39 40 struct expansionitem { 41 bool isstring; 42 union { 43 char *string; 44 unsigned param; 45 }; 46 }; 47 DECLARRAY(expansionitem, static UNUSED); 48 DEFARRAY(expansionitem, static); 49 50 struct macro { 51 struct place defplace; 52 struct place expansionplace; 53 unsigned hash; 54 char *name; 55 bool hasparams; 56 struct stringarray params; 57 struct expansionitemarray expansion; 58 bool inuse; 59 }; 60 DECLARRAY(macro, static UNUSED); 61 DEFARRAY(macro, static); 62 DECLARRAY(macroarray, static UNUSED); 63 DEFARRAY(macroarray, static); 64 65 static struct macroarrayarray macros; 66 static unsigned total_macros; 67 static unsigned hashmask; 68 69 //////////////////////////////////////////////////////////// 70 // macro structure ops 71 72 static 73 struct expansionitem * 74 expansionitem_create_string(const char *string) 75 { 76 struct expansionitem *ei; 77 78 ei = domalloc(sizeof(*ei)); 79 ei->isstring = true; 80 ei->string = dostrdup(string); 81 return ei; 82 } 83 84 static 85 struct expansionitem * 86 expansionitem_create_stringlen(const char *string, size_t len) 87 { 88 struct expansionitem *ei; 89 90 ei = domalloc(sizeof(*ei)); 91 ei->isstring = true; 92 ei->string = dostrndup(string, len); 93 return ei; 94 } 95 96 static 97 struct expansionitem * 98 expansionitem_create_param(unsigned param) 99 { 100 struct expansionitem *ei; 101 102 ei = domalloc(sizeof(*ei)); 103 ei->isstring = false; 104 ei->param = param; 105 return ei; 106 } 107 108 static 109 void 110 expansionitem_destroy(struct expansionitem *ei) 111 { 112 if (ei->isstring) { 113 dostrfree(ei->string); 114 } 115 dofree(ei, sizeof(*ei)); 116 } 117 118 static 119 bool 120 expansionitem_eq(const struct expansionitem *ei1, 121 const struct expansionitem *ei2) 122 { 123 if (ei1->isstring != ei2->isstring) { 124 return false; 125 } 126 if (ei1->isstring) { 127 if (strcmp(ei1->string, ei2->string) != 0) { 128 return false; 129 } 130 } else { 131 if (ei1->param != ei2->param) { 132 return false; 133 } 134 } 135 return true; 136 } 137 138 static 139 struct macro * 140 macro_create(struct place *p1, const char *name, unsigned hash, 141 struct place *p2) 142 { 143 struct macro *m; 144 145 m = domalloc(sizeof(*m)); 146 m->defplace = *p1; 147 m->expansionplace = *p2; 148 m->hash = hash; 149 m->name = dostrdup(name); 150 m->hasparams = false; 151 stringarray_init(&m->params); 152 expansionitemarray_init(&m->expansion); 153 m->inuse = false; 154 return m; 155 } 156 157 DESTROYALL_ARRAY(expansionitem, ); 158 159 static 160 void 161 macro_destroy(struct macro *m) 162 { 163 expansionitemarray_destroyall(&m->expansion); 164 expansionitemarray_cleanup(&m->expansion); 165 dostrfree(m->name); 166 dofree(m, sizeof(*m)); 167 } 168 169 static 170 bool 171 macro_eq(const struct macro *m1, const struct macro *m2) 172 { 173 unsigned num1, num2, i; 174 struct expansionitem *ei1, *ei2; 175 const char *p1, *p2; 176 177 if (strcmp(m1->name, m2->name) != 0) { 178 return false; 179 } 180 181 if (m1->hasparams != m2->hasparams) { 182 return false; 183 } 184 185 num1 = expansionitemarray_num(&m1->expansion); 186 num2 = expansionitemarray_num(&m2->expansion); 187 if (num1 != num2) { 188 return false; 189 } 190 191 for (i=0; i<num1; i++) { 192 ei1 = expansionitemarray_get(&m1->expansion, i); 193 ei2 = expansionitemarray_get(&m2->expansion, i); 194 if (!expansionitem_eq(ei1, ei2)) { 195 return false; 196 } 197 } 198 199 num1 = stringarray_num(&m1->params); 200 num2 = stringarray_num(&m2->params); 201 if (num1 != num2) { 202 return false; 203 } 204 205 for (i=0; i<num1; i++) { 206 p1 = stringarray_get(&m1->params, i); 207 p2 = stringarray_get(&m2->params, i); 208 if (strcmp(p1, p2) != 0) { 209 return false; 210 } 211 } 212 return true; 213 } 214 215 //////////////////////////////////////////////////////////// 216 // macro table 217 218 /* 219 * Unless I've screwed up, this is something called Fletcher's Checksum 220 * that showed up in Dr. Dobbs in, according to my notes, May 1992. The 221 * implementation is new. 222 */ 223 static 224 unsigned 225 hashfunc(const char *s, size_t len) 226 { 227 uint16_t x1, x2, a; 228 size_t i; 229 230 x1 = (uint16_t) (len >> 16); 231 x2 = (uint16_t) (len); 232 if (x1==0) { 233 x1++; 234 } 235 if (x2==0) { 236 x2++; 237 } 238 239 for (i=0; i<len; i+=2) { 240 if (i==len-1) { 241 a = (unsigned char)s[i]; 242 /* don't run off the end of the array */ 243 } 244 else { 245 a = (unsigned char)s[i] + 246 ((uint16_t)(unsigned char)s[i+1] << 8); 247 } 248 x1 += a; 249 if (x1 < a) { 250 x1++; 251 } 252 x2 += x1; 253 if (x2 < x1) { 254 x2++; 255 } 256 } 257 258 x1 ^= 0xffff; 259 x2 ^= 0xffff; 260 return ((uint32_t)x2)*65535U + x1; 261 } 262 263 static 264 void 265 macrotable_init(void) 266 { 267 unsigned i; 268 269 macroarrayarray_init(¯os); 270 macroarrayarray_setsize(¯os, 4); 271 for (i=0; i<4; i++) { 272 macroarrayarray_set(¯os, i, NULL); 273 } 274 total_macros = 0; 275 hashmask = 0x3; 276 } 277 278 DESTROYALL_ARRAY(macro, ); 279 280 static 281 void 282 macrotable_cleanup(void) 283 { 284 struct macroarray *bucket; 285 unsigned numbuckets, i; 286 287 numbuckets = macroarrayarray_num(¯os); 288 for (i=0; i<numbuckets; i++) { 289 bucket = macroarrayarray_get(¯os, i); 290 if (bucket != NULL) { 291 macroarray_destroyall(bucket); 292 macroarray_destroy(bucket); 293 } 294 } 295 macroarrayarray_setsize(¯os, 0); 296 macroarrayarray_cleanup(¯os); 297 } 298 299 static 300 struct macro * 301 macrotable_findlen(const char *name, size_t len, bool remove) 302 { 303 unsigned hash; 304 struct macroarray *bucket; 305 struct macro *m, *m2; 306 unsigned i, num; 307 size_t mlen; 308 309 hash = hashfunc(name, len); 310 bucket = macroarrayarray_get(¯os, hash & hashmask); 311 if (bucket == NULL) { 312 return NULL; 313 } 314 num = macroarray_num(bucket); 315 for (i=0; i<num; i++) { 316 m = macroarray_get(bucket, i); 317 if (hash != m->hash) { 318 continue; 319 } 320 mlen = strlen(m->name); 321 if (len == mlen && !memcmp(name, m->name, len)) { 322 if (remove) { 323 if (i < num-1) { 324 m2 = macroarray_get(bucket, num-1); 325 macroarray_set(bucket, i, m2); 326 } 327 macroarray_setsize(bucket, num-1); 328 total_macros--; 329 } 330 return m; 331 } 332 } 333 return NULL; 334 } 335 336 static 337 struct macro * 338 macrotable_find(const char *name, bool remove) 339 { 340 return macrotable_findlen(name, strlen(name), remove); 341 } 342 343 static 344 void 345 macrotable_rehash(void) 346 { 347 struct macroarray *newbucket, *oldbucket; 348 struct macro *m; 349 unsigned newmask, tossbit; 350 unsigned numbuckets, i; 351 unsigned oldnum, j, k; 352 353 numbuckets = macroarrayarray_num(¯os); 354 macroarrayarray_setsize(¯os, numbuckets*2); 355 356 assert(hashmask == numbuckets - 1); 357 newmask = (hashmask << 1) | 1U; 358 tossbit = newmask & ~hashmask; 359 hashmask = newmask; 360 361 for (i=0; i<numbuckets; i++) { 362 newbucket = NULL; 363 oldbucket = macroarrayarray_get(¯os, i); 364 if (oldbucket == NULL) { 365 macroarrayarray_set(¯os, numbuckets + i, NULL); 366 continue; 367 } 368 oldnum = macroarray_num(oldbucket); 369 for (j=0; j<oldnum; j++) { 370 m = macroarray_get(oldbucket, j); 371 if (m->hash & tossbit) { 372 if (newbucket == NULL) { 373 newbucket = macroarray_create(); 374 } 375 macroarray_set(oldbucket, j, NULL); 376 macroarray_add(newbucket, m, NULL); 377 } 378 } 379 for (j=k=0; j<oldnum; j++) { 380 m = macroarray_get(oldbucket, j); 381 if (m != NULL) { 382 if (k < j) { 383 macroarray_set(oldbucket, k, m); 384 } 385 k++; 386 } 387 } 388 macroarray_setsize(oldbucket, k); 389 macroarrayarray_set(¯os, numbuckets + i, newbucket); 390 } 391 } 392 393 static 394 void 395 macrotable_add(struct macro *m) 396 { 397 unsigned hash; 398 struct macroarray *bucket; 399 unsigned numbuckets; 400 401 numbuckets = macroarrayarray_num(¯os); 402 if (total_macros > 0 && total_macros / numbuckets > 9) { 403 macrotable_rehash(); 404 } 405 406 hash = hashfunc(m->name, strlen(m->name)); 407 bucket = macroarrayarray_get(¯os, hash & hashmask); 408 if (bucket == NULL) { 409 bucket = macroarray_create(); 410 macroarrayarray_set(¯os, hash & hashmask, bucket); 411 } 412 macroarray_add(bucket, m, NULL); 413 total_macros++; 414 } 415 416 //////////////////////////////////////////////////////////// 417 // external macro definition interface 418 419 static 420 struct macro * 421 macro_define_common_start(struct place *p1, const char *macro, 422 struct place *p2) 423 { 424 struct macro *m; 425 unsigned hash; 426 427 if (!is_identifier(macro)) { 428 complain(p1, "Invalid macro name %s", macro); 429 complain_fail(); 430 } 431 432 hash = hashfunc(macro, strlen(macro)); 433 m = macro_create(p1, macro, hash, p2); 434 return m; 435 } 436 437 static 438 void 439 macro_define_common_end(struct macro *m) 440 { 441 struct macro *oldm; 442 bool ok; 443 444 oldm = macrotable_find(m->name, false); 445 if (oldm != NULL) { 446 ok = macro_eq(m, oldm); 447 if (ok) { 448 /* in traditional cpp this is silent */ 449 //complain(&m->defplace, 450 // "Warning: redefinition of %s", m->name); 451 //complain(&oldm->defplace, 452 // "Previous definition was here"); 453 //if (mode.werror) { 454 // complain_fail(); 455 //} 456 } else { 457 complain(&m->defplace, 458 "Warning: non-identical redefinition of %s", 459 m->name); 460 complain(&oldm->defplace, 461 "Previous definition was here"); 462 /* in traditional cpp this is not fatal */ 463 if (mode.werror) { 464 complain_fail(); 465 } 466 } 467 macro_destroy(m); 468 return; 469 } 470 macrotable_add(m); 471 } 472 473 static 474 void 475 macro_parse_parameters(struct macro *m, struct place *p, const char *params) 476 { 477 size_t len; 478 const char *s; 479 char *param; 480 481 while (params != NULL) { 482 len = strspn(params, ws); 483 params += len; 484 p->column += len; 485 s = strchr(params, ','); 486 if (s) { 487 len = s-params; 488 param = dostrndup(params, len); 489 s++; 490 } else { 491 len = strlen(params); 492 param = dostrndup(params, len); 493 } 494 notrailingws(param, strlen(param)); 495 if (!is_identifier(param)) { 496 complain(p, "Invalid macro parameter name %s", param); 497 complain_fail(); 498 } else { 499 stringarray_add(&m->params, param, NULL); 500 } 501 params = s; 502 p->column += len; 503 } 504 } 505 506 static 507 bool 508 isparam(struct macro *m, const char *name, size_t len, unsigned *num_ret) 509 { 510 unsigned num, i; 511 const char *param; 512 513 num = stringarray_num(&m->params); 514 for (i=0; i<num; i++) { 515 param = stringarray_get(&m->params, i); 516 if (strlen(param) == len && !memcmp(name, param, len)) { 517 *num_ret = i; 518 return true; 519 } 520 } 521 return false; 522 } 523 524 static 525 void 526 macro_parse_expansion(struct macro *m, const char *buf) 527 { 528 size_t blockstart, wordstart, pos; 529 struct expansionitem *ei; 530 unsigned param; 531 532 pos = blockstart = 0; 533 while (buf[pos] != '\0') { 534 pos += strspn(buf+pos, ws); 535 if (strchr(alnum, buf[pos])) { 536 wordstart = pos; 537 pos += strspn(buf+pos, alnum); 538 if (isparam(m, buf+wordstart, pos-wordstart, ¶m)) { 539 if (wordstart > blockstart) { 540 ei = expansionitem_create_stringlen( 541 buf + blockstart, 542 wordstart - blockstart); 543 expansionitemarray_add(&m->expansion, 544 ei, NULL); 545 } 546 ei = expansionitem_create_param(param); 547 expansionitemarray_add(&m->expansion, ei,NULL); 548 blockstart = pos; 549 continue; 550 } 551 continue; 552 } 553 pos++; 554 } 555 if (pos > blockstart) { 556 ei = expansionitem_create_stringlen(buf + blockstart, 557 pos - blockstart); 558 expansionitemarray_add(&m->expansion, ei, NULL); 559 } 560 } 561 562 void 563 macro_define_plain(struct place *p1, const char *macro, 564 struct place *p2, const char *expansion) 565 { 566 struct macro *m; 567 struct expansionitem *ei; 568 569 m = macro_define_common_start(p1, macro, p2); 570 ei = expansionitem_create_string(expansion); 571 expansionitemarray_add(&m->expansion, ei, NULL); 572 macro_define_common_end(m); 573 } 574 575 void 576 macro_define_params(struct place *p1, const char *macro, 577 struct place *p2, const char *params, 578 struct place *p3, const char *expansion) 579 { 580 struct macro *m; 581 582 m = macro_define_common_start(p1, macro, p3); 583 m->hasparams = true; 584 macro_parse_parameters(m, p2, params); 585 macro_parse_expansion(m, expansion); 586 macro_define_common_end(m); 587 } 588 589 void 590 macro_undef(const char *macro) 591 { 592 struct macro *m; 593 594 m = macrotable_find(macro, true); 595 if (m) { 596 macro_destroy(m); 597 } 598 } 599 600 bool 601 macro_isdefined(const char *macro) 602 { 603 struct macro *m; 604 605 m = macrotable_find(macro, false); 606 return m != NULL; 607 } 608 609 //////////////////////////////////////////////////////////// 610 // macro expansion 611 612 struct expstate { 613 bool honordefined; 614 enum { ES_NORMAL, ES_WANTLPAREN, ES_NOARG, ES_HAVEARG } state; 615 struct macro *curmacro; 616 struct stringarray args; 617 unsigned argparens; 618 619 bool tobuf; 620 char *buf; 621 size_t bufpos, bufmax; 622 }; 623 624 static struct expstate mainstate; 625 626 static void doexpand(struct expstate *es, struct place *p, 627 char *buf, size_t len); 628 629 static 630 void 631 expstate_init(struct expstate *es, bool tobuf, bool honordefined) 632 { 633 es->honordefined = honordefined; 634 es->state = ES_NORMAL; 635 es->curmacro = NULL; 636 stringarray_init(&es->args); 637 es->argparens = 0; 638 es->tobuf = tobuf; 639 es->buf = NULL; 640 es->bufpos = 0; 641 es->bufmax = 0; 642 } 643 644 static 645 void 646 expstate_cleanup(struct expstate *es) 647 { 648 assert(es->state == ES_NORMAL); 649 stringarray_cleanup(&es->args); 650 if (es->buf) { 651 dofree(es->buf, es->bufmax); 652 } 653 } 654 655 static 656 void 657 expstate_destroyargs(struct expstate *es) 658 { 659 unsigned i, num; 660 661 num = stringarray_num(&es->args); 662 for (i=0; i<num; i++) { 663 dostrfree(stringarray_get(&es->args, i)); 664 } 665 stringarray_setsize(&es->args, 0); 666 } 667 668 static 669 void 670 expand_send(struct expstate *es, struct place *p, const char *buf, size_t len) 671 { 672 size_t oldmax; 673 674 if (es->tobuf) { 675 assert(es->bufpos <= es->bufmax); 676 if (es->bufpos + len > es->bufmax) { 677 oldmax = es->bufmax; 678 if (es->bufmax == 0) { 679 es->bufmax = 64; 680 } 681 while (es->bufpos + len > es->bufmax) { 682 es->bufmax *= 2; 683 } 684 es->buf = dorealloc(es->buf, oldmax, es->bufmax); 685 } 686 memcpy(es->buf + es->bufpos, buf, len); 687 es->bufpos += len; 688 assert(es->bufpos <= es->bufmax); 689 } else { 690 output(p, buf, len); 691 } 692 } 693 694 static 695 void 696 expand_send_eof(struct expstate *es, struct place *p) 697 { 698 if (es->tobuf) { 699 expand_send(es, p, "", 1); 700 es->bufpos--; 701 } else { 702 output_eof(); 703 } 704 } 705 706 static 707 void 708 expand_newarg(struct expstate *es, char *buf, size_t len) 709 { 710 char *text; 711 712 text = dostrndup(buf, len); 713 stringarray_add(&es->args, text, NULL); 714 } 715 716 static 717 void 718 expand_appendarg(struct expstate *es, char *buf, size_t len) 719 { 720 unsigned num; 721 char *text; 722 size_t oldlen; 723 724 num = stringarray_num(&es->args); 725 assert(num > 0); 726 727 text = stringarray_get(&es->args, num - 1); 728 oldlen = strlen(text); 729 text = dorealloc(text, oldlen + 1, oldlen + len + 1); 730 memcpy(text + oldlen, buf, len); 731 text[oldlen+len] = '\0'; 732 stringarray_set(&es->args, num - 1, text); 733 } 734 735 static 736 char * 737 expand_substitute(struct place *p, struct expstate *es) 738 { 739 struct expansionitem *ei; 740 unsigned i, num; 741 size_t len; 742 char *arg; 743 char *ret; 744 unsigned numargs, numparams; 745 746 numargs = stringarray_num(&es->args); 747 numparams = stringarray_num(&es->curmacro->params); 748 749 if (numargs == 0 && numparams == 1) { 750 /* no arguments <=> one empty argument */ 751 stringarray_add(&es->args, dostrdup(""), NULL); 752 numargs++; 753 } 754 if (numargs != numparams) { 755 complain(p, "Wrong number of arguments for macro %s; " 756 "found %u, expected %u", 757 es->curmacro->name, numargs, numparams); 758 complain_fail(); 759 while (numargs < numparams) { 760 stringarray_add(&es->args, dostrdup(""), NULL); 761 numargs++; 762 } 763 } 764 765 len = 0; 766 num = expansionitemarray_num(&es->curmacro->expansion); 767 for (i=0; i<num; i++) { 768 ei = expansionitemarray_get(&es->curmacro->expansion, i); 769 if (ei->isstring) { 770 len += strlen(ei->string); 771 } else { 772 arg = stringarray_get(&es->args, ei->param); 773 len += strlen(arg); 774 } 775 } 776 777 ret = domalloc(len+1); 778 *ret = '\0'; 779 for (i=0; i<num; i++) { 780 ei = expansionitemarray_get(&es->curmacro->expansion, i); 781 if (ei->isstring) { 782 strlcat(ret, ei->string, len+1); 783 } else { 784 arg = stringarray_get(&es->args, ei->param); 785 strlcat(ret, arg, len+1); 786 } 787 } 788 789 return ret; 790 } 791 792 static 793 void 794 expand_domacro(struct expstate *es, struct place *p) 795 { 796 struct macro *m; 797 char *newbuf, *newbuf2; 798 799 if (es->curmacro == NULL) { 800 /* defined() */ 801 if (stringarray_num(&es->args) != 1) { 802 complain(p, "Too many arguments for defined()"); 803 complain_fail(); 804 expand_send(es, p, "0", 1); 805 return; 806 } 807 m = macrotable_find(stringarray_get(&es->args, 0), false); 808 expand_send(es, p, (m != NULL) ? "1" : "0", 1); 809 expstate_destroyargs(es); 810 return; 811 } 812 813 assert(es->curmacro->inuse == false); 814 es->curmacro->inuse = true; 815 816 newbuf = expand_substitute(p, es); 817 newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false); 818 dostrfree(newbuf); 819 expstate_destroyargs(es); 820 doexpand(es, p, newbuf2, strlen(newbuf2)); 821 dostrfree(newbuf2); 822 823 es->curmacro->inuse = false; 824 } 825 826 /* 827 * The traditional behavior if a function-like macro appears without 828 * arguments is to pretend it isn't a macro; that is, just emit its 829 * name. 830 */ 831 static 832 void 833 expand_missingargs(struct expstate *es, struct place *p, bool needspace) 834 { 835 if (es->curmacro == NULL) { 836 /* defined */ 837 expand_send(es, p, "defined", 7); 838 return; 839 } 840 expand_send(es, p, es->curmacro->name, strlen(es->curmacro->name)); 841 /* send a space in case we ate whitespace after the macro name */ 842 if (needspace) { 843 expand_send(es, p, " ", 1); 844 } 845 } 846 847 static 848 void 849 expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len) 850 { 851 switch (es->state) { 852 case ES_NORMAL: 853 expand_send(es, p, buf, len); 854 break; 855 case ES_WANTLPAREN: 856 break; 857 case ES_NOARG: 858 expand_newarg(es, buf, len); 859 es->state = ES_HAVEARG; 860 break; 861 case ES_HAVEARG: 862 expand_appendarg(es, buf, len); 863 break; 864 } 865 } 866 867 static 868 void 869 expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) 870 { 871 struct macro *m; 872 struct expansionitem *ei; 873 char *newbuf; 874 875 switch (es->state) { 876 case ES_NORMAL: 877 if (es->honordefined && 878 len == 7 && !memcmp(buf, "defined", 7)) { 879 es->curmacro = NULL; 880 es->state = ES_WANTLPAREN; 881 break; 882 } 883 m = macrotable_findlen(buf, len, false); 884 if (m == NULL || m->inuse) { 885 expand_send(es, p, buf, len); 886 } else if (!m->hasparams) { 887 m->inuse = true; 888 assert(expansionitemarray_num(&m->expansion) == 1); 889 ei = expansionitemarray_get(&m->expansion, 0); 890 assert(ei->isstring); 891 newbuf = macroexpand(p, ei->string, 892 strlen(ei->string), false); 893 doexpand(es, p, newbuf, strlen(newbuf)); 894 dostrfree(newbuf); 895 m->inuse = false; 896 } else { 897 es->curmacro = m; 898 es->state = ES_WANTLPAREN; 899 } 900 break; 901 case ES_WANTLPAREN: 902 if (es->curmacro != NULL) { 903 expand_missingargs(es, p, true); 904 es->state = ES_NORMAL; 905 /* try again */ 906 expand_got_word(es, p, buf, len); 907 } else { 908 /* "defined foo" means "defined(foo)" */ 909 expand_newarg(es, buf, len); 910 es->state = ES_NORMAL; 911 expand_domacro(es, p); 912 } 913 break; 914 case ES_NOARG: 915 expand_newarg(es, buf, len); 916 es->state = ES_HAVEARG; 917 break; 918 case ES_HAVEARG: 919 expand_appendarg(es, buf, len); 920 break; 921 } 922 } 923 924 static 925 void 926 expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) 927 { 928 switch (es->state) { 929 case ES_NORMAL: 930 expand_send(es, p, buf, len); 931 break; 932 case ES_WANTLPAREN: 933 es->state = ES_NOARG; 934 break; 935 case ES_NOARG: 936 expand_newarg(es, buf, len); 937 es->state = ES_HAVEARG; 938 es->argparens++; 939 break; 940 case ES_HAVEARG: 941 expand_appendarg(es, buf, len); 942 es->argparens++; 943 break; 944 } 945 } 946 947 static 948 void 949 expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) 950 { 951 switch (es->state) { 952 case ES_NORMAL: 953 expand_send(es, p, buf, len); 954 break; 955 case ES_WANTLPAREN: 956 expand_missingargs(es, p, false); 957 es->state = ES_NORMAL; 958 /* try again */ 959 expand_got_rparen(es, p, buf, len); 960 break; 961 case ES_NOARG: 962 assert(es->argparens == 0); 963 if (stringarray_num(&es->args) > 0) { 964 /* we are after a comma; enter an empty argument */ 965 expand_newarg(es, buf, 0); 966 } 967 es->state = ES_NORMAL; 968 expand_domacro(es, p); 969 break; 970 case ES_HAVEARG: 971 if (es->argparens > 0) { 972 es->argparens--; 973 expand_appendarg(es, buf, len); 974 } else { 975 es->state = ES_NORMAL; 976 expand_domacro(es, p); 977 } 978 break; 979 } 980 } 981 982 static 983 void 984 expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len) 985 { 986 switch (es->state) { 987 case ES_NORMAL: 988 expand_send(es, p, buf, len); 989 break; 990 case ES_WANTLPAREN: 991 expand_missingargs(es, p, false); 992 es->state = ES_NORMAL; 993 /* try again */ 994 expand_got_comma(es, p, buf, len); 995 break; 996 case ES_NOARG: 997 assert(es->argparens == 0); 998 expand_newarg(es, buf, 0); 999 break; 1000 case ES_HAVEARG: 1001 if (es->argparens > 0) { 1002 expand_appendarg(es, buf, len); 1003 } else { 1004 es->state = ES_NOARG; 1005 } 1006 break; 1007 } 1008 } 1009 1010 static 1011 void 1012 expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len) 1013 { 1014 switch (es->state) { 1015 case ES_NORMAL: 1016 expand_send(es, p, buf, len); 1017 break; 1018 case ES_WANTLPAREN: 1019 expand_missingargs(es, p, false); 1020 es->state = ES_NORMAL; 1021 /* try again */ 1022 expand_got_other(es, p, buf, len); 1023 break; 1024 case ES_NOARG: 1025 expand_newarg(es, buf, len); 1026 es->state = ES_HAVEARG; 1027 break; 1028 case ES_HAVEARG: 1029 expand_appendarg(es, buf, len); 1030 break; 1031 } 1032 } 1033 1034 static 1035 void 1036 expand_got_eof(struct expstate *es, struct place *p) 1037 { 1038 switch (es->state) { 1039 case ES_NORMAL: 1040 break; 1041 case ES_WANTLPAREN: 1042 expand_missingargs(es, p, false); 1043 break; 1044 case ES_NOARG: 1045 case ES_HAVEARG: 1046 if (es->curmacro) { 1047 complain(p, "Unclosed argument list for macro %s", 1048 es->curmacro->name); 1049 } else { 1050 complain(p, "Unclosed argument list for defined()"); 1051 } 1052 complain_fail(); 1053 expstate_destroyargs(es); 1054 break; 1055 } 1056 expand_send_eof(es, p); 1057 es->state = ES_NORMAL; 1058 es->curmacro = NULL; 1059 es->argparens = 0; 1060 } 1061 1062 static 1063 void 1064 doexpand(struct expstate *es, struct place *p, char *buf, size_t len) 1065 { 1066 char *s; 1067 size_t x; 1068 bool inquote = false; 1069 char quote = '\0'; 1070 1071 while (len > 0) { 1072 x = strspn(buf, ws); 1073 if (x > len) { 1074 /* XXX gross, need strnspn */ 1075 x = len; 1076 } 1077 1078 if (x > 0) { 1079 expand_got_ws(es, p, buf, x); 1080 buf += x; 1081 len -= x; 1082 continue; 1083 } 1084 1085 x = strspn(buf, alnum); 1086 if (x > len) { 1087 /* XXX gross, need strnspn */ 1088 x = len; 1089 } 1090 1091 if (!inquote && x > 0) { 1092 expand_got_word(es, p, buf, x); 1093 buf += x; 1094 len -= x; 1095 continue; 1096 } 1097 1098 if (!inquote && len > 1 && buf[0] == '/' && buf[1] == '*') { 1099 s = strstr(buf, "*/"); 1100 if (s) { 1101 x = s - buf; 1102 } else { 1103 x = len; 1104 } 1105 expand_got_ws(es, p, buf, x); 1106 buf += x; 1107 len -= x; 1108 continue; 1109 } 1110 1111 if (!inquote && buf[0] == '(') { 1112 expand_got_lparen(es, p, buf, 1); 1113 buf++; 1114 len--; 1115 continue; 1116 } 1117 1118 if (!inquote && buf[0] == ')') { 1119 expand_got_rparen(es, p, buf, 1); 1120 buf++; 1121 len--; 1122 continue; 1123 } 1124 1125 if (!inquote && buf[0] == ',') { 1126 expand_got_comma(es, p, buf, 1); 1127 buf++; 1128 len--; 1129 continue; 1130 } 1131 1132 if (len > 1 && buf[0] == '\\' && 1133 (buf[1] == '"' || buf[1] == '\'')) { 1134 expand_got_other(es, p, buf, 2); 1135 buf += 2; 1136 len -= 2; 1137 continue; 1138 } 1139 if (!inquote && (buf[0] == '"' || buf[0] == '\'')) { 1140 inquote = true; 1141 quote = buf[0]; 1142 } else if (inquote && buf[0] == quote) { 1143 inquote = false; 1144 } 1145 1146 expand_got_other(es, p, buf, 1); 1147 buf++; 1148 len--; 1149 } 1150 } 1151 1152 char * 1153 macroexpand(struct place *p, char *buf, size_t len, bool honordefined) 1154 { 1155 struct expstate es; 1156 char *ret; 1157 1158 expstate_init(&es, true, honordefined); 1159 doexpand(&es, p, buf, len); 1160 expand_got_eof(&es, p); 1161 1162 /* trim to fit, so the malloc debugging won't complain */ 1163 es.buf = dorealloc(es.buf, es.bufmax, strlen(es.buf) + 1); 1164 1165 ret = es.buf; 1166 es.buf = NULL; 1167 es.bufpos = es.bufmax = 0; 1168 1169 expstate_cleanup(&es); 1170 1171 return ret; 1172 } 1173 1174 void 1175 macro_sendline(struct place *p, char *buf, size_t len) 1176 { 1177 doexpand(&mainstate, p, buf, len); 1178 output(p, "\n", 1); 1179 } 1180 1181 void 1182 macro_sendeof(struct place *p) 1183 { 1184 expand_got_eof(&mainstate, p); 1185 } 1186 1187 //////////////////////////////////////////////////////////// 1188 // module initialization 1189 1190 void 1191 macros_init(void) 1192 { 1193 macrotable_init(); 1194 expstate_init(&mainstate, false, false); 1195 } 1196 1197 void 1198 macros_cleanup(void) 1199 { 1200 expstate_cleanup(&mainstate); 1201 macrotable_cleanup(); 1202 } 1203