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