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