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