Line data Source code
1 : /* This file is part of GNU cflow
2 : Copyright (C) 1997, 2005, 2007, 2010 Sergey Poznyakoff
3 :
4 : GNU cflow is free software; you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation; either version 3 of the License, or
7 : (at your option) any later version.
8 :
9 : GNU cflow is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public
15 : License along with GNU cflow; if not, write to the Free Software
16 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 : MA 02110-1301 USA */
18 :
19 : %top {
20 : #include <cflow.h>
21 : #include <ctype.h>
22 : #include <parser.h>
23 : }
24 :
25 : %x comment
26 : %x string
27 : %x stringwait
28 : %x longline
29 : %{
30 :
31 : struct obstack string_stk;
32 :
33 : int line_num;
34 : char *filename;
35 : char *canonical_filename;
36 : YYSTYPE yylval;
37 : unsigned input_file_count; /* Number of input files, processed by source() */
38 :
39 : int ident();
40 : void update_loc();
41 : #define lex_error(msg) error_at_line(0, 0, filename, line_num, "%s", msg)
42 :
43 : /* Keep the token returned at the previous call to yylex. This is used
44 : as a lexical tie-in to ensure that the next token after STRUCT is
45 : IDENTIFIER. See get_token and ident below. */
46 : static int prev_token;
47 :
48 : %}
49 : FILENAME [^\n*?]*
50 : ONUMBER (0[0-7]*)
51 : HNUMBER (0[xX][0-9a-fA-F]*)
52 : DNUMBER ([1-9][0-9]*)
53 : DIGITS [0-9][0-9]*
54 : IDENT [a-zA-Z_][a-zA-Z0-9_]*
55 : WS [ \t\f\r]*
56 : %%
57 : /* comments */
58 0 : "//".*\n ++line_num;
59 8217 : "/*" BEGIN(comment);
60 8217 : <comment>[^*\n]* ;
61 23565 : <comment>[^*\n]*\n ++line_num;
62 15348 : <comment>"*"+[^*/\n]* ;
63 3848 : <comment>"*"+[^*/\n]*\n ++line_num;
64 15988 : <comment>"*"+"/" BEGIN(INITIAL);
65 8217 : /* Line directives */
66 11777 : ^{WS}#{WS}line{WS}{DIGITS}.*\n |
67 1440 : ^{WS}#{WS}{DIGITS}.*\n { update_loc(); }
68 1440 : /* skip any preproc */
69 1601 : ^{WS}#.*\\\n { BEGIN(longline); ++line_num; }
70 4233 : {WS}#.*\n ++line_num;
71 5320 : <longline>.*\\\n ++line_num;
72 1570 : <longline>.*\n { BEGIN(INITIAL); ++line_num; }
73 4233 : /* keywords */
74 1248 : auto /* ignored */;
75 305 : extern return EXTERN;
76 1827 : static return STATIC;
77 448 : typedef return TYPEDEF;
78 3427 : struct {yylval.str = "struct"; return STRUCT;}
79 304 : union {yylval.str = "union"; return STRUCT;}
80 1680 : enum {yylval.str = "enum"; return STRUCT;}
81 11340 : \* { yylval.str = "*";
82 11420 : return MODIFIER;
83 11340 : }
84 : /* Operators
85 : *
86 : */
87 8128 : "->" {yylval.str = "->"; return MEMBER_OF;}
88 3024 : "." {yylval.str = "."; return MEMBER_OF;}
89 8144 : "*=" {yylval.str = "*="; return OP;}
90 3024 : "/=" {yylval.str = "/="; return OP;}
91 48 : "/" {yylval.str = "/"; return OP;}
92 0 : "%=" {yylval.str = "%="; return OP;}
93 48 : "%" {yylval.str = "%"; return OP;}
94 362 : "+=" {yylval.str = "+="; return OP;}
95 1261 : "+" {yylval.str = "+"; return OP;}
96 395 : "-=" {yylval.str = "-="; return OP;}
97 1825 : "-" {yylval.str = "-"; return OP;}
98 49 : "<<=" {yylval.str = "<<="; return OP;}
99 580 : ">>=" {yylval.str = ">>="; return OP;}
100 16 : "&=" {yylval.str = "&="; return OP;}
101 112 : "|=" {yylval.str = "|="; return OP;}
102 0 : "^=" {yylval.str = "^="; return OP;}
103 112 : "^" {yylval.str = "^"; return OP;}
104 583 : "||" {yylval.str = "||"; return OP;}
105 192 : "|" {yylval.str = "|"; return OP;}
106 1571 : "&&" {yylval.str = "&&"; return OP;}
107 2426 : "&" {yylval.str = "&"; return OP;}
108 4214 : "==" {yylval.str = "=="; return OP;}
109 16516 : "=" {yylval.str = "="; return '=';}
110 3925 : "!=" {yylval.str = "!="; return OP;}
111 15468 : "!" {yylval.str = "!"; return OP;}
112 958 : ">=" {yylval.str = ">="; return OP;}
113 1493 : ">" {yylval.str = ">"; return OP;}
114 373 : "<=" {yylval.str = "<="; return OP;}
115 975 : "<" {yylval.str = "<"; return OP;}
116 114 : "<<" {yylval.str = "<<"; return OP;}
117 684 : ">>" {yylval.str = ">>"; return OP;}
118 2357 : "++" {yylval.str = "++"; return OP;}
119 340 : "--" {yylval.str = "--"; return OP;}
120 2357 : '.' |
121 324 : '\\.' |
122 : '\\[0-7]{2,3}' |
123 3296 : '\\[xX][0-9a-fA-F]{1,2}' return STRING;
124 3296 : /* Identifiers and constants
125 : *
126 : */
127 : "..." |
128 142868 : {IDENT} return ident();
129 149533 : {ONUMBER} { obstack_grow(&string_stk, yytext, yyleng+1);
130 6665 : yylval.str = obstack_finish(&string_stk);
131 13330 : return WORD;
132 : }
133 38918 : [+\-]?{DNUMBER}[^eE.] { yyless(yyleng-1);
134 38918 : obstack_grow(&string_stk, yytext, yyleng+1);
135 38918 : yylval.str = obstack_finish(&string_stk);
136 77836 : return WORD;}
137 : {HNUMBER} |
138 : [+\-]?{DIGITS}?\.{DIGITS}([eE][+\-]?{DIGITS})? |
139 : [+\-]?{DIGITS}\.([eE][+\-]?{DIGITS})? {
140 0 : obstack_grow(&string_stk, yytext, yyleng+1);
141 0 : yylval.str = obstack_finish(&string_stk);
142 0 : return WORD;
143 : }
144 :
145 : /* strings
146 : * State map:
147 : *
148 : * "<string>blahblahblah"<stringwait>
149 : * <stringwait>"<string>blahblahblah"<stringwait>
150 : * <stringwait>.<INITIAL>
151 : */
152 5459 : \" BEGIN(string);
153 10918 : <string>[^\\"\n]* ;
154 5224 : <string>\n { ++line_num; lex_error(_("unterminated string?")); }
155 5224 : <string>\\. ;
156 584 : <string>\\\n ++line_num;
157 6043 : <string>\" BEGIN(stringwait);
158 5459 : <stringwait>{WS} ;
159 5779 : <stringwait>\n ++line_num;
160 320 : <stringwait>\" BEGIN(string);
161 0 : <stringwait>. {
162 5507 : BEGIN(INITIAL);
163 10918 : yyless(0); /* put the symbol back */
164 5459 : return STRING;
165 : }
166 94489 : \n ++line_num;
167 94489 : {WS} ;
168 211994 : /*\f ;*/
169 309741 : ^\{ return LBRACE0;
170 3371 : ^\} return RBRACE0;
171 178168 : . return yytext[0];
172 3371 : %%
173 174910 :
174 0 : static char *keywords[] = {
175 : "break",
176 : "case",
177 : "continue",
178 : "default",
179 : "do",
180 : "else",
181 : "for",
182 : "goto",
183 : "if",
184 : "return",
185 : "sizeof",
186 : "switch",
187 : "while"
188 : };
189 :
190 : static char *types[] = {
191 : "char",
192 : "double",
193 : "float",
194 : "int",
195 : "void",
196 : };
197 :
198 : static char *qualifiers[] = {
199 : "long",
200 : "const",
201 : "register",
202 : "restrict",
203 : "short",
204 : "signed",
205 : "unsigned",
206 : "volatile",
207 : "inline"
208 : };
209 :
210 : void
211 : init_tokens()
212 19 : {
213 : int i;
214 : Symbol *sp;
215 :
216 : for (i = 0; i < NUMITEMS(keywords); i++) {
217 266 : sp = install(keywords[i], INSTALL_OVERWRITE);
218 247 : sp->type = SymToken;
219 247 : sp->token_type = WORD;
220 247 : }
221 :
222 : for (i = 0; i < NUMITEMS(types); i++) {
223 114 : sp = install(types[i], INSTALL_OVERWRITE);
224 95 : sp->type = SymToken;
225 95 : sp->token_type = TYPE;
226 95 : sp->source = NULL;
227 95 : sp->def_line = -1;
228 95 : sp->ref_line = NULL;
229 95 : }
230 :
231 : for (i = 0; i < NUMITEMS(qualifiers); i++) {
232 190 : sp = install(qualifiers[i], INSTALL_OVERWRITE);
233 171 : sp->type = SymToken;
234 171 : sp->token_type = QUALIFIER;
235 171 : sp->source = NULL;
236 171 : sp->def_line = -1;
237 171 : sp->ref_line = NULL;
238 171 : }
239 : sp = install("...", INSTALL_OVERWRITE);
240 19 : sp->type = SymToken;
241 19 : sp->token_type = IDENTIFIER;
242 19 : sp->source = NULL;
243 19 : sp->def_line = -1;
244 19 : sp->ref_line = NULL;
245 19 : }
246 19 :
247 : void
248 : init_lex(int debug_level)
249 19 : {
250 : yy_flex_debug = debug_level;
251 19 : obstack_init(&string_stk);
252 19 : init_tokens();
253 19 : }
254 19 :
255 : int
256 : ident()
257 142868 : {
258 : /* Do not attempt any symbol table lookup if the previous token was
259 : STRUCT. This helps properly parse constructs like:
260 :
261 : typedef struct foo foo;
262 : struct foo {
263 : int dummy;
264 : };
265 : */
266 : if (prev_token != STRUCT) {
267 142868 : Symbol *sp = lookup(yytext);
268 141220 : if (sp && sp->type == SymToken) {
269 141220 : yylval.str = sp->name;
270 37177 : return sp->token_type;
271 37177 : }
272 : }
273 : obstack_grow(&string_stk, yytext, yyleng);
274 105691 : obstack_1grow(&string_stk, 0);
275 105691 : yylval.str = obstack_finish(&string_stk);
276 105691 : return IDENTIFIER;
277 105691 : }
278 :
279 :
280 :
281 : char *pp_bin;
282 : char *pp_opts;
283 : static struct obstack *opt_stack;
284 :
285 : void
286 : set_preprocessor(const char *arg)
287 0 : {
288 : pp_bin = arg ? xstrdup(arg) : NULL;
289 0 : }
290 0 :
291 : void
292 : pp_option(const char *arg)
293 0 : {
294 : if (!opt_stack) {
295 0 : if (!pp_bin)
296 0 : pp_bin = CFLOW_PREPROC;
297 0 : opt_stack = xmalloc(sizeof *opt_stack);
298 0 : obstack_init(opt_stack);
299 0 : }
300 : obstack_1grow(opt_stack, ' ');
301 0 : obstack_grow(opt_stack, arg, strlen (arg));
302 0 : }
303 0 :
304 : void
305 : pp_finalize()
306 0 : {
307 : char *s = obstack_finish(opt_stack);
308 0 : if (!pp_opts)
309 0 : pp_opts = xstrdup(s);
310 0 : else {
311 : pp_opts = xrealloc(pp_opts, strlen(pp_opts) + strlen(s) + 1);
312 0 : strcat(pp_opts, s);
313 0 : }
314 : obstack_free(opt_stack, s);
315 0 : free(opt_stack);
316 0 : opt_stack = NULL;
317 0 : }
318 0 :
319 : FILE *
320 : pp_open(const char *name)
321 0 : {
322 : FILE *fp;
323 : char *s;
324 : size_t size;
325 :
326 : if (opt_stack)
327 0 : pp_finalize();
328 0 : size = strlen(pp_bin) + 1 + strlen(name) + 1;
329 0 : if (pp_opts)
330 0 : size += strlen(pp_opts);
331 0 : s = xmalloc(size);
332 0 : strcpy(s, pp_bin);
333 0 : if (pp_opts)
334 0 : strcat(s, pp_opts);
335 0 : strcat(s, " ");
336 0 : strcat(s, name);
337 0 : if (debug)
338 0 : printf(_("Command line: %s\n"), s);
339 0 : fp = popen(s, "r");
340 0 : if (!fp)
341 0 : error(0, errno, _("cannot execute `%s'"), s);
342 0 : free(s);
343 0 : return fp;
344 0 : }
345 :
346 : void
347 : pp_close(FILE *fp)
348 0 : {
349 : pclose(fp);
350 0 : }
351 0 :
352 :
353 :
354 : int
355 : yywrap()
356 227 : {
357 : if (!yyin)
358 227 : return 1;
359 0 : if (preprocess_option)
360 227 : pp_close(yyin);
361 0 : else
362 : fclose(yyin);
363 227 : yyin = NULL;
364 227 : #ifdef FLEX_SCANNER
365 : yy_delete_buffer(YY_CURRENT_BUFFER);
366 227 : #endif
367 : delete_statics();
368 227 : return 1;
369 227 : }
370 :
371 : static int hit_eof;
372 :
373 : int
374 : get_token()
375 435276 : {
376 : int tok;
377 :
378 : if (hit_eof)
379 435276 : tok = 0;
380 10 : else {
381 : tok = yylex();
382 435266 : prev_token = tok;
383 435266 : if (!tok)
384 435266 : hit_eof = 1;
385 227 : }
386 : return tok;
387 435276 : }
388 :
389 : int
390 : source(char *name)
391 227 : {
392 : FILE *fp;
393 :
394 : fp = fopen(name, "r");
395 227 : if (!fp) {
396 227 : error(0, errno, _("cannot open `%s'"), name);
397 0 : return 1;
398 0 : }
399 : if (preprocess_option) {
400 227 : fclose(fp);
401 0 : fp = pp_open(name);
402 0 : if (!fp)
403 0 : return 1;
404 0 : }
405 : obstack_grow(&string_stk, name, strlen(name)+1);
406 227 : filename = obstack_finish(&string_stk);
407 227 : canonical_filename = filename;
408 227 : line_num = 1;
409 227 : input_file_count++;
410 227 : hit_eof = 0;
411 227 :
412 : yyrestart(fp);
413 227 : return 0;
414 227 : }
415 :
416 : static int
417 : getnum(unsigned base, int count)
418 0 : {
419 : int c, n;
420 : unsigned i;
421 :
422 : for (n = 0; count; count--) {
423 0 : if (isdigit(c = input()))
424 0 : i = c - '0';
425 0 : else
426 : i = toupper(c) - 'A' + 10;
427 0 : if (i > base) {
428 0 : unput(c);
429 0 : break;
430 0 : }
431 : n = n * base + i;
432 0 : }
433 : return n;
434 0 : }
435 :
436 : int
437 : backslash()
438 0 : {
439 : int c;
440 :
441 : switch (c = input()) {
442 0 : case 'a': return '\a';
443 0 : case 'b': return '\b';
444 0 : case 'f': return '\f';
445 0 : case 'n': return '\n';
446 0 : case 'r': return '\r';
447 0 : case 't': return '\t';
448 0 : case 'x': return getnum(16,2);
449 0 : case '0': return getnum(8,3);
450 0 : }
451 : return c;
452 0 : }
453 :
454 : void
455 : update_loc()
456 1440 : {
457 : char *p;
458 :
459 : for (p = strchr(yytext, '#')+1; *p && isspace(*p); p++)
460 1440 : ;
461 : if (p[0] == 'l') /* line */
462 1440 : p += 4;
463 1440 :
464 : line_num = strtoul(p, &p, 10);
465 1440 : for ( ; *p && isspace(*p); p++)
466 1440 : ;
467 : if (p[0] == '"') {
468 1440 : int n;
469 :
470 : for (p++, n = 0; p[n] && p[n] != '"'; n++)
471 1440 : ;
472 : obstack_grow(&string_stk, p, n);
473 1440 : obstack_1grow(&string_stk, 0);
474 1440 : filename = obstack_finish(&string_stk);
475 1440 : }
476 : if (debug > 1)
477 1440 : printf(_("New location: %s:%d\n"), filename, line_num);
478 1350 : }
479 1440 :
|