1 %{
2 /* Id: scanner.l,v 1.50 2011/06/03 15:42:45 plunky Exp */
3 /* $NetBSD: scanner.l,v 1.1.1.4 2011/09/01 12:46:55 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
yyinput(char * b,int m)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 PCC_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