scan-decls.c revision 18334
1/* scan-decls.c - Extracts declarations from cpp output.
2   Copyright (C) 1993, 1995 Free Software Foundation, Inc.
3
4This program is free software; you can redistribute it and/or modify it
5under the terms of the GNU General Public License as published by the
6Free Software Foundation; either version 2, or (at your option) any
7later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18   Written by Per Bothner <bothner@cygnus.com>, July 1993.  */
19
20#include <stdio.h>
21#include <ctype.h>
22#include "hconfig.h"
23#include "cpplib.h"
24
25int brace_nesting = 0;
26
27/* The first extern_C_braces_length elements of extern_C_braces
28   indicate the (brace nesting levels of) left braces that were
29   prefixed by extern "C".  */
30int extern_C_braces_length = 0;
31char extern_C_braces[20];
32#define in_extern_C_brace (extern_C_braces_length>0)
33
34/* True if the function declaration currently being scanned is
35   prefixed by extern "C".  */
36int current_extern_C = 0;
37
38static void
39skip_to_closing_brace (pfile)
40     cpp_reader *pfile;
41{
42  int nesting = 1;
43  for (;;)
44    {
45      enum cpp_token token = cpp_get_token (pfile);
46      if (token == CPP_EOF)
47	break;
48      if (token == CPP_LBRACE)
49	nesting++;
50      if (token == CPP_RBRACE && --nesting == 0)
51	break;
52    }
53}
54
55/* This function scans a C source file (actually, the output of cpp),
56   reading from FP.  It looks for function declarations, and
57   external variable declarations.
58
59   The following grammar (as well as some extra stuff) is recognized:
60
61   declaration:
62     (decl-specifier)* declarator ("," declarator)* ";"
63   decl-specifier:
64     identifier
65     keyword
66     extern "C"
67   declarator:
68     (ptr-operator)* dname [ "(" argument-declaration-list ")" ]
69   ptr-operator:
70     ("*" | "&") ("const" | "volatile")*
71   dname:
72     identifier
73
74Here dname is the actual name being declared.
75*/
76
77int
78scan_decls (pfile, argc, argv)
79     cpp_reader *pfile;
80     int argc;
81     char**argv;
82{
83  int saw_extern, saw_inline;
84  int old_written;
85  /* If declarator_start is non-zero, it marks the start of the current
86     declarator.  If it is zero, we are either still parsing the
87     decl-specs, or prev_id_start marks the start of the declarator. */
88  int declarator_start;
89  int prev_id_start, prev_id_end;
90  enum cpp_token token;
91
92 new_statement:
93  CPP_SET_WRITTEN (pfile, 0);
94  token = cpp_get_token (pfile);
95
96 handle_statement:
97  current_extern_C = 0;
98  saw_extern = 0;
99  saw_inline = 0;
100  if (token == CPP_RBRACE)
101    {
102      /* Pop an 'extern "C"' nesting level, if appropriate.  */
103      if (extern_C_braces_length
104	  && extern_C_braces[extern_C_braces_length - 1] == brace_nesting)
105	extern_C_braces_length--;
106      brace_nesting--;
107      goto new_statement;
108    }
109  if (token == CPP_LBRACE)
110    {
111      brace_nesting++;
112      goto new_statement;
113    }
114  if (token == CPP_EOF)
115    return 0;
116  if (token == CPP_SEMICOLON)
117    goto new_statement;
118  if (token != CPP_NAME)
119    goto new_statement;
120
121  prev_id_start = 0;
122  declarator_start = 0;
123  for (;;)
124    {
125      int start_written = CPP_WRITTEN (pfile);
126      token = cpp_get_token (pfile);
127    handle_token:
128      switch (token)
129	{
130	case CPP_LPAREN:
131	  /* Looks like this is the start of a formal parameter list. */
132	  if (prev_id_start)
133	    {
134	      int nesting = 1;
135	      int have_arg_list = 0;
136	      cpp_buffer *fbuf = cpp_file_buffer (pfile);
137	      long func_lineno;
138	      cpp_buf_line_and_col (fbuf, &func_lineno, NULL);
139	      for (;;)
140		{
141		  token = cpp_get_token (pfile);
142		  if (token == CPP_LPAREN)
143		    nesting++;
144		  else if (token == CPP_RPAREN)
145		    {
146		      nesting--;
147		      if (nesting == 0)
148			break;
149		    }
150		  else if (token == CPP_EOF)
151		    break;
152		  else if (token == CPP_NAME || token == CPP_3DOTS)
153		    have_arg_list = 1;
154		}
155	      recognized_function (pfile->token_buffer + prev_id_start,
156				   prev_id_end - prev_id_start,
157				   (saw_inline ? 'I'
158				    : in_extern_C_brace || current_extern_C
159				    ? 'F' : 'f'),
160				   pfile->token_buffer, prev_id_start,
161				   have_arg_list,
162				   fbuf->nominal_fname, func_lineno);
163	      token = cpp_get_non_space_token (pfile);
164	      if (token == CPP_LBRACE)
165		{
166		  /* skip body of (normally) inline function */
167		  skip_to_closing_brace (pfile);
168		  goto new_statement;
169		}
170	      goto maybe_handle_comma;
171	    }
172	  break;
173	case CPP_OTHER:
174	  if (CPP_WRITTEN (pfile) == start_written + 1
175	      && (CPP_PWRITTEN (pfile)[-1] == '*'
176		  || CPP_PWRITTEN (pfile)[-1] == '&'))
177	    declarator_start = start_written;
178	  else
179	    goto handle_statement;
180	  break;
181	case CPP_COMMA:
182	case CPP_SEMICOLON:
183	  if (prev_id_start && saw_extern)
184	    {
185	      recognized_extern (pfile->token_buffer + prev_id_start,
186				 prev_id_end - prev_id_start,
187				 pfile->token_buffer,
188				 prev_id_start);
189	    }
190	  /* ... fall through ... */
191	maybe_handle_comma:
192	  if (token != CPP_COMMA)
193	    goto new_statement;
194	handle_comma:
195	  /* Handle multiple declarators in a single declaration,
196	     as in:  extern char *strcpy (), *strcat (), ... ; */
197	  if (declarator_start == 0)
198	    declarator_start = prev_id_start;
199	  CPP_SET_WRITTEN (pfile, declarator_start);
200	  break;
201	case CPP_NAME:
202	  /* "inline" and "extern" are recognized but skipped */
203	  if (strcmp (pfile->token_buffer, "inline") == 0)
204	    {
205	      saw_inline = 1;
206	      CPP_SET_WRITTEN (pfile, start_written);
207	    }
208	  if (strcmp (pfile->token_buffer, "extern") == 0)
209	    {
210	      saw_extern = 1;
211	      CPP_SET_WRITTEN (pfile, start_written);
212	      token = cpp_get_non_space_token (pfile);
213	      if (token == CPP_STRING
214		  && strcmp (pfile->token_buffer, "\"C\"") == 0)
215		{
216		  CPP_SET_WRITTEN (pfile, start_written);
217		  current_extern_C = 1;
218		  token = cpp_get_non_space_token (pfile);
219		  if (token == CPP_LBRACE)
220		    {
221		      brace_nesting++;
222		      extern_C_braces[extern_C_braces_length++]
223			= brace_nesting;
224		      goto new_statement;
225		    }
226		}
227	      else
228		goto handle_token;
229	      break;
230	    }
231	  /* This may be the name of a variable or function. */
232	  prev_id_start = start_written;
233	  prev_id_end = CPP_WRITTEN (pfile);
234	  break;
235
236	case CPP_EOF:
237	  return;  /* ??? FIXME */
238
239	case CPP_LBRACE:  case CPP_RBRACE:  case CPP_DIRECTIVE:
240	  goto new_statement;  /* handle_statement? */
241
242	case CPP_HSPACE:  case CPP_VSPACE:  case CPP_COMMENT:  case CPP_POP:
243	  /* Skip initial white space. */
244	  if (start_written == 0)
245	    CPP_SET_WRITTEN (pfile, 0);
246	  break;
247
248	 default:
249	  prev_id_start = 0;
250	}
251    }
252}
253