0
|
1 /* scan-decls.c - Extracts declarations from cpp output.
|
|
2 Copyright (C) 1993, 1995, 1997, 1998,
|
|
3 1999, 2000, 2003, 2004, 2007 Free Software Foundation, Inc.
|
|
4
|
|
5 This program is free software; you can redistribute it and/or modify it
|
|
6 under the terms of the GNU General Public License as published by the
|
|
7 Free Software Foundation; either version 3, or (at your option) any
|
|
8 later version.
|
|
9
|
|
10 This program is distributed in the hope that it will be useful,
|
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 GNU General Public License for more details.
|
|
14
|
|
15 You should have received a copy of the GNU General Public License
|
|
16 along with this program; see the file COPYING3. If not see
|
|
17 <http://www.gnu.org/licenses/>.
|
|
18
|
|
19 Written by Per Bothner <bothner@cygnus.com>, July 1993. */
|
|
20
|
|
21 #include "bconfig.h"
|
|
22 #include "system.h"
|
|
23 #include "coretypes.h"
|
|
24 #include "tm.h"
|
|
25 #include "cpplib.h"
|
|
26 #include "scan.h"
|
|
27
|
|
28 static void skip_to_closing_brace (cpp_reader *);
|
|
29 static const cpp_token *get_a_token (cpp_reader *);
|
|
30
|
|
31 int brace_nesting = 0;
|
|
32
|
|
33 /* The first extern_C_braces_length elements of extern_C_braces
|
|
34 indicate the (brace nesting levels of) left braces that were
|
|
35 prefixed by extern "C". */
|
|
36 int extern_C_braces_length = 0;
|
|
37 /* 20 is not enough anymore on Solaris 9. */
|
|
38 #define MAX_EXTERN_C_BRACES 200
|
|
39 char extern_C_braces[MAX_EXTERN_C_BRACES];
|
|
40 #define in_extern_C_brace (extern_C_braces_length>0)
|
|
41
|
|
42 /* True if the function declaration currently being scanned is
|
|
43 prefixed by extern "C". */
|
|
44 int current_extern_C = 0;
|
|
45
|
|
46 /* Get a token but skip padding. */
|
|
47 static const cpp_token *
|
|
48 get_a_token (cpp_reader *pfile)
|
|
49 {
|
|
50 for (;;)
|
|
51 {
|
|
52 const cpp_token *result = cpp_get_token (pfile);
|
|
53 if (result->type != CPP_PADDING)
|
|
54 return result;
|
|
55 }
|
|
56 }
|
|
57
|
|
58 static void
|
|
59 skip_to_closing_brace (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
|
|
94 Here dname is the actual name being declared.
|
|
95 */
|
|
96
|
|
97 int
|
|
98 scan_decls (cpp_reader *pfile, int argc ATTRIBUTE_UNUSED,
|
|
99 char **argv ATTRIBUTE_UNUSED)
|
|
100 {
|
|
101 int saw_extern, saw_inline;
|
|
102 cpp_token prev_id;
|
|
103 const cpp_token *token;
|
|
104
|
|
105 new_statement:
|
|
106 token = get_a_token (pfile);
|
|
107
|
|
108 handle_statement:
|
|
109 current_extern_C = 0;
|
|
110 saw_extern = 0;
|
|
111 saw_inline = 0;
|
|
112 if (token->type == CPP_OPEN_BRACE)
|
|
113 {
|
|
114 /* Pop an 'extern "C"' nesting level, if appropriate. */
|
|
115 if (extern_C_braces_length
|
|
116 && extern_C_braces[extern_C_braces_length - 1] == brace_nesting)
|
|
117 extern_C_braces_length--;
|
|
118 brace_nesting--;
|
|
119 goto new_statement;
|
|
120 }
|
|
121 if (token->type == CPP_OPEN_BRACE)
|
|
122 {
|
|
123 brace_nesting++;
|
|
124 goto new_statement;
|
|
125 }
|
|
126
|
|
127 if (token->type == CPP_EOF)
|
|
128 return 0;
|
|
129
|
|
130 if (token->type == CPP_SEMICOLON)
|
|
131 goto new_statement;
|
|
132 if (token->type != CPP_NAME)
|
|
133 goto new_statement;
|
|
134
|
|
135 prev_id.type = CPP_EOF;
|
|
136 for (;;)
|
|
137 {
|
|
138 switch (token->type)
|
|
139 {
|
|
140 default:
|
|
141 goto handle_statement;
|
|
142 case CPP_MULT:
|
|
143 case CPP_AND:
|
|
144 /* skip */
|
|
145 break;
|
|
146
|
|
147 case CPP_COMMA:
|
|
148 case CPP_SEMICOLON:
|
|
149 if (prev_id.type != CPP_EOF && saw_extern)
|
|
150 {
|
|
151 recognized_extern (&prev_id);
|
|
152 }
|
|
153 if (token->type == CPP_COMMA)
|
|
154 break;
|
|
155 /* ... fall through ... */
|
|
156 case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE:
|
|
157 goto new_statement;
|
|
158
|
|
159 case CPP_EOF:
|
|
160 return 0;
|
|
161
|
|
162 case CPP_OPEN_PAREN:
|
|
163 /* Looks like this is the start of a formal parameter list. */
|
|
164 if (prev_id.type != CPP_EOF)
|
|
165 {
|
|
166 int nesting = 1;
|
|
167 int have_arg_list = 0;
|
|
168 const struct line_map *map;
|
|
169 unsigned int line;
|
|
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 map = linemap_lookup (&line_table, token->src_loc);
|
|
188 line = SOURCE_LINE (map, token->src_loc);
|
|
189 recognized_function (&prev_id, line,
|
|
190 (saw_inline ? 'I'
|
|
191 : in_extern_C_brace || current_extern_C
|
|
192 ? 'F' : 'f'), have_arg_list);
|
|
193 token = get_a_token (pfile);
|
|
194 if (token->type == CPP_OPEN_BRACE)
|
|
195 {
|
|
196 /* skip body of (normally) inline function */
|
|
197 skip_to_closing_brace (pfile);
|
|
198 goto new_statement;
|
|
199 }
|
|
200
|
|
201 /* skip a possible __attribute__ or throw expression after the
|
|
202 parameter list */
|
|
203 while (token->type != CPP_SEMICOLON && token->type != CPP_EOF)
|
|
204 token = get_a_token (pfile);
|
|
205 if (token->type == CPP_EOF)
|
|
206 return 0;
|
|
207 goto new_statement;
|
|
208 }
|
|
209 break;
|
|
210 case CPP_NAME:
|
|
211 /* "inline" and "extern" are recognized but skipped */
|
|
212 if (cpp_ideq (token, "inline"))
|
|
213 {
|
|
214 saw_inline = 1;
|
|
215 }
|
|
216 else if (cpp_ideq (token, "extern"))
|
|
217 {
|
|
218 saw_extern = 1;
|
|
219 token = get_a_token (pfile);
|
|
220 if (token->type == CPP_STRING
|
|
221 && token->val.str.len == 1
|
|
222 && token->val.str.text[0] == 'C')
|
|
223 {
|
|
224 current_extern_C = 1;
|
|
225 token = get_a_token (pfile);
|
|
226 if (token->type == CPP_OPEN_BRACE)
|
|
227 {
|
|
228 brace_nesting++;
|
|
229 extern_C_braces[extern_C_braces_length++]
|
|
230 = brace_nesting;
|
|
231 if (extern_C_braces_length >= MAX_EXTERN_C_BRACES)
|
|
232 {
|
|
233 fprintf (stderr,
|
|
234 "Internal error: out-of-bounds index\n");
|
|
235 exit (FATAL_EXIT_CODE);
|
|
236 }
|
|
237 goto new_statement;
|
|
238 }
|
|
239 }
|
|
240 else
|
|
241 continue;
|
|
242 break;
|
|
243 }
|
|
244 /* This may be the name of a variable or function. */
|
|
245 prev_id = *token;
|
|
246 break;
|
|
247 }
|
|
248 token = get_a_token (pfile);
|
|
249 }
|
|
250 }
|