/* */
This source file includes following definitions.
- Cpp
- process_attribute
- function_definition
- condition_macro
- enumerator_list
1 /*
2 * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009,
3 * 2010
4 * Tama Communications Corporation
5 *
6 * This file is part of GNU GLOBAL.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #else
28 #include <strings.h>
29 #endif
30
31 #include "internal.h"
32 #include "die.h"
33 #include "strbuf.h"
34 #include "strlimcpy.h"
35 #include "token.h"
36 #include "cpp_res.h"
37
38 static void process_attribute(const struct parser_param *);
39 static int function_definition(const struct parser_param *);
40 static void condition_macro(const struct parser_param *, int);
41 static int enumerator_list(const struct parser_param *);
42
43 /** max size of complete name of class */
44 #define MAXCOMPLETENAME 1024
45 /** max size of class stack */
46 #define MAXCLASSSTACK 100
47 #define IS_CV_QUALIFIER(c) ((c) == CPP_CONST || (c) == CPP_VOLATILE)
48
49 #define MAXPIFSTACK 100
50
51 /**
52 * @name #ifdef stack.
53 */
54
55 static struct {
56 short start; /**< level when @CODE{\#if} block started */
57 short end; /**< level when @CODE{\#if} block end */
58 short if0only; /**< @CODE{\#if 0} or notdef only */
59 } pifstack[MAXPIFSTACK], *cur;
60 static int piflevel; /**< condition macro level */
61 static int level; /**< brace level */
62 static int namespacelevel; /**< namespace block level */
63
64 /**
65 * Cpp: read C++ file and pickup tag entries.
66 */
67 void
68 Cpp(const struct parser_param *param)
69 {
70 int c, cc;
71 int savelevel;
72 int startclass, startthrow, startmacro, startsharp, startequal;
73 char classname[MAXTOKEN];
74 char completename[MAXCOMPLETENAME];
75 char *completename_limit = &completename[sizeof(completename)];
76 int classlevel;
77 struct {
78 char *classname;
79 char *terminate;
80 int level;
81 } stack[MAXCLASSSTACK];
82 const char *interested = "{}=;~";
83 STRBUF *sb = strbuf_open(0);
84
85 *classname = *completename = 0;
86 stack[0].classname = completename;
87 stack[0].terminate = completename;
88 stack[0].level = 0;
89 level = classlevel = piflevel = namespacelevel = 0;
90 savelevel = -1;
91 startclass = startthrow = startmacro = startsharp = startequal = 0;
92
93 if (!opentoken(param->file))
94 die("'%s' cannot open.", param->file);
95 cmode = 1; /* allow token like '#xxx' */
96 crflag = 1; /* require '\n' as a token */
97 cppmode = 1; /* treat '::' as a token */
98
99 while ((cc = nexttoken(interested, cpp_reserved_word)) != EOF) {
100 if (cc == '~' && level == stack[classlevel].level)
101 continue;
102 switch (cc) {
103 case SYMBOL: /* symbol */
104 if (startclass || startthrow) {
105 PUT(PARSER_REF_SYM, token, lineno, sp);
106 } else if (peekc(0) == '('/* ) */) {
107 if (param->isnotfunction(token)) {
108 PUT(PARSER_REF_SYM, token, lineno, sp);
109 } else if (level > stack[classlevel].level || startequal || startmacro) {
110 PUT(PARSER_REF_SYM, token, lineno, sp);
111 } else if (level == stack[classlevel].level && !startmacro && !startsharp && !startequal) {
112 char savetok[MAXTOKEN], *saveline;
113 int savelineno = lineno;
114
115 strlimcpy(savetok, token, sizeof(savetok));
116 strbuf_reset(sb);
117 strbuf_puts(sb, sp);
118 saveline = strbuf_value(sb);
119 if (function_definition(param)) {
120 /* ignore constructor */
121 if (strcmp(stack[classlevel].classname, savetok))
122 PUT(PARSER_DEF, savetok, savelineno, saveline);
123 } else {
124 PUT(PARSER_REF_SYM, savetok, savelineno, saveline);
125 }
126 }
127 } else {
128 PUT(PARSER_REF_SYM, token, lineno, sp);
129 }
130 break;
131 case CPP_USING:
132 /*
133 * using namespace name;
134 * using ...;
135 */
136 if ((c = nexttoken(interested, cpp_reserved_word)) == CPP_NAMESPACE) {
137 if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL) {
138 PUT(PARSER_REF_SYM, token, lineno, sp);
139 } else {
140 if (param->flags & PARSER_WARNING)
141 warning("missing namespace name. [+%d %s].", lineno, curfile);
142 pushbacktoken();
143 }
144 } else
145 pushbacktoken();
146 break;
147 case CPP_NAMESPACE:
148 crflag = 0;
149 /*
150 * namespace name = ...;
151 * namespace [name] { ... }
152 */
153 if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL) {
154 PUT(PARSER_DEF, token, lineno, sp);
155 if ((c = nexttoken(interested, cpp_reserved_word)) == '=') {
156 crflag = 1;
157 break;
158 }
159 }
160 /*
161 * Namespace block doesn't have any influence on level.
162 */
163 if (c == '{') /* } */ {
164 namespacelevel++;
165 } else {
166 if (param->flags & PARSER_WARNING)
167 warning("missing namespace block. [+%d %s](0x%x).", lineno, curfile, c);
168 }
169 crflag = 1;
170 break;
171 case CPP_EXTERN: /* for 'extern "C"/"C++"' */
172 if (peekc(0) != '"') /* " */
173 continue; /* If does not start with '"', continue. */
174 while ((c = nexttoken(interested, cpp_reserved_word)) == '\n')
175 ;
176 /*
177 * 'extern "C"/"C++"' block is a kind of namespace block.
178 * (It doesn't have any influence on level.)
179 */
180 if (c == '{') /* } */
181 namespacelevel++;
182 else
183 pushbacktoken();
184 break;
185 case CPP_CLASS:
186 DBG_PRINT(level, "class");
187 if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL) {
188 strlimcpy(classname, token, sizeof(classname));
189 /*
190 * Ignore forward definitions.
191 * "class name;"
192 */
193 if (peekc(0) != ';') {
194 startclass = 1;
195 PUT(PARSER_DEF, token, lineno, sp);
196 }
197 }
198 break;
199 case '{': /* } */
200 DBG_PRINT(level, "{"); /* } */
201 ++level;
202 if ((param->flags & PARSER_BEGIN_BLOCK) && atfirst) {
203 if ((param->flags & PARSER_WARNING) && level != 1)
204 warning("forced level 1 block start by '{' at column 0 [+%d %s].", lineno, curfile); /* } */
205 level = 1;
206 }
207 if (startclass) {
208 char *p = stack[classlevel].terminate;
209 char *q = classname;
210
211 if (++classlevel >= MAXCLASSSTACK)
212 die("class stack over flow.[%s]", curfile);
213 if (classlevel > 1 && p < completename_limit)
214 *p++ = '.';
215 stack[classlevel].classname = p;
216 while (*q && p < completename_limit)
217 *p++ = *q++;
218 stack[classlevel].terminate = p;
219 stack[classlevel].level = level;
220 *p++ = 0;
221 }
222 startclass = startthrow = 0;
223 break;
224 /* { */
225 case '}':
226 if (--level < 0) {
227 if (namespacelevel > 0)
228 namespacelevel--;
229 else if (param->flags & PARSER_WARNING)
230 warning("missing left '{' [+%d %s].", lineno, curfile); /* } */
231 level = 0;
232 }
233 if ((param->flags & PARSER_END_BLOCK) && atfirst) {
234 if ((param->flags & PARSER_WARNING) && level != 0)
235 /* { */
236 warning("forced level 0 block end by '}' at column 0 [+%d %s].", lineno, curfile);
237 level = 0;
238 }
239 if (level < stack[classlevel].level)
240 *(stack[--classlevel].terminate) = 0;
241 /* { */
242 DBG_PRINT(level, "}");
243 break;
244 case '=':
245 /* dirty hack. Don't mimic this. */
246 if (peekc(0) == '=') {
247 throwaway_nextchar();
248 } else {
249 startequal = 1;
250 }
251 break;
252 case ';':
253 startthrow = startequal = 0;
254 break;
255 case '\n':
256 if (startmacro && level != savelevel) {
257 if (param->flags & PARSER_WARNING)
258 warning("different level before and after #define macro. reseted. [+%d %s].", lineno, curfile);
259 level = savelevel;
260 }
261 startmacro = startsharp = 0;
262 break;
263 /*
264 * #xxx
265 */
266 case SHARP_DEFINE:
267 case SHARP_UNDEF:
268 startmacro = 1;
269 savelevel = level;
270 if ((c = nexttoken(interested, cpp_reserved_word)) != SYMBOL) {
271 pushbacktoken();
272 break;
273 }
274 if (peekc(1) == '('/* ) */) {
275 PUT(PARSER_DEF, token, lineno, sp);
276 while ((c = nexttoken("()", cpp_reserved_word)) != EOF && c != '\n' && c != /* ( */ ')')
277 if (c == SYMBOL)
278 PUT(PARSER_REF_SYM, token, lineno, sp);
279 if (c == '\n')
280 pushbacktoken();
281 } else {
282 PUT(PARSER_DEF, token, lineno, sp);
283 }
284 break;
285 case SHARP_IMPORT:
286 case SHARP_INCLUDE:
287 case SHARP_INCLUDE_NEXT:
288 case SHARP_ERROR:
289 case SHARP_LINE:
290 case SHARP_PRAGMA:
291 case SHARP_WARNING:
292 case SHARP_IDENT:
293 case SHARP_SCCS:
294 while ((c = nexttoken(interested, cpp_reserved_word)) != EOF && c != '\n')
295 ;
296 break;
297 case SHARP_IFDEF:
298 case SHARP_IFNDEF:
299 case SHARP_IF:
300 case SHARP_ELIF:
301 case SHARP_ELSE:
302 case SHARP_ENDIF:
303 condition_macro(param, cc);
304 break;
305 case SHARP_SHARP: /* ## */
306 (void)nexttoken(interested, cpp_reserved_word);
307 break;
308 case CPP_NEW:
309 if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL)
310 PUT(PARSER_REF_SYM, token, lineno, sp);
311 break;
312 case CPP_STRUCT:
313 case CPP_ENUM:
314 case CPP_UNION:
315 while ((c = nexttoken(interested, cpp_reserved_word)) == CPP___ATTRIBUTE__)
316 process_attribute(param);
317 if (c == SYMBOL) {
318 if (peekc(0) == '{') /* } */ {
319 PUT(PARSER_DEF, token, lineno, sp);
320 } else {
321 PUT(PARSER_REF_SYM, token, lineno, sp);
322 }
323 c = nexttoken(interested, cpp_reserved_word);
324 }
325 if (c == '{' /* } */ && cc == CPP_ENUM) {
326 enumerator_list(param);
327 } else {
328 pushbacktoken();
329 }
330 break;
331 case CPP_TEMPLATE:
332 {
333 int level = 0;
334
335 while ((c = nexttoken("<>", cpp_reserved_word)) != EOF) {
336 if (c == '<')
337 ++level;
338 else if (c == '>') {
339 if (--level == 0)
340 break;
341 } else if (c == SYMBOL) {
342 PUT(PARSER_REF_SYM, token, lineno, sp);
343 }
344 }
345 if (c == EOF && (param->flags & PARSER_WARNING))
346 warning("template <...> isn't closed. [+%d %s].", lineno, curfile);
347 }
348 break;
349 case CPP_OPERATOR:
350 while ((c = nexttoken(";{", /* } */ cpp_reserved_word)) != EOF) {
351 if (c == '{') /* } */ {
352 pushbacktoken();
353 break;
354 } else if (c == ';') {
355 break;
356 } else if (c == SYMBOL) {
357 PUT(PARSER_REF_SYM, token, lineno, sp);
358 }
359 }
360 if (c == EOF && (param->flags & PARSER_WARNING))
361 warning("'{' doesn't exist after 'operator'. [+%d %s].", lineno, curfile); /* } */
362 break;
363 /* control statement check */
364 case CPP_THROW:
365 startthrow = 1;
366 case CPP_BREAK:
367 case CPP_CASE:
368 case CPP_CATCH:
369 case CPP_CONTINUE:
370 case CPP_DEFAULT:
371 case CPP_DELETE:
372 case CPP_DO:
373 case CPP_ELSE:
374 case CPP_FOR:
375 case CPP_GOTO:
376 case CPP_IF:
377 case CPP_RETURN:
378 case CPP_SWITCH:
379 case CPP_TRY:
380 case CPP_WHILE:
381 if ((param->flags & PARSER_WARNING) && !startmacro && level == 0)
382 warning("Out of function. %8s [+%d %s]", token, lineno, curfile);
383 break;
384 case CPP_TYPEDEF:
385 {
386 /*
387 * This parser is too complex to maintain.
388 * We should rewrite the whole.
389 */
390 char savetok[MAXTOKEN];
391 int savelineno = 0;
392 int typedef_savelevel = level;
393
394 savetok[0] = 0;
395
396 /* skip CV qualifiers */
397 do {
398 c = nexttoken("{}(),;", cpp_reserved_word);
399 } while (IS_CV_QUALIFIER(c) || c == '\n');
400
401 if ((param->flags & PARSER_WARNING) && c == EOF) {
402 warning("unexpected eof. [+%d %s]", lineno, curfile);
403 break;
404 } else if (c == CPP_ENUM || c == CPP_STRUCT || c == CPP_UNION) {
405 char *interest_enum = "{},;";
406 int c_ = c;
407
408 while ((c = nexttoken(interest_enum, cpp_reserved_word)) == CPP___ATTRIBUTE__)
409 process_attribute(param);
410 /* read tag name if exist */
411 if (c == SYMBOL) {
412 if (peekc(0) == '{') /* } */ {
413 PUT(PARSER_DEF, token, lineno, sp);
414 } else {
415 PUT(PARSER_REF_SYM, token, lineno, sp);
416 }
417 c = nexttoken(interest_enum, cpp_reserved_word);
418 }
419 if (c_ == CPP_ENUM) {
420 if (c == '{') /* } */
421 c = enumerator_list(param);
422 else
423 pushbacktoken();
424 } else {
425 for (; c != EOF; c = nexttoken(interest_enum, cpp_reserved_word)) {
426 switch (c) {
427 case SHARP_IFDEF:
428 case SHARP_IFNDEF:
429 case SHARP_IF:
430 case SHARP_ELIF:
431 case SHARP_ELSE:
432 case SHARP_ENDIF:
433 condition_macro(param, c);
434 continue;
435 default:
436 break;
437 }
438 if (c == ';' && level == typedef_savelevel) {
439 if (savetok[0])
440 PUT(PARSER_DEF, savetok, savelineno, sp);
441 break;
442 } else if (c == '{')
443 level++;
444 else if (c == '}') {
445 if (--level == typedef_savelevel)
446 break;
447 } else if (c == SYMBOL) {
448 PUT(PARSER_REF_SYM, token, lineno, sp);
449 /* save lastest token */
450 strlimcpy(savetok, token, sizeof(savetok));
451 savelineno = lineno;
452 }
453 }
454 if (c == ';')
455 break;
456 }
457 if ((param->flags & PARSER_WARNING) && c == EOF) {
458 warning("unexpected eof. [+%d %s]", lineno, curfile);
459 break;
460 }
461 } else if (c == SYMBOL) {
462 PUT(PARSER_REF_SYM, token, lineno, sp);
463 }
464 savetok[0] = 0;
465 while ((c = nexttoken("(),;", cpp_reserved_word)) != EOF) {
466 switch (c) {
467 case SHARP_IFDEF:
468 case SHARP_IFNDEF:
469 case SHARP_IF:
470 case SHARP_ELIF:
471 case SHARP_ELSE:
472 case SHARP_ENDIF:
473 condition_macro(param, c);
474 continue;
475 default:
476 break;
477 }
478 if (c == '(')
479 level++;
480 else if (c == ')')
481 level--;
482 else if (c == SYMBOL) {
483 if (level > typedef_savelevel) {
484 PUT(PARSER_REF_SYM, token, lineno, sp);
485 } else {
486 /* put latest token if any */
487 if (savetok[0]) {
488 PUT(PARSER_REF_SYM, savetok, savelineno, sp);
489 }
490 /* save lastest token */
491 strlimcpy(savetok, token, sizeof(savetok));
492 savelineno = lineno;
493 }
494 } else if (c == ',' || c == ';') {
495 if (savetok[0]) {
496 PUT(PARSER_DEF, savetok, lineno, sp);
497 savetok[0] = 0;
498 }
499 }
500 if (level == typedef_savelevel && c == ';')
501 break;
502 }
503 if (param->flags & PARSER_WARNING) {
504 if (c == EOF)
505 warning("unexpected eof. [+%d %s]", lineno, curfile);
506 else if (level != typedef_savelevel)
507 warning("unmatched () block. (last at level %d.)[+%d %s]", level, lineno, curfile);
508 }
509 }
510 break;
511 case CPP___ATTRIBUTE__:
512 process_attribute(param);
513 break;
514 default:
515 break;
516 }
517 }
518 strbuf_close(sb);
519 if (param->flags & PARSER_WARNING) {
520 if (level != 0)
521 warning("unmatched {} block. (last at level %d.)[+%d %s]", level, lineno, curfile);
522 if (piflevel != 0)
523 warning("unmatched #if block. (last at level %d.)[+%d %s]", piflevel, lineno, curfile);
524 }
525 closetoken();
526 }
527 /**
528 * process_attribute: skip attributes in @CODE{__attribute__((...))}.
529 */
530 static void
531 process_attribute(const struct parser_param *param)
532 {
533 int brace = 0;
534 int c;
535 /*
536 * Skip '...' in __attribute__((...))
537 * but pick up symbols in it.
538 */
539 while ((c = nexttoken("()", cpp_reserved_word)) != EOF) {
540 if (c == '(')
541 brace++;
542 else if (c == ')')
543 brace--;
544 else if (c == SYMBOL) {
545 PUT(PARSER_REF_SYM, token, lineno, sp);
546 }
547 if (brace == 0)
548 break;
549 }
550 }
551 /**
552 * function_definition: return if function definition or not.
553 *
554 * @return target type
555 */
556 static int
557 function_definition(const struct parser_param *param)
558 {
559 int c;
560 int brace_level;
561
562 brace_level = 0;
563 while ((c = nexttoken("()", cpp_reserved_word)) != EOF) {
564 switch (c) {
565 case SHARP_IFDEF:
566 case SHARP_IFNDEF:
567 case SHARP_IF:
568 case SHARP_ELIF:
569 case SHARP_ELSE:
570 case SHARP_ENDIF:
571 condition_macro(param, c);
572 continue;
573 default:
574 break;
575 }
576 if (c == '('/* ) */)
577 brace_level++;
578 else if (c == /* ( */')') {
579 if (--brace_level == 0)
580 break;
581 }
582 /* pick up symbol */
583 if (c == SYMBOL)
584 PUT(PARSER_REF_SYM, token, lineno, sp);
585 }
586 if (c == EOF)
587 return 0;
588 if (peekc(0) == ';') {
589 (void)nexttoken(";", NULL);
590 return 0;
591 }
592 brace_level = 0;
593 while ((c = nexttoken(",;[](){}=", cpp_reserved_word)) != EOF) {
594 switch (c) {
595 case SHARP_IFDEF:
596 case SHARP_IFNDEF:
597 case SHARP_IF:
598 case SHARP_ELIF:
599 case SHARP_ELSE:
600 case SHARP_ENDIF:
601 condition_macro(param, c);
602 continue;
603 case CPP___ATTRIBUTE__:
604 process_attribute(param);
605 continue;
606 default:
607 break;
608 }
609 if (c == '('/* ) */ || c == '[')
610 brace_level++;
611 else if (c == /* ( */')' || c == ']')
612 brace_level--;
613 else if (brace_level == 0 && (c == ';' || c == ','))
614 break;
615 else if (c == '{' /* } */) {
616 pushbacktoken();
617 return 1;
618 } else if (c == /* { */'}') {
619 pushbacktoken();
620 break;
621 } else if (c == '=')
622 break;
623 /* pick up symbol */
624 if (c == SYMBOL)
625 PUT(PARSER_REF_SYM, token, lineno, sp);
626 }
627 return 0;
628 }
629
630 /**
631 * condition_macro:
632 *
633 * @param[in] param
634 * @param[in] cc token
635 */
636 static void
637 condition_macro(const struct parser_param *param, int cc)
638 {
639 cur = &pifstack[piflevel];
640 if (cc == SHARP_IFDEF || cc == SHARP_IFNDEF || cc == SHARP_IF) {
641 DBG_PRINT(piflevel, "#if");
642 if (++piflevel >= MAXPIFSTACK)
643 die("#if pifstack over flow. [%s]", curfile);
644 ++cur;
645 cur->start = level;
646 cur->end = -1;
647 cur->if0only = 0;
648 if (peekc(0) == '0')
649 cur->if0only = 1;
650 else if ((cc = nexttoken(NULL, cpp_reserved_word)) == SYMBOL && !strcmp(token, "notdef"))
651 cur->if0only = 1;
652 else
653 pushbacktoken();
654 } else if (cc == SHARP_ELIF || cc == SHARP_ELSE) {
655 DBG_PRINT(piflevel - 1, "#else");
656 if (cur->end == -1)
657 cur->end = level;
658 else if (cur->end != level && (param->flags & PARSER_WARNING))
659 warning("uneven level. [+%d %s]", lineno, curfile);
660 level = cur->start;
661 cur->if0only = 0;
662 } else if (cc == SHARP_ENDIF) {
663 int minus = 0;
664
665 --piflevel;
666 if (piflevel < 0) {
667 minus = 1;
668 piflevel = 0;
669 }
670 DBG_PRINT(piflevel, "#endif");
671 if (minus) {
672 if (param->flags & PARSER_WARNING)
673 warning("unmatched #if block. reseted. [+%d %s]", lineno, curfile);
674 } else {
675 if (cur->if0only)
676 level = cur->start;
677 else if (cur->end != -1) {
678 if (cur->end != level && (param->flags & PARSER_WARNING))
679 warning("uneven level. [+%d %s]", lineno, curfile);
680 level = cur->end;
681 }
682 }
683 }
684 while ((cc = nexttoken(NULL, cpp_reserved_word)) != EOF && cc != '\n') {
685 if (cc == SYMBOL && strcmp(token, "defined") != 0) {
686 PUT(PARSER_REF_SYM, token, lineno, sp);
687 }
688 }
689 }
690
691 /**
692 * enumerator_list: process @CODE{"symbol (= expression), ... \}"}
693 */
694 static int
695 enumerator_list(const struct parser_param *param)
696 {
697 int savelevel = level;
698 int in_expression = 0;
699 int c = '{';
700
701 for (; c != EOF; c = nexttoken("{}(),=", cpp_reserved_word)) {
702 switch (c) {
703 case SHARP_IFDEF:
704 case SHARP_IFNDEF:
705 case SHARP_IF:
706 case SHARP_ELIF:
707 case SHARP_ELSE:
708 case SHARP_ENDIF:
709 condition_macro(param, c);
710 break;
711 case SYMBOL:
712 if (in_expression)
713 PUT(PARSER_REF_SYM, token, lineno, sp);
714 else
715 PUT(PARSER_DEF, token, lineno, sp);
716 break;
717 case '{':
718 case '(':
719 level++;
720 break;
721 case '}':
722 case ')':
723 if (--level == savelevel)
724 return c;
725 break;
726 case ',':
727 if (level == savelevel + 1)
728 in_expression = 0;
729 break;
730 case '=':
731 in_expression = 1;
732 break;
733 default:
734 break;
735 }
736 }
737
738 return c;
739 }
/* */