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