Line data Source code
1 : /* This file is part of GNU cflow
2 : Copyright (C) 1997, 2005, 2006, 2007, 2009, 2010, 2011 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 : #include <cflow.h>
20 : #include <parser.h>
21 :
22 : typedef struct {
23 : char *name;
24 : int type_end;
25 : int parmcnt;
26 : int line;
27 : enum storage storage;
28 : } Ident;
29 :
30 : void parse_declaration(Ident*, int);
31 : void parse_variable_declaration(Ident*, int);
32 : void parse_function_declaration(Ident*, int);
33 : void parse_dcl(Ident*, int maybe_knr);
34 : void parse_knr_dcl(Ident*);
35 : void parse_typedef();
36 : void expression();
37 : void initializer_list();
38 : void func_body();
39 : void declare(Ident*, int maybe_knr);
40 : void declare_type(Ident*);
41 : int dcl(Ident*);
42 : int parmdcl(Ident*);
43 : int dirdcl(Ident*);
44 : void skip_struct();
45 : Symbol *get_symbol(char *name);
46 : void maybe_parm_list(int *parm_cnt_return);
47 :
48 : void call(char*, int);
49 : void reference(char*, int);
50 :
51 : int level; /* Current nesting level */
52 : Symbol *caller; /* Current caller */
53 : struct obstack text_stk; /* Obstack for composing declaration line */
54 :
55 : int parm_level; /* Parameter declaration nesting level */
56 :
57 : typedef struct {
58 : int type;
59 : char *token;
60 : int line;
61 : } TOKSTK;
62 :
63 : typedef int Stackpos[1];
64 :
65 : TOKSTK tok;
66 : TOKSTK *token_stack;
67 : int tos;
68 : int curs;
69 : int token_stack_length = 64;
70 : int token_stack_increase = 32;
71 : static int need_space;
72 :
73 : void mark(Stackpos);
74 : void restore(Stackpos);
75 : void tokpush(int,int,char*);
76 : void save_token(TOKSTK *);
77 :
78 : static void
79 174 : print_token(TOKSTK *tokptr)
80 : {
81 174 : switch (tokptr->type) {
82 : case IDENTIFIER:
83 : case TYPE:
84 : case WORD:
85 : case MODIFIER:
86 : case STRUCT:
87 : case PARM_WRAPPER:
88 : case QUALIFIER:
89 : case OP:
90 84 : fprintf(stderr, "`%s'", tokptr->token);
91 84 : break;
92 : case LBRACE0:
93 : case LBRACE:
94 8 : fprintf(stderr, "`{'");
95 8 : break;
96 : case RBRACE0:
97 : case RBRACE:
98 12 : fprintf(stderr, "`}'");
99 12 : break;
100 : case EXTERN:
101 0 : fprintf(stderr, "`extern'");
102 0 : break;
103 : case STATIC:
104 2 : fprintf(stderr, "`static'");
105 2 : break;
106 : case TYPEDEF:
107 0 : fprintf(stderr, "`typedef'");
108 0 : break;
109 : case STRING:
110 12 : fprintf(stderr, "\"%s\"", tokptr->token);
111 12 : break;
112 : default:
113 56 : fprintf(stderr, "`%c'", tokptr->type);
114 : }
115 174 : }
116 :
117 : static void
118 178 : file_error(char *msg, TOKSTK *tokptr)
119 : {
120 178 : fprintf(stderr, "%s:%d: %s", filename, tok.line, msg);
121 178 : if (tokptr) {
122 174 : fprintf(stderr, _(" near "));
123 174 : print_token(tokptr);
124 : }
125 178 : fprintf(stderr, "\n");
126 178 : }
127 :
128 : void
129 36822 : mark(Stackpos pos)
130 : {
131 36822 : pos[0] = curs;
132 36822 : }
133 :
134 : void
135 13219 : restore(Stackpos pos)
136 : {
137 13219 : curs = pos[0];
138 13219 : if (curs)
139 13219 : tok = token_stack[curs-1];
140 13219 : }
141 :
142 : void
143 431913 : tokpush(int type, int line, char *token)
144 : {
145 431913 : token_stack[tos].type = type;
146 431913 : token_stack[tos].token = token;
147 431913 : token_stack[tos].line = line;
148 431913 : if (++tos == token_stack_length) {
149 526 : token_stack_length += token_stack_increase;
150 526 : token_stack = xrealloc(token_stack,
151 : token_stack_length*sizeof(*token_stack));
152 : }
153 431913 : }
154 :
155 : void
156 57354 : cleanup_stack()
157 : {
158 57354 : int delta = tos - curs;
159 :
160 57354 : if (delta)
161 5362 : memmove(token_stack, token_stack+curs, delta*sizeof(token_stack[0]));
162 :
163 57354 : tos = delta;
164 57354 : curs = 0;
165 57354 : }
166 :
167 : void
168 250 : clearstack()
169 : {
170 250 : tos = curs = 0;
171 250 : }
172 :
173 : int
174 584964 : nexttoken()
175 : {
176 : int type;
177 :
178 584964 : if (curs == tos) {
179 430793 : type = get_token();
180 430793 : tokpush(type, line_num, yylval.str);
181 : }
182 584964 : tok = token_stack[curs];
183 584964 : curs++;
184 584964 : return tok.type;
185 : }
186 :
187 : int
188 122535 : putback()
189 : {
190 122535 : if (curs == 0)
191 0 : error(10, 0, _("INTERNAL ERROR: cannot return token to stream"));
192 122535 : curs--;
193 122535 : if (curs > 0) {
194 115464 : tok.type = token_stack[curs-1].type;
195 115464 : tok.token = token_stack[curs-1].token;
196 : } else
197 7071 : tok.type = 0;
198 122535 : return tok.type;
199 : }
200 :
201 : void
202 21 : init_parse()
203 : {
204 21 : obstack_init(&text_stk);
205 21 : token_stack = xmalloc(token_stack_length*sizeof(*token_stack));
206 21 : clearstack();
207 21 : }
208 :
209 : void
210 21665 : save_token(TOKSTK *tokptr)
211 : {
212 : int len;
213 :
214 21665 : switch (tokptr->type) {
215 : case IDENTIFIER:
216 : case TYPE:
217 : case STRUCT:
218 : case PARM_WRAPPER:
219 : case WORD:
220 : case QUALIFIER:
221 10190 : if (need_space)
222 3026 : obstack_1grow(&text_stk, ' ');
223 10190 : len = strlen(tokptr->token);
224 10190 : obstack_grow(&text_stk, tokptr->token, len);
225 10190 : need_space = 1;
226 10190 : break;
227 : case MODIFIER:
228 1894 : if (need_space)
229 1714 : obstack_1grow(&text_stk, ' ');
230 1894 : if (tokptr->token[0] == '*')
231 1894 : need_space = 0;
232 : else
233 0 : need_space = 1;
234 1894 : len = strlen(tokptr->token);
235 1894 : obstack_grow(&text_stk, tokptr->token, len);
236 1894 : break;
237 : case EXTERN: /* storage class specifiers are already taken care of */
238 : case STATIC:
239 1587 : break;
240 : case ',':
241 895 : obstack_1grow(&text_stk, ',');
242 895 : need_space = 1;
243 895 : break;
244 : case '(':
245 3070 : if (need_space)
246 3052 : obstack_1grow(&text_stk, ' ');
247 3070 : obstack_1grow(&text_stk, tokptr->type);
248 3070 : need_space = 0;
249 3070 : break;
250 : case ')':
251 3038 : obstack_1grow(&text_stk, tokptr->type);
252 3038 : need_space = 1;
253 3038 : break;
254 : case '[':
255 : case ']':
256 762 : obstack_1grow(&text_stk, tokptr->type);
257 762 : need_space = 0;
258 762 : break;
259 : case OP:
260 2 : obstack_1grow(&text_stk, ' ');
261 2 : obstack_grow(&text_stk, tokptr->token, strlen(tokptr->token));
262 2 : need_space = 1;
263 2 : break;
264 : default:
265 227 : if (verbose)
266 46 : file_error(_("unrecognized definition"), tokptr);
267 : }
268 21665 : }
269 :
270 : static Stackpos start_pos; /* Start position in stack for saving tokens */
271 : static int save_end; /* Stack position up to which the tokens are saved */
272 :
273 : void
274 14438 : save_stack()
275 : {
276 14438 : mark(start_pos);
277 14438 : save_end = curs - 1;
278 14438 : }
279 :
280 : void
281 9663 : undo_save_stack()
282 : {
283 9663 : save_end = -1;
284 9663 : }
285 :
286 : char *
287 4983 : finish_save_stack(char *name)
288 : {
289 : int i;
290 4983 : int level = 0;
291 4983 : int found_ident = !omit_symbol_names_option;
292 :
293 4983 : need_space = 0;
294 39350 : for (i = 0; i < save_end ; i++) {
295 34367 : switch (token_stack[i].type) {
296 : case '(':
297 3141 : if (omit_arguments_option) {
298 1792 : if (level == 0) {
299 1721 : save_token(token_stack+i);
300 : }
301 1792 : level++;
302 : }
303 3141 : break;
304 : case ')':
305 3109 : if (omit_arguments_option)
306 1760 : level--;
307 3109 : break;
308 : case IDENTIFIER:
309 11321 : if (!found_ident && strcmp (name, token_stack[i].token) == 0) {
310 4396 : need_space = 1;
311 4396 : found_ident = 1;
312 4396 : continue;
313 : }
314 : }
315 29971 : if (level == 0)
316 19944 : save_token(token_stack+i);
317 : }
318 4983 : obstack_1grow(&text_stk, 0);
319 4983 : return obstack_finish(&text_stk);
320 : }
321 :
322 : void
323 1205 : skip_to(int c)
324 : {
325 3145 : while (nexttoken()) {
326 1940 : if (tok.type == c)
327 1205 : break;
328 : }
329 1205 : }
330 :
331 : int
332 160 : skip_balanced(int open_tok, int close_tok, int level)
333 : {
334 160 : if (level == 0) {
335 0 : if (nexttoken() != open_tok) {
336 0 : return 1;
337 : }
338 0 : level++;
339 : }
340 3344 : while (nexttoken()) {
341 3184 : if (tok.type == LBRACE0 && open_tok == '{')
342 0 : tok.type = '{';
343 3184 : else if (tok.type == RBRACE0 && close_tok == '}')
344 128 : tok.type = '}';
345 :
346 3184 : if (tok.type == open_tok)
347 0 : level++;
348 3184 : else if (tok.type == close_tok) {
349 160 : if (--level == 0) {
350 160 : nexttoken();
351 160 : return 0;
352 : }
353 : }
354 : }
355 0 : return -1;
356 : }
357 :
358 : int
359 229 : yyparse()
360 : {
361 : Ident identifier;
362 :
363 229 : level = 0;
364 229 : caller = NULL;
365 229 : clearstack();
366 7278 : while (nexttoken()) {
367 6820 : identifier.storage = ExternStorage;
368 6820 : switch (tok.type) {
369 : case 0:
370 0 : return 0;
371 : case QUALIFIER:
372 112 : continue;
373 : case TYPEDEF:
374 304 : parse_typedef();
375 304 : break;
376 : case EXTERN:
377 144 : identifier.storage = ExplicitExternStorage;
378 144 : parse_declaration(&identifier, 0);
379 144 : break;
380 : case STATIC:
381 1789 : identifier.storage = StaticStorage;
382 1789 : nexttoken();
383 : /* FALLTHRU */
384 : default:
385 6260 : parse_declaration(&identifier, 0);
386 6260 : break;
387 : }
388 6708 : cleanup_stack();
389 : }
390 229 : return 0;
391 : }
392 :
393 : static int
394 11854 : is_function()
395 : {
396 : Stackpos sp;
397 11854 : int res = 0;
398 :
399 11854 : mark(sp);
400 : while (1) {
401 37057 : switch (tok.type) {
402 : case QUALIFIER:
403 : case TYPE:
404 : case IDENTIFIER:
405 : case MODIFIER:
406 : case STATIC:
407 : case EXTERN:
408 25203 : nexttoken();
409 25203 : continue;
410 : case PARM_WRAPPER:
411 0 : if (skip_balanced('(', ')', 0) == -1)
412 0 : file_error(_("unexpected end of file in declaration"),
413 : NULL);
414 0 : continue;
415 : case '(':
416 4143 : res = nexttoken() != MODIFIER;
417 4143 : break;
418 : default:
419 7711 : break;
420 : }
421 11854 : break;
422 25203 : }
423 :
424 11854 : restore(sp);
425 11854 : return res;
426 : }
427 :
428 : void
429 11854 : parse_declaration(Ident *ident, int parm)
430 : {
431 11854 : if (is_function())
432 4095 : parse_function_declaration(ident, parm);
433 : else
434 7759 : parse_variable_declaration(ident, parm);
435 11854 : delete_parms(parm_level);
436 11854 : }
437 :
438 :
439 : void
440 74964 : expression()
441 : {
442 : char *name;
443 : int line;
444 : int parens_lev;
445 :
446 74964 : parens_lev = 0;
447 : while (1) {
448 320469 : switch (tok.type) {
449 : case ';':
450 30303 : return;
451 : case LBRACE:
452 : case LBRACE0:
453 : case RBRACE:
454 : case RBRACE0:
455 6642 : putback();
456 6642 : return;
457 : case ',':
458 46634 : if (parens_lev == 0)
459 38019 : return;
460 8615 : break;
461 : case 0:
462 0 : if (verbose)
463 0 : file_error(_("unexpected end of file in expression"),
464 : NULL);
465 0 : return;
466 :
467 : case IDENTIFIER:
468 76021 : name = tok.token;
469 76021 : line = tok.line;
470 76021 : nexttoken();
471 76021 : if (tok.type == '(') {
472 13080 : call(name, line);
473 13080 : parens_lev++;
474 : } else {
475 62941 : reference(name, line);
476 62941 : if (tok.type == MEMBER_OF) {
477 28908 : while (tok.type == MEMBER_OF)
478 9636 : nexttoken();
479 : } else {
480 53305 : putback();
481 : }
482 : }
483 76021 : break;
484 : case '(':
485 : /* maybe typecast */
486 13128 : if (nexttoken() == TYPE)
487 770 : skip_to(')');
488 : else {
489 12358 : putback();
490 12358 : parens_lev++;
491 : }
492 13128 : break;
493 : case ')':
494 25438 : parens_lev--;
495 25438 : break;
496 : }
497 245505 : nexttoken();
498 245505 : }
499 : }
500 :
501 : void
502 4095 : parse_function_declaration(Ident *ident, int parm)
503 : {
504 4095 : int error_recovery = 0;
505 4095 : ident->type_end = -1;
506 4095 : parse_knr_dcl(ident);
507 :
508 : restart:
509 4455 : switch (tok.type) {
510 : case ')':
511 58 : if (parm)
512 0 : break;
513 : /*FALLTHROUGH*/
514 : default:
515 360 : if (error_recovery)
516 326 : nexttoken();
517 : else {
518 34 : if (verbose)
519 8 : file_error(_("expected `;'"), &tok);
520 34 : error_recovery = 1;
521 : }
522 360 : goto restart;
523 :
524 : case ';':
525 : case ',':
526 1149 : break;
527 : case LBRACE0:
528 : case LBRACE:
529 2946 : if (ident->name) {
530 2946 : caller = lookup(ident->name);
531 2946 : func_body();
532 : }
533 2946 : break;
534 : case 0:
535 0 : if (verbose)
536 0 : file_error(_("unexpected end of file in declaration"), NULL);
537 : }
538 4095 : }
539 :
540 : int
541 304 : fake_struct(Ident *ident)
542 : {
543 : Stackpos sp;
544 :
545 304 : mark(sp);
546 304 : ident->type_end = -1;
547 304 : if (tok.type == STRUCT) {
548 48 : if (nexttoken() == IDENTIFIER) {
549 16 : ident->type_end = tos;
550 : }
551 48 : putback();
552 48 : skip_struct();
553 96 : if (tok.type == IDENTIFIER || tok.type == MODIFIER) {
554 48 : TOKSTK hold = tok;
555 48 : restore(sp);
556 48 : if (ident->type_end == -1) {
557 : /* there was no tag. Insert { ... } */
558 32 : tos = curs;
559 32 : token_stack[curs].type = IDENTIFIER;
560 32 : token_stack[curs].token = "{ ... }";
561 32 : tos++;
562 : } else {
563 16 : tos = curs + 1;
564 : }
565 48 : tokpush(hold.type, hold.line, hold.token);
566 0 : } else if (tok.type == '(')
567 0 : return 0;
568 0 : else if (tok.type != ';')
569 0 : file_error(_("missing `;' after struct declaration"), &tok);
570 48 : return 1;
571 : }
572 256 : return 0;
573 : }
574 :
575 : void
576 10226 : parse_variable_declaration(Ident *ident, int parm)
577 : {
578 : Stackpos sp;
579 :
580 10226 : mark(sp);
581 10226 : ident->type_end = -1;
582 10226 : if (tok.type == STRUCT) {
583 1200 : if (nexttoken() == IDENTIFIER) {
584 1200 : ident->type_end = tos;
585 : }
586 1200 : putback();
587 1200 : skip_struct();
588 3392 : while (tok.type == MODIFIER || tok.type == QUALIFIER)
589 992 : nexttoken();
590 1200 : if (tok.type == IDENTIFIER) {
591 1072 : TOKSTK hold = tok;
592 1072 : restore(sp);
593 1072 : if (ident->type_end == -1) {
594 : /* there was no tag. Insert { ... } */
595 0 : tos = curs;
596 0 : token_stack[curs].type = IDENTIFIER;
597 0 : token_stack[curs].token = "{ ... }";
598 0 : tos++;
599 : } else {
600 1072 : tos = curs + 1;
601 : }
602 1072 : tokpush(hold.type, hold.line, hold.token);
603 : } else {
604 128 : if (tok.type == ';')
605 10354 : return;
606 0 : restore(sp);
607 : }
608 : }
609 : again:
610 10343 : parse_dcl(ident, 0);
611 :
612 : select:
613 12137 : switch (tok.type) {
614 : case ')':
615 3531 : if (parm)
616 3500 : break;
617 : /*FALLTHROUGH*/
618 : default:
619 249 : if (verbose)
620 84 : file_error(_("expected `;'"), &tok);
621 : /* FIXME: should putback() here */
622 : /* FALLTHRU */
623 : case ';':
624 4571 : break;
625 : case ',':
626 2174 : if (parm)
627 1929 : break;
628 245 : tos = ident->type_end;
629 245 : restore(sp);
630 245 : goto again;
631 : case '=':
632 1794 : nexttoken();
633 1794 : if (tok.type == LBRACE || tok.type == LBRACE0)
634 304 : initializer_list();
635 : else
636 1490 : expression();
637 1794 : goto select;
638 : break;
639 : case LBRACE0:
640 : case LBRACE:
641 93 : func_body();
642 93 : break;
643 : case 0:
644 5 : if (verbose)
645 2 : file_error(_("unexpected end of file in declaration"), NULL);
646 : }
647 : }
648 :
649 : void
650 304 : initializer_list()
651 : {
652 304 : int lev = 0;
653 : while (1) {
654 42848 : switch (tok.type) {
655 : case LBRACE:
656 : case LBRACE0:
657 1376 : lev++;
658 1376 : break;
659 : case RBRACE:
660 : case RBRACE0:
661 1376 : if (--lev <= 0) {
662 304 : nexttoken();
663 304 : return;
664 : }
665 1072 : break;
666 : case 0:
667 0 : file_error(_("unexpected end of file in initializer list"),
668 : NULL);
669 0 : return;
670 : case ',':
671 1056 : break;
672 : default:
673 39040 : expression();
674 39040 : break;
675 : }
676 42544 : nexttoken();
677 42544 : }
678 : }
679 :
680 : void
681 4095 : parse_knr_dcl(Ident *ident)
682 : {
683 4095 : ident->type_end = -1;
684 4095 : parse_dcl(ident, !strict_ansi);
685 4095 : }
686 :
687 : void
688 1248 : skip_struct()
689 : {
690 1248 : if (nexttoken() == IDENTIFIER) {
691 1216 : nexttoken();
692 32 : } else if (tok.type == ';')
693 0 : return;
694 :
695 1248 : if (tok.type == LBRACE || tok.type == LBRACE0) {
696 160 : if (skip_balanced('{', '}', 1) == -1) {
697 0 : file_error(_("unexpected end of file in struct"), NULL);
698 0 : return;
699 : }
700 : }
701 :
702 2496 : while (tok.type == PARM_WRAPPER) {
703 0 : if (skip_balanced('(', ')', 0) == -1)
704 0 : file_error(_("unexpected end of file in struct"), NULL);
705 : }
706 : }
707 :
708 : void
709 304 : parse_typedef()
710 : {
711 : Ident ident;
712 :
713 304 : ident.name = NULL;
714 304 : ident.type_end = -1;
715 304 : ident.parmcnt = -1;
716 304 : ident.line = -1;
717 304 : ident.storage = AnyStorage;
718 :
719 304 : nexttoken();
720 304 : if (!fake_struct(&ident))
721 256 : putback();
722 :
723 304 : dcl(&ident);
724 304 : if (ident.name)
725 208 : declare_type(&ident);
726 304 : }
727 :
728 : void
729 14438 : parse_dcl(Ident *ident, int maybe_knr)
730 : {
731 14438 : ident->parmcnt = -1;
732 14438 : ident->name = NULL;
733 14438 : putback();
734 14438 : dcl(ident);
735 14438 : save_stack();
736 14438 : if (ident->name)
737 13515 : declare(ident, maybe_knr);
738 : else
739 923 : undo_save_stack();
740 14438 : }
741 :
742 : int
743 14876 : dcl(Ident *idptr)
744 : {
745 49820 : while (nexttoken() != 0 && tok.type != '(') {
746 34805 : if (tok.type == MODIFIER) {
747 4505 : if (idptr && idptr->type_end == -1)
748 3970 : idptr->type_end = curs-1;
749 30300 : } else if (tok.type == PARM_WRAPPER) {
750 0 : if (skip_balanced('(', ')', 0) == -1) {
751 0 : file_error(_("unexpected end of file in function declaration"),
752 : NULL);
753 0 : return 1;
754 : }
755 30300 : } else if (tok.type == IDENTIFIER) {
756 : int type;
757 :
758 46475 : while (tok.type == IDENTIFIER)
759 16629 : nexttoken();
760 14923 : type = tok.type;
761 14923 : putback();
762 14923 : if (!(type == TYPE ||
763 : type == MODIFIER || type == QUALIFIER))
764 13723 : break;
765 15377 : } else if (tok.type == ')' || tok.type == ';') {
766 1014 : return 1;
767 : }
768 : }
769 13862 : if (idptr && idptr->type_end == -1)
770 8707 : idptr->type_end = curs-1;
771 13862 : return dirdcl(idptr);
772 : }
773 :
774 : int
775 13862 : dirdcl(Ident *idptr)
776 : {
777 13862 : int wrapper = 0;
778 13862 : int *parm_ptr = NULL;
779 :
780 13862 : if (tok.type == '(') {
781 134 : dcl(idptr);
782 134 : if (tok.type != ')' && verbose) {
783 14 : file_error(_("expected `)'"), &tok);
784 14 : return 1;
785 : }
786 13728 : } else if (tok.type == IDENTIFIER) {
787 13723 : if (idptr) {
788 13723 : idptr->name = tok.token;
789 13723 : idptr->line = tok.line;
790 13723 : parm_ptr = &idptr->parmcnt;
791 : }
792 : }
793 :
794 13848 : if (nexttoken() == PARM_WRAPPER) {
795 0 : wrapper = 1;
796 0 : nexttoken(); /* read '(' */
797 : } else
798 13848 : putback();
799 :
800 32356 : while (nexttoken() == '[' || tok.type == '(') {
801 4660 : if (tok.type == '[')
802 435 : skip_to(']');
803 : else {
804 4225 : maybe_parm_list(parm_ptr);
805 4225 : if (tok.type != ')' && verbose) {
806 0 : file_error(_("expected `)'"), &tok);
807 0 : return 1;
808 : }
809 : }
810 : }
811 13848 : if (wrapper)
812 0 : nexttoken(); /* read ')' */
813 :
814 27696 : while (tok.type == PARM_WRAPPER) {
815 0 : if (skip_balanced('(', ')', 0) == -1)
816 0 : file_error(_("unexpected end of file in function declaration"),
817 : NULL);
818 : }
819 :
820 13848 : return 0;
821 : }
822 :
823 : int
824 0 : parmdcl(Ident *idptr)
825 : {
826 : int type;
827 :
828 0 : while (nexttoken() != 0 && tok.type != '(') {
829 0 : if (tok.type == MODIFIER) {
830 0 : if (idptr && idptr->type_end == -1)
831 0 : idptr->type_end = curs-1;
832 0 : } else if (tok.type == IDENTIFIER) {
833 0 : while (tok.type == IDENTIFIER)
834 0 : nexttoken();
835 0 : type = tok.type;
836 0 : putback();
837 0 : if (type != MODIFIER)
838 0 : break;
839 0 : } else if (tok.type == ')' || tok.type == ',')
840 0 : return 0;
841 : }
842 0 : if (idptr && idptr->type_end == -1)
843 0 : idptr->type_end = curs-1;
844 0 : return dirdcl(idptr);
845 : }
846 :
847 :
848 : void
849 4225 : maybe_parm_list(int *parm_cnt_return)
850 : {
851 4225 : int parmcnt = 0;
852 : Ident ident;
853 : int level;
854 :
855 4225 : parm_level++;
856 15896 : while (nexttoken()) {
857 11671 : switch (tok.type) {
858 : case ')':
859 4225 : if (parm_cnt_return)
860 4177 : *parm_cnt_return = parmcnt;
861 4225 : parm_level--;
862 8450 : return;
863 : case ',':
864 1929 : break;
865 : case QUALIFIER:
866 : case IDENTIFIER:
867 : case MODIFIER: /* unsigned * */
868 : case STRUCT:
869 : case UNION:
870 : case TYPE:
871 5450 : parmcnt++;
872 5450 : ident.storage = AutoStorage;
873 5450 : parse_declaration(&ident, 1);
874 5450 : putback();
875 5450 : break;
876 : default:
877 67 : if (verbose)
878 22 : file_error(_("unexpected token in parameter list"),
879 : &tok);
880 67 : level = 0;
881 : do {
882 1035 : if (tok.type == '(')
883 5 : level++;
884 1030 : else if (tok.type == ')') {
885 72 : if (level-- == 0)
886 67 : break;
887 : }
888 968 : } while (nexttoken());
889 : ;
890 67 : putback();
891 : }
892 : }
893 0 : if (verbose)
894 0 : file_error(_("unexpected end of file in parameter list"), NULL);
895 : }
896 :
897 : void
898 3039 : func_body()
899 : {
900 : Ident ident;
901 :
902 3039 : level++;
903 3039 : move_parms(level);
904 3039 : while (level) {
905 50646 : cleanup_stack();
906 50646 : nexttoken();
907 50646 : switch (tok.type) {
908 : default:
909 34434 : expression();
910 34434 : break;
911 : case STATIC:
912 16 : ident.storage = StaticStorage;
913 16 : nexttoken();
914 16 : parse_variable_declaration(&ident, 0);
915 16 : break;
916 : case TYPE:
917 : case STRUCT:
918 2451 : ident.storage = AutoStorage;
919 2451 : parse_variable_declaration(&ident, 0);
920 2451 : break;
921 : case EXTERN:
922 0 : ident.storage = ExplicitExternStorage;
923 0 : parse_declaration(&ident, 0);
924 0 : break;
925 : case LBRACE0:
926 : case '{':
927 5362 : level++;
928 5362 : break;
929 : case RBRACE0:
930 3025 : if (use_indentation) {
931 1123 : if (verbose && level != 1)
932 2 : file_error(_("forced function body close"), NULL);
933 2264 : for ( ; level; level--) {
934 1141 : delete_autos(level);
935 : }
936 1123 : break;
937 : }
938 : /* else: */
939 : /* FALLTHRU */
940 : case '}':
941 7260 : delete_autos(level);
942 7260 : level--;
943 7260 : break;
944 : case 0:
945 0 : if (verbose)
946 0 : file_error(_("unexpected end of file in function body"),
947 : NULL);
948 0 : caller = NULL;
949 3039 : return;
950 : }
951 : }
952 3039 : caller = NULL;
953 : }
954 :
955 : int
956 263 : get_knr_args(Ident *ident)
957 : {
958 : int parmcnt, stop;
959 : Stackpos sp, new_sp;
960 : Ident id;
961 :
962 263 : switch (tok.type) {
963 : case IDENTIFIER:
964 : case TYPE:
965 : case STRUCT:
966 : /* maybe K&R function definition */
967 :
968 0 : mark(sp);
969 0 : parmcnt = 0;
970 :
971 0 : for (stop = 0; !stop && parmcnt < ident->parmcnt;
972 0 : nexttoken()) {
973 0 : id.type_end = -1;
974 0 : switch (tok.type) {
975 : case LBRACE:
976 : case LBRACE0:
977 0 : putback();
978 0 : stop = 1;
979 0 : break;
980 : case TYPE:
981 : case IDENTIFIER:
982 : case STRUCT:
983 0 : putback();
984 0 : mark(new_sp);
985 0 : if (dcl(&id) == 0) {
986 0 : parmcnt++;
987 0 : if (tok.type == ',') {
988 : do {
989 0 : tos = id.type_end; /* ouch! */
990 0 : restore(new_sp);
991 0 : dcl(&id);
992 0 : } while (tok.type == ',');
993 0 : } else if (tok.type != ';')
994 0 : putback();
995 0 : break;
996 : }
997 : /* else */
998 : /* FALLTHRU */
999 : default:
1000 0 : restore(sp);
1001 0 : return 1;
1002 : }
1003 : }
1004 : }
1005 263 : return 0;
1006 : }
1007 :
1008 : void
1009 13515 : declare(Ident *ident, int maybe_knr)
1010 : {
1011 : Symbol *sp;
1012 :
1013 13515 : if (ident->storage == AutoStorage) {
1014 7232 : undo_save_stack();
1015 7232 : sp = install_ident(ident->name, ident->storage);
1016 7232 : if (parm_level) {
1017 4570 : sp->level = parm_level;
1018 4570 : sp->flag = symbol_parm;
1019 : } else
1020 2662 : sp->level = level;
1021 7232 : sp->arity = -1;
1022 7232 : return;
1023 : }
1024 :
1025 6283 : if ((ident->parmcnt >= 0
1026 4177 : && (!maybe_knr || get_knr_args(ident) == 0)
1027 5381 : && !(tok.type == LBRACE || tok.type == LBRACE0 || tok.type == TYPE
1028 1204 : || tok.type == PARM_WRAPPER))
1029 5079 : || (ident->parmcnt < 0 && ident->storage == ExplicitExternStorage)) {
1030 1300 : undo_save_stack();
1031 : /* add_external()?? */
1032 1300 : return;
1033 : }
1034 :
1035 4983 : sp = get_symbol(ident->name);
1036 4983 : if (sp->source) {
1037 284 : if (ident->storage == StaticStorage
1038 0 : && (sp->storage != StaticStorage || level > 0)) {
1039 0 : sp = install_ident(ident->name, ident->storage);
1040 : } else {
1041 284 : if (sp->arity >= 0)
1042 34 : error_at_line(0, 0, filename, ident->line,
1043 17 : _("%s/%d redefined"),
1044 : ident->name, sp->arity);
1045 : else
1046 534 : error_at_line(0, 0, filename, ident->line,
1047 267 : _("%s redefined"),
1048 : ident->name);
1049 284 : error_at_line(0, 0, sp->source, sp->def_line,
1050 284 : _("this is the place of previous definition"));
1051 : }
1052 : }
1053 :
1054 4983 : sp->type = SymIdentifier;
1055 4983 : sp->arity = ident->parmcnt;
1056 4983 : ident_change_storage(sp,
1057 4983 : (ident->storage == ExplicitExternStorage) ?
1058 : ExternStorage : ident->storage);
1059 4983 : sp->decl = finish_save_stack(ident->name);
1060 4983 : sp->source = filename;
1061 4983 : sp->def_line = ident->line;
1062 4983 : sp->level = level;
1063 4983 : if (debug)
1064 4683 : printf(_("%s:%d: %s/%d defined to %s\n"),
1065 : filename,
1066 : line_num,
1067 : ident->name, ident->parmcnt,
1068 : sp->decl);
1069 : }
1070 :
1071 : void
1072 208 : declare_type(Ident *ident)
1073 : {
1074 : Symbol *sp;
1075 :
1076 208 : undo_save_stack();
1077 208 : sp = lookup(ident->name);
1078 208 : for ( ; sp; sp = sp->next)
1079 0 : if (sp->type == SymToken && sp->token_type == TYPE)
1080 0 : break;
1081 208 : if (!sp)
1082 208 : sp = install(ident->name, INSTALL_UNIT_LOCAL);
1083 208 : sp->type = SymToken;
1084 208 : sp->token_type = TYPE;
1085 208 : sp->source = filename;
1086 208 : sp->def_line = ident->line;
1087 208 : sp->ref_line = NULL;
1088 208 : if (debug)
1089 195 : printf(_("%s:%d: type %s\n"), filename, line_num, ident->name);
1090 208 : }
1091 :
1092 : Symbol *
1093 81004 : get_symbol(char *name)
1094 : {
1095 81004 : Symbol *sp = lookup(name) ;
1096 :
1097 81004 : if (sp) {
1098 70735 : for (; sp; sp = sp->next) {
1099 70735 : if (sp->type == SymIdentifier && strcmp(sp->name, name) == 0)
1100 70735 : break;
1101 : }
1102 70735 : if (sp)
1103 70735 : return sp;
1104 : }
1105 10269 : return install_ident(name, ExternStorage);
1106 : }
1107 :
1108 : Symbol *
1109 76021 : add_reference(char *name, int line)
1110 : {
1111 76021 : Symbol *sp = get_symbol(name);
1112 : Ref *refptr;
1113 :
1114 76021 : if (sp->storage == AutoStorage
1115 52436 : || (sp->storage == StaticStorage && globals_only()))
1116 23585 : return NULL;
1117 52436 : refptr = xmalloc(sizeof(*refptr));
1118 52436 : refptr->source = filename;
1119 52436 : refptr->line = line;
1120 52436 : if (!sp->ref_line)
1121 9661 : sp->ref_line = linked_list_create(free);
1122 52436 : linked_list_append(&sp->ref_line, refptr);
1123 52436 : return sp;
1124 : }
1125 :
1126 :
1127 : void
1128 13080 : call(char *name, int line)
1129 : {
1130 : Symbol *sp;
1131 :
1132 13080 : sp = add_reference(name, line);
1133 13080 : if (!sp)
1134 13096 : return;
1135 13064 : if (sp->arity < 0)
1136 2594 : sp->arity = 0;
1137 13064 : if (caller) {
1138 11432 : if (!data_in_list(caller, sp->caller))
1139 8365 : linked_list_append(&sp->caller, caller);
1140 11432 : if (!data_in_list(sp, caller->callee))
1141 8365 : linked_list_append(&caller->callee, sp);
1142 : }
1143 : }
1144 :
1145 : void
1146 62941 : reference(char *name, int line)
1147 : {
1148 62941 : Symbol *sp = add_reference(name, line);
1149 62941 : if (!sp)
1150 86510 : return;
1151 39372 : if (caller) {
1152 29445 : if (!data_in_list(caller, sp->caller))
1153 13686 : linked_list_append(&sp->caller, caller);
1154 29445 : if (!data_in_list(sp, caller->callee))
1155 13686 : linked_list_append(&caller->callee, sp);
1156 : }
1157 : }
1158 :
|