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