2 /* $Id: scanner.l,v 1.49 2009/02/14 09:23:55 ragge Exp $ */
5 * Copyright (c) 2004 Anders Magnusson. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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 *);
64 extern int yyget_lineno (void);
65 extern void yyset_lineno (int);
67 static int inch(void);
69 static int scale, gotdef, contr;
72 #ifdef FLEX_SCANNER /* should be set by autoconf instead */
74 yyinput(char *b, int m)
78 for (i = 0; i < m; i++) {
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__)
96 #define ECHO putstr((usch *)yytext)
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);
112 #else /* Assume lex here */
115 #define input() inch()
116 #define unput(ch) unch(ch)
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
132 %s IFR CONTR DEF COMMENT
136 "\n" { int os = YYSTATE;
141 if (ifiles->lineno == 1)
146 if ((os != 0 || slow) && !contr)
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;
165 if ((p = c = yylex()) == '(')
167 if (c != IDENT || (p != IDENT && p != '('))
168 error("syntax error");
169 if (p == '(' && yylex() != ')')
170 error("syntax error");
176 yylval.node.op = NUMBER;
179 = lookup((usch *)yytext, FIND) != 0;
183 yylval.node.nd_val = 0;
188 if (slow && !YYSTATE)
190 scale = yytext[0] == '0' ? 8 : 10;
194 0[xX]{H}+{IS}? { scale = 16;
195 num: if (YYSTATE == IFR)
199 0{D}+{IS}? { scale = 8; goto num; }
200 {D}+{IS}? { scale = 10; goto num; }
202 if (YYSTATE || slow) {
203 yylval.node.op = NUMBER;
204 yylval.node.nd_val = charcon((usch *)yytext);
210 putstr((usch *)yytext);
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;
222 error("preprocessor directive found "
223 "while expanding macro");
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);
251 int prtcm = Cflag && !flslvl && !slow;
254 if (Cflag && !flslvl && readmac)
258 putstr((usch *)yytext);
260 more: while ((c = input()) && c != '*') {
262 putch(c), ifiles->lineno++;
263 else if (c == 1) /* WARN */
272 if ((c = input()) && c != '/') {
280 if (!tflag && !Cflag && !flslvl)
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})* */
296 if (YYSTATE == CONTR) {
298 /*error("undefined control");*/
299 while (input() != '\n')
305 BEGIN 0; /* 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));
316 putstr((usch *)yytext);
322 while (input() != '\n')
331 if (yytext[0] == 6) { /* PRAGS */
332 usch *obp = stringbuf;
333 extern usch *prtprag(usch *);
334 *stringbuf++ = yytext[0];
336 *stringbuf = input();
337 } while (*stringbuf++ != 14);
348 usch *yyp, yybuf[CPPBUF];
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);
365 ifiles->curptr = ifiles->buffer;
366 ifiles->maxread = ifiles->buffer + len;
370 #define unch(c) *--ifiles->curptr = c
377 again: switch (c = inpch()) {
378 case '\\': /* continued lines */
379 msdos: if ((c = inpch()) == '\n') {
383 } else if (c == '\r')
387 case '?': /* trigraphs */
388 if ((c = inpch()) != '?') {
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;
415 * Let the command-line args be faked defines at beginning of file.
418 prinit(struct initar *it, struct includ *ic)
420 char *a, *pre, *post;
423 prinit(it->next, ic);
424 pre = post = NULL; /* XXX gcc */
428 if ((a = strchr(it->str, '=')) != NULL) {
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");
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.
463 extern struct initar *initar;
473 if ((ic->infil = open((char *)file, O_RDONLY)) < 0)
475 ic->orgfn = ic->fname = file;
476 if (++inclevel > MAX_INCLEVEL)
477 error("Limit for nested includes exceeded");
480 ic->orgfn = ic->fname = (usch *)"<stdin>";
482 ic->buffer = ic->bbuf+NAMEMAX;
483 ic->curptr = ic->buffer;
486 ic->maxread = ic->curptr;
492 write(ofd, ic->buffer, strlen((char *)ic->buffer));
498 if ((c = yylex()) != 0)
499 error("yylex returned %d", c);
501 if (otrulvl != trulvl || flslvl)
502 error("unterminated conditional");
511 * Print current position to output file.
516 usch *s, *os = stringbuf;
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));
526 putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
535 if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c);
540 int yywrap(void) { return 1; }
555 * Convert string numbers to unsigned long long and check overflow.
560 unsigned long long rv = 0;
561 unsigned long long rv2 = 0;
568 while (isxdigit(c)) {
569 rv = rv * rad + dig2num(c);
572 error("Constant \"%s\" is out of range", yytext);
577 while (*y == 'l' || *y == 'L')
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);
593 p++; /* skip first ' */
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;
608 while (isxdigit(c = *p)) {
609 val = val * 16 + dig2num(c);
613 case '0': case '1': case '2': case '3': case '4':
614 case '5': case '6': case '7':
616 while (isdigit(c = *p)) {
617 val = val * 8 + (c - '0');
621 default: val = p[-1];
635 while ((t = yylex()) == WSPACE)
639 warning("newline expected, got \"%s\"", yytext);
640 /* ignore rest of line */
641 while ((t = yylex()) && t != '\n')
645 error("newline expected, got \"%s\"", yytext);
656 else if (--flslvl!=0) {
666 error("If-less else");
667 if (elslvl==trulvl+flslvl)
668 error("Too many else");
669 elslvl=trulvl+flslvl;
679 /* just ignore the rest of the line */
680 while (input() != '\n')
694 if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0)
713 if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0)
730 error("If-less endif");
739 * Walk over the string s and search for defined, and replace it with
740 * spaces and a 1 or 0.
750 if (memcmp(s, "defined", 7))
752 /* Ok, got defined, can scratch it now */
755 #define WSARG(x) (x == ' ' || x == '\t')
756 if (*s != '(' && !WSARG(*s))
764 #define IDARG(x) ((x>= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x == '_'))
765 #define NUMARG(x) (x >= '0' && x <= '9')
767 error("bad defined arg");
769 while (IDARG(*s) || NUMARG(*s))
773 *bc = (lookup(bc, FIND) != 0) + '0';
774 memset(bc+1, ' ', s-bc-1);
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.
788 usch *opb = stringbuf;
791 while ((c = input()) != '\n') {
793 if ((c = input()) == '*') {
794 /* ignore comments here whatsoever */
799 } else if (c == '/') {
800 while ((c = input()) && c != '\n')
811 fixdefined(opb); /* XXX can fail if #line? */
812 cunput(1); /* WARN XXX */
818 /* line now expanded */
819 while (stringbuf > opb)
820 cunput(*--stringbuf);
845 else if (--flslvl!=0)
860 error("If-less elif");
867 usch *cp = stringbuf;
869 while ((c = input()) && c != '\n')
886 if (c != WSPACE && c != '\n')
901 if (yylex() != WSPACE || yylex() != IDENT)
903 if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
915 if (yylex() != WSPACE)
918 putstr((usch *)"#pragma ");
922 putch(c); /* Do arg expansion instead? */
923 } while (c && c != '\n');
930 badop(const char *op)
932 error("invalid operator in preprocessor expression: %s", op);