scan-decls.c revision 52284
1/* scan-decls.c - Extracts declarations from cpp output. 2 Copyright (C) 1993, 1995, 97-98, 1999 Free Software Foundation, Inc. 3 4This program is free software; you can redistribute it and/or modify it 5under the terms of the GNU General Public License as published by the 6Free Software Foundation; either version 2, or (at your option) any 7later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with this program; if not, write to the Free Software 16Foundation, 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 25int 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". */ 30int extern_C_braces_length = 0; 31char 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". */ 36int current_extern_C = 0; 37 38static void 39skip_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 74Here dname is the actual name being declared. 75*/ 76 77int 78scan_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} 256