1/* Id: token.c,v 1.64 2011/08/30 20:12:21 plunky Exp */ 2/* $NetBSD$ */ 3 4/* 5 * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/* 29 * Tokenizer for the C preprocessor. 30 * There are three main routines: 31 * - fastscan() loops over the input stream searching for magic 32 * characters that may require actions. 33 * - sloscan() tokenize the input stream and returns tokens. 34 * It may recurse into itself during expansion. 35 * - yylex() returns something from the input stream that 36 * is suitable for yacc. 37 * 38 * Other functions of common use: 39 * - inpch() returns a raw character from the current input stream. 40 * - inch() is like inpch but \\n and trigraphs are expanded. 41 * - unch() pushes back a character to the input stream. 42 */ 43 44#include "config.h" 45 46#include <stdlib.h> 47#include <string.h> 48#include <ctype.h> 49#ifdef HAVE_UNISTD_H 50#include <unistd.h> 51#endif 52#include <fcntl.h> 53#include <errno.h> 54 55#include "compat.h" 56#include "cpp.h" 57#include "y.tab.h" 58 59static void cvtdig(int rad); 60static int charcon(usch *); 61static void elsestmt(void); 62static void ifdefstmt(void); 63static void ifndefstmt(void); 64static void endifstmt(void); 65static void ifstmt(void); 66static void cpperror(void); 67static void pragmastmt(void); 68static void undefstmt(void); 69static void cppwarning(void); 70static void elifstmt(void); 71static void badop(const char *); 72static int chktg(void); 73static int inpch(void); 74 75extern int yyget_lineno (void); 76extern void yyset_lineno (int); 77 78static int inch(void); 79 80int inif; 81 82#define PUTCH(ch) if (!flslvl) putch(ch) 83/* protection against recursion in #include */ 84#define MAX_INCLEVEL 100 85static int inclevel; 86 87/* get next character unaltered */ 88#define NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch()) 89 90usch yytext[CPPBUF]; 91 92char spechr[256] = { 93 0, 0, 0, 0, C_SPEC, C_SPEC, 0, 0, 94 0, C_WSNL, C_SPEC|C_WSNL, 0, 95 0, C_WSNL, 0, 0, 96 0, 0, 0, 0, 0, 0, 0, 0, 97 0, 0, 0, 0, 0, 0, 0, 0, 98 99 C_WSNL, C_2, C_SPEC, 0, 0, 0, C_2, C_SPEC, 100 0, 0, 0, C_2, 0, C_2, 0, C_SPEC|C_2, 101 C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 102 C_I, C_I, 0, 0, C_2, C_2, C_2, C_SPEC, 103 104 0, C_I, C_I, C_I, C_I, C_I|C_EP, C_I, C_I, 105 C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 106 C_I|C_EP, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 107 C_I, C_I, C_I, 0, C_SPEC, 0, 0, C_I, 108 109 0, C_I, C_I, C_I, C_I, C_I|C_EP, C_I, C_I, 110 C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 111 C_I|C_EP, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 112 C_I, C_I, C_I, 0, C_2, 0, 0, 0, 113 114}; 115 116/* 117 * No-replacement array. If a macro is found and exists in this array 118 * then no replacement shall occur. This is a stack. 119 */ 120struct symtab *norep[RECMAX]; /* Symbol table index table */ 121int norepptr = 1; /* Top of index table */ 122unsigned short bptr[RECMAX]; /* currently active noexpand macro stack */ 123int bidx; /* Top of bptr stack */ 124 125static void 126unch(int c) 127{ 128 129 --ifiles->curptr; 130 if (ifiles->curptr < ifiles->bbuf) 131 error("pushback buffer full"); 132 *ifiles->curptr = (usch)c; 133} 134 135static int 136eatcmnt(void) 137{ 138 int ch; 139 140 if (Cflag) { PUTCH('/'); PUTCH('*'); } 141 for (;;) { 142 ch = inch(); 143 if (ch == '\n') { 144 ifiles->lineno++; 145 PUTCH('\n'); 146 } 147 if (ch == -1) 148 return -1; 149 if (ch == '*') { 150 ch = inch(); 151 if (ch == '/') { 152 if (Cflag) { 153 PUTCH('*'); 154 PUTCH('/'); 155 } else 156 PUTCH(' '); 157 break; 158 } 159 unch(ch); 160 ch = '*'; 161 } 162 if (Cflag) PUTCH(ch); 163 } 164 return 0; 165} 166 167/* 168 * Scan quickly the input file searching for: 169 * - '#' directives 170 * - keywords (if not flslvl) 171 * - comments 172 * 173 * Handle strings, numbers and trigraphs with care. 174 * Only data from pp files are scanned here, never any rescans. 175 * TODO: Only print out strings before calling other functions. 176 */ 177static void 178fastscan(void) 179{ 180 struct symtab *nl; 181 int ch, i = 0; 182 int nnl = 0; 183 usch *cp; 184 185 goto run; 186 for (;;) { 187 ch = NXTCH(); 188xloop: if (ch == -1) 189 return; 190#ifdef PCC_DEBUG 191 if (dflag>1) 192 printf("fastscan ch %d (%c)\n", ch, ch > 31 ? ch : '@'); 193#endif 194 if ((spechr[ch] & C_SPEC) == 0) { 195 PUTCH(ch); 196 continue; 197 } 198 switch (ch) { 199 case EBLOCK: 200 case WARN: 201 case CONC: 202 error("bad char passed"); 203 break; 204 205 case '/': /* Comments */ 206 if ((ch = inch()) == '/') { 207cppcmt: if (Cflag) { PUTCH(ch); } else { PUTCH(' '); } 208 do { 209 if (Cflag) PUTCH(ch); 210 ch = inch(); 211 } while (ch != -1 && ch != '\n'); 212 goto xloop; 213 } else if (ch == '*') { 214 if (eatcmnt()) 215 return; 216 } else { 217 PUTCH('/'); 218 goto xloop; 219 } 220 break; 221 222 case '?': /* trigraphs */ 223 if ((ch = chktg())) 224 goto xloop; 225 PUTCH('?'); 226 break; 227 228 case '\\': 229 if ((ch = NXTCH()) == '\n') { 230 ifiles->lineno++; 231 continue; 232 } else { 233 PUTCH('\\'); 234 } 235 goto xloop; 236 237 case '\n': /* newlines, for pp directives */ 238 while (nnl > 0) { PUTCH('\n'); nnl--; } 239run2: ifiles->lineno++; 240 do { 241 PUTCH(ch); 242run: ch = NXTCH(); 243 if (ch == '/') { 244 ch = NXTCH(); 245 if (ch == '/') 246 goto cppcmt; 247 if (ch == '*') { 248 if (eatcmnt()) 249 return; 250 goto run; 251 } 252 unch(ch); 253 ch = '/'; 254 } 255 } while (ch == ' ' || ch == '\t'); 256 if (ch == '\\') { 257 ch = NXTCH(); 258 if (ch == '\n') 259 goto run2; 260 unch(ch); 261 ch = '\\'; 262 } 263 if (ch == '#') { 264 ppdir(); 265 continue; 266 } else if (ch == '%') { 267 ch = NXTCH(); 268 if (ch == ':') { 269 ppdir(); 270 continue; 271 } else { 272 unch(ch); 273 ch = '%'; 274 } 275 } else if (ch == '?') { 276 if ((ch = chktg()) == '#') { 277 ppdir(); 278 continue; 279 } else if (ch == 0) 280 ch = '?'; 281 } 282 goto xloop; 283 284 case '\"': /* strings */ 285str: PUTCH(ch); 286 while ((ch = NXTCH()) != '\"') { 287 if (ch == '\n') 288 goto xloop; 289 if (ch == '\\') { 290 if ((ch = NXTCH()) != '\n') { 291 PUTCH('\\'); 292 PUTCH(ch); 293 } else 294 nnl++; 295 continue; 296 } 297 if (ch < 0) 298 return; 299 PUTCH(ch); 300 } 301 PUTCH(ch); 302 break; 303 304 case '.': /* for pp-number */ 305 PUTCH(ch); 306 ch = NXTCH(); 307 if (ch < '0' || ch > '9') 308 goto xloop; 309 /* FALLTHROUGH */ 310 case '0': case '1': case '2': case '3': case '4': 311 case '5': case '6': case '7': case '8': case '9': 312 do { 313 PUTCH(ch); 314nxt: ch = NXTCH(); 315 if (ch == '\\') { 316 ch = NXTCH(); 317 if (ch == '\n') { 318 goto nxt; 319 } else { 320 unch(ch); 321 ch = '\\'; 322 } 323 } 324 if (spechr[ch] & C_EP) { 325 PUTCH(ch); 326 ch = NXTCH(); 327 if (ch == '-' || ch == '+') 328 continue; 329 } 330 } while ((spechr[ch] & C_ID) || (ch == '.')); 331 goto xloop; 332 333 case '\'': /* character literal */ 334con: PUTCH(ch); 335 if (tflag) 336 continue; /* character constants ignored */ 337 while ((ch = NXTCH()) != '\'') { 338 if (ch == '\n') 339 goto xloop; 340 if (ch == '\\') { 341 if ((ch = NXTCH()) != '\n') { 342 PUTCH('\\'); 343 PUTCH(ch); 344 } else 345 nnl++; 346 continue; 347 } 348 if (ch < 0) 349 return; 350 PUTCH(ch); 351 } 352 PUTCH(ch); 353 break; 354 355 case 'L': 356 ch = NXTCH(); 357 if (ch == '\"') { 358 PUTCH('L'); 359 goto str; 360 } 361 if (ch == '\'') { 362 PUTCH('L'); 363 goto con; 364 } 365 unch(ch); 366 ch = 'L'; 367 /* FALLTHROUGH */ 368 default: 369 if ((spechr[ch] & C_ID) == 0) 370 error("fastscan"); 371 if (flslvl) { 372 while (spechr[ch] & C_ID) 373 ch = NXTCH(); 374 goto xloop; 375 } 376 i = 0; 377 do { 378 yytext[i++] = (usch)ch; 379 ch = NXTCH(); 380 if (ch == '\\') { 381 ch = NXTCH(); 382 if (ch != '\n') { 383 unch(ch); 384 ch = '\\'; 385 } else { 386 putch('\n'); 387 ifiles->lineno++; 388 ch = NXTCH(); 389 } 390 } 391 if (ch < 0) 392 return; 393 } while (spechr[ch] & C_ID); 394 395 yytext[i] = 0; 396 unch(ch); 397 398 cp = stringbuf; 399 if ((nl = lookup((usch *)yytext, FIND)) && kfind(nl)) { 400 putstr(stringbuf); 401 } else 402 putstr((usch *)yytext); 403 stringbuf = cp; 404 405 break; 406 } 407 } 408} 409 410int 411sloscan(void) 412{ 413 int ch; 414 int yyp; 415 416zagain: 417 yyp = 0; 418 ch = inch(); 419 yytext[yyp++] = (usch)ch; 420 switch (ch) { 421 case -1: 422 return 0; 423 case '\n': 424 /* sloscan() never passes \n, that's up to fastscan() */ 425 unch(ch); 426 goto yyret; 427 428 case '\r': /* Ignore CR's */ 429 yyp = 0; 430 break; 431 432 case '0': case '1': case '2': case '3': case '4': case '5': 433 case '6': case '7': case '8': case '9': 434 /* readin a "pp-number" */ 435ppnum: for (;;) { 436 ch = inch(); 437 if (spechr[ch] & C_EP) { 438 yytext[yyp++] = (usch)ch; 439 ch = inch(); 440 if (ch == '-' || ch == '+') { 441 yytext[yyp++] = (usch)ch; 442 } else 443 unch(ch); 444 continue; 445 } 446 if ((spechr[ch] & C_ID) || ch == '.') { 447 yytext[yyp++] = (usch)ch; 448 continue; 449 } 450 break; 451 } 452 unch(ch); 453 yytext[yyp] = 0; 454 455 return NUMBER; 456 457 case '\'': 458chlit: 459 for (;;) { 460 if ((ch = inch()) == '\\') { 461 yytext[yyp++] = (usch)ch; 462 yytext[yyp++] = (usch)inch(); 463 continue; 464 } else if (ch == '\n') { 465 /* not a constant */ 466 while (yyp > 1) 467 unch(yytext[--yyp]); 468 ch = '\''; 469 goto any; 470 } else 471 yytext[yyp++] = (usch)ch; 472 if (ch == '\'') 473 break; 474 } 475 yytext[yyp] = 0; 476 477 return (NUMBER); 478 479 case ' ': 480 case '\t': 481 while ((ch = inch()) == ' ' || ch == '\t') 482 yytext[yyp++] = (usch)ch; 483 unch(ch); 484 yytext[yyp] = 0; 485 return(WSPACE); 486 487 case '/': 488 if ((ch = inch()) == '/') { 489 do { 490 yytext[yyp++] = (usch)ch; 491 ch = inch(); 492 } while (ch && ch != '\n'); 493 yytext[yyp] = 0; 494 unch(ch); 495 goto zagain; 496 } else if (ch == '*') { 497 int c, wrn; 498 extern int readmac; 499 500 if (Cflag && !flslvl && readmac) { 501 unch(ch); 502 yytext[yyp] = 0; 503 return CMNT; 504 } 505 506 wrn = 0; 507 more: while ((c = inch()) && c != '*') { 508 if (c == '\n') 509 putch(c), ifiles->lineno++; 510 else if (c == EBLOCK) { 511 (void)inch(); 512 (void)inch(); 513 } else if (c == 1) /* WARN */ 514 wrn = 1; 515 } 516 if (c == 0) 517 return 0; 518 if ((c = inch()) && c != '/') { 519 unch(c); 520 goto more; 521 } 522 if (c == 0) 523 return 0; 524 if (!tflag && !Cflag && !flslvl) 525 unch(' '); 526 if (wrn) 527 unch(1); 528 goto zagain; 529 } 530 unch(ch); 531 ch = '/'; 532 goto any; 533 534 case '.': 535 ch = inch(); 536 if (isdigit(ch)) { 537 yytext[yyp++] = (usch)ch; 538 goto ppnum; 539 } else { 540 unch(ch); 541 ch = '.'; 542 } 543 goto any; 544 545 case '\"': 546 if (tflag && defining) 547 goto any; 548 strng: 549 for (;;) { 550 if ((ch = inch()) == '\\') { 551 yytext[yyp++] = (usch)ch; 552 yytext[yyp++] = (usch)inch(); 553 continue; 554 } else 555 yytext[yyp++] = (usch)ch; 556 if (ch == '\"') 557 break; 558 } 559 yytext[yyp] = 0; 560 return(STRING); 561 562 case 'L': 563 if ((ch = inch()) == '\"' && !tflag) { 564 yytext[yyp++] = (usch)ch; 565 goto strng; 566 } else if (ch == '\'' && !tflag) { 567 yytext[yyp++] = (usch)ch; 568 goto chlit; 569 } 570 unch(ch); 571 /* FALLTHROUGH */ 572 573 /* Yetch, all identifiers */ 574 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 575 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 576 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': 577 case 's': case 't': case 'u': case 'v': case 'w': case 'x': 578 case 'y': case 'z': 579 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 580 case 'G': case 'H': case 'I': case 'J': case 'K': 581 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': 582 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': 583 case 'Y': case 'Z': 584 case '_': /* {L}({L}|{D})* */ 585 586 /* Special hacks */ 587 for (;;) { /* get chars */ 588 ch = inch(); 589 if (isalpha(ch) || isdigit(ch) || ch == '_') { 590 yytext[yyp++] = (usch)ch; 591 } else { 592 if (ch != -1) 593 unch(ch); 594 break; 595 } 596 } 597 yytext[yyp] = 0; /* need already string */ 598 /* end special hacks */ 599 600 return IDENT; 601 default: 602 any: 603 yytext[yyp] = 0; 604 return yytext[0]; 605 606 } /* endcase */ 607 goto zagain; 608 609yyret: 610 yytext[yyp] = 0; 611 return ch; 612} 613 614int 615yylex(void) 616{ 617 static int ifdef, noex; 618 struct symtab *nl; 619 int ch, c2; 620 621 while ((ch = sloscan()) == WSPACE) 622 ; 623 if (ch < 128 && spechr[ch] & C_2) 624 c2 = inpch(); 625 else 626 c2 = 0; 627 628#define C2(a,b,c) case a: if (c2 == b) return c; break 629 switch (ch) { 630 C2('=', '=', EQ); 631 C2('!', '=', NE); 632 C2('|', '|', OROR); 633 C2('&', '&', ANDAND); 634 case '<': 635 if (c2 == '<') return LS; 636 if (c2 == '=') return LE; 637 break; 638 case '>': 639 if (c2 == '>') return RS; 640 if (c2 == '=') return GE; 641 break; 642 case '+': 643 case '-': 644 if (ch == c2) 645 badop(""); 646 break; 647 648 case '/': 649 if (Cflag == 0 || c2 != '*') 650 break; 651 /* Found comment that need to be skipped */ 652 for (;;) { 653 ch = inpch(); 654 c1: if (ch != '*') 655 continue; 656 if ((ch = inpch()) == '/') 657 break; 658 goto c1; 659 } 660 return yylex(); 661 662 case NUMBER: 663 if (yytext[0] == '\'') { 664 yylval.node.op = NUMBER; 665 yylval.node.nd_val = charcon((usch *)yytext); 666 } else 667 cvtdig(yytext[0] != '0' ? 10 : 668 yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8); 669 return NUMBER; 670 671 case IDENT: 672 if (strcmp((char *)yytext, "defined") == 0) { 673 ifdef = 1; 674 return DEFINED; 675 } 676 nl = lookup((usch *)yytext, FIND); 677 if (ifdef) { 678 yylval.node.nd_val = nl != NULL; 679 ifdef = 0; 680 } else if (nl && noex == 0) { 681 usch *och = stringbuf; 682 int i; 683 684 i = kfind(nl); 685 unch(WARN); 686 if (i) 687 unpstr(stringbuf); 688 else 689 unpstr(nl->namep); 690 stringbuf = och; 691 noex = 1; 692 return yylex(); 693 } else { 694 yylval.node.nd_val = 0; 695 } 696 yylval.node.op = NUMBER; 697 return NUMBER; 698 case WARN: 699 noex = 0; 700 return yylex(); 701 default: 702 return ch; 703 } 704 unch(c2); 705 return ch; 706} 707 708usch *yyp, yybuf[CPPBUF]; 709 710int yywrap(void); 711 712static int 713inpch(void) 714{ 715 int len; 716 717 if (ifiles->curptr < ifiles->maxread) 718 return *ifiles->curptr++; 719 720 if (ifiles->infil == -1) 721 return -1; 722 if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0) 723 error("read error on file %s", ifiles->orgfn); 724 if (len == 0) 725 return -1; 726 ifiles->curptr = ifiles->buffer; 727 ifiles->maxread = ifiles->buffer + len; 728 return inpch(); 729} 730 731static int 732inch(void) 733{ 734 int c; 735 736again: switch (c = inpch()) { 737 case '\\': /* continued lines */ 738msdos: if ((c = inpch()) == '\n') { 739 ifiles->lineno++; 740 goto again; 741 } else if (c == '\r') 742 goto msdos; 743 unch(c); 744 return '\\'; 745 case '?': /* trigraphs */ 746 if ((c = chktg())) { 747 unch(c); 748 goto again; 749 } 750 return '?'; 751 default: 752 return c; 753 } 754} 755 756/* 757 * Let the command-line args be faked defines at beginning of file. 758 */ 759static void 760prinit(struct initar *it, struct includ *ic) 761{ 762 const char *pre, *post; 763 char *a; 764 765 if (it->next) 766 prinit(it->next, ic); 767 pre = post = NULL; /* XXX gcc */ 768 switch (it->type) { 769 case 'D': 770 pre = "#define "; 771 if ((a = strchr(it->str, '=')) != NULL) { 772 *a = ' '; 773 post = "\n"; 774 } else 775 post = " 1\n"; 776 break; 777 case 'U': 778 pre = "#undef "; 779 post = "\n"; 780 break; 781 case 'i': 782 pre = "#include \""; 783 post = "\"\n"; 784 break; 785 default: 786 error("prinit"); 787 } 788 strlcat((char *)ic->buffer, pre, CPPBUF+1); 789 strlcat((char *)ic->buffer, it->str, CPPBUF+1); 790 if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1) 791 error("line exceeds buffer size"); 792 793 ic->lineno--; 794 while (*ic->maxread) 795 ic->maxread++; 796} 797 798/* 799 * A new file included. 800 * If ifiles == NULL, this is the first file and already opened (stdin). 801 * Return 0 on success, -1 if file to be included is not found. 802 */ 803int 804pushfile(const usch *file, const usch *fn, int idx, void *incs) 805{ 806 extern struct initar *initar; 807 struct includ ibuf; 808 struct includ *ic; 809 int otrulvl; 810 811 ic = &ibuf; 812 ic->next = ifiles; 813 814 if (file != NULL) { 815 if ((ic->infil = open((const char *)file, O_RDONLY)) < 0) 816 return -1; 817 ic->orgfn = ic->fname = file; 818 if (++inclevel > MAX_INCLEVEL) 819 error("Limit for nested includes exceeded"); 820 } else { 821 ic->infil = 0; 822 ic->orgfn = ic->fname = (const usch *)"<stdin>"; 823 } 824#ifndef BUF_STACK 825 ic->bbuf = malloc(BBUFSZ); 826#endif 827 ic->buffer = ic->bbuf+NAMEMAX; 828 ic->curptr = ic->buffer; 829 ifiles = ic; 830 ic->lineno = 1; 831 ic->maxread = ic->curptr; 832 ic->idx = idx; 833 ic->incs = incs; 834 ic->fn = fn; 835 prtline(); 836 if (initar) { 837 int oin = ic->infil; 838 ic->infil = -1; 839 *ic->maxread = 0; 840 prinit(initar, ic); 841 initar = NULL; 842 if (dMflag) 843 write(ofd, ic->buffer, strlen((char *)ic->buffer)); 844 fastscan(); 845 prtline(); 846 ic->infil = oin; 847 } 848 849 otrulvl = trulvl; 850 851 fastscan(); 852 853 if (otrulvl != trulvl || flslvl) 854 error("unterminated conditional"); 855 856#ifndef BUF_STACK 857 free(ic->bbuf); 858#endif 859 ifiles = ic->next; 860 close(ic->infil); 861 inclevel--; 862 return 0; 863} 864 865/* 866 * Print current position to output file. 867 */ 868void 869prtline(void) 870{ 871 usch *s, *os = stringbuf; 872 873 if (Mflag) { 874 if (dMflag) 875 return; /* no output */ 876 if (ifiles->lineno == 1) { 877 s = sheap("%s: %s\n", Mfile, ifiles->fname); 878 write(ofd, s, strlen((char *)s)); 879 } 880 } else if (!Pflag) 881 putstr(sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname)); 882 stringbuf = os; 883} 884 885void 886cunput(int c) 887{ 888#ifdef PCC_DEBUG 889// extern int dflag; 890// if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c); 891#endif 892#if 0 893if (c == 10) { 894 printf("c == 10!!!\n"); 895} 896#endif 897 unch(c); 898} 899 900int yywrap(void) { return 1; } 901 902static int 903dig2num(int c) 904{ 905 if (c >= 'a') 906 c = c - 'a' + 10; 907 else if (c >= 'A') 908 c = c - 'A' + 10; 909 else 910 c = c - '0'; 911 return c; 912} 913 914/* 915 * Convert string numbers to unsigned long long and check overflow. 916 */ 917static void 918cvtdig(int rad) 919{ 920 unsigned long long rv = 0; 921 unsigned long long rv2 = 0; 922 usch *y = yytext; 923 int c; 924 925 c = *y++; 926 if (rad == 16) 927 y++; 928 while (isxdigit(c)) { 929 rv = rv * rad + dig2num(c); 930 /* check overflow */ 931 if (rv / rad < rv2) 932 error("Constant \"%s\" is out of range", yytext); 933 rv2 = rv; 934 c = *y++; 935 } 936 y--; 937 while (*y == 'l' || *y == 'L') 938 y++; 939 yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER; 940 yylval.node.nd_uval = rv; 941 if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0) 942 yylval.node.op = UNUMBER; 943 if (yylval.node.op == NUMBER && yylval.node.nd_val < 0) 944 /* too large for signed, see 6.4.4.1 */ 945 error("Constant \"%s\" is out of range", yytext); 946} 947 948static int 949charcon(usch *p) 950{ 951 int val, c; 952 953 p++; /* skip first ' */ 954 val = 0; 955 if (*p++ == '\\') { 956 switch (*p++) { 957 case 'a': val = '\a'; break; 958 case 'b': val = '\b'; break; 959 case 'f': val = '\f'; break; 960 case 'n': val = '\n'; break; 961 case 'r': val = '\r'; break; 962 case 't': val = '\t'; break; 963 case 'v': val = '\v'; break; 964 case '\"': val = '\"'; break; 965 case '\'': val = '\''; break; 966 case '\\': val = '\\'; break; 967 case 'x': 968 while (isxdigit(c = *p)) { 969 val = val * 16 + dig2num(c); 970 p++; 971 } 972 break; 973 case '0': case '1': case '2': case '3': case '4': 974 case '5': case '6': case '7': 975 p--; 976 while (isdigit(c = *p)) { 977 val = val * 8 + (c - '0'); 978 p++; 979 } 980 break; 981 default: val = p[-1]; 982 } 983 984 } else 985 val = p[-1]; 986 return val; 987} 988 989static void 990chknl(int ignore) 991{ 992 int t; 993 994 while ((t = sloscan()) == WSPACE) 995 ; 996 if (t != '\n') { 997 if (t && t != (usch)-1) { 998 if (ignore) { 999 warning("newline expected, got \"%s\"", yytext); 1000 /* ignore rest of line */ 1001 while ((t = sloscan()) && t != '\n') 1002 ; 1003 } 1004 else 1005 error("newline expected, got \"%s\"", yytext); 1006 } else { 1007 if (ignore) 1008 warning("no newline at end of file"); 1009 else 1010 error("no newline at end of file"); 1011 } 1012 } 1013} 1014 1015static void 1016elsestmt(void) 1017{ 1018 if (flslvl) { 1019 if (elflvl > trulvl) 1020 ; 1021 else if (--flslvl!=0) { 1022 flslvl++; 1023 } else { 1024 trulvl++; 1025 prtline(); 1026 } 1027 } else if (trulvl) { 1028 flslvl++; 1029 trulvl--; 1030 } else 1031 error("If-less else"); 1032 if (elslvl==trulvl+flslvl) 1033 error("Too many else"); 1034 elslvl=trulvl+flslvl; 1035 chknl(1); 1036} 1037 1038static void 1039skpln(void) 1040{ 1041 /* just ignore the rest of the line */ 1042 while (inch() != '\n') 1043 ; 1044 unch('\n'); 1045 flslvl++; 1046} 1047 1048static void 1049ifdefstmt(void) 1050{ 1051 int t; 1052 1053 if (flslvl) { 1054 skpln(); 1055 return; 1056 } 1057 do 1058 t = sloscan(); 1059 while (t == WSPACE); 1060 if (t != IDENT) 1061 error("bad ifdef"); 1062 if (lookup((usch *)yytext, FIND) == 0) { 1063 putch('\n'); 1064 flslvl++; 1065 } else 1066 trulvl++; 1067 chknl(0); 1068} 1069 1070static void 1071ifndefstmt(void) 1072{ 1073 int t; 1074 1075 if (flslvl) { 1076 skpln(); 1077 return; 1078 } 1079 do 1080 t = sloscan(); 1081 while (t == WSPACE); 1082 if (t != IDENT) 1083 error("bad ifndef"); 1084 if (lookup((usch *)yytext, FIND) != 0) { 1085 putch('\n'); 1086 flslvl++; 1087 } else 1088 trulvl++; 1089 chknl(0); 1090} 1091 1092static void 1093endifstmt(void) 1094{ 1095 if (flslvl) { 1096 flslvl--; 1097 if (flslvl == 0) { 1098 putch('\n'); 1099 prtline(); 1100 } 1101 } else if (trulvl) 1102 trulvl--; 1103 else 1104 error("If-less endif"); 1105 if (flslvl == 0) 1106 elflvl = 0; 1107 elslvl = 0; 1108 chknl(1); 1109} 1110 1111static void 1112ifstmt(void) 1113{ 1114 if (flslvl == 0) { 1115 if (yyparse() == 0) { 1116 putch('\n'); 1117 ++flslvl; 1118 } else 1119 ++trulvl; 1120 } else 1121 ++flslvl; 1122} 1123 1124static void 1125elifstmt(void) 1126{ 1127 if (flslvl == 0) 1128 elflvl = trulvl; 1129 if (flslvl) { 1130 if (elflvl > trulvl) 1131 ; 1132 else if (--flslvl!=0) 1133 ++flslvl; 1134 else { 1135 if (yyparse()) { 1136 ++trulvl; 1137 prtline(); 1138 } else { 1139 putch('\n'); 1140 ++flslvl; 1141 } 1142 } 1143 } else if (trulvl) { 1144 ++flslvl; 1145 --trulvl; 1146 } else 1147 error("If-less elif"); 1148} 1149 1150static usch * 1151svinp(void) 1152{ 1153 int c; 1154 usch *cp = stringbuf; 1155 1156 while ((c = inch()) && c != '\n') 1157 savch(c); 1158 savch('\n'); 1159 savch(0); 1160 return cp; 1161} 1162 1163static void 1164cpperror(void) 1165{ 1166 usch *cp; 1167 int c; 1168 1169 if (flslvl) 1170 return; 1171 c = sloscan(); 1172 if (c != WSPACE && c != '\n') 1173 error("bad error"); 1174 cp = svinp(); 1175 if (flslvl) 1176 stringbuf = cp; 1177 else 1178 error("%s", cp); 1179} 1180 1181static void 1182cppwarning(void) 1183{ 1184 usch *cp; 1185 int c; 1186 1187 if (flslvl) 1188 return; 1189 c = sloscan(); 1190 if (c != WSPACE && c != '\n') 1191 error("bad warning"); 1192 1193 /* svinp() add an unwanted \n */ 1194 cp = stringbuf; 1195 while ((c = inch()) && c != '\n') 1196 savch(c); 1197 savch(0); 1198 1199 if (flslvl) 1200 stringbuf = cp; 1201 else 1202 warning("#warning %s", cp); 1203 1204 unch('\n'); 1205} 1206 1207static void 1208undefstmt(void) 1209{ 1210 struct symtab *np; 1211 1212 if (flslvl) 1213 return; 1214 if (sloscan() != WSPACE || sloscan() != IDENT) 1215 error("bad undef"); 1216 if (flslvl == 0 && (np = lookup((usch *)yytext, FIND))) 1217 np->value = 0; 1218 chknl(0); 1219} 1220 1221static void 1222pragmastmt(void) 1223{ 1224 int c; 1225 1226 if (sloscan() != WSPACE) 1227 error("bad pragma"); 1228 if (!flslvl) 1229 putstr((const usch *)"\n#pragma "); 1230 do { 1231 c = inch(); 1232 if (!flslvl) 1233 putch(c); /* Do arg expansion instead? */ 1234 } while (c && c != '\n'); 1235 if (c == '\n') 1236 unch(c); 1237 prtline(); 1238} 1239 1240static void 1241badop(const char *op) 1242{ 1243 error("invalid operator in preprocessor expression: %s", op); 1244} 1245 1246int 1247cinput(void) 1248{ 1249 return inch(); 1250} 1251 1252/* 1253 * Check for (and convert) trigraphs. 1254 */ 1255int 1256chktg(void) 1257{ 1258 int c; 1259 1260 if ((c = inpch()) != '?') { 1261 unch(c); 1262 return 0; 1263 } 1264 switch (c = inpch()) { 1265 case '=': c = '#'; break; 1266 case '(': c = '['; break; 1267 case ')': c = ']'; break; 1268 case '<': c = '{'; break; 1269 case '>': c = '}'; break; 1270 case '/': c = '\\'; break; 1271 case '\'': c = '^'; break; 1272 case '!': c = '|'; break; 1273 case '-': c = '~'; break; 1274 default: 1275 unch(c); 1276 unch('?'); 1277 c = 0; 1278 } 1279 return c; 1280} 1281 1282static struct { 1283 const char *name; 1284 void (*fun)(void); 1285} ppd[] = { 1286 { "ifndef", ifndefstmt }, 1287 { "ifdef", ifdefstmt }, 1288 { "if", ifstmt }, 1289 { "include", include }, 1290 { "else", elsestmt }, 1291 { "endif", endifstmt }, 1292 { "error", cpperror }, 1293 { "warning", cppwarning }, 1294 { "define", define }, 1295 { "undef", undefstmt }, 1296 { "line", line }, 1297 { "pragma", pragmastmt }, 1298 { "elif", elifstmt }, 1299#ifdef GCC_COMPAT 1300 { "include_next", include_next }, 1301#endif 1302}; 1303 1304/* 1305 * Handle a preprocessor directive. 1306 */ 1307void 1308ppdir(void) 1309{ 1310 char bp[20]; 1311 int ch, i; 1312 1313 while ((ch = inch()) == ' ' || ch == '\t') 1314 ; 1315 if (ch == '\n') { /* empty directive */ 1316 unch(ch); 1317 return; 1318 } 1319 if (ch < 'a' || ch > 'z') 1320 goto out; /* something else, ignore */ 1321 i = 0; 1322 do { 1323 bp[i++] = (usch)ch; 1324 if (i == sizeof(bp)-1) 1325 goto out; /* too long */ 1326 ch = inch(); 1327 } while ((ch >= 'a' && ch <= 'z') || (ch == '_')); 1328 unch(ch); 1329 bp[i++] = 0; 1330 1331 /* got keyword */ 1332#define SZ (int)(sizeof(ppd)/sizeof(ppd[0])) 1333 for (i = 0; i < SZ; i++) 1334 if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0) 1335 break; 1336 if (i == SZ) 1337 goto out; 1338 1339 /* Found matching keyword */ 1340 (*ppd[i].fun)(); 1341 return; 1342 1343out: while ((ch = inch()) != '\n' && ch != -1) 1344 ; 1345 unch('\n'); 1346} 1347