OSDN Git Service

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