1 /*
2 * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
3 * 2010, 2015
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 * #ifdef stack.
58 */
59 static struct {
60 short start; /* level when '#if' block started */
61 short end; /* level when '#if' block end */
62 short if0only; /* '#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; /* 'extern "C"' block level */
67
68 /**
69 * yacc: read yacc file and pickup tag entries.
70 */
71 void
yacc(const struct parser_param * param)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
C(const struct parser_param * param)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
C_family(const struct parser_param * param,int type)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 while (c == '\n')
303 c = nexttoken(interested, c_reserved_word);
304 if (c == SYMBOL) {
305 if (peekc(0) == '{') /* } */ {
306 PUT(PARSER_DEF, token, lineno, sp);
307 } else {
308 PUT(PARSER_REF_SYM, token, lineno, sp);
309 }
310 c = nexttoken(interested, c_reserved_word);
311 }
312 while (c == '\n')
313 c = nexttoken(interested, c_reserved_word);
314 if (c == '{' /* } */ && cc == C_ENUM) {
315 enumerator_list(param);
316 } else {
317 pushbacktoken();
318 }
319 break;
320 /* control statement check */
321 case C_BREAK:
322 case C_CASE:
323 case C_CONTINUE:
324 case C_DEFAULT:
325 case C_DO:
326 case C_ELSE:
327 case C_FOR:
328 case C_GOTO:
329 case C_IF:
330 case C_RETURN:
331 case C_SWITCH:
332 case C_WHILE:
333 if ((param->flags & PARSER_WARNING) && !startmacro && level == 0)
334 warning("Out of function. %8s [+%d %s]", token, lineno, curfile);
335 break;
336 case C_TYPEDEF:
337 {
338 /*
339 * This parser is too complex to maintain.
340 * We should rewrite the whole.
341 */
342 char savetok[MAXTOKEN];
343 int savelineno = 0;
344 int typedef_savelevel = level;
345
346 savetok[0] = 0;
347
348 /* skip type qualifiers */
349 do {
350 c = nexttoken("{}(),;", c_reserved_word);
351 } while (IS_TYPE_QUALIFIER(c) || c == '\n');
352
353 if ((param->flags & PARSER_WARNING) && c == EOF) {
354 warning("unexpected eof. [+%d %s]", lineno, curfile);
355 break;
356 } else if (c == C_ENUM || c == C_STRUCT || c == C_UNION) {
357 char *interest_enum = "{},;";
358 int c_ = c;
359
360 while ((c = nexttoken(interest_enum, c_reserved_word)) == C___ATTRIBUTE__)
361 process_attribute(param);
362 while (c == '\n')
363 c = nexttoken(interest_enum, c_reserved_word);
364 /* read tag name if exist */
365 if (c == SYMBOL) {
366 if (peekc(0) == '{') /* } */ {
367 PUT(PARSER_DEF, token, lineno, sp);
368 } else {
369 PUT(PARSER_REF_SYM, token, lineno, sp);
370 }
371 c = nexttoken(interest_enum, c_reserved_word);
372 }
373 while (c == '\n')
374 c = nexttoken(interest_enum, c_reserved_word);
375 if (c_ == C_ENUM) {
376 if (c == '{') /* } */
377 c = enumerator_list(param);
378 else
379 pushbacktoken();
380 } else {
381 for (; c != EOF; c = nexttoken(interest_enum, c_reserved_word)) {
382 switch (c) {
383 case SHARP_IFDEF:
384 case SHARP_IFNDEF:
385 case SHARP_IF:
386 case SHARP_ELIF:
387 case SHARP_ELSE:
388 case SHARP_ENDIF:
389 condition_macro(param, c);
390 continue;
391 default:
392 break;
393 }
394 if (c == ';' && level == typedef_savelevel) {
395 if (savetok[0]) {
396 PUT(PARSER_DEF, savetok, savelineno, sp);
397 savetok[0] = 0;
398 }
399 break;
400 } else if (c == '{')
401 level++;
402 else if (c == '}') {
403 savetok[0] = 0;
404 if (--level == typedef_savelevel)
405 break;
406 } else if (c == SYMBOL) {
407 if (level > typedef_savelevel)
408 PUT(PARSER_REF_SYM, token, lineno, sp);
409 /* save lastest token */
410 strlimcpy(savetok, token, sizeof(savetok));
411 savelineno = lineno;
412 }
413 }
414 if (c == ';')
415 break;
416 }
417 if ((param->flags & PARSER_WARNING) && c == EOF) {
418 warning("unexpected eof. [+%d %s]", lineno, curfile);
419 break;
420 }
421 } else if (c == SYMBOL) {
422 PUT(PARSER_REF_SYM, token, lineno, sp);
423 }
424 savetok[0] = 0;
425 while ((c = nexttoken("(),;", c_reserved_word)) != EOF) {
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 == '(')
439 level++;
440 else if (c == ')')
441 level--;
442 else if (c == SYMBOL) {
443 if (level > typedef_savelevel) {
444 PUT(PARSER_REF_SYM, token, lineno, sp);
445 } else {
446 /* put latest token if any */
447 if (savetok[0]) {
448 PUT(PARSER_REF_SYM, savetok, savelineno, sp);
449 }
450 /* save lastest token */
451 strlimcpy(savetok, token, sizeof(savetok));
452 savelineno = lineno;
453 }
454 } else if (c == ',' || c == ';') {
455 if (savetok[0]) {
456 PUT(PARSER_DEF, savetok, lineno, sp);
457 savetok[0] = 0;
458 }
459 }
460 if (level == typedef_savelevel && c == ';')
461 break;
462 }
463 if (param->flags & PARSER_WARNING) {
464 if (c == EOF)
465 warning("unexpected eof. [+%d %s]", lineno, curfile);
466 else if (level != typedef_savelevel)
467 warning("unmatched () block. (last at level %d.)[+%d %s]", level, lineno, curfile);
468 }
469 }
470 break;
471 case C___ATTRIBUTE__:
472 process_attribute(param);
473 break;
474 default:
475 break;
476 }
477 }
478 strbuf_close(sb);
479 if (param->flags & PARSER_WARNING) {
480 if (level != 0)
481 warning("unmatched {} block. (last at level %d.)[+%d %s]", level, lineno, curfile);
482 if (piflevel != 0)
483 warning("unmatched #if block. (last at level %d.)[+%d %s]", piflevel, lineno, curfile);
484 }
485 closetoken();
486 }
487 /**
488 * process_attribute: skip attributes in '__attribute__((...))'.
489 */
490 static void
process_attribute(const struct parser_param * param)491 process_attribute(const struct parser_param *param)
492 {
493 int brace = 0;
494 int c;
495 /*
496 * Skip '...' in __attribute__((...))
497 * but pick up symbols in it.
498 */
499 while ((c = nexttoken("()", c_reserved_word)) != EOF) {
500 if (c == '(')
501 brace++;
502 else if (c == ')')
503 brace--;
504 else if (c == SYMBOL) {
505 PUT(PARSER_REF_SYM, token, lineno, sp);
506 }
507 if (brace == 0)
508 break;
509 }
510 }
511 /**
512 * function_definition: return if function definition or not.
513 *
514 * @param param
515 * @param[out] arg1 the first argument
516 * @return target type
517 */
518 static int
function_definition(const struct parser_param * param,char arg1[MAXTOKEN])519 function_definition(const struct parser_param *param, char arg1[MAXTOKEN])
520 {
521 int c;
522 int brace_level, isdefine;
523 int accept_arg1 = 0;
524
525 brace_level = isdefine = 0;
526 while ((c = nexttoken("()", c_reserved_word)) != EOF) {
527 switch (c) {
528 case SHARP_IFDEF:
529 case SHARP_IFNDEF:
530 case SHARP_IF:
531 case SHARP_ELIF:
532 case SHARP_ELSE:
533 case SHARP_ENDIF:
534 condition_macro(param, c);
535 continue;
536 default:
537 break;
538 }
539 if (c == '('/* ) */)
540 brace_level++;
541 else if (c == /* ( */')') {
542 if (--brace_level == 0)
543 break;
544 }
545 /* pick up symbol */
546 if (c == SYMBOL) {
547 if (accept_arg1 == 0) {
548 accept_arg1 = 1;
549 strlimcpy(arg1, token, MAXTOKEN);
550 }
551 PUT(PARSER_REF_SYM, token, lineno, sp);
552 }
553 }
554 if (c == EOF)
555 return 0;
556 brace_level = 0;
557 while ((c = nexttoken(",;[](){}=", c_reserved_word)) != EOF) {
558 switch (c) {
559 case SHARP_IFDEF:
560 case SHARP_IFNDEF:
561 case SHARP_IF:
562 case SHARP_ELIF:
563 case SHARP_ELSE:
564 case SHARP_ENDIF:
565 condition_macro(param, c);
566 continue;
567 case C___ATTRIBUTE__:
568 process_attribute(param);
569 continue;
570 case SHARP_DEFINE:
571 pushbacktoken();
572 return 0;
573 default:
574 break;
575 }
576 if (c == '('/* ) */ || c == '[')
577 brace_level++;
578 else if (c == /* ( */')' || c == ']')
579 brace_level--;
580 else if (brace_level == 0
581 && ((c == SYMBOL && strcmp(token, "__THROW")) || IS_RESERVED_WORD(c)))
582 isdefine = 1;
583 else if (c == ';' || c == ',') {
584 if (!isdefine)
585 break;
586 } else if (c == '{' /* } */) {
587 pushbacktoken();
588 return 1;
589 } else if (c == /* { */'}')
590 break;
591 else if (c == '=')
592 break;
593
594 /* pick up symbol */
595 if (c == SYMBOL)
596 PUT(PARSER_REF_SYM, token, lineno, sp);
597 }
598 return 0;
599 }
600
601 /**
602 * condition_macro:
603 *
604 * @param param
605 * @param[in] cc token
606 */
607 static void
condition_macro(const struct parser_param * param,int cc)608 condition_macro(const struct parser_param *param, int cc)
609 {
610 cur = &stack[piflevel];
611 if (cc == SHARP_IFDEF || cc == SHARP_IFNDEF || cc == SHARP_IF) {
612 DBG_PRINT(piflevel, "#if");
613 if (++piflevel >= MAXPIFSTACK)
614 die("#if stack over flow. [%s]", curfile);
615 ++cur;
616 cur->start = level;
617 cur->end = -1;
618 cur->if0only = 0;
619 if (peekc(0) == '0')
620 cur->if0only = 1;
621 else if ((cc = nexttoken(NULL, c_reserved_word)) == SYMBOL && !strcmp(token, "notdef"))
622 cur->if0only = 1;
623 else
624 pushbacktoken();
625 } else if (cc == SHARP_ELIF || cc == SHARP_ELSE) {
626 DBG_PRINT(piflevel - 1, "#else");
627 if (cur->end == -1)
628 cur->end = level;
629 else if (cur->end != level && (param->flags & PARSER_WARNING))
630 warning("uneven level. [+%d %s]", lineno, curfile);
631 level = cur->start;
632 cur->if0only = 0;
633 } else if (cc == SHARP_ENDIF) {
634 int minus = 0;
635
636 --piflevel;
637 if (piflevel < 0) {
638 minus = 1;
639 piflevel = 0;
640 }
641 DBG_PRINT(piflevel, "#endif");
642 if (minus) {
643 if (param->flags & PARSER_WARNING)
644 warning("unmatched #if block. reseted. [+%d %s]", lineno, curfile);
645 } else {
646 if (cur->if0only)
647 level = cur->start;
648 else if (cur->end != -1) {
649 if (cur->end != level && (param->flags & PARSER_WARNING))
650 warning("uneven level. [+%d %s]", lineno, curfile);
651 level = cur->end;
652 }
653 }
654 }
655 while ((cc = nexttoken(NULL, c_reserved_word)) != EOF && cc != '\n') {
656 if (cc == SYMBOL && strcmp(token, "defined") != 0)
657 PUT(PARSER_REF_SYM, token, lineno, sp);
658 }
659 }
660
661 /**
662 * enumerator_list: process "symbol (= expression), ... "}
663 */
664 static int
enumerator_list(const struct parser_param * param)665 enumerator_list(const struct parser_param *param)
666 {
667 int savelevel = level;
668 int in_expression = 0;
669 int c = '{';
670
671 for (; c != EOF; c = nexttoken("{}(),=", c_reserved_word)) {
672 switch (c) {
673 case SHARP_IFDEF:
674 case SHARP_IFNDEF:
675 case SHARP_IF:
676 case SHARP_ELIF:
677 case SHARP_ELSE:
678 case SHARP_ENDIF:
679 condition_macro(param, c);
680 break;
681 case SYMBOL:
682 if (in_expression)
683 PUT(PARSER_REF_SYM, token, lineno, sp);
684 else
685 PUT(PARSER_DEF, token, lineno, sp);
686 break;
687 case '{':
688 case '(':
689 level++;
690 break;
691 case '}':
692 case ')':
693 if (--level == savelevel)
694 return c;
695 break;
696 case ',':
697 if (level == savelevel + 1)
698 in_expression = 0;
699 break;
700 case '=':
701 in_expression = 1;
702 break;
703 default:
704 break;
705 }
706 }
707
708 return c;
709 }
710