* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / cc / cpp / scanner.l
blobf1e4bf976bd058db050b621f2b74804c9712a608
1 %{
2 /*      $Id: scanner.l,v 1.49 2009/02/14 09:23:55 ragge Exp $   */
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  */
30 #include "config.h"
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>
41 #include "compat.h"
42 #include "cpp.h"
43 #include "y.tab.h"
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);
64 extern int yyget_lineno (void);
65 extern void yyset_lineno (int);
67 static int inch(void);
69 static int scale, gotdef, contr;
70 int inif;
72 #ifdef FLEX_SCANNER /* should be set by autoconf instead */
73 static int
74 yyinput(char *b, int m)
76         int c, i;
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;
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
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;
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 ]
132 %s IFR CONTR DEF COMMENT
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                         }
151 "\r"                    { ; /* Ignore CR's */ }
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                         }
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                         }
187 [0-9][0-9]*             {
188                                 if (slow && !YYSTATE)
189                                         return IDENT;
190                                 scale = yytext[0] == '0' ? 8 : 10;
191                                 goto num;
192                         }
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                         }
213 <IFR>.                  { return yytext[0]; }
215 {D}+{E}{FS}?            { PRTOUT(FPOINT); }
216 {D}*"."{D}+({E})?{FS}?  { PRTOUT(FPOINT); }
217 {D}+"."{D}*({E})?{FS}?  { PRTOUT(FPOINT); }
219 ^{WS}*#{WS}*            {       extern int inmac;
221                                 if (inmac)
222                                         error("preprocessor directive found "
223                                             "while expanding macro");
224                                 contr = 1;
225                                 BEGIN CONTR;
226                         }
227 {WS}+                   { PRTOUT(WSPACE); }
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; }
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;
254                                 if (Cflag && !flslvl && readmac)
255                                         return CMNT;
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                         }
286 <DEF>"##"               { return CONCAT; }
287 <DEF>"#"                { return MKSTR; }
288 <DEF>"..."              { return ELLIPS; }
289 <DEF>"__VA_ARGS__"      { return VA_ARGS; }
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                         }
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                         }
348 usch *yyp, yybuf[CPPBUF];
350 int yylex(void);
351 int yywrap(void);
353 static int
354 inpch(void)
356         int len;
358         if (ifiles->curptr < ifiles->maxread)
359                 return *ifiles->curptr++;
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();
370 #define unch(c) *--ifiles->curptr = c
372 static int
373 inch(void)
375         int c;
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         }
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)
420         char *a, *pre, *post;
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");
450         ic->lineno--;
451         while (*ic->maxread)
452                 ic->maxread++;
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  */
461 pushfile(usch *file)
463         extern struct initar *initar;
464         struct includ ibuf;
465         struct includ *ic;
466         int c, otrulvl;
468         ic = &ibuf;
469         ic->next = ifiles;
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         }
496         otrulvl = trulvl;
498         if ((c = yylex()) != 0)
499                 error("yylex returned %d", c);
501         if (otrulvl != trulvl || flslvl)
502                 error("unterminated conditional");
504         ifiles = ic->next;
505         close(ic->infil);
506         inclevel--;
507         return 0;
511  * Print current position to output file.
512  */
513 void
514 prtline()
516         usch *s, *os = stringbuf;
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;
530 void
531 cunput(int c)
533 #ifdef CPP_DEBUG
534         extern int dflag;
535         if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c);
536 #endif
537         unput(c);
540 int yywrap(void) { return 1; }
542 static int
543 dig2num(int c)
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;
555  * Convert string numbers to unsigned long long and check overflow.
556  */
557 static void
558 cvtdig(int rad)
560         unsigned long long rv = 0;
561         unsigned long long rv2 = 0;
562         char *y = yytext;
563         int c;
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);
588 static int
589 charcon(usch *p)
591         int val, c;
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                 }
624         } else
625                 val = p[-1];
626         return val;
629 static void
630 chknl(int ignore)
632         int t;
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;
650 static void
651 elsestmt(void)
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);
673 static void
674 ifdefstmt(void)          
676         int t;
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);
701 static void
702 ifndefstmt(void)          
704         int t;
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);
720 static void
721 endifstmt(void)          
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);
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)
745         usch *bc, oc;
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         }
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)
788         usch *opb = stringbuf;
789         int c;
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);
823 static void
824 ifstmt(void)
826         if (flslvl == 0) {
827                 slow = 1;
828                 if (yyparse())
829                         ++trulvl;
830                 else
831                         ++flslvl;
832                 slow = 0;
833         } else
834                 ++flslvl;
837 static void
838 elifstmt(void)
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");
863 static usch *
864 svinp(void)
866         int c;
867         usch *cp = stringbuf;
869         while ((c = input()) && c != '\n')
870                 savch(c);
871         savch('\n');
872         savch(0);
873         BEGIN 0;
874         return cp;
877 static void
878 cpperror(void)
880         usch *cp;
881         int c;
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);
895 static void
896 undefstmt(void)
898         struct symtab *np;
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);
909 static void
910 pragmastmt(void)
912         int c;
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;
929 static void
930 badop(const char *op)
932         error("invalid operator in preprocessor expression: %s", op);
936 cinput()
938         return input();