/* */
This source file includes following definitions.
- yacc
- C
- C_family
- process_attribute
- function_definition
- condition_macro
- enumerator_list
1 /*
2 * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
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 "c_res.h"
37
38 static void C_family(const struct parser_param *, int);
39 static void process_attribute(const struct parser_param *);
40 static int function_definition(const struct parser_param *, char *);
41 static void condition_macro(const struct parser_param *, int);
42 static int enumerator_list(const struct parser_param *);
43
44 #define IS_TYPE_QUALIFIER(c) ((c) == C_CONST || (c) == C_RESTRICT || (c) == C_VOLATILE)
45
46 #define DECLARATIONS 0
47 #define RULES 1
48 #define PROGRAMS 2
49
50 #define TYPE_C 0
51 #define TYPE_LEX 1
52 #define TYPE_YACC 2
53
54 #define MAXPIFSTACK 100
55
56 /**
57 * @name #ifdef stack.
58 */
59 static struct {
60 short start; /**< level when @CODE{\#if} block started */
61 short end; /**< level when @CODE{\#if} block end */
62 short if0only; /**< @CODE{\#if 0} or notdef only */
63 } stack[MAXPIFSTACK], *cur;
64 static int piflevel; /**< condition macro level */
65 static int level; /**< brace level */
66 static int externclevel; /**< @CODE{extern "C"} block level */
67
68 /**
69 * yacc: read yacc file and pickup tag entries.
70 */
71 void
72 yacc(const struct parser_param *param)
73 {
74 C_family(param, TYPE_YACC);
75 }
76 /**
77 * C: read C file and pickup tag entries.
78 */
79 void
80 C(const struct parser_param *param)
81 {
82 C_family(param, TYPE_C);
83 }
84 /**
85 * @param[in] param source file
86 * @param[in] type #TYPE_C, #TYPE_YACC, #TYPE_LEX
87 */
88 static void
89 C_family(const struct parser_param *param, int type)
90 {
91 int c, cc;
92 int savelevel;
93 int startmacro, startsharp;
94 const char *interested = "{}=;";
95 STRBUF *sb = strbuf_open(0);
96 /*
97 * yacc file format is like the following.
98 *
99 * declarations
100 * %%
101 * rules
102 * %%
103 * programs
104 *
105 */
106 int yaccstatus = (type == TYPE_YACC) ? DECLARATIONS : PROGRAMS;
107 int inC = (type == TYPE_YACC) ? 0 : 1; /* 1 while C source */
108
109 level = piflevel = externclevel = 0;
110 savelevel = -1;
111 startmacro = startsharp = 0;
112
113 if (!opentoken(param->file))
114 die("'%s' cannot open.", param->file);
115 cmode = 1; /* allow token like '#xxx' */
116 crflag = 1; /* require '\n' as a token */
117 if (type == TYPE_YACC)
118 ymode = 1; /* allow token like '%xxx' */
119
120 while ((cc = nexttoken(interested, c_reserved_word)) != EOF) {
121 switch (cc) {
122 case SYMBOL: /* symbol */
123 if (inC && peekc(0) == '('/* ) */) {
124 if (param->isnotfunction(token)) {
125 PUT(PARSER_REF_SYM, token, lineno, sp);
126 } else if (level > 0 || startmacro) {
127 PUT(PARSER_REF_SYM, token, lineno, sp);
128 } else if (level == 0 && !startmacro && !startsharp) {
129 char arg1[MAXTOKEN], savetok[MAXTOKEN], *saveline;
130 int savelineno = lineno;
131
132 strlimcpy(savetok, token, sizeof(savetok));
133 strbuf_reset(sb);
134 strbuf_puts(sb, sp);
135 saveline = strbuf_value(sb);
136 arg1[0] = '\0';
137 /*
138 * Guile function entry using guile-snarf is like follows:
139 *
140 * SCM_DEFINE (scm_list, "list", 0, 0, 1,
141 * (SCM objs),
142 * "Return a list containing OBJS, the arguments to `list'.")
143 * #define FUNC_NAME s_scm_list
144 * {
145 * return objs;
146 * }
147 * #undef FUNC_NAME
148 *
149 * We should assume the first argument as a function name instead of 'SCM_DEFINE'.
150 */
151 if (function_definition(param, arg1)) {
152 if (!strcmp(savetok, "SCM_DEFINE") && *arg1)
153 strlimcpy(savetok, arg1, sizeof(savetok));
154 PUT(PARSER_DEF, savetok, savelineno, saveline);
155 } else {
156 PUT(PARSER_REF_SYM, savetok, savelineno, saveline);
157 }
158 }
159 } else {
160 PUT(PARSER_REF_SYM, token, lineno, sp);
161 }
162 break;
163 case '{': /* } */
164 DBG_PRINT(level, "{"); /* } */
165 if (yaccstatus == RULES && level == 0)
166 inC = 1;
167 ++level;
168 if ((param->flags & PARSER_BEGIN_BLOCK) && atfirst) {
169 if ((param->flags & PARSER_WARNING) && level != 1)
170 warning("forced level 1 block start by '{' at column 0 [+%d %s].", lineno, curfile); /* } */
171 level = 1;
172 }
173 break;
174 /* { */
175 case '}':
176 if (--level < 0) {
177 if (externclevel > 0)
178 externclevel--;
179 else if (param->flags & PARSER_WARNING)
180 warning("missing left '{' [+%d %s].", lineno, curfile); /* } */
181 level = 0;
182 }
183 if ((param->flags & PARSER_END_BLOCK) && atfirst) {
184 if ((param->flags & PARSER_WARNING) && level != 0) /* { */
185 warning("forced level 0 block end by '}' at column 0 [+%d %s].", lineno, curfile);
186 level = 0;
187 }
188 if (yaccstatus == RULES && level == 0)
189 inC = 0;
190 /* { */
191 DBG_PRINT(level, "}");
192 break;
193 case '\n':
194 if (startmacro && level != savelevel) {
195 if (param->flags & PARSER_WARNING)
196 warning("different level before and after #define macro. reseted. [+%d %s].", lineno, curfile);
197 level = savelevel;
198 }
199 startmacro = startsharp = 0;
200 break;
201 case YACC_SEP: /* %% */
202 if (level != 0) {
203 if (param->flags & PARSER_WARNING)
204 warning("forced level 0 block end by '%%' [+%d %s].", lineno, curfile);
205 level = 0;
206 }
207 if (yaccstatus == DECLARATIONS) {
208 PUT(PARSER_DEF, "yyparse", lineno, sp);
209 yaccstatus = RULES;
210 } else if (yaccstatus == RULES)
211 yaccstatus = PROGRAMS;
212 inC = (yaccstatus == PROGRAMS) ? 1 : 0;
213 break;
214 case YACC_BEGIN: /* %{ */
215 if (level != 0) {
216 if (param->flags & PARSER_WARNING)
217 warning("forced level 0 block end by '%%{' [+%d %s].", lineno, curfile);
218 level = 0;
219 }
220 if (inC == 1 && (param->flags & PARSER_WARNING))
221 warning("'%%{' appeared in C mode. [+%d %s].", lineno, curfile);
222 inC = 1;
223 break;
224 case YACC_END: /* %} */
225 if (level != 0) {
226 if (param->flags & PARSER_WARNING)
227 warning("forced level 0 block end by '%%}' [+%d %s].", lineno, curfile);
228 level = 0;
229 }
230 if (inC == 0 && (param->flags & PARSER_WARNING))
231 warning("'%%}' appeared in Yacc mode. [+%d %s].", lineno, curfile);
232 inC = 0;
233 break;
234 case YACC_UNION: /* %union {...} */
235 if (yaccstatus == DECLARATIONS)
236 PUT(PARSER_DEF, "YYSTYPE", lineno, sp);
237 break;
238 /*
239 * #xxx
240 */
241 case SHARP_DEFINE:
242 case SHARP_UNDEF:
243 startmacro = 1;
244 savelevel = level;
245 if ((c = nexttoken(interested, c_reserved_word)) != SYMBOL) {
246 pushbacktoken();
247 break;
248 }
249 if (peekc(1) == '('/* ) */) {
250 PUT(PARSER_DEF, token, lineno, sp);
251 while ((c = nexttoken("()", c_reserved_word)) != EOF && c != '\n' && c != /* ( */ ')')
252 if (c == SYMBOL)
253 PUT(PARSER_REF_SYM, token, lineno, sp);
254 if (c == '\n')
255 pushbacktoken();
256 } else {
257 PUT(PARSER_DEF, token, lineno, sp);
258 }
259 break;
260 case SHARP_IMPORT:
261 case SHARP_INCLUDE:
262 case SHARP_INCLUDE_NEXT:
263 case SHARP_ERROR:
264 case SHARP_LINE:
265 case SHARP_PRAGMA:
266 case SHARP_WARNING:
267 case SHARP_IDENT:
268 case SHARP_SCCS:
269 while ((c = nexttoken(interested, c_reserved_word)) != EOF && c != '\n')
270 ;
271 break;
272 case SHARP_IFDEF:
273 case SHARP_IFNDEF:
274 case SHARP_IF:
275 case SHARP_ELIF:
276 case SHARP_ELSE:
277 case SHARP_ENDIF:
278 condition_macro(param, cc);
279 break;
280 case SHARP_SHARP: /* ## */
281 (void)nexttoken(interested, c_reserved_word);
282 break;
283 case C_EXTERN: /* for 'extern "C"/"C++"' */
284 if (peekc(0) != '"') /* " */
285 continue; /* If does not start with '"', continue. */
286 while ((c = nexttoken(interested, c_reserved_word)) == '\n')
287 ;
288 /*
289 * 'extern "C"/"C++"' block is a kind of namespace block.
290 * (It doesn't have any influence on level.)
291 */
292 if (c == '{') /* } */
293 externclevel++;
294 else
295 pushbacktoken();
296 break;
297 case C_STRUCT:
298 case C_ENUM:
299 case C_UNION:
300 while ((c = nexttoken(interested, c_reserved_word)) == C___ATTRIBUTE__)
301 process_attribute(param);
302 if (c == SYMBOL) {
303 if (peekc(0) == '{') /* } */ {
304 PUT(PARSER_DEF, token, lineno, sp);
305 } else {
306 PUT(PARSER_REF_SYM, token, lineno, sp);
307 }
308 c = nexttoken(interested, c_reserved_word);
309 }
310 if (c == '{' /* } */ && cc == C_ENUM) {
311 enumerator_list(param);
312 } else {
313 pushbacktoken();
314 }
315 break;
316 /* control statement check */
317 case C_BREAK:
318 case C_CASE:
319 case C_CONTINUE:
320 case C_DEFAULT:
321 case C_DO:
322 case C_ELSE:
323 case C_FOR:
324 case C_GOTO:
325 case C_IF:
326 case C_RETURN:
327 case C_SWITCH:
328 case C_WHILE:
329 if ((param->flags & PARSER_WARNING) && !startmacro && level == 0)
330 warning("Out of function. %8s [+%d %s]", token, lineno, curfile);
331 break;
332 case C_TYPEDEF:
333 {
334 /*
335 * This parser is too complex to maintain.
336 * We should rewrite the whole.
337 */
338 char savetok[MAXTOKEN];
339 int savelineno = 0;
340 int typedef_savelevel = level;
341
342 savetok[0] = 0;
343
344 /* skip type qualifiers */
345 do {
346 c = nexttoken("{}(),;", c_reserved_word);
347 } while (IS_TYPE_QUALIFIER(c) || c == '\n');
348
349 if ((param->flags & PARSER_WARNING) && c == EOF) {
350 warning("unexpected eof. [+%d %s]", lineno, curfile);
351 break;
352 } else if (c == C_ENUM || c == C_STRUCT || c == C_UNION) {
353 char *interest_enum = "{},;";
354 int c_ = c;
355
356 while ((c = nexttoken(interest_enum, c_reserved_word)) == C___ATTRIBUTE__)
357 process_attribute(param);
358 /* read tag name if exist */
359 if (c == SYMBOL) {
360 if (peekc(0) == '{') /* } */ {
361 PUT(PARSER_DEF, token, lineno, sp);
362 } else {
363 PUT(PARSER_REF_SYM, token, lineno, sp);
364 }
365 c = nexttoken(interest_enum, c_reserved_word);
366 }
367
368 if (c_ == C_ENUM) {
369 if (c == '{') /* } */
370 c = enumerator_list(param);
371 else
372 pushbacktoken();
373 } else {
374 for (; c != EOF; c = nexttoken(interest_enum, c_reserved_word)) {
375 switch (c) {
376 case SHARP_IFDEF:
377 case SHARP_IFNDEF:
378 case SHARP_IF:
379 case SHARP_ELIF:
380 case SHARP_ELSE:
381 case SHARP_ENDIF:
382 condition_macro(param, c);
383 continue;
384 default:
385 break;
386 }
387 if (c == ';' && level == typedef_savelevel) {
388 if (savetok[0])
389 PUT(PARSER_DEF, savetok, savelineno, sp);
390 break;
391 } else if (c == '{')
392 level++;
393 else if (c == '}') {
394 if (--level == typedef_savelevel)
395 break;
396 } else if (c == SYMBOL) {
397 PUT(PARSER_REF_SYM, token, lineno, sp);
398 /* save lastest token */
399 strlimcpy(savetok, token, sizeof(savetok));
400 savelineno = lineno;
401 }
402 }
403 if (c == ';')
404 break;
405 }
406 if ((param->flags & PARSER_WARNING) && c == EOF) {
407 warning("unexpected eof. [+%d %s]", lineno, curfile);
408 break;
409 }
410 } else if (c == SYMBOL) {
411 PUT(PARSER_REF_SYM, token, lineno, sp);
412 }
413 savetok[0] = 0;
414 while ((c = nexttoken("(),;", c_reserved_word)) != EOF) {
415 switch (c) {
416 case SHARP_IFDEF:
417 case SHARP_IFNDEF:
418 case SHARP_IF:
419 case SHARP_ELIF:
420 case SHARP_ELSE:
421 case SHARP_ENDIF:
422 condition_macro(param, c);
423 continue;
424 default:
425 break;
426 }
427 if (c == '(')
428 level++;
429 else if (c == ')')
430 level--;
431 else if (c == SYMBOL) {
432 if (level > typedef_savelevel) {
433 PUT(PARSER_REF_SYM, token, lineno, sp);
434 } else {
435 /* put latest token if any */
436 if (savetok[0]) {
437 PUT(PARSER_REF_SYM, savetok, savelineno, sp);
438 }
439 /* save lastest token */
440 strlimcpy(savetok, token, sizeof(savetok));
441 savelineno = lineno;
442 }
443 } else if (c == ',' || c == ';') {
444 if (savetok[0]) {
445 PUT(PARSER_DEF, savetok, lineno, sp);
446 savetok[0] = 0;
447 }
448 }
449 if (level == typedef_savelevel && c == ';')
450 break;
451 }
452 if (param->flags & PARSER_WARNING) {
453 if (c == EOF)
454 warning("unexpected eof. [+%d %s]", lineno, curfile);
455 else if (level != typedef_savelevel)
456 warning("unmatched () block. (last at level %d.)[+%d %s]", level, lineno, curfile);
457 }
458 }
459 break;
460 case C___ATTRIBUTE__:
461 process_attribute(param);
462 break;
463 default:
464 break;
465 }
466 }
467 strbuf_close(sb);
468 if (param->flags & PARSER_WARNING) {
469 if (level != 0)
470 warning("unmatched {} block. (last at level %d.)[+%d %s]", level, lineno, curfile);
471 if (piflevel != 0)
472 warning("unmatched #if block. (last at level %d.)[+%d %s]", piflevel, lineno, curfile);
473 }
474 closetoken();
475 }
476 /**
477 * process_attribute: skip attributes in @CODE{__attribute__((...))}.
478 */
479 static void
480 process_attribute(const struct parser_param *param)
481 {
482 int brace = 0;
483 int c;
484 /*
485 * Skip '...' in __attribute__((...))
486 * but pick up symbols in it.
487 */
488 while ((c = nexttoken("()", c_reserved_word)) != EOF) {
489 if (c == '(')
490 brace++;
491 else if (c == ')')
492 brace--;
493 else if (c == SYMBOL) {
494 PUT(PARSER_REF_SYM, token, lineno, sp);
495 }
496 if (brace == 0)
497 break;
498 }
499 }
500 /**
501 * function_definition: return if function definition or not.
502 *
503 * @param param
504 * @param[out] arg1 the first argument
505 * @return target type
506 */
507 static int
508 function_definition(const struct parser_param *param, char arg1[MAXTOKEN])
509 {
510 int c;
511 int brace_level, isdefine;
512 int accept_arg1 = 0;
513
514 brace_level = isdefine = 0;
515 while ((c = nexttoken("()", c_reserved_word)) != EOF) {
516 switch (c) {
517 case SHARP_IFDEF:
518 case SHARP_IFNDEF:
519 case SHARP_IF:
520 case SHARP_ELIF:
521 case SHARP_ELSE:
522 case SHARP_ENDIF:
523 condition_macro(param, c);
524 continue;
525 default:
526 break;
527 }
528 if (c == '('/* ) */)
529 brace_level++;
530 else if (c == /* ( */')') {
531 if (--brace_level == 0)
532 break;
533 }
534 /* pick up symbol */
535 if (c == SYMBOL) {
536 if (accept_arg1 == 0) {
537 accept_arg1 = 1;
538 strlimcpy(arg1, token, MAXTOKEN);
539 }
540 PUT(PARSER_REF_SYM, token, lineno, sp);
541 }
542 }
543 if (c == EOF)
544 return 0;
545 brace_level = 0;
546 while ((c = nexttoken(",;[](){}=", c_reserved_word)) != EOF) {
547 switch (c) {
548 case SHARP_IFDEF:
549 case SHARP_IFNDEF:
550 case SHARP_IF:
551 case SHARP_ELIF:
552 case SHARP_ELSE:
553 case SHARP_ENDIF:
554 condition_macro(param, c);
555 continue;
556 case C___ATTRIBUTE__:
557 process_attribute(param);
558 continue;
559 default:
560 break;
561 }
562 if (c == '('/* ) */ || c == '[')
563 brace_level++;
564 else if (c == /* ( */')' || c == ']')
565 brace_level--;
566 else if (brace_level == 0
567 && ((c == SYMBOL && strcmp(token, "__THROW")) || IS_RESERVED_WORD(c)))
568 isdefine = 1;
569 else if (c == ';' || c == ',') {
570 if (!isdefine)
571 break;
572 } else if (c == '{' /* } */) {
573 pushbacktoken();
574 return 1;
575 } else if (c == /* { */'}')
576 break;
577 else if (c == '=')
578 break;
579
580 /* pick up symbol */
581 if (c == SYMBOL)
582 PUT(PARSER_REF_SYM, token, lineno, sp);
583 }
584 return 0;
585 }
586
587 /**
588 * condition_macro:
589 *
590 * @param param
591 * @param[in] cc token
592 */
593 static void
594 condition_macro(const struct parser_param *param, int cc)
595 {
596 cur = &stack[piflevel];
597 if (cc == SHARP_IFDEF || cc == SHARP_IFNDEF || cc == SHARP_IF) {
598 DBG_PRINT(piflevel, "#if");
599 if (++piflevel >= MAXPIFSTACK)
600 die("#if stack over flow. [%s]", curfile);
601 ++cur;
602 cur->start = level;
603 cur->end = -1;
604 cur->if0only = 0;
605 if (peekc(0) == '0')
606 cur->if0only = 1;
607 else if ((cc = nexttoken(NULL, c_reserved_word)) == SYMBOL && !strcmp(token, "notdef"))
608 cur->if0only = 1;
609 else
610 pushbacktoken();
611 } else if (cc == SHARP_ELIF || cc == SHARP_ELSE) {
612 DBG_PRINT(piflevel - 1, "#else");
613 if (cur->end == -1)
614 cur->end = level;
615 else if (cur->end != level && (param->flags & PARSER_WARNING))
616 warning("uneven level. [+%d %s]", lineno, curfile);
617 level = cur->start;
618 cur->if0only = 0;
619 } else if (cc == SHARP_ENDIF) {
620 int minus = 0;
621
622 --piflevel;
623 if (piflevel < 0) {
624 minus = 1;
625 piflevel = 0;
626 }
627 DBG_PRINT(piflevel, "#endif");
628 if (minus) {
629 if (param->flags & PARSER_WARNING)
630 warning("unmatched #if block. reseted. [+%d %s]", lineno, curfile);
631 } else {
632 if (cur->if0only)
633 level = cur->start;
634 else if (cur->end != -1) {
635 if (cur->end != level && (param->flags & PARSER_WARNING))
636 warning("uneven level. [+%d %s]", lineno, curfile);
637 level = cur->end;
638 }
639 }
640 }
641 while ((cc = nexttoken(NULL, c_reserved_word)) != EOF && cc != '\n') {
642 if (cc == SYMBOL && strcmp(token, "defined") != 0)
643 PUT(PARSER_REF_SYM, token, lineno, sp);
644 }
645 }
646
647 /**
648 * enumerator_list: process @CODE{"symbol (= expression), ... \}"}
649 */
650 static int
651 enumerator_list(const struct parser_param *param)
652 {
653 int savelevel = level;
654 int in_expression = 0;
655 int c = '{';
656
657 for (; c != EOF; c = nexttoken("{}(),=", c_reserved_word)) {
658 switch (c) {
659 case SHARP_IFDEF:
660 case SHARP_IFNDEF:
661 case SHARP_IF:
662 case SHARP_ELIF:
663 case SHARP_ELSE:
664 case SHARP_ENDIF:
665 condition_macro(param, c);
666 break;
667 case SYMBOL:
668 if (in_expression)
669 PUT(PARSER_REF_SYM, token, lineno, sp);
670 else
671 PUT(PARSER_DEF, token, lineno, sp);
672 break;
673 case '{':
674 case '(':
675 level++;
676 break;
677 case '}':
678 case ')':
679 if (--level == savelevel)
680 return c;
681 break;
682 case ',':
683 if (level == savelevel + 1)
684 in_expression = 0;
685 break;
686 case '=':
687 in_expression = 1;
688 break;
689 default:
690 break;
691 }
692 }
693
694 return c;
695 }
/* */