LCOV - code coverage report
Current view: top level - src - parser.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 532 632 84.2 %
Date: 2015-04-20 Functions: 39 40 97.5 %

          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             : 

Generated by: LCOV version 1.10