github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/cmd/cc/macbody (about) 1 // Inferno utils/cc/macbody 2 // http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 #define VARMAC 0x80 32 33 int32 34 getnsn(void) 35 { 36 int32 n; 37 int c; 38 39 c = getnsc(); 40 if(c < '0' || c > '9') 41 return -1; 42 n = 0; 43 while(c >= '0' && c <= '9') { 44 n = n*10 + c-'0'; 45 c = getc(); 46 } 47 unget(c); 48 return n; 49 } 50 51 Sym* 52 getsym(void) 53 { 54 int c; 55 char *cp; 56 57 c = getnsc(); 58 if(!isalpha(c) && c != '_' && c < 0x80) { 59 unget(c); 60 return S; 61 } 62 for(cp = symb;;) { 63 if(cp <= symb+NSYMB-4) 64 *cp++ = c; 65 c = getc(); 66 if(isalnum(c) || c == '_' || c >= 0x80) 67 continue; 68 unget(c); 69 break; 70 } 71 *cp = 0; 72 if(cp > symb+NSYMB-4) 73 yyerror("symbol too large: %s", symb); 74 return lookup(); 75 } 76 77 Sym* 78 getsymdots(int *dots) 79 { 80 int c; 81 Sym *s; 82 83 s = getsym(); 84 if(s != S) 85 return s; 86 87 c = getnsc(); 88 if(c != '.'){ 89 unget(c); 90 return S; 91 } 92 if(getc() != '.' || getc() != '.') 93 yyerror("bad dots in macro"); 94 *dots = 1; 95 return slookup("__VA_ARGS__"); 96 } 97 98 int 99 getcom(void) 100 { 101 int c; 102 103 for(;;) { 104 c = getnsc(); 105 if(c != '/') 106 break; 107 c = getc(); 108 if(c == '/') { 109 while(c != '\n') 110 c = getc(); 111 break; 112 } 113 if(c != '*') 114 break; 115 c = getc(); 116 for(;;) { 117 if(c == '*') { 118 c = getc(); 119 if(c != '/') 120 continue; 121 c = getc(); 122 break; 123 } 124 if(c == '\n') { 125 yyerror("comment across newline"); 126 break; 127 } 128 c = getc(); 129 } 130 if(c == '\n') 131 break; 132 } 133 return c; 134 } 135 136 void 137 dodefine(char *cp) 138 { 139 Sym *s; 140 char *p; 141 int32 l; 142 143 ensuresymb(strlen(cp)); 144 strcpy(symb, cp); 145 p = strchr(symb, '='); 146 if(p) { 147 *p++ = 0; 148 s = lookup(); 149 l = strlen(p) + 2; /* +1 null, +1 nargs */ 150 s->macro = alloc(l); 151 strcpy(s->macro+1, p); 152 } else { 153 s = lookup(); 154 s->macro = "\0001"; /* \000 is nargs */ 155 } 156 if(debug['m']) 157 print("#define (-D) %s %s\n", s->name, s->macro+1); 158 } 159 160 struct 161 { 162 char *macname; 163 void (*macf)(void); 164 } mactab[] = 165 { 166 "ifdef", 0, /* macif(0) */ 167 "ifndef", 0, /* macif(1) */ 168 "else", 0, /* macif(2) */ 169 170 "line", maclin, 171 "define", macdef, 172 "include", macinc, 173 "undef", macund, 174 175 "pragma", macprag, 176 "endif", macend, 177 0 178 }; 179 180 void 181 domacro(void) 182 { 183 int i; 184 Sym *s; 185 186 s = getsym(); 187 if(s == S) 188 s = slookup("endif"); 189 for(i=0; mactab[i].macname; i++) 190 if(strcmp(s->name, mactab[i].macname) == 0) { 191 if(mactab[i].macf) 192 (*mactab[i].macf)(); 193 else 194 macif(i); 195 return; 196 } 197 yyerror("unknown #: %s", s->name); 198 macend(); 199 } 200 201 void 202 macund(void) 203 { 204 Sym *s; 205 206 s = getsym(); 207 macend(); 208 if(s == S) { 209 yyerror("syntax in #undef"); 210 return; 211 } 212 s->macro = 0; 213 } 214 215 #define NARG 25 216 void 217 macdef(void) 218 { 219 Sym *s, *a; 220 char *args[NARG], *np, *base; 221 int n, i, c, len, dots; 222 int ischr; 223 224 s = getsym(); 225 if(s == S) 226 goto bad; 227 if(s->macro) 228 yyerror("macro redefined: %s", s->name); 229 c = getc(); 230 n = -1; 231 dots = 0; 232 if(c == '(') { 233 n++; 234 c = getnsc(); 235 if(c != ')') { 236 unget(c); 237 for(;;) { 238 a = getsymdots(&dots); 239 if(a == S) 240 goto bad; 241 if(n >= NARG) { 242 yyerror("too many arguments in #define: %s", s->name); 243 goto bad; 244 } 245 args[n++] = a->name; 246 c = getnsc(); 247 if(c == ')') 248 break; 249 if(c != ',' || dots) 250 goto bad; 251 } 252 } 253 c = getc(); 254 } 255 if(isspace(c)) 256 if(c != '\n') 257 c = getnsc(); 258 base = hunk; 259 len = 1; 260 ischr = 0; 261 for(;;) { 262 if(isalpha(c) || c == '_') { 263 np = symb; 264 *np++ = c; 265 c = getc(); 266 while(isalnum(c) || c == '_') { 267 *np++ = c; 268 c = getc(); 269 } 270 *np = 0; 271 for(i=0; i<n; i++) 272 if(strcmp(symb, args[i]) == 0) 273 break; 274 if(i >= n) { 275 i = strlen(symb); 276 base = allocn(base, len, i); 277 memcpy(base+len, symb, i); 278 len += i; 279 continue; 280 } 281 base = allocn(base, len, 2); 282 base[len++] = '#'; 283 base[len++] = 'a' + i; 284 continue; 285 } 286 if(ischr){ 287 if(c == '\\'){ 288 base = allocn(base, len, 1); 289 base[len++] = c; 290 c = getc(); 291 }else if(c == ischr) 292 ischr = 0; 293 }else{ 294 if(c == '"' || c == '\''){ 295 base = allocn(base, len, 1); 296 base[len++] = c; 297 ischr = c; 298 c = getc(); 299 continue; 300 } 301 if(c == '/') { 302 c = getc(); 303 if(c == '/'){ 304 c = getc(); 305 for(;;) { 306 if(c == '\n') 307 break; 308 c = getc(); 309 } 310 continue; 311 } 312 if(c == '*'){ 313 c = getc(); 314 for(;;) { 315 if(c == '*') { 316 c = getc(); 317 if(c != '/') 318 continue; 319 c = getc(); 320 break; 321 } 322 if(c == '\n') { 323 yyerror("comment and newline in define: %s", s->name); 324 break; 325 } 326 c = getc(); 327 } 328 continue; 329 } 330 base = allocn(base, len, 1); 331 base[len++] = '/'; 332 continue; 333 } 334 } 335 if(c == '\\') { 336 c = getc(); 337 if(c == '\n') { 338 c = getc(); 339 continue; 340 } 341 else if(c == '\r') { 342 c = getc(); 343 if(c == '\n') { 344 c = getc(); 345 continue; 346 } 347 } 348 base = allocn(base, len, 1); 349 base[len++] = '\\'; 350 continue; 351 } 352 if(c == '\n') 353 break; 354 if(c == '#') 355 if(n > 0) { 356 base = allocn(base, len, 1); 357 base[len++] = c; 358 } 359 base = allocn(base, len, 1); 360 base[len++] = c; 361 c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)); 362 if(c == '\n') 363 lineno++; 364 if(c == -1) { 365 yyerror("eof in a macro: %s", s->name); 366 break; 367 } 368 } 369 do { 370 base = allocn(base, len, 1); 371 base[len++] = 0; 372 } while(len & 3); 373 374 *base = n+1; 375 if(dots) 376 *base |= VARMAC; 377 s->macro = base; 378 if(debug['m']) 379 print("#define %s %s\n", s->name, s->macro+1); 380 return; 381 382 bad: 383 if(s == S) 384 yyerror("syntax in #define"); 385 else 386 yyerror("syntax in #define: %s", s->name); 387 macend(); 388 } 389 390 void 391 macexpand(Sym *s, char *b) 392 { 393 char buf[2000]; 394 int n, l, c, nargs; 395 char *arg[NARG], *cp, *ob, *ecp, dots; 396 397 ob = b; 398 if(*s->macro == 0) { 399 strcpy(b, s->macro+1); 400 if(debug['m']) 401 print("#expand %s %s\n", s->name, ob); 402 return; 403 } 404 405 nargs = (char)(*s->macro & ~VARMAC) - 1; 406 dots = *s->macro & VARMAC; 407 408 c = getnsc(); 409 if(c != '(') 410 goto bad; 411 n = 0; 412 c = getc(); 413 if(c != ')') { 414 unget(c); 415 l = 0; 416 cp = buf; 417 ecp = cp + sizeof(buf)-4; 418 arg[n++] = cp; 419 for(;;) { 420 if(cp >= ecp) 421 goto toobig; 422 c = getc(); 423 if(c == '"') 424 for(;;) { 425 if(cp >= ecp) 426 goto toobig; 427 *cp++ = c; 428 c = getc(); 429 if(c == '\\') { 430 *cp++ = c; 431 c = getc(); 432 continue; 433 } 434 if(c == '\n') 435 goto bad; 436 if(c == '"') 437 break; 438 } 439 if(c == '\'') 440 for(;;) { 441 if(cp >= ecp) 442 goto toobig; 443 *cp++ = c; 444 c = getc(); 445 if(c == '\\') { 446 *cp++ = c; 447 c = getc(); 448 continue; 449 } 450 if(c == '\n') 451 goto bad; 452 if(c == '\'') 453 break; 454 } 455 if(c == '/') { 456 c = getc(); 457 switch(c) { 458 case '*': 459 for(;;) { 460 c = getc(); 461 if(c == '*') { 462 c = getc(); 463 if(c == '/') 464 break; 465 } 466 } 467 *cp++ = ' '; 468 continue; 469 case '/': 470 while((c = getc()) != '\n') 471 ; 472 break; 473 default: 474 unget(c); 475 c = '/'; 476 } 477 } 478 if(l == 0) { 479 if(c == ',') { 480 if(n == nargs && dots) { 481 *cp++ = ','; 482 continue; 483 } 484 *cp++ = 0; 485 arg[n++] = cp; 486 if(n > nargs) 487 break; 488 continue; 489 } 490 if(c == ')') 491 break; 492 } 493 if(c == '\n') 494 c = ' '; 495 *cp++ = c; 496 if(c == '(') 497 l++; 498 if(c == ')') 499 l--; 500 } 501 *cp = 0; 502 } 503 if(n != nargs) { 504 yyerror("argument mismatch expanding: %s", s->name); 505 *b = 0; 506 return; 507 } 508 cp = s->macro+1; 509 for(;;) { 510 c = *cp++; 511 if(c == '\n') 512 c = ' '; 513 if(c != '#') { 514 *b++ = c; 515 if(c == 0) 516 break; 517 continue; 518 } 519 c = *cp++; 520 if(c == 0) 521 goto bad; 522 if(c == '#') { 523 *b++ = c; 524 continue; 525 } 526 c -= 'a'; 527 if(c < 0 || c >= n) 528 continue; 529 strcpy(b, arg[c]); 530 b += strlen(arg[c]); 531 } 532 *b = 0; 533 if(debug['m']) 534 print("#expand %s %s\n", s->name, ob); 535 return; 536 537 bad: 538 yyerror("syntax in macro expansion: %s", s->name); 539 *b = 0; 540 return; 541 542 toobig: 543 yyerror("too much text in macro expansion: %s", s->name); 544 *b = 0; 545 } 546 547 void 548 macinc(void) 549 { 550 int c0, c, i, f; 551 char str[STRINGSZ], *hp; 552 553 c0 = getnsc(); 554 if(c0 != '"') { 555 c = c0; 556 if(c0 != '<') 557 goto bad; 558 c0 = '>'; 559 } 560 for(hp = str;;) { 561 c = getc(); 562 if(c == c0) 563 break; 564 if(c == '\n') 565 goto bad; 566 *hp++ = c; 567 } 568 *hp = 0; 569 570 c = getcom(); 571 if(c != '\n') 572 goto bad; 573 574 f = -1; 575 for(i=0; i<ninclude; i++) { 576 if(i == 0 && c0 == '>') 577 continue; 578 ensuresymb(strlen(include[i])+strlen(str)+2); 579 strcpy(symb, include[i]); 580 strcat(symb, "/"); 581 if(strcmp(symb, "./") == 0) 582 symb[0] = 0; 583 strcat(symb, str); 584 f = open(symb, OREAD); 585 if(f >= 0) 586 break; 587 } 588 if(f < 0) 589 strcpy(symb, str); 590 c = strlen(symb) + 1; 591 hp = alloc(c); 592 memcpy(hp, symb, c); 593 newio(); 594 pushio(); 595 newfile(hp, f); 596 return; 597 598 bad: 599 unget(c); 600 yyerror("syntax in #include"); 601 macend(); 602 } 603 604 void 605 maclin(void) 606 { 607 char *cp; 608 int c; 609 int32 n; 610 611 n = getnsn(); 612 c = getc(); 613 if(n < 0) 614 goto bad; 615 616 for(;;) { 617 if(c == ' ' || c == '\t') { 618 c = getc(); 619 continue; 620 } 621 if(c == '"') 622 break; 623 if(c == '\n') { 624 strcpy(symb, "<noname>"); 625 goto nn; 626 } 627 goto bad; 628 } 629 cp = symb; 630 for(;;) { 631 c = getc(); 632 if(c == '"') 633 break; 634 *cp++ = c; 635 } 636 *cp = 0; 637 c = getcom(); 638 if(c != '\n') 639 goto bad; 640 641 nn: 642 c = strlen(symb) + 1; 643 cp = alloc(c); 644 memcpy(cp, symb, c); 645 linklinehist(ctxt, lineno, cp, n); 646 return; 647 648 bad: 649 unget(c); 650 yyerror("syntax in #line"); 651 macend(); 652 } 653 654 void 655 macif(int f) 656 { 657 int c, l, bol; 658 Sym *s; 659 660 if(f == 2) 661 goto skip; 662 s = getsym(); 663 if(s == S) 664 goto bad; 665 if(getcom() != '\n') 666 goto bad; 667 if((s->macro != 0) ^ f) 668 return; 669 670 skip: 671 bol = 1; 672 l = 0; 673 for(;;) { 674 c = getc(); 675 if(c != '#') { 676 if(!isspace(c)) 677 bol = 0; 678 if(c == '\n') 679 bol = 1; 680 continue; 681 } 682 if(!bol) 683 continue; 684 s = getsym(); 685 if(s == S) 686 continue; 687 if(strcmp(s->name, "endif") == 0) { 688 if(l) { 689 l--; 690 continue; 691 } 692 macend(); 693 return; 694 } 695 if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) { 696 l++; 697 continue; 698 } 699 if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) { 700 macend(); 701 return; 702 } 703 } 704 705 bad: 706 yyerror("syntax in #if(n)def"); 707 macend(); 708 } 709 710 void 711 macprag(void) 712 { 713 Sym *s; 714 int c0, c; 715 char *hp; 716 717 s = getsym(); 718 719 if(s && strcmp(s->name, "lib") == 0) 720 goto praglib; 721 if(s && strcmp(s->name, "pack") == 0) { 722 pragpack(); 723 return; 724 } 725 if(s && strcmp(s->name, "fpround") == 0) { 726 pragfpround(); 727 return; 728 } 729 if(s && strcmp(s->name, "textflag") == 0) { 730 pragtextflag(); 731 return; 732 } 733 if(s && strcmp(s->name, "dataflag") == 0) { 734 pragdataflag(); 735 return; 736 } 737 if(s && strcmp(s->name, "varargck") == 0) { 738 pragvararg(); 739 return; 740 } 741 if(s && strcmp(s->name, "incomplete") == 0) { 742 pragincomplete(); 743 return; 744 } 745 if(s && (strncmp(s->name, "cgo_", 4) == 0 || strncmp(s->name, "dyn", 3) == 0)) { 746 pragcgo(s->name); 747 return; 748 } 749 while(getnsc() != '\n') 750 ; 751 return; 752 753 praglib: 754 c0 = getnsc(); 755 if(c0 != '"') { 756 c = c0; 757 if(c0 != '<') 758 goto bad; 759 c0 = '>'; 760 } 761 for(hp = symb;;) { 762 c = getc(); 763 if(c == c0) 764 break; 765 if(c == '\n') 766 goto bad; 767 *hp++ = c; 768 } 769 *hp = 0; 770 c = getcom(); 771 if(c != '\n') 772 goto bad; 773 774 /* 775 * put pragma-line in as a funny history 776 */ 777 c = strlen(symb) + 1; 778 hp = alloc(c); 779 memcpy(hp, symb, c); 780 781 linklinehist(ctxt, lineno, hp, -1); 782 return; 783 784 bad: 785 unget(c); 786 yyerror("syntax in #pragma lib"); 787 macend(); 788 } 789 790 void 791 macend(void) 792 { 793 int c; 794 795 for(;;) { 796 c = getnsc(); 797 if(c < 0 || c == '\n') 798 return; 799 } 800 }