1#define VARMAC 0x80 2 3long 4getnsn(void) 5{ 6 long n; 7 int c; 8 9 c = getnsc(); 10 if(c < '0' || c > '9') 11 return -1; 12 n = 0; 13 while(c >= '0' && c <= '9') { 14 n = n*10 + c-'0'; 15 c = getc(); 16 } 17 unget(c); 18 return n; 19} 20 21Sym* 22getsym(void) 23{ 24 int c; 25 char *cp; 26 27 c = getnsc(); 28 if(!isalpha(c) && c != '_' && c < Runeself) { 29 unget(c); 30 return S; 31 } 32 for(cp = symb;;) { 33 if(cp <= symb+NSYMB-4) 34 *cp++ = c; 35 c = getc(); 36 if(isalnum(c) || c == '_' || c >= Runeself) 37 continue; 38 unget(c); 39 break; 40 } 41 *cp = 0; 42 if(cp > symb+NSYMB-4) 43 yyerror("symbol too large: %s", symb); 44 return lookup(); 45} 46 47Sym* 48getsymdots(int *dots) 49{ 50 int c; 51 Sym *s; 52 53 s = getsym(); 54 if(s != S) 55 return s; 56 57 c = getnsc(); 58 if(c != '.'){ 59 unget(c); 60 return S; 61 } 62 if(getc() != '.' || getc() != '.') 63 yyerror("bad dots in macro"); 64 *dots = 1; 65 return slookup("__VA_ARGS__"); 66} 67 68int 69getcom(void) 70{ 71 int c; 72 73 for(;;) { 74 c = getnsc(); 75 if(c != '/') 76 break; 77 c = getc(); 78 if(c == '/') { 79 while(c != '\n') 80 c = getc(); 81 break; 82 } 83 if(c != '*') 84 break; 85 c = getc(); 86 for(;;) { 87 if(c == '*') { 88 c = getc(); 89 if(c != '/') 90 continue; 91 c = getc(); 92 break; 93 } 94 if(c == '\n') { 95 yyerror("comment across newline"); 96 break; 97 } 98 c = getc(); 99 } 100 if(c == '\n') 101 break; 102 } 103 return c; 104} 105 106void 107dodefine(char *cp) 108{ 109 Sym *s; 110 char *p; 111 long l; 112 113 strcpy(symb, cp); 114 p = strchr(symb, '='); 115 if(p) { 116 *p++ = 0; 117 s = lookup(); 118 l = strlen(p) + 2; /* +1 null, +1 nargs */ 119 while(l & 3) 120 l++; 121 while(nhunk < l) 122 gethunk(); 123 *hunk = 0; 124 strcpy(hunk+1, p); 125 s->macro = hunk; 126 hunk += l; 127 nhunk -= l; 128 } else { 129 s = lookup(); 130 s->macro = "\0001"; /* \000 is nargs */ 131 } 132 if(debug['m']) 133 print("#define (-D) %s %s\n", s->name, s->macro+1); 134} 135 136struct 137{ 138 char *macname; 139 void (*macf)(void); 140} mactab[] = 141{ 142 "ifdef", 0, /* macif(0) */ 143 "ifndef", 0, /* macif(1) */ 144 "else", 0, /* macif(2) */ 145 146 "line", maclin, 147 "define", macdef, 148 "include", macinc, 149 "undef", macund, 150 151 "pragma", macprag, 152 "endif", macend, 153 0 154}; 155 156void 157domacro(void) 158{ 159 int i; 160 Sym *s; 161 162 s = getsym(); 163 if(s == S) 164 s = slookup("endif"); 165 for(i=0; mactab[i].macname; i++) 166 if(strcmp(s->name, mactab[i].macname) == 0) { 167 if(mactab[i].macf) 168 (*mactab[i].macf)(); 169 else 170 macif(i); 171 return; 172 } 173 yyerror("unknown #: %s", s->name); 174 macend(); 175} 176 177void 178macund(void) 179{ 180 Sym *s; 181 182 s = getsym(); 183 macend(); 184 if(s == S) { 185 yyerror("syntax in #undef"); 186 return; 187 } 188 s->macro = 0; 189} 190 191#define NARG 25 192void 193macdef(void) 194{ 195 Sym *s, *a; 196 char *args[NARG], *np, *base; 197 int n, i, c, len, dots; 198 int ischr; 199 200 s = getsym(); 201 if(s == S) 202 goto bad; 203 if(s->macro) 204 yyerror("macro redefined: %s", s->name); 205 c = getc(); 206 n = -1; 207 dots = 0; 208 if(c == '(') { 209 n++; 210 c = getnsc(); 211 if(c != ')') { 212 unget(c); 213 for(;;) { 214 a = getsymdots(&dots); 215 if(a == S) 216 goto bad; 217 if(n >= NARG) { 218 yyerror("too many arguments in #define: %s", s->name); 219 goto bad; 220 } 221 args[n++] = a->name; 222 c = getnsc(); 223 if(c == ')') 224 break; 225 if(c != ',' || dots) 226 goto bad; 227 } 228 } 229 c = getc(); 230 } 231 if(isspace(c)) 232 if(c != '\n') 233 c = getnsc(); 234 base = hunk; 235 len = 1; 236 ischr = 0; 237 for(;;) { 238 if(isalpha(c) || c == '_') { 239 np = symb; 240 *np++ = c; 241 c = getc(); 242 while(isalnum(c) || c == '_') { 243 *np++ = c; 244 c = getc(); 245 } 246 *np = 0; 247 for(i=0; i<n; i++) 248 if(strcmp(symb, args[i]) == 0) 249 break; 250 if(i >= n) { 251 i = strlen(symb); 252 base = allocn(base, len, i); 253 memcpy(base+len, symb, i); 254 len += i; 255 continue; 256 } 257 base = allocn(base, len, 2); 258 base[len++] = '#'; 259 base[len++] = 'a' + i; 260 continue; 261 } 262 if(ischr){ 263 if(c == '\\'){ 264 base = allocn(base, len, 1); 265 base[len++] = c; 266 c = getc(); 267 }else if(c == ischr) 268 ischr = 0; 269 }else{ 270 if(c == '"' || c == '\''){ 271 base = allocn(base, len, 1); 272 base[len++] = c; 273 ischr = c; 274 c = getc(); 275 continue; 276 } 277 if(c == '/') { 278 c = getc(); 279 if(c == '/'){ 280 c = getc(); 281 for(;;) { 282 if(c == '\n') 283 break; 284 c = getc(); 285 } 286 continue; 287 } 288 if(c == '*'){ 289 c = getc(); 290 for(;;) { 291 if(c == '*') { 292 c = getc(); 293 if(c != '/') 294 continue; 295 c = getc(); 296 break; 297 } 298 if(c == '\n') { 299 yyerror("comment and newline in define: %s", s->name); 300 break; 301 } 302 c = getc(); 303 } 304 continue; 305 } 306 base = allocn(base, len, 1); 307 base[len++] = '/'; 308 continue; 309 } 310 } 311 if(c == '\\') { 312 c = getc(); 313 if(c == '\n') { 314 c = getc(); 315 continue; 316 } 317 else if(c == '\r') { 318 c = getc(); 319 if(c == '\n') { 320 c = getc(); 321 continue; 322 } 323 } 324 base = allocn(base, len, 1); 325 base[len++] = '\\'; 326 continue; 327 } 328 if(c == '\n') 329 break; 330 if(c == '#') 331 if(n > 0) { 332 base = allocn(base, len, 1); 333 base[len++] = c; 334 } 335 base = allocn(base, len, 1); 336 base[len++] = c; 337 c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)); 338 if(c == '\n') 339 lineno++; 340 if(c == -1) { 341 yyerror("eof in a macro: %s", s->name); 342 break; 343 } 344 } 345 do { 346 base = allocn(base, len, 1); 347 base[len++] = 0; 348 } while(len & 3); 349 350 *base = n+1; 351 if(dots) 352 *base |= VARMAC; 353 s->macro = base; 354 if(debug['m']) 355 print("#define %s %s\n", s->name, s->macro+1); 356 return; 357 358bad: 359 if(s == S) 360 yyerror("syntax in #define"); 361 else 362 yyerror("syntax in #define: %s", s->name); 363 macend(); 364} 365 366void 367macexpand(Sym *s, char *b) 368{ 369 char buf[2000]; 370 int n, l, c, nargs; 371 char *arg[NARG], *cp, *ob, *ecp, dots; 372 373 ob = b; 374 if(*s->macro == 0) { 375 strcpy(b, s->macro+1); 376 if(debug['m']) 377 print("#expand %s %s\n", s->name, ob); 378 return; 379 } 380 381 nargs = (char)(*s->macro & ~VARMAC) - 1; 382 dots = *s->macro & VARMAC; 383 384 c = getnsc(); 385 if(c != '(') 386 goto bad; 387 n = 0; 388 c = getc(); 389 if(c != ')') { 390 unget(c); 391 l = 0; 392 cp = buf; 393 ecp = cp + sizeof(buf)-4; 394 arg[n++] = cp; 395 for(;;) { 396 if(cp >= ecp) 397 goto toobig; 398 c = getc(); 399 if(c == '"') 400 for(;;) { 401 if(cp >= ecp) 402 goto toobig; 403 *cp++ = c; 404 c = getc(); 405 if(c == '\\') { 406 *cp++ = c; 407 c = getc(); 408 continue; 409 } 410 if(c == '\n') 411 goto bad; 412 if(c == '"') 413 break; 414 } 415 if(c == '\'') 416 for(;;) { 417 if(cp >= ecp) 418 goto toobig; 419 *cp++ = c; 420 c = getc(); 421 if(c == '\\') { 422 *cp++ = c; 423 c = getc(); 424 continue; 425 } 426 if(c == '\n') 427 goto bad; 428 if(c == '\'') 429 break; 430 } 431 if(c == '/') { 432 c = getc(); 433 switch(c) { 434 case '*': 435 for(;;) { 436 c = getc(); 437 if(c == '*') { 438 c = getc(); 439 if(c == '/') 440 break; 441 } 442 } 443 *cp++ = ' '; 444 continue; 445 case '/': 446 while((c = getc()) != '\n') 447 ; 448 break; 449 default: 450 unget(c); 451 c = '/'; 452 } 453 } 454 if(l == 0) { 455 if(c == ',') { 456 if(n == nargs && dots) { 457 *cp++ = ','; 458 continue; 459 } 460 *cp++ = 0; 461 arg[n++] = cp; 462 if(n > nargs) 463 break; 464 continue; 465 } 466 if(c == ')') 467 break; 468 } 469 if(c == '\n') 470 c = ' '; 471 *cp++ = c; 472 if(c == '(') 473 l++; 474 if(c == ')') 475 l--; 476 } 477 *cp = 0; 478 } 479 if(n != nargs) { 480 yyerror("argument mismatch expanding: %s", s->name); 481 *b = 0; 482 return; 483 } 484 cp = s->macro+1; 485 for(;;) { 486 c = *cp++; 487 if(c == '\n') 488 c = ' '; 489 if(c != '#') { 490 *b++ = c; 491 if(c == 0) 492 break; 493 continue; 494 } 495 c = *cp++; 496 if(c == 0) 497 goto bad; 498 if(c == '#') { 499 *b++ = c; 500 continue; 501 } 502 c -= 'a'; 503 if(c < 0 || c >= n) 504 continue; 505 strcpy(b, arg[c]); 506 b += strlen(arg[c]); 507 } 508 *b = 0; 509 if(debug['m']) 510 print("#expand %s %s\n", s->name, ob); 511 return; 512 513bad: 514 yyerror("syntax in macro expansion: %s", s->name); 515 *b = 0; 516 return; 517 518toobig: 519 yyerror("too much text in macro expansion: %s", s->name); 520 *b = 0; 521} 522 523void 524macinc(void) 525{ 526 int c0, c, i, f; 527 char str[STRINGSZ], *hp; 528 529 c0 = getnsc(); 530 if(c0 != '"') { 531 c = c0; 532 if(c0 != '<') 533 goto bad; 534 c0 = '>'; 535 } 536 for(hp = str;;) { 537 c = getc(); 538 if(c == c0) 539 break; 540 if(c == '\n') 541 goto bad; 542 *hp++ = c; 543 } 544 *hp = 0; 545 546 c = getcom(); 547 if(c != '\n') 548 goto bad; 549 550 f = -1; 551 for(i=0; i<ninclude; i++) { 552 if(i == 0 && c0 == '>') 553 continue; 554 strcpy(symb, include[i]); 555 strcat(symb, "/"); 556 if(strcmp(symb, "./") == 0) 557 symb[0] = 0; 558 strcat(symb, str); 559 f = open(symb, 0); 560 if(f >= 0) 561 break; 562 } 563 if(f < 0) 564 strcpy(symb, str); 565 c = strlen(symb) + 1; 566 while(c & 3) 567 c++; 568 while(nhunk < c) 569 gethunk(); 570 hp = hunk; 571 memcpy(hunk, symb, c); 572 nhunk -= c; 573 hunk += c; 574 newio(); 575 pushio(); 576 newfile(hp, f); 577 return; 578 579bad: 580 unget(c); 581 yyerror("syntax in #include"); 582 macend(); 583} 584 585void 586maclin(void) 587{ 588 char *cp; 589 int c; 590 long n; 591 592 n = getnsn(); 593 c = getc(); 594 if(n < 0) 595 goto bad; 596 597 for(;;) { 598 if(c == ' ' || c == '\t') { 599 c = getc(); 600 continue; 601 } 602 if(c == '"') 603 break; 604 if(c == '\n') { 605 strcpy(symb, "<noname>"); 606 goto nn; 607 } 608 goto bad; 609 } 610 cp = symb; 611 for(;;) { 612 c = getc(); 613 if(c == '"') 614 break; 615 *cp++ = c; 616 } 617 *cp = 0; 618 c = getcom(); 619 if(c != '\n') 620 goto bad; 621 622nn: 623 c = strlen(symb) + 1; 624 while(c & 3) 625 c++; 626 while(nhunk < c) 627 gethunk(); 628 cp = hunk; 629 memcpy(hunk, symb, c); 630 nhunk -= c; 631 hunk += c; 632 linehist(cp, n); 633 return; 634 635bad: 636 unget(c); 637 yyerror("syntax in #line"); 638 macend(); 639} 640 641void 642macif(int f) 643{ 644 int c, l, bol; 645 Sym *s; 646 647 if(f == 2) 648 goto skip; 649 s = getsym(); 650 if(s == S) 651 goto bad; 652 if(getcom() != '\n') 653 goto bad; 654 if((s->macro != 0) ^ f) 655 return; 656 657skip: 658 bol = 1; 659 l = 0; 660 for(;;) { 661 c = getc(); 662 if(c != '#') { 663 if(!isspace(c)) 664 bol = 0; 665 if(c == '\n') 666 bol = 1; 667 continue; 668 } 669 if(!bol) 670 continue; 671 s = getsym(); 672 if(s == S) 673 continue; 674 if(strcmp(s->name, "endif") == 0) { 675 if(l) { 676 l--; 677 continue; 678 } 679 macend(); 680 return; 681 } 682 if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) { 683 l++; 684 continue; 685 } 686 if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) { 687 macend(); 688 return; 689 } 690 } 691 692bad: 693 yyerror("syntax in #if(n)def"); 694 macend(); 695} 696 697void 698macprag(void) 699{ 700 Sym *s; 701 int c0, c; 702 char *hp; 703 Hist *h; 704 705 s = getsym(); 706 707 if(s && strcmp(s->name, "lib") == 0) 708 goto praglib; 709 if(s && strcmp(s->name, "pack") == 0) { 710 pragpack(); 711 return; 712 } 713 if(s && strcmp(s->name, "fpround") == 0) { 714 pragfpround(); 715 return; 716 } 717 if(s && strcmp(s->name, "profile") == 0) { 718 pragprofile(); 719 return; 720 } 721 if(s && strcmp(s->name, "varargck") == 0) { 722 pragvararg(); 723 return; 724 } 725 if(s && strcmp(s->name, "incomplete") == 0) { 726 pragincomplete(); 727 return; 728 } 729 while(getnsc() != '\n') 730 ; 731 return; 732 733praglib: 734 c0 = getnsc(); 735 if(c0 != '"') { 736 c = c0; 737 if(c0 != '<') 738 goto bad; 739 c0 = '>'; 740 } 741 for(hp = symb;;) { 742 c = getc(); 743 if(c == c0) 744 break; 745 if(c == '\n') 746 goto bad; 747 *hp++ = c; 748 } 749 *hp = 0; 750 c = getcom(); 751 if(c != '\n') 752 goto bad; 753 754 /* 755 * put pragma-line in as a funny history 756 */ 757 c = strlen(symb) + 1; 758 while(c & 3) 759 c++; 760 while(nhunk < c) 761 gethunk(); 762 hp = hunk; 763 memcpy(hunk, symb, c); 764 nhunk -= c; 765 hunk += c; 766 767 h = alloc(sizeof(Hist)); 768 h->name = hp; 769 h->line = lineno; 770 h->offset = -1; 771 h->link = H; 772 if(ehist == H) { 773 hist = h; 774 ehist = h; 775 return; 776 } 777 ehist->link = h; 778 ehist = h; 779 return; 780 781bad: 782 unget(c); 783 yyerror("syntax in #pragma lib"); 784 macend(); 785} 786 787void 788macend(void) 789{ 790 int c; 791 792 for(;;) { 793 c = getnsc(); 794 if(c < 0 || c == '\n') 795 return; 796 } 797} 798 799void 800linehist(char *f, int offset) 801{ 802 Hist *h; 803 804 /* 805 * overwrite the last #line directive if 806 * no alloc has happened since the last one 807 */ 808 if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0) 809 if(f && ehist->name && strcmp(f, ehist->name) == 0) { 810 ehist->line = lineno; 811 ehist->offset = offset; 812 return; 813 } 814 815 if(debug['f']) 816 if(f) { 817 if(offset) 818 print("%4ld: %s (#line %d)\n", lineno, f, offset); 819 else 820 print("%4ld: %s\n", lineno, f); 821 } else 822 print("%4ld: <pop>\n", lineno); 823 newflag = 0; 824 825 h = alloc(sizeof(Hist)); 826 h->name = f; 827 h->line = lineno; 828 h->offset = offset; 829 h->link = H; 830 if(ehist == H) { 831 hist = h; 832 ehist = h; 833 return; 834 } 835 ehist->link = h; 836 ehist = h; 837} 838 839void 840gethunk(void) 841{ 842 char *h; 843 long nh; 844 845 nh = NHUNK; 846 if(thunk >= 10L*NHUNK) 847 nh = 10L*NHUNK; 848 h = (char*)mysbrk(nh); 849 if(h == (char*)-1) { 850 yyerror("out of memory"); 851 errorexit(); 852 } 853 hunk = h; 854 nhunk = nh; 855 thunk += nh; 856} 857