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 172 : print_token(TOKSTK *tokptr)
80 : {
81 172 : 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 54 : fprintf(stderr, "`%c'", tokptr->type);
114 : }
115 172 : }
116 :
117 : static void
118 176 : file_error(char *msg, TOKSTK *tokptr)
119 : {
120 176 : fprintf(stderr, "%s:%d: %s", filename, tok.line, msg);
121 176 : if (tokptr) {
122 172 : fprintf(stderr, _(" near "));
123 172 : print_token(tokptr);
124 : }
125 176 : fprintf(stderr, "\n");
126 176 : }
127 :
128 : void
129 37700 : mark(Stackpos pos)
130 : {
131 37700 : pos[0] = curs;
132 37700 : }
133 :
134 : void
135 13650 : restore(Stackpos pos)
136 : {
137 13650 : curs = pos[0];
138 13650 : if (curs)
139 13650 : tok = token_stack[curs-1];
140 13650 : }
141 :
142 : void
143 436540 : tokpush(int type, int line, char *token)
144 : {
145 436540 : token_stack[tos].type = type;
146 436540 : token_stack[tos].token = token;
147 436540 : token_stack[tos].line = line;
148 436540 : 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 436540 : }
154 :
155 : void
156 57719 : cleanup_stack()
157 : {
158 57719 : int delta = tos - curs;
159 :
160 57719 : if (delta)
161 5330 : memmove(token_stack, token_stack+curs, delta*sizeof(token_stack[0]));
162 :
163 57719 : tos = delta;
164 57719 : curs = 0;
165 57719 : }
166 :
167 : void
168 246 : clearstack()
169 : {
170 246 : tos = curs = 0;
171 246 : }
172 :
173 : int
174 591409 : nexttoken()
175 : {
176 : int type;
177 :
178 591409 : if (curs == tos) {
179 435276 : type = get_token();
180 435276 : tokpush(type, line_num, yylval.str);
181 : }
182 591409 : tok = token_stack[curs];
183 591409 : curs++;
184 591409 : return tok.type;
185 : }
186 :
187 : int
188 123572 : putback()
189 : {
190 123572 : if (curs == 0)
191 0 : error(10, 0, _("INTERNAL ERROR: cannot return token to stream"));
192 123572 : curs--;
193 123572 : if (curs > 0) {
194 116246 : tok.type = token_stack[curs-1].type;
195 116246 : tok.token = token_stack[curs-1].token;
196 : } else
197 7326 : tok.type = 0;
198 123572 : return tok.type;
199 : }
200 :
201 : void
202 19 : init_parse()
203 : {
204 19 : obstack_init(&text_stk);
205 19 : token_stack = xmalloc(token_stack_length*sizeof(*token_stack));
206 19 : clearstack();
207 19 : }
208 :
209 : void
210 21773 : save_token(TOKSTK *tokptr)
211 : {
212 : int len;
213 :
214 21773 : switch (tokptr->type) {
215 : case IDENTIFIER:
216 : case TYPE:
217 : case STRUCT:
218 : case PARM_WRAPPER:
219 : case WORD:
220 : case QUALIFIER:
221 10305 : if (need_space)
222 3018 : obstack_1grow(&text_stk, ' ');
223 10305 : len = strlen(tokptr->token);
224 10305 : obstack_grow(&text_stk, tokptr->token, len);
225 10305 : need_space = 1;
226 10305 : break;
227 : case MODIFIER:
228 1887 : if (need_space)
229 1714 : obstack_1grow(&text_stk, ' ');
230 1887 : if (tokptr->token[0] == '*')
231 1887 : need_space = 0;
232 : else
233 0 : need_space = 1;
234 1887 : len = strlen(tokptr->token);
235 1887 : obstack_grow(&text_stk, tokptr->token, len);
236 1887 : break;
237 : case EXTERN: /* storage class specifiers are already taken care of */
238 : case STATIC:
239 1587 : break;
240 : case ',':
241 846 : obstack_1grow(&text_stk, ',');
242 846 : need_space = 1;
243 846 : break;
244 : case '(':
245 3133 : if (need_space)
246 3115 : obstack_1grow(&text_stk, ' ');
247 3133 : obstack_1grow(&text_stk, tokptr->type);
248 3133 : need_space = 0;
249 3133 : break;
250 : case ')':
251 3101 : obstack_1grow(&text_stk, tokptr->type);
252 3101 : need_space = 1;
253 3101 : 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 150 : if (verbose)
266 46 : file_error(_("unrecognized definition"), tokptr);
267 : }
268 21773 : }
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 14773 : save_stack()
275 : {
276 14773 : mark(start_pos);
277 14773 : save_end = curs - 1;
278 14773 : }
279 :
280 : void
281 9903 : undo_save_stack()
282 : {
283 9903 : save_end = -1;
284 9903 : }
285 :
286 : char *
287 5078 : finish_save_stack(char *name)
288 : {
289 : int i;
290 5078 : int level = 0;
291 5078 : int found_ident = !omit_symbol_names_option;
292 :
293 5078 : need_space = 0;
294 39457 : for (i = 0; i < save_end ; i++) {
295 34379 : switch (token_stack[i].type) {
296 : case '(':
297 3204 : if (omit_arguments_option) {
298 1828 : if (level == 0) {
299 1757 : save_token(token_stack+i);
300 : }
301 1828 : level++;
302 : }
303 3204 : break;
304 : case ')':
305 3172 : if (omit_arguments_option)
306 1796 : level--;
307 3172 : break;
308 : case IDENTIFIER:
309 11336 : if (!found_ident && strcmp (name, token_stack[i].token) == 0) {
310 4480 : need_space = 1;
311 4480 : found_ident = 1;
312 4480 : continue;
313 : }
314 : }
315 29899 : if (level == 0)
316 20016 : save_token(token_stack+i);
317 : }
318 5078 : obstack_1grow(&text_stk, 0);
319 5078 : 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 192 : skip_balanced(int open_tok, int close_tok, int level)
333 : {
334 192 : if (level == 0) {
335 0 : if (nexttoken() != open_tok) {
336 0 : return 1;
337 : }
338 0 : level++;
339 : }
340 4048 : while (nexttoken()) {
341 3856 : if (tok.type == LBRACE0 && open_tok == '{')
342 0 : tok.type = '{';
343 3856 : else if (tok.type == RBRACE0 && close_tok == '}')
344 160 : tok.type = '}';
345 :
346 3856 : if (tok.type == open_tok)
347 0 : level++;
348 3856 : else if (tok.type == close_tok) {
349 192 : if (--level == 0) {
350 192 : nexttoken();
351 192 : return 0;
352 : }
353 : }
354 : }
355 0 : return -1;
356 : }
357 :
358 : int
359 227 : yyparse()
360 : {
361 : Ident identifier;
362 :
363 227 : level = 0;
364 227 : caller = NULL;
365 227 : clearstack();
366 7369 : while (nexttoken()) {
367 6915 : identifier.storage = ExternStorage;
368 6915 : switch (tok.type) {
369 : case 0:
370 0 : return 0;
371 : case QUALIFIER:
372 80 : 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 6387 : parse_declaration(&identifier, 0);
386 6387 : break;
387 : }
388 6835 : cleanup_stack();
389 : }
390 227 : return 0;
391 : }
392 :
393 : static int
394 12093 : is_function()
395 : {
396 : Stackpos sp;
397 12093 : int res = 0;
398 :
399 12093 : mark(sp);
400 : while (1) {
401 37678 : switch (tok.type) {
402 : case QUALIFIER:
403 : case TYPE:
404 : case IDENTIFIER:
405 : case MODIFIER:
406 : case STATIC:
407 : case EXTERN:
408 25585 : nexttoken();
409 25585 : 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 4206 : res = nexttoken() != MODIFIER;
417 4206 : break;
418 : default:
419 7887 : break;
420 : }
421 12093 : break;
422 25585 : }
423 :
424 12093 : restore(sp);
425 12093 : return res;
426 : }
427 :
428 : void
429 12093 : parse_declaration(Ident *ident, int parm)
430 : {
431 12093 : if (is_function())
432 4158 : parse_function_declaration(ident, parm);
433 : else
434 7935 : parse_variable_declaration(ident, parm);
435 12093 : delete_parms(parm_level);
436 12093 : }
437 :
438 :
439 : void
440 75203 : expression()
441 : {
442 : char *name;
443 : int line;
444 : int parens_lev;
445 :
446 75203 : parens_lev = 0;
447 : while (1) {
448 321713 : switch (tok.type) {
449 : case ';':
450 30558 : return;
451 : case LBRACE:
452 : case LBRACE0:
453 : case RBRACE:
454 : case RBRACE0:
455 6626 : putback();
456 6626 : return;
457 : case ',':
458 46874 : if (parens_lev == 0)
459 38019 : return;
460 8855 : 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 76532 : name = tok.token;
469 76532 : line = tok.line;
470 76532 : nexttoken();
471 76532 : if (tok.type == '(') {
472 13303 : call(name, line);
473 13303 : parens_lev++;
474 : } else {
475 63229 : reference(name, line);
476 63229 : if (tok.type == MEMBER_OF) {
477 30732 : while (tok.type == MEMBER_OF)
478 10244 : nexttoken();
479 : } else {
480 52985 : putback();
481 : }
482 : }
483 76532 : break;
484 : case '(':
485 : /* maybe typecast */
486 13064 : if (nexttoken() == TYPE)
487 770 : skip_to(')');
488 : else {
489 12294 : putback();
490 12294 : parens_lev++;
491 : }
492 13064 : break;
493 : case ')':
494 25597 : parens_lev--;
495 25597 : break;
496 : }
497 246510 : nexttoken();
498 246510 : }
499 : }
500 :
501 : void
502 4158 : parse_function_declaration(Ident *ident, int parm)
503 : {
504 4158 : int error_recovery = 0;
505 4158 : ident->type_end = -1;
506 4158 : parse_knr_dcl(ident);
507 :
508 : restart:
509 4518 : 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 3009 : if (ident->name) {
530 3009 : caller = lookup(ident->name);
531 3009 : func_body();
532 : }
533 3009 : break;
534 : case 0:
535 0 : if (verbose)
536 0 : file_error(_("unexpected end of file in declaration"), NULL);
537 : }
538 4158 : }
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 10530 : parse_variable_declaration(Ident *ident, int parm)
577 : {
578 : Stackpos sp;
579 :
580 10530 : mark(sp);
581 10530 : ident->type_end = -1;
582 10530 : if (tok.type == STRUCT) {
583 1424 : if (nexttoken() == IDENTIFIER) {
584 1424 : ident->type_end = tos;
585 : }
586 1424 : putback();
587 1424 : skip_struct();
588 4000 : while (tok.type == MODIFIER || tok.type == QUALIFIER)
589 1152 : nexttoken();
590 1424 : if (tok.type == IDENTIFIER) {
591 1216 : TOKSTK hold = tok;
592 1216 : restore(sp);
593 1216 : 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 1216 : tos = curs + 1;
601 : }
602 1216 : tokpush(hold.type, hold.line, hold.token);
603 : } else {
604 208 : if (tok.type == ';')
605 10674 : return;
606 64 : restore(sp);
607 : }
608 : }
609 : again:
610 10615 : parse_dcl(ident, 0);
611 :
612 : select:
613 12537 : switch (tok.type) {
614 : case ')':
615 3611 : if (parm)
616 3580 : break;
617 : /*FALLTHROUGH*/
618 : default:
619 233 : if (verbose)
620 82 : file_error(_("expected `;'"), &tok);
621 : /* FIXME: should putback() here */
622 : /* FALLTHRU */
623 : case ';':
624 4731 : break;
625 : case ',':
626 2206 : if (parm)
627 1977 : break;
628 229 : tos = ident->type_end;
629 229 : restore(sp);
630 229 : goto again;
631 : case '=':
632 1922 : nexttoken();
633 1922 : if (tok.type == LBRACE || tok.type == LBRACE0)
634 320 : initializer_list();
635 : else
636 1602 : expression();
637 1922 : 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 320 : initializer_list()
651 : {
652 320 : int lev = 0;
653 : while (1) {
654 42896 : switch (tok.type) {
655 : case LBRACE:
656 : case LBRACE0:
657 1392 : lev++;
658 1392 : break;
659 : case RBRACE:
660 : case RBRACE0:
661 1392 : if (--lev <= 0) {
662 320 : nexttoken();
663 320 : 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 39056 : expression();
674 39056 : break;
675 : }
676 42576 : nexttoken();
677 42576 : }
678 : }
679 :
680 : void
681 4158 : parse_knr_dcl(Ident *ident)
682 : {
683 4158 : ident->type_end = -1;
684 4158 : parse_dcl(ident, !strict_ansi);
685 4158 : }
686 :
687 : void
688 1472 : skip_struct()
689 : {
690 1472 : if (nexttoken() == IDENTIFIER) {
691 1440 : nexttoken();
692 32 : } else if (tok.type == ';')
693 0 : return;
694 :
695 1472 : if (tok.type == LBRACE || tok.type == LBRACE0) {
696 192 : if (skip_balanced('{', '}', 1) == -1) {
697 0 : file_error(_("unexpected end of file in struct"), NULL);
698 0 : return;
699 : }
700 : }
701 :
702 2944 : 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 14773 : parse_dcl(Ident *ident, int maybe_knr)
730 : {
731 14773 : ident->parmcnt = -1;
732 14773 : ident->name = NULL;
733 14773 : putback();
734 14773 : dcl(ident);
735 14773 : save_stack();
736 14773 : if (ident->name)
737 13850 : declare(ident, maybe_knr);
738 : else
739 923 : undo_save_stack();
740 14773 : }
741 :
742 : int
743 15211 : dcl(Ident *idptr)
744 : {
745 51161 : while (nexttoken() != 0 && tok.type != '(') {
746 35811 : if (tok.type == MODIFIER) {
747 4665 : if (idptr && idptr->type_end == -1)
748 4066 : idptr->type_end = curs-1;
749 31146 : } 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 31146 : } else if (tok.type == IDENTIFIER) {
756 : int type;
757 :
758 47944 : while (tok.type == IDENTIFIER)
759 17236 : nexttoken();
760 15354 : type = tok.type;
761 15354 : putback();
762 15354 : if (!(type == TYPE ||
763 : type == MODIFIER || type == QUALIFIER))
764 14058 : break;
765 15792 : } else if (tok.type == ')' || tok.type == ';') {
766 1014 : return 1;
767 : }
768 : }
769 14197 : if (idptr && idptr->type_end == -1)
770 8754 : idptr->type_end = curs-1;
771 14197 : return dirdcl(idptr);
772 : }
773 :
774 : int
775 14197 : dirdcl(Ident *idptr)
776 : {
777 14197 : int wrapper = 0;
778 14197 : int *parm_ptr = NULL;
779 :
780 14197 : 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 14063 : } else if (tok.type == IDENTIFIER) {
787 14058 : if (idptr) {
788 14058 : idptr->name = tok.token;
789 14058 : idptr->line = tok.line;
790 14058 : parm_ptr = &idptr->parmcnt;
791 : }
792 : }
793 :
794 14183 : if (nexttoken() == PARM_WRAPPER) {
795 0 : wrapper = 1;
796 0 : nexttoken(); /* read '(' */
797 : } else
798 14183 : putback();
799 :
800 33105 : while (nexttoken() == '[' || tok.type == '(') {
801 4739 : if (tok.type == '[')
802 435 : skip_to(']');
803 : else {
804 4304 : maybe_parm_list(parm_ptr);
805 4304 : if (tok.type != ')' && verbose) {
806 0 : file_error(_("expected `)'"), &tok);
807 0 : return 1;
808 : }
809 : }
810 : }
811 14183 : if (wrapper)
812 0 : nexttoken(); /* read ')' */
813 :
814 28366 : 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 14183 : 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 4304 : maybe_parm_list(int *parm_cnt_return)
850 : {
851 4304 : int parmcnt = 0;
852 : Ident ident;
853 : int level;
854 :
855 4304 : parm_level++;
856 16214 : while (nexttoken()) {
857 11910 : switch (tok.type) {
858 : case ')':
859 4304 : if (parm_cnt_return)
860 4256 : *parm_cnt_return = parmcnt;
861 4304 : parm_level--;
862 8608 : return;
863 : case ',':
864 1977 : break;
865 : case QUALIFIER:
866 : case IDENTIFIER:
867 : case MODIFIER: /* unsigned * */
868 : case STRUCT:
869 : case UNION:
870 : case TYPE:
871 5562 : parmcnt++;
872 5562 : ident.storage = AutoStorage;
873 5562 : parse_declaration(&ident, 1);
874 5562 : putback();
875 5562 : 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 331 : if (tok.type == '(')
883 21 : level++;
884 310 : else if (tok.type == ')') {
885 88 : if (level-- == 0)
886 67 : break;
887 : }
888 264 : } 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 3102 : func_body()
899 : {
900 : Ident ident;
901 :
902 3102 : level++;
903 3102 : move_parms(level);
904 3102 : while (level) {
905 50884 : cleanup_stack();
906 50884 : nexttoken();
907 50884 : switch (tok.type) {
908 : default:
909 34545 : expression();
910 34545 : 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 2579 : ident.storage = AutoStorage;
919 2579 : parse_variable_declaration(&ident, 0);
920 2579 : break;
921 : case EXTERN:
922 0 : ident.storage = ExplicitExternStorage;
923 0 : parse_declaration(&ident, 0);
924 0 : break;
925 : case LBRACE0:
926 : case '{':
927 5330 : level++;
928 5330 : break;
929 : case RBRACE0:
930 3088 : if (use_indentation) {
931 1147 : if (verbose && level != 1)
932 2 : file_error(_("forced function body close"), NULL);
933 2312 : for ( ; level; level--) {
934 1165 : delete_autos(level);
935 : }
936 1147 : break;
937 : }
938 : /* else: */
939 : /* FALLTHRU */
940 : case '}':
941 7267 : delete_autos(level);
942 7267 : level--;
943 7267 : 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 3102 : return;
950 : }
951 : }
952 3102 : caller = NULL;
953 : }
954 :
955 : int
956 266 : get_knr_args(Ident *ident)
957 : {
958 : int parmcnt, stop;
959 : Stackpos sp, new_sp;
960 : Ident id;
961 :
962 266 : 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 266 : return 0;
1006 : }
1007 :
1008 : void
1009 13850 : declare(Ident *ident, int maybe_knr)
1010 : {
1011 : Symbol *sp;
1012 :
1013 13850 : if (ident->storage == AutoStorage) {
1014 7456 : undo_save_stack();
1015 7456 : sp = install_ident(ident->name, ident->storage);
1016 7456 : if (parm_level) {
1017 4682 : sp->level = parm_level;
1018 4682 : sp->flag = symbol_parm;
1019 : } else
1020 2774 : sp->level = level;
1021 7456 : sp->arity = -1;
1022 7456 : return;
1023 : }
1024 :
1025 6394 : if ((ident->parmcnt >= 0
1026 4256 : && (!maybe_knr || get_knr_args(ident) == 0)
1027 5476 : && !(tok.type == LBRACE || tok.type == LBRACE0 || tok.type == TYPE
1028 1220 : || tok.type == PARM_WRAPPER))
1029 5174 : || (ident->parmcnt < 0 && ident->storage == ExplicitExternStorage)) {
1030 1316 : undo_save_stack();
1031 : /* add_external()?? */
1032 1316 : return;
1033 : }
1034 :
1035 5078 : sp = get_symbol(ident->name);
1036 5078 : 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 5078 : sp->type = SymIdentifier;
1055 5078 : sp->arity = ident->parmcnt;
1056 5078 : ident_change_storage(sp,
1057 5078 : (ident->storage == ExplicitExternStorage) ?
1058 : ExternStorage : ident->storage);
1059 5078 : sp->decl = finish_save_stack(ident->name);
1060 5078 : sp->source = filename;
1061 5078 : sp->def_line = ident->line;
1062 5078 : sp->level = level;
1063 5078 : if (debug)
1064 4773 : 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 81610 : get_symbol(char *name)
1094 : {
1095 81610 : Symbol *sp = lookup(name) ;
1096 :
1097 81610 : if (sp) {
1098 71119 : for (; sp; sp = sp->next) {
1099 71119 : if (sp->type == SymIdentifier && strcmp(sp->name, name) == 0)
1100 71119 : break;
1101 : }
1102 71119 : if (sp)
1103 71119 : return sp;
1104 : }
1105 10491 : return install_ident(name, ExternStorage);
1106 : }
1107 :
1108 : Symbol *
1109 76532 : add_reference(char *name, int line)
1110 : {
1111 76532 : Symbol *sp = get_symbol(name);
1112 : Ref *refptr;
1113 :
1114 76532 : if (sp->storage == AutoStorage
1115 52371 : || (sp->storage == StaticStorage && globals_only()))
1116 24161 : return NULL;
1117 52371 : refptr = xmalloc(sizeof(*refptr));
1118 52371 : refptr->source = filename;
1119 52371 : refptr->line = line;
1120 52371 : if (!sp->ref_line)
1121 9884 : sp->ref_line = linked_list_create(free);
1122 52371 : linked_list_append(&sp->ref_line, refptr);
1123 52371 : return sp;
1124 : }
1125 :
1126 :
1127 : void
1128 13303 : call(char *name, int line)
1129 : {
1130 : Symbol *sp;
1131 :
1132 13303 : sp = add_reference(name, line);
1133 13303 : if (!sp)
1134 13319 : return;
1135 13287 : if (sp->arity < 0)
1136 2737 : sp->arity = 0;
1137 13287 : if (caller) {
1138 11655 : if (!data_in_list(caller, sp->caller))
1139 8572 : linked_list_append(&sp->caller, caller);
1140 11655 : if (!data_in_list(sp, caller->callee))
1141 8572 : linked_list_append(&caller->callee, sp);
1142 : }
1143 : }
1144 :
1145 : void
1146 63229 : reference(char *name, int line)
1147 : {
1148 63229 : Symbol *sp = add_reference(name, line);
1149 63229 : if (!sp)
1150 87374 : return;
1151 39084 : if (caller) {
1152 29157 : if (!data_in_list(caller, sp->caller))
1153 13798 : linked_list_append(&sp->caller, caller);
1154 29157 : if (!data_in_list(sp, caller->callee))
1155 13798 : linked_list_append(&caller->callee, sp);
1156 : }
1157 : }
1158 :
|