scan-decls.c revision 50397
1237263Snp/* scan-decls.c - Extracts declarations from cpp output.
2237263Snp   Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
3237263Snp
4237263SnpThis program is free software; you can redistribute it and/or modify it
5237263Snpunder the terms of the GNU General Public License as published by the
6237263SnpFree Software Foundation; either version 2, or (at your option) any
7237263Snplater version.
8237263Snp
9237263SnpThis program is distributed in the hope that it will be useful,
10237263Snpbut WITHOUT ANY WARRANTY; without even the implied warranty of
11237263SnpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12237263SnpGNU General Public License for more details.
13237263Snp
14237263SnpYou should have received a copy of the GNU General Public License
15237263Snpalong with this program; if not, write to the Free Software
16237263SnpFoundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17237263Snp
18237263Snp   Written by Per Bothner <bothner@cygnus.com>, July 1993.  */
19237263Snp
20237263Snp#include "hconfig.h"
21237263Snp#include "system.h"
22237263Snp#include "gansidecl.h"
23237263Snp#include "cpplib.h"
24237263Snp#include "scan.h"
25237263Snp
26174641Skmacyint brace_nesting = 0;
27237263Snp
28237263Snp/* The first extern_C_braces_length elements of extern_C_braces
29174641Skmacy   indicate the (brace nesting levels of) left braces that were
30237263Snp   prefixed by extern "C".  */
31174641Skmacyint extern_C_braces_length = 0;
32237263Snpchar extern_C_braces[20];
33237263Snp#define in_extern_C_brace (extern_C_braces_length>0)
34237263Snp
35237263Snp/* True if the function declaration currently being scanned is
36237263Snp   prefixed by extern "C".  */
37237263Snpint current_extern_C = 0;
38237263Snp
39237263Snpstatic void
40237263Snpskip_to_closing_brace (pfile)
41237263Snp     cpp_reader *pfile;
42237263Snp{
43237263Snp  int nesting = 1;
44239544Snp  for (;;)
45237263Snp    {
46237263Snp      enum cpp_token token = cpp_get_token (pfile);
47237263Snp      if (token == CPP_EOF)
48237263Snp	break;
49174641Skmacy      if (token == CPP_LBRACE)
50237263Snp	nesting++;
51237263Snp      if (token == CPP_RBRACE && --nesting == 0)
52237263Snp	break;
53237263Snp    }
54174641Skmacy}
55237263Snp
56174641Skmacy/* This function scans a C source file (actually, the output of cpp),
57237263Snp   reading from FP.  It looks for function declarations, and
58237263Snp   external variable declarations.
59237263Snp
60237263Snp   The following grammar (as well as some extra stuff) is recognized:
61174641Skmacy
62237263Snp   declaration:
63237263Snp     (decl-specifier)* declarator ("," declarator)* ";"
64237263Snp   decl-specifier:
65174641Skmacy     identifier
66237263Snp     keyword
67237263Snp     extern "C"
68237263Snp   declarator:
69237263Snp     (ptr-operator)* dname [ "(" argument-declaration-list ")" ]
70237263Snp   ptr-operator:
71237263Snp     ("*" | "&") ("const" | "volatile")*
72237263Snp   dname:
73237263Snp     identifier
74181067Skmacy
75237263SnpHere dname is the actual name being declared.
76237263Snp*/
77237263Snp
78237263Snpint
79181067Skmacyscan_decls (pfile, argc, argv)
80237263Snp     cpp_reader *pfile;
81237263Snp     int argc;
82237263Snp     char **argv;
83237263Snp{
84237263Snp  int saw_extern, saw_inline;
85237263Snp  int start_written;
86174641Skmacy  /* If declarator_start is non-zero, it marks the start of the current
87237263Snp     declarator.  If it is zero, we are either still parsing the
88237263Snp     decl-specs, or prev_id_start marks the start of the declarator.  */
89237263Snp  int declarator_start;
90237263Snp  int prev_id_start, prev_id_end;
91174641Skmacy  enum cpp_token token;
92237263Snp
93174641Skmacy new_statement:
94237263Snp  CPP_SET_WRITTEN (pfile, 0);
95237263Snp  start_written = 0;
96237263Snp  token = cpp_get_token (pfile);
97174641Skmacy
98237263Snp handle_statement:
99237263Snp  current_extern_C = 0;
100237263Snp  saw_extern = 0;
101237263Snp  saw_inline = 0;
102237263Snp  if (token == CPP_RBRACE)
103174641Skmacy    {
104237263Snp      /* Pop an 'extern "C"' nesting level, if appropriate.  */
105237263Snp      if (extern_C_braces_length
106174641Skmacy	  && extern_C_braces[extern_C_braces_length - 1] == brace_nesting)
107237263Snp	extern_C_braces_length--;
108237263Snp      brace_nesting--;
109237263Snp      goto new_statement;
110174641Skmacy    }
111237263Snp  if (token == CPP_LBRACE)
112237263Snp    {
113174641Skmacy      brace_nesting++;
114237263Snp      goto new_statement;
115237263Snp    }
116237263Snp  if (token == CPP_EOF)
117237263Snp    return 0;
118237263Snp  if (token == CPP_SEMICOLON)
119174641Skmacy    goto new_statement;
120237263Snp  if (token != CPP_NAME)
121237263Snp    goto new_statement;
122237263Snp
123237263Snp  prev_id_start = 0;
124237263Snp  declarator_start = 0;
125237263Snp  for (;;)
126174641Skmacy    {
127237263Snp      switch (token)
128237263Snp	{
129237263Snp	case CPP_LPAREN:
130237263Snp	  /* Looks like this is the start of a formal parameter list.  */
131237263Snp	  if (prev_id_start)
132237263Snp	    {
133237263Snp	      int nesting = 1;
134237263Snp	      int have_arg_list = 0;
135237263Snp	      cpp_buffer *fbuf = cpp_file_buffer (pfile);
136237263Snp	      long func_lineno;
137237263Snp	      cpp_buf_line_and_col (fbuf, &func_lineno, NULL);
138237263Snp	      for (;;)
139237263Snp		{
140237263Snp		  token = cpp_get_token (pfile);
141237263Snp		  if (token == CPP_LPAREN)
142237263Snp		    nesting++;
143237263Snp		  else if (token == CPP_RPAREN)
144237263Snp		    {
145237263Snp		      nesting--;
146237263Snp		      if (nesting == 0)
147237263Snp			break;
148237263Snp		    }
149237263Snp		  else if (token == CPP_EOF)
150174641Skmacy		    break;
151237263Snp		  else if (token == CPP_NAME || token == CPP_3DOTS)
152237263Snp		    have_arg_list = 1;
153237263Snp		}
154237263Snp	      recognized_function (pfile->token_buffer + prev_id_start,
155237263Snp				   prev_id_end - prev_id_start,
156237263Snp				   (saw_inline ? 'I'
157237263Snp				    : in_extern_C_brace || current_extern_C
158237263Snp				    ? 'F' : 'f'),
159237263Snp				   pfile->token_buffer, prev_id_start,
160237263Snp				   have_arg_list,
161237263Snp				   fbuf->nominal_fname, func_lineno);
162237263Snp	      token = cpp_get_non_space_token (pfile);
163237263Snp	      if (token == CPP_LBRACE)
164237263Snp		{
165237263Snp		  /* skip body of (normally) inline function */
166237263Snp		  skip_to_closing_brace (pfile);
167237263Snp		  goto new_statement;
168237263Snp		}
169237263Snp	      goto maybe_handle_comma;
170237263Snp	    }
171237263Snp	  break;
172237263Snp	case CPP_OTHER:
173237263Snp	  if (CPP_WRITTEN (pfile) == start_written + 1
174237263Snp	      && (CPP_PWRITTEN (pfile)[-1] == '*'
175237263Snp		  || CPP_PWRITTEN (pfile)[-1] == '&'))
176237263Snp	    declarator_start = start_written;
177237263Snp	  else
178237263Snp	    goto handle_statement;
179237263Snp	  break;
180237263Snp	case CPP_COMMA:
181237263Snp	case CPP_SEMICOLON:
182237263Snp	  if (prev_id_start && saw_extern)
183237263Snp	    {
184237263Snp	      recognized_extern (pfile->token_buffer + prev_id_start,
185237263Snp				 prev_id_end - prev_id_start,
186237263Snp				 pfile->token_buffer,
187237263Snp				 prev_id_start);
188237263Snp	    }
189237263Snp	  /* ... fall through ...  */
190237263Snp	maybe_handle_comma:
191237263Snp	  if (token != CPP_COMMA)
192237263Snp	    goto new_statement;
193237263Snp	handle_comma:
194237263Snp	  /* Handle multiple declarators in a single declaration,
195237263Snp	     as in:  extern char *strcpy (), *strcat (), ... ; */
196237263Snp	  if (declarator_start == 0)
197237263Snp	    declarator_start = prev_id_start;
198237263Snp	  CPP_SET_WRITTEN (pfile, declarator_start);
199237263Snp	  break;
200237263Snp	case CPP_NAME:
201237263Snp	  /* "inline" and "extern" are recognized but skipped */
202237263Snp	  if (strcmp (pfile->token_buffer, "inline") == 0)
203237263Snp	    {
204237263Snp	      saw_inline = 1;
205237263Snp	      CPP_SET_WRITTEN (pfile, start_written);
206237263Snp	    }
207237263Snp	  if (strcmp (pfile->token_buffer, "extern") == 0)
208237263Snp	    {
209237263Snp	      saw_extern = 1;
210237263Snp	      CPP_SET_WRITTEN (pfile, start_written);
211237263Snp	      token = cpp_get_non_space_token (pfile);
212237263Snp	      if (token == CPP_STRING
213237263Snp		  && strcmp (pfile->token_buffer, "\"C\"") == 0)
214237263Snp		{
215237263Snp		  CPP_SET_WRITTEN (pfile, start_written);
216237263Snp		  current_extern_C = 1;
217237263Snp		  token = cpp_get_non_space_token (pfile);
218237263Snp		  if (token == CPP_LBRACE)
219237263Snp		    {
220237263Snp		      brace_nesting++;
221237263Snp		      extern_C_braces[extern_C_braces_length++]
222237263Snp			= brace_nesting;
223237263Snp		      goto new_statement;
224237263Snp		    }
225237263Snp		}
226237263Snp	      else
227237263Snp		continue;
228237263Snp	      break;
229237263Snp	    }
230237263Snp	  /* This may be the name of a variable or function.  */
231237263Snp	  prev_id_start = start_written;
232237263Snp	  prev_id_end = CPP_WRITTEN (pfile);
233237263Snp	  break;
234237263Snp
235237263Snp	case CPP_EOF:
236237263Snp	  return 0;
237237263Snp
238237263Snp	case CPP_LBRACE:  case CPP_RBRACE:  case CPP_DIRECTIVE:
239237263Snp	  goto new_statement;  /* handle_statement? */
240237263Snp
241237263Snp	case CPP_HSPACE:  case CPP_VSPACE:  case CPP_COMMENT:  case CPP_POP:
242237263Snp	  /* Skip initial white space.  */
243237263Snp	  if (start_written == 0)
244237263Snp	    CPP_SET_WRITTEN (pfile, 0);
245237263Snp	  break;
246237263Snp
247237263Snp	 default:
248237263Snp	  prev_id_start = 0;
249237263Snp	}
250237263Snp
251237263Snp      start_written = CPP_WRITTEN (pfile);
252237263Snp      token = cpp_get_token (pfile);
253237263Snp    }
254237263Snp}
255237263Snp