1 %{ 2 /* Id: scanner.l,v 1.49 2009/02/14 09:23:55 ragge Exp */ 3 /* $NetBSD: scanner.l,v 1.1.1.3 2010/06/03 18:57:36 plunky Exp $ */ 4 5 /* 6 * Copyright (c) 2004 Anders Magnusson. All rights reserved. 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 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include <stdlib.h> 34 #include <string.h> 35 #include <ctype.h> 36 #ifdef HAVE_UNISTD_H 37 #include <unistd.h> 38 #endif 39 #include <fcntl.h> 40 #include <errno.h> 41 42 #include "compat.h" 43 #include "cpp.h" 44 #include "y.tab.h" 45 %} 46 47 %{ 48 static void cvtdig(int rad); 49 static int charcon(usch *); 50 static void elsestmt(void); 51 static void ifdefstmt(void); 52 static void ifndefstmt(void); 53 static void endifstmt(void); 54 static void ifstmt(void); 55 static void cpperror(void); 56 static void pragmastmt(void); 57 static void undefstmt(void); 58 static void cpperror(void); 59 static void elifstmt(void); 60 static void storepb(void); 61 static void badop(const char *); 62 void include(void); 63 void define(void); 64 65 extern int yyget_lineno (void); 66 extern void yyset_lineno (int); 67 68 static int inch(void); 69 70 static int scale, gotdef, contr; 71 int inif; 72 73 #ifdef FLEX_SCANNER /* should be set by autoconf instead */ 74 static int 75 yyinput(char *b, int m) 76 { 77 int c, i; 78 79 for (i = 0; i < m; i++) { 80 if ((c = inch()) < 0) 81 break; 82 *b++ = c; 83 if (c == '\n') { 84 i++; 85 break; 86 } 87 } 88 return i; 89 } 90 #undef YY_INPUT 91 #undef YY_BUF_SIZE 92 #define YY_BUF_SIZE (8*65536) 93 #define YY_INPUT(b,r,m) (r = yyinput(b, m)) 94 #ifdef HAVE_CPP_VARARG_MACRO_GCC 95 #define fprintf(x, ...) error(__VA_ARGS__) 96 #endif 97 #define ECHO putstr((usch *)yytext) 98 #undef fileno 99 #define fileno(x) 0 100 101 #if YY_FLEX_SUBMINOR_VERSION >= 31 102 /* Hack to avoid unnecessary warnings */ 103 FILE *yyget_in (void); 104 FILE *yyget_out (void); 105 int yyget_leng (void); 106 char *yyget_text (void); 107 void yyset_in (FILE * in_str ); 108 void yyset_out (FILE * out_str ); 109 int yyget_debug (void); 110 void yyset_debug (int bdebug ); 111 int yylex_destroy (void); 112 #endif 113 #else /* Assume lex here */ 114 #undef input 115 #undef unput 116 #define input() inch() 117 #define unput(ch) unch(ch) 118 #endif 119 #define PRTOUT(x) if (YYSTATE || slow) return x; if (!flslvl) putstr((usch *)yytext); 120 /* protection against recursion in #include */ 121 #define MAX_INCLEVEL 100 122 static int inclevel; 123 %} 124 125 D [0-9] 126 L [a-zA-Z_] 127 H [a-fA-F0-9] 128 E [Ee][+-]?{D}+ 129 FS (f|F|l|L) 130 IS (u|U|l|L)* 131 WS [\t ] 132 133 %s IFR CONTR DEF COMMENT 134 135 %% 136 137 "\n" { int os = YYSTATE; 138 if (os != IFR) 139 BEGIN 0; 140 ifiles->lineno++; 141 if (flslvl == 0) { 142 if (ifiles->lineno == 1) 143 prtline(); 144 else 145 putch('\n'); 146 } 147 if ((os != 0 || slow) && !contr) 148 return '\n'; 149 contr = 0; 150 } 151 152 "\r" { ; /* Ignore CR's */ } 153 154 <IFR>"++" { badop("++"); } 155 <IFR>"--" { badop("--"); } 156 <IFR>"==" { return EQ; } 157 <IFR>"!=" { return NE; } 158 <IFR>"<=" { return LE; } 159 <IFR>"<<" { return LS; } 160 <IFR>">>" { return RS; } 161 <IFR>">=" { return GE; } 162 <IFR>"||" { return OROR; } 163 <IFR>"&&" { return ANDAND; } 164 <IFR>"defined" { int p, c; 165 gotdef = 1; 166 if ((p = c = yylex()) == '(') 167 c = yylex(); 168 if (c != IDENT || (p != IDENT && p != '(')) 169 error("syntax error"); 170 if (p == '(' && yylex() != ')') 171 error("syntax error"); 172 return NUMBER; 173 } 174 175 <IFR>{WS}+ { ; } 176 <IFR>{L}({L}|{D})* { 177 yylval.node.op = NUMBER; 178 if (gotdef) { 179 yylval.node.nd_val 180 = lookup((usch *)yytext, FIND) != 0; 181 gotdef = 0; 182 return IDENT; 183 } 184 yylval.node.nd_val = 0; 185 return NUMBER; 186 } 187 188 [0-9][0-9]* { 189 if (slow && !YYSTATE) 190 return IDENT; 191 scale = yytext[0] == '0' ? 8 : 10; 192 goto num; 193 } 194 195 0[xX]{H}+{IS}? { scale = 16; 196 num: if (YYSTATE == IFR) 197 cvtdig(scale); 198 PRTOUT(NUMBER); 199 } 200 0{D}+{IS}? { scale = 8; goto num; } 201 {D}+{IS}? { scale = 10; goto num; } 202 '(\\.|[^\\'])+' { 203 if (YYSTATE || slow) { 204 yylval.node.op = NUMBER; 205 yylval.node.nd_val = charcon((usch *)yytext); 206 return (NUMBER); 207 } 208 if (tflag) 209 yyless(1); 210 if (!flslvl) 211 putstr((usch *)yytext); 212 } 213 214 <IFR>. { return yytext[0]; } 215 216 {D}+{E}{FS}? { PRTOUT(FPOINT); } 217 {D}*"."{D}+({E})?{FS}? { PRTOUT(FPOINT); } 218 {D}+"."{D}*({E})?{FS}? { PRTOUT(FPOINT); } 219 220 ^{WS}*#{WS}* { extern int inmac; 221 222 if (inmac) 223 error("preprocessor directive found " 224 "while expanding macro"); 225 contr = 1; 226 BEGIN CONTR; 227 } 228 {WS}+ { PRTOUT(WSPACE); } 229 230 <CONTR>"ifndef" { contr = 0; ifndefstmt(); } 231 <CONTR>"ifdef" { contr = 0; ifdefstmt(); } 232 <CONTR>"if" { contr = 0; storepb(); BEGIN IFR; ifstmt(); BEGIN 0; } 233 <CONTR>"include" { contr = 0; BEGIN 0; include(); prtline(); } 234 <CONTR>"else" { contr = 0; elsestmt(); } 235 <CONTR>"endif" { contr = 0; endifstmt(); } 236 <CONTR>"error" { contr = 0; if (slow) return IDENT; cpperror(); BEGIN 0; } 237 <CONTR>"define" { contr = 0; BEGIN DEF; define(); BEGIN 0; } 238 <CONTR>"undef" { contr = 0; if (slow) return IDENT; undefstmt(); } 239 <CONTR>"line" { contr = 0; storepb(); BEGIN 0; line(); } 240 <CONTR>"pragma" { contr = 0; pragmastmt(); BEGIN 0; } 241 <CONTR>"elif" { contr = 0; storepb(); BEGIN IFR; elifstmt(); BEGIN 0; } 242 243 244 245 "//".*$ { /* if (tflag) yyless(..) */ 246 if (Cflag && !flslvl && !slow) 247 putstr((usch *)yytext); 248 else if (!flslvl) 249 putch(' '); 250 } 251 "/*" { int c, wrn; 252 int prtcm = Cflag && !flslvl && !slow; 253 extern int readmac; 254 255 if (Cflag && !flslvl && readmac) 256 return CMNT; 257 258 if (prtcm) 259 putstr((usch *)yytext); 260 wrn = 0; 261 more: while ((c = input()) && c != '*') { 262 if (c == '\n') 263 putch(c), ifiles->lineno++; 264 else if (c == 1) /* WARN */ 265 wrn = 1; 266 else if (prtcm) 267 putch(c); 268 } 269 if (c == 0) 270 return 0; 271 if (prtcm) 272 putch(c); 273 if ((c = input()) && c != '/') { 274 unput(c); 275 goto more; 276 } 277 if (prtcm) 278 putch(c); 279 if (c == 0) 280 return 0; 281 if (!tflag && !Cflag && !flslvl) 282 unput(' '); 283 if (wrn) 284 unput(1); 285 } 286 287 <DEF>"##" { return CONCAT; } 288 <DEF>"#" { return MKSTR; } 289 <DEF>"..." { return ELLIPS; } 290 <DEF>"__VA_ARGS__" { return VA_ARGS; } 291 292 L?\"(\\.|[^\\"])*\" { PRTOUT(STRING); } 293 [a-zA-Z_0-9]+ { /* {L}({L}|{D})* */ 294 struct symtab *nl; 295 if (slow) 296 return IDENT; 297 if (YYSTATE == CONTR) { 298 if (flslvl == 0) { 299 /*error("undefined control");*/ 300 while (input() != '\n') 301 ; 302 unput('\n'); 303 BEGIN 0; 304 goto xx; 305 } else { 306 BEGIN 0; /* do nothing */ 307 } 308 } 309 if (flslvl) { 310 ; /* do nothing */ 311 } else if (isdigit((int)yytext[0]) == 0 && 312 (nl = lookup((usch *)yytext, FIND)) != 0) { 313 usch *op = stringbuf; 314 putstr(gotident(nl)); 315 stringbuf = op; 316 } else 317 putstr((usch *)yytext); 318 xx: ; 319 } 320 321 . { 322 if (contr) { 323 while (input() != '\n') 324 ; 325 unput('\n'); 326 BEGIN 0; 327 contr = 0; 328 goto yy; 329 } 330 if (YYSTATE || slow) 331 return yytext[0]; 332 if (yytext[0] == 6) { /* PRAGS */ 333 usch *obp = stringbuf; 334 extern usch *prtprag(usch *); 335 *stringbuf++ = yytext[0]; 336 do { 337 *stringbuf = input(); 338 } while (*stringbuf++ != 14); 339 prtprag(obp); 340 stringbuf = obp; 341 } else { 342 PRTOUT(yytext[0]); 343 } 344 yy:; 345 } 346 347 %% 348 349 usch *yyp, yybuf[CPPBUF]; 350 351 int yylex(void); 352 int yywrap(void); 353 354 static int 355 inpch(void) 356 { 357 int len; 358 359 if (ifiles->curptr < ifiles->maxread) 360 return *ifiles->curptr++; 361 362 if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0) 363 error("read error on file %s", ifiles->orgfn); 364 if (len == 0) 365 return -1; 366 ifiles->curptr = ifiles->buffer; 367 ifiles->maxread = ifiles->buffer + len; 368 return inpch(); 369 } 370 371 #define unch(c) *--ifiles->curptr = c 372 373 static int 374 inch(void) 375 { 376 int c; 377 378 again: switch (c = inpch()) { 379 case '\\': /* continued lines */ 380 msdos: if ((c = inpch()) == '\n') { 381 ifiles->lineno++; 382 putch('\n'); 383 goto again; 384 } else if (c == '\r') 385 goto msdos; 386 unch(c); 387 return '\\'; 388 case '?': /* trigraphs */ 389 if ((c = inpch()) != '?') { 390 unch(c); 391 return '?'; 392 } 393 switch (c = inpch()) { 394 case '=': c = '#'; break; 395 case '(': c = '['; break; 396 case ')': c = ']'; break; 397 case '<': c = '{'; break; 398 case '>': c = '}'; break; 399 case '/': c = '\\'; break; 400 case '\'': c = '^'; break; 401 case '!': c = '|'; break; 402 case '-': c = '~'; break; 403 default: 404 unch(c); 405 unch('?'); 406 return '?'; 407 } 408 unch(c); 409 goto again; 410 default: 411 return c; 412 } 413 } 414 415 /* 416 * Let the command-line args be faked defines at beginning of file. 417 */ 418 static void 419 prinit(struct initar *it, struct includ *ic) 420 { 421 char *a, *pre, *post; 422 423 if (it->next) 424 prinit(it->next, ic); 425 pre = post = NULL; /* XXX gcc */ 426 switch (it->type) { 427 case 'D': 428 pre = "#define "; 429 if ((a = strchr(it->str, '=')) != NULL) { 430 *a = ' '; 431 post = "\n"; 432 } else 433 post = " 1\n"; 434 break; 435 case 'U': 436 pre = "#undef "; 437 post = "\n"; 438 break; 439 case 'i': 440 pre = "#include \""; 441 post = "\"\n"; 442 break; 443 default: 444 error("prinit"); 445 } 446 strlcat((char *)ic->buffer, pre, CPPBUF+1); 447 strlcat((char *)ic->buffer, it->str, CPPBUF+1); 448 if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1) 449 error("line exceeds buffer size"); 450 451 ic->lineno--; 452 while (*ic->maxread) 453 ic->maxread++; 454 } 455 456 /* 457 * A new file included. 458 * If ifiles == NULL, this is the first file and already opened (stdin). 459 * Return 0 on success, -1 if file to be included is not found. 460 */ 461 int 462 pushfile(usch *file) 463 { 464 extern struct initar *initar; 465 struct includ ibuf; 466 struct includ *ic; 467 int c, otrulvl; 468 469 ic = &ibuf; 470 ic->next = ifiles; 471 472 slow = 0; 473 if (file != NULL) { 474 if ((ic->infil = open((char *)file, O_RDONLY)) < 0) 475 return -1; 476 ic->orgfn = ic->fname = file; 477 if (++inclevel > MAX_INCLEVEL) 478 error("Limit for nested includes exceeded"); 479 } else { 480 ic->infil = 0; 481 ic->orgfn = ic->fname = (usch *)"<stdin>"; 482 } 483 ic->buffer = ic->bbuf+NAMEMAX; 484 ic->curptr = ic->buffer; 485 ifiles = ic; 486 ic->lineno = 1; 487 ic->maxread = ic->curptr; 488 prtline(); 489 if (initar) { 490 *ic->maxread = 0; 491 prinit(initar, ic); 492 if (dMflag) 493 write(ofd, ic->buffer, strlen((char *)ic->buffer)); 494 initar = NULL; 495 } 496 497 otrulvl = trulvl; 498 499 if ((c = yylex()) != 0) 500 error("yylex returned %d", c); 501 502 if (otrulvl != trulvl || flslvl) 503 error("unterminated conditional"); 504 505 ifiles = ic->next; 506 close(ic->infil); 507 inclevel--; 508 return 0; 509 } 510 511 /* 512 * Print current position to output file. 513 */ 514 void 515 prtline() 516 { 517 usch *s, *os = stringbuf; 518 519 if (Mflag) { 520 if (dMflag) 521 return; /* no output */ 522 if (ifiles->lineno == 1) { 523 s = sheap("%s: %s\n", Mfile, ifiles->fname); 524 write(ofd, s, strlen((char *)s)); 525 } 526 } else if (!Pflag) 527 putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname)); 528 stringbuf = os; 529 } 530 531 void 532 cunput(int c) 533 { 534 #ifdef CPP_DEBUG 535 extern int dflag; 536 if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c); 537 #endif 538 unput(c); 539 } 540 541 int yywrap(void) { return 1; } 542 543 static int 544 dig2num(int c) 545 { 546 if (c >= 'a') 547 c = c - 'a' + 10; 548 else if (c >= 'A') 549 c = c - 'A' + 10; 550 else 551 c = c - '0'; 552 return c; 553 } 554 555 /* 556 * Convert string numbers to unsigned long long and check overflow. 557 */ 558 static void 559 cvtdig(int rad) 560 { 561 unsigned long long rv = 0; 562 unsigned long long rv2 = 0; 563 char *y = yytext; 564 int c; 565 566 c = *y++; 567 if (rad == 16) 568 y++; 569 while (isxdigit(c)) { 570 rv = rv * rad + dig2num(c); 571 /* check overflow */ 572 if (rv / rad < rv2) 573 error("Constant \"%s\" is out of range", yytext); 574 rv2 = rv; 575 c = *y++; 576 } 577 y--; 578 while (*y == 'l' || *y == 'L') 579 y++; 580 yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER; 581 yylval.node.nd_uval = rv; 582 if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0) 583 yylval.node.op = UNUMBER; 584 if (yylval.node.op == NUMBER && yylval.node.nd_val < 0) 585 /* too large for signed */ 586 error("Constant \"%s\" is out of range", yytext); 587 } 588 589 static int 590 charcon(usch *p) 591 { 592 int val, c; 593 594 p++; /* skip first ' */ 595 val = 0; 596 if (*p++ == '\\') { 597 switch (*p++) { 598 case 'a': val = '\a'; break; 599 case 'b': val = '\b'; break; 600 case 'f': val = '\f'; break; 601 case 'n': val = '\n'; break; 602 case 'r': val = '\r'; break; 603 case 't': val = '\t'; break; 604 case 'v': val = '\v'; break; 605 case '\"': val = '\"'; break; 606 case '\'': val = '\''; break; 607 case '\\': val = '\\'; break; 608 case 'x': 609 while (isxdigit(c = *p)) { 610 val = val * 16 + dig2num(c); 611 p++; 612 } 613 break; 614 case '0': case '1': case '2': case '3': case '4': 615 case '5': case '6': case '7': 616 p--; 617 while (isdigit(c = *p)) { 618 val = val * 8 + (c - '0'); 619 p++; 620 } 621 break; 622 default: val = p[-1]; 623 } 624 625 } else 626 val = p[-1]; 627 return val; 628 } 629 630 static void 631 chknl(int ignore) 632 { 633 int t; 634 635 slow = 1; 636 while ((t = yylex()) == WSPACE) 637 ; 638 if (t != '\n') { 639 if (ignore) { 640 warning("newline expected, got \"%s\"", yytext); 641 /* ignore rest of line */ 642 while ((t = yylex()) && t != '\n') 643 ; 644 } 645 else 646 error("newline expected, got \"%s\"", yytext); 647 } 648 slow = 0; 649 } 650 651 static void 652 elsestmt(void) 653 { 654 if (flslvl) { 655 if (elflvl > trulvl) 656 ; 657 else if (--flslvl!=0) { 658 flslvl++; 659 } else { 660 trulvl++; 661 prtline(); 662 } 663 } else if (trulvl) { 664 flslvl++; 665 trulvl--; 666 } else 667 error("If-less else"); 668 if (elslvl==trulvl+flslvl) 669 error("Too many else"); 670 elslvl=trulvl+flslvl; 671 chknl(1); 672 } 673 674 static void 675 ifdefstmt(void) 676 { 677 int t; 678 679 if (flslvl) { 680 /* just ignore the rest of the line */ 681 while (input() != '\n') 682 ; 683 unput('\n'); 684 yylex(); 685 flslvl++; 686 return; 687 } 688 slow = 1; 689 do 690 t = yylex(); 691 while (t == WSPACE); 692 if (t != IDENT) 693 error("bad ifdef"); 694 slow = 0; 695 if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0) 696 trulvl++; 697 else 698 flslvl++; 699 chknl(0); 700 } 701 702 static void 703 ifndefstmt(void) 704 { 705 int t; 706 707 slow = 1; 708 do 709 t = yylex(); 710 while (t == WSPACE); 711 if (t != IDENT) 712 error("bad ifndef"); 713 slow = 0; 714 if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0) 715 trulvl++; 716 else 717 flslvl++; 718 chknl(0); 719 } 720 721 static void 722 endifstmt(void) 723 { 724 if (flslvl) { 725 flslvl--; 726 if (flslvl == 0) 727 prtline(); 728 } else if (trulvl) 729 trulvl--; 730 else 731 error("If-less endif"); 732 if (flslvl == 0) 733 elflvl = 0; 734 elslvl = 0; 735 chknl(1); 736 } 737 738 /* 739 * Note! Ugly! 740 * Walk over the string s and search for defined, and replace it with 741 * spaces and a 1 or 0. 742 */ 743 static void 744 fixdefined(usch *s) 745 { 746 usch *bc, oc; 747 748 for (; *s; s++) { 749 if (*s != 'd') 750 continue; 751 if (memcmp(s, "defined", 7)) 752 continue; 753 /* Ok, got defined, can scratch it now */ 754 memset(s, ' ', 7); 755 s += 7; 756 #define WSARG(x) (x == ' ' || x == '\t') 757 if (*s != '(' && !WSARG(*s)) 758 continue; 759 while (WSARG(*s)) 760 s++; 761 if (*s == '(') 762 s++; 763 while (WSARG(*s)) 764 s++; 765 #define IDARG(x) ((x>= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x == '_')) 766 #define NUMARG(x) (x >= '0' && x <= '9') 767 if (!IDARG(*s)) 768 error("bad defined arg"); 769 bc = s; 770 while (IDARG(*s) || NUMARG(*s)) 771 s++; 772 oc = *s; 773 *s = 0; 774 *bc = (lookup(bc, FIND) != 0) + '0'; 775 memset(bc+1, ' ', s-bc-1); 776 *s = oc; 777 } 778 } 779 780 /* 781 * get the full line of identifiers after an #if, pushback a WARN and 782 * the line and prepare for expmac() to expand. 783 * This is done before switching state. When expmac is finished, 784 * pushback the expanded line, change state and call yyparse. 785 */ 786 static void 787 storepb(void) 788 { 789 usch *opb = stringbuf; 790 int c; 791 792 while ((c = input()) != '\n') { 793 if (c == '/') { 794 if ((c = input()) == '*') { 795 /* ignore comments here whatsoever */ 796 usch *g = stringbuf; 797 getcmnt(); 798 stringbuf = g; 799 continue; 800 } else if (c == '/') { 801 while ((c = input()) && c != '\n') 802 ; 803 break; 804 } 805 unput(c); 806 c = '/'; 807 } 808 savch(c); 809 } 810 cunput('\n'); 811 savch(0); 812 fixdefined(opb); /* XXX can fail if #line? */ 813 cunput(1); /* WARN XXX */ 814 unpstr(opb); 815 stringbuf = opb; 816 slow = 1; 817 expmac(NULL); 818 slow = 0; 819 /* line now expanded */ 820 while (stringbuf > opb) 821 cunput(*--stringbuf); 822 } 823 824 static void 825 ifstmt(void) 826 { 827 if (flslvl == 0) { 828 slow = 1; 829 if (yyparse()) 830 ++trulvl; 831 else 832 ++flslvl; 833 slow = 0; 834 } else 835 ++flslvl; 836 } 837 838 static void 839 elifstmt(void) 840 { 841 if (flslvl == 0) 842 elflvl = trulvl; 843 if (flslvl) { 844 if (elflvl > trulvl) 845 ; 846 else if (--flslvl!=0) 847 ++flslvl; 848 else { 849 slow = 1; 850 if (yyparse()) { 851 ++trulvl; 852 prtline(); 853 } else 854 ++flslvl; 855 slow = 0; 856 } 857 } else if (trulvl) { 858 ++flslvl; 859 --trulvl; 860 } else 861 error("If-less elif"); 862 } 863 864 static usch * 865 svinp(void) 866 { 867 int c; 868 usch *cp = stringbuf; 869 870 while ((c = input()) && c != '\n') 871 savch(c); 872 savch('\n'); 873 savch(0); 874 BEGIN 0; 875 return cp; 876 } 877 878 static void 879 cpperror(void) 880 { 881 usch *cp; 882 int c; 883 884 if (flslvl) 885 return; 886 c = yylex(); 887 if (c != WSPACE && c != '\n') 888 error("bad error"); 889 cp = svinp(); 890 if (flslvl) 891 stringbuf = cp; 892 else 893 error("%s", cp); 894 } 895 896 static void 897 undefstmt(void) 898 { 899 struct symtab *np; 900 901 slow = 1; 902 if (yylex() != WSPACE || yylex() != IDENT) 903 error("bad undef"); 904 if (flslvl == 0 && (np = lookup((usch *)yytext, FIND))) 905 np->value = 0; 906 slow = 0; 907 chknl(0); 908 } 909 910 static void 911 pragmastmt(void) 912 { 913 int c; 914 915 slow = 1; 916 if (yylex() != WSPACE) 917 error("bad pragma"); 918 if (!flslvl) 919 putstr((usch *)"#pragma "); 920 do { 921 c = input(); 922 if (!flslvl) 923 putch(c); /* Do arg expansion instead? */ 924 } while (c && c != '\n'); 925 ifiles->lineno++; 926 prtline(); 927 slow = 0; 928 } 929 930 static void 931 badop(const char *op) 932 { 933 error("invalid operator in preprocessor expression: %s", op); 934 } 935 936 int 937 cinput() 938 { 939 return input(); 940 } 941