OSDN Git Service

Fix copyrights.
[pf3gnuchains/gcc-fork.git] / gcc / scan-decls.c
1 /* scan-decls.c - Extracts declarations from cpp output.
2    Copyright (C) 1993, 1995, 1997, 1998,
3    1999, 2000 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 2, 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; if not, write to the Free Software
17 Foundation, 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
26 static void skip_to_closing_brace PARAMS ((cpp_reader *));
27
28 int brace_nesting = 0;
29
30 /* The first extern_C_braces_length elements of extern_C_braces
31    indicate the (brace nesting levels of) left braces that were
32    prefixed by extern "C".  */
33 int extern_C_braces_length = 0;
34 char extern_C_braces[20];
35 #define in_extern_C_brace (extern_C_braces_length>0)
36
37 /* True if the function declaration currently being scanned is
38    prefixed by extern "C".  */
39 int current_extern_C = 0;
40
41 static void
42 skip_to_closing_brace (pfile)
43      cpp_reader *pfile;
44 {
45   int nesting = 1;
46   for (;;)
47     {
48       enum cpp_token token = cpp_get_token (pfile);
49       if (token == CPP_EOF)
50         break;
51       if (token == CPP_LBRACE)
52         nesting++;
53       if (token == CPP_RBRACE && --nesting == 0)
54         break;
55     }
56 }
57
58 /* This function scans a C source file (actually, the output of cpp),
59    reading from FP.  It looks for function declarations, and
60    external variable declarations.  
61
62    The following grammar (as well as some extra stuff) is recognized:
63
64    declaration:
65      (decl-specifier)* declarator ("," declarator)* ";"
66    decl-specifier:
67      identifier
68      keyword
69      extern "C"
70    declarator:
71      (ptr-operator)* dname [ "(" argument-declaration-list ")" ]
72    ptr-operator:
73      ("*" | "&") ("const" | "volatile")*
74    dname:
75      identifier
76
77 Here dname is the actual name being declared.
78 */
79
80 int
81 scan_decls (pfile, argc, argv)
82      cpp_reader *pfile;
83      int argc ATTRIBUTE_UNUSED;
84      char **argv ATTRIBUTE_UNUSED;
85 {
86   int saw_extern, saw_inline;
87   int start_written;
88   /* If declarator_start is non-zero, it marks the start of the current
89      declarator.  If it is zero, we are either still parsing the
90      decl-specs, or prev_id_start marks the start of the declarator.  */
91   int declarator_start;
92   int prev_id_start, prev_id_end = 0;
93   enum cpp_token token;
94
95  new_statement:
96   CPP_SET_WRITTEN (pfile, 0);
97   start_written = 0;
98   token = cpp_get_token (pfile);
99
100  handle_statement:
101   current_extern_C = 0;
102   saw_extern = 0;
103   saw_inline = 0;
104   if (token == CPP_RBRACE)
105     {
106       /* Pop an 'extern "C"' nesting level, if appropriate.  */
107       if (extern_C_braces_length
108           && extern_C_braces[extern_C_braces_length - 1] == brace_nesting)
109         extern_C_braces_length--;
110       brace_nesting--;
111       goto new_statement;
112     }
113   if (token == CPP_LBRACE)
114     {
115       brace_nesting++;
116       goto new_statement;
117     }
118   if (token == CPP_EOF)
119     return 0;
120   if (token == CPP_SEMICOLON)
121     goto new_statement;
122   if (token != CPP_NAME)
123     goto new_statement;
124
125   prev_id_start = 0;
126   declarator_start = 0;
127   for (;;)
128     {
129       switch (token)
130         {
131         case CPP_LPAREN:
132           /* Looks like this is the start of a formal parameter list.  */
133           if (prev_id_start)
134             {
135               int nesting = 1;
136               int have_arg_list = 0;
137               cpp_buffer *fbuf = cpp_file_buffer (pfile);
138               long func_lineno;
139               cpp_buf_line_and_col (fbuf, &func_lineno, NULL);
140               for (;;)
141                 {
142                   token = cpp_get_token (pfile);
143                   if (token == CPP_LPAREN)
144                     nesting++;
145                   else if (token == CPP_RPAREN)
146                     {
147                       nesting--;
148                       if (nesting == 0)
149                         break;
150                     }
151                   else if (token == CPP_EOF)
152                     break;
153                   else if (token == CPP_NAME || token == CPP_3DOTS)
154                     have_arg_list = 1;
155                 }
156               recognized_function (pfile->token_buffer + prev_id_start,
157                                    prev_id_end - prev_id_start,
158                                    (saw_inline ? 'I'
159                                     : in_extern_C_brace || current_extern_C
160                                     ? 'F' : 'f'),
161                                    pfile->token_buffer, prev_id_start,
162                                    have_arg_list,
163                                    fbuf->nominal_fname, func_lineno);
164               token = cpp_get_non_space_token (pfile);
165               if (token == CPP_LBRACE)
166                 {
167                   /* skip body of (normally) inline function */
168                   skip_to_closing_brace (pfile);
169                   goto new_statement;
170                 }
171               goto maybe_handle_comma;
172             }
173           break;
174         case CPP_OTHER:
175           if (CPP_WRITTEN (pfile) == (size_t) start_written + 1
176               && (CPP_PWRITTEN (pfile)[-1] == '*'
177                   || CPP_PWRITTEN (pfile)[-1] == '&'))
178             declarator_start = start_written;
179           else
180             goto handle_statement;
181           break;
182         case CPP_COMMA:
183         case CPP_SEMICOLON:
184           if (prev_id_start && saw_extern)
185             {
186               recognized_extern (pfile->token_buffer + prev_id_start,
187                                  prev_id_end - prev_id_start,
188                                  pfile->token_buffer,
189                                  prev_id_start);
190             }
191           /* ... fall through ...  */
192         maybe_handle_comma:
193           if (token != CPP_COMMA)
194             goto new_statement;
195 #if 0
196         handle_comma:
197 #endif
198           /* Handle multiple declarators in a single declaration,
199              as in:  extern char *strcpy (), *strcat (), ... ; */
200           if (declarator_start == 0)
201             declarator_start = prev_id_start;
202           CPP_SET_WRITTEN (pfile, declarator_start);
203           break;
204         case CPP_NAME:
205           /* "inline" and "extern" are recognized but skipped */
206           if (strcmp (pfile->token_buffer, "inline") == 0)
207             {
208               saw_inline = 1;
209               CPP_SET_WRITTEN (pfile, start_written);
210             }
211           if (strcmp (pfile->token_buffer, "extern") == 0)
212             {
213               saw_extern = 1;
214               CPP_SET_WRITTEN (pfile, start_written);
215               token = cpp_get_non_space_token (pfile);
216               if (token == CPP_STRING
217                   && strcmp (pfile->token_buffer, "\"C\"") == 0)
218                 {
219                   CPP_SET_WRITTEN (pfile, start_written);
220                   current_extern_C = 1;
221                   token = cpp_get_non_space_token (pfile);
222                   if (token == CPP_LBRACE)
223                     {
224                       brace_nesting++;
225                       extern_C_braces[extern_C_braces_length++]
226                         = brace_nesting;
227                       goto new_statement;
228                     }
229                 }
230               else
231                 continue;
232               break;
233             }
234           /* This may be the name of a variable or function.  */
235           prev_id_start = start_written;
236           prev_id_end = CPP_WRITTEN (pfile);
237           break;
238
239         case CPP_EOF:
240           return 0;
241
242         case CPP_LBRACE:  case CPP_RBRACE:  case CPP_DIRECTIVE:
243           goto new_statement;  /* handle_statement? */
244           
245         case CPP_HSPACE:  case CPP_VSPACE:  case CPP_COMMENT:  case CPP_POP:
246           /* Skip initial white space.  */
247           if (start_written == 0)
248             CPP_SET_WRITTEN (pfile, 0);
249           break;
250
251          default:
252           prev_id_start = 0;
253         }
254
255       start_written = CPP_WRITTEN (pfile);
256       token = cpp_get_token (pfile);
257     }
258 }