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