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