118334Speter/* scan-decls.c - Extracts declarations from cpp output. 290075Sobrien Copyright (C) 1993, 1995, 1997, 1998, 3169689Skan 1999, 2000, 2003, 2004 Free Software Foundation, Inc. 418334Speter 518334SpeterThis program is free software; you can redistribute it and/or modify it 618334Speterunder the terms of the GNU General Public License as published by the 718334SpeterFree Software Foundation; either version 2, or (at your option) any 818334Speterlater version. 918334Speter 1018334SpeterThis program is distributed in the hope that it will be useful, 1118334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of 1218334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1318334SpeterGNU General Public License for more details. 1418334Speter 1518334SpeterYou should have received a copy of the GNU General Public License 1618334Speteralong with this program; if not, write to the Free Software 17169689SkanFoundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 1818334Speter 1918334Speter Written by Per Bothner <bothner@cygnus.com>, July 1993. */ 2018334Speter 21132718Skan#include "bconfig.h" 2250397Sobrien#include "system.h" 23132718Skan#include "coretypes.h" 24132718Skan#include "tm.h" 2518334Speter#include "cpplib.h" 2650397Sobrien#include "scan.h" 2718334Speter 28132718Skanstatic void skip_to_closing_brace (cpp_reader *); 29132718Skanstatic const cpp_token *get_a_token (cpp_reader *); 3090075Sobrien 3118334Speterint brace_nesting = 0; 3218334Speter 3318334Speter/* The first extern_C_braces_length elements of extern_C_braces 3418334Speter indicate the (brace nesting levels of) left braces that were 3518334Speter prefixed by extern "C". */ 3618334Speterint extern_C_braces_length = 0; 37122180Skan/* 20 is not enough anymore on Solaris 9. */ 38122180Skan#define MAX_EXTERN_C_BRACES 200 39122180Skanchar extern_C_braces[MAX_EXTERN_C_BRACES]; 4018334Speter#define in_extern_C_brace (extern_C_braces_length>0) 4118334Speter 4218334Speter/* True if the function declaration currently being scanned is 4318334Speter prefixed by extern "C". */ 4418334Speterint current_extern_C = 0; 4518334Speter 4690075Sobrien/* Get a token but skip padding. */ 4790075Sobrienstatic const cpp_token * 48132718Skanget_a_token (cpp_reader *pfile) 4990075Sobrien{ 5090075Sobrien for (;;) 5190075Sobrien { 5290075Sobrien const cpp_token *result = cpp_get_token (pfile); 5390075Sobrien if (result->type != CPP_PADDING) 5490075Sobrien return result; 5590075Sobrien } 5690075Sobrien} 5790075Sobrien 5818334Speterstatic void 59132718Skanskip_to_closing_brace (cpp_reader *pfile) 6018334Speter{ 6118334Speter int nesting = 1; 6218334Speter for (;;) 6318334Speter { 6490075Sobrien enum cpp_ttype token = get_a_token (pfile)->type; 6590075Sobrien 6618334Speter if (token == CPP_EOF) 6718334Speter break; 6890075Sobrien if (token == CPP_OPEN_BRACE) 6918334Speter nesting++; 7090075Sobrien if (token == CPP_CLOSE_BRACE && --nesting == 0) 7118334Speter break; 7218334Speter } 7318334Speter} 7418334Speter 7518334Speter/* This function scans a C source file (actually, the output of cpp), 7618334Speter reading from FP. It looks for function declarations, and 77117395Skan external variable declarations. 7818334Speter 7918334Speter The following grammar (as well as some extra stuff) is recognized: 8018334Speter 8118334Speter declaration: 8218334Speter (decl-specifier)* declarator ("," declarator)* ";" 8318334Speter decl-specifier: 8418334Speter identifier 8518334Speter keyword 8618334Speter extern "C" 8718334Speter declarator: 8818334Speter (ptr-operator)* dname [ "(" argument-declaration-list ")" ] 8918334Speter ptr-operator: 9018334Speter ("*" | "&") ("const" | "volatile")* 9118334Speter dname: 9218334Speter identifier 9318334Speter 9418334SpeterHere dname is the actual name being declared. 9518334Speter*/ 9618334Speter 9718334Speterint 98132718Skanscan_decls (cpp_reader *pfile, int argc ATTRIBUTE_UNUSED, 99132718Skan char **argv ATTRIBUTE_UNUSED) 10018334Speter{ 10118334Speter int saw_extern, saw_inline; 10290075Sobrien cpp_token prev_id; 10390075Sobrien const cpp_token *token; 10418334Speter 10518334Speter new_statement: 10690075Sobrien token = get_a_token (pfile); 10718334Speter 10818334Speter handle_statement: 10918334Speter current_extern_C = 0; 11018334Speter saw_extern = 0; 11118334Speter saw_inline = 0; 11290075Sobrien if (token->type == CPP_OPEN_BRACE) 11318334Speter { 11418334Speter /* Pop an 'extern "C"' nesting level, if appropriate. */ 11518334Speter if (extern_C_braces_length 11618334Speter && extern_C_braces[extern_C_braces_length - 1] == brace_nesting) 11718334Speter extern_C_braces_length--; 11818334Speter brace_nesting--; 11918334Speter goto new_statement; 12018334Speter } 12190075Sobrien if (token->type == CPP_OPEN_BRACE) 12218334Speter { 12318334Speter brace_nesting++; 12418334Speter goto new_statement; 12518334Speter } 12690075Sobrien 12790075Sobrien if (token->type == CPP_EOF) 12818334Speter return 0; 12990075Sobrien 13090075Sobrien if (token->type == CPP_SEMICOLON) 13118334Speter goto new_statement; 13290075Sobrien if (token->type != CPP_NAME) 13318334Speter goto new_statement; 13418334Speter 13590075Sobrien prev_id.type = CPP_EOF; 13618334Speter for (;;) 13718334Speter { 13890075Sobrien switch (token->type) 13918334Speter { 14090075Sobrien default: 14190075Sobrien goto handle_statement; 14290075Sobrien case CPP_MULT: 14390075Sobrien case CPP_AND: 14490075Sobrien /* skip */ 14590075Sobrien break; 14690075Sobrien 14790075Sobrien case CPP_COMMA: 14890075Sobrien case CPP_SEMICOLON: 14990075Sobrien if (prev_id.type != CPP_EOF && saw_extern) 15090075Sobrien { 15190075Sobrien recognized_extern (&prev_id); 15290075Sobrien } 15390075Sobrien if (token->type == CPP_COMMA) 15490075Sobrien break; 15590075Sobrien /* ... fall through ... */ 15690075Sobrien case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE: 15790075Sobrien goto new_statement; 158117395Skan 15990075Sobrien case CPP_EOF: 16090075Sobrien return 0; 16190075Sobrien 16290075Sobrien case CPP_OPEN_PAREN: 16350397Sobrien /* Looks like this is the start of a formal parameter list. */ 16490075Sobrien if (prev_id.type != CPP_EOF) 16518334Speter { 16618334Speter int nesting = 1; 16718334Speter int have_arg_list = 0; 168169689Skan const struct line_map *map; 169169689Skan unsigned int line; 17018334Speter for (;;) 17118334Speter { 17290075Sobrien token = get_a_token (pfile); 17390075Sobrien if (token->type == CPP_OPEN_PAREN) 17418334Speter nesting++; 17590075Sobrien else if (token->type == CPP_CLOSE_PAREN) 17618334Speter { 17718334Speter nesting--; 17818334Speter if (nesting == 0) 17918334Speter break; 18018334Speter } 18190075Sobrien else if (token->type == CPP_EOF) 18218334Speter break; 18390075Sobrien else if (token->type == CPP_NAME 18490075Sobrien || token->type == CPP_ELLIPSIS) 18518334Speter have_arg_list = 1; 18618334Speter } 187169689Skan map = linemap_lookup (&line_table, token->src_loc); 188169689Skan line = SOURCE_LINE (map, token->src_loc); 189169689Skan recognized_function (&prev_id, line, 19018334Speter (saw_inline ? 'I' 19118334Speter : in_extern_C_brace || current_extern_C 19290075Sobrien ? 'F' : 'f'), have_arg_list); 19390075Sobrien token = get_a_token (pfile); 19490075Sobrien if (token->type == CPP_OPEN_BRACE) 19518334Speter { 19618334Speter /* skip body of (normally) inline function */ 19718334Speter skip_to_closing_brace (pfile); 19818334Speter goto new_statement; 19918334Speter } 20090075Sobrien 20190075Sobrien /* skip a possible __attribute__ or throw expression after the 20290075Sobrien parameter list */ 20390075Sobrien while (token->type != CPP_SEMICOLON && token->type != CPP_EOF) 20490075Sobrien token = get_a_token (pfile); 205169689Skan if (token->type == CPP_EOF) 206169689Skan return 0; 20790075Sobrien goto new_statement; 20818334Speter } 20918334Speter break; 21018334Speter case CPP_NAME: 21118334Speter /* "inline" and "extern" are recognized but skipped */ 21290075Sobrien if (cpp_ideq (token, "inline")) 21318334Speter { 21418334Speter saw_inline = 1; 21518334Speter } 21690075Sobrien else if (cpp_ideq (token, "extern")) 21718334Speter { 21818334Speter saw_extern = 1; 21990075Sobrien token = get_a_token (pfile); 22090075Sobrien if (token->type == CPP_STRING 22190075Sobrien && token->val.str.len == 1 22290075Sobrien && token->val.str.text[0] == 'C') 22318334Speter { 22418334Speter current_extern_C = 1; 22590075Sobrien token = get_a_token (pfile); 22690075Sobrien if (token->type == CPP_OPEN_BRACE) 22718334Speter { 22818334Speter brace_nesting++; 22918334Speter extern_C_braces[extern_C_braces_length++] 23018334Speter = brace_nesting; 231122180Skan if (extern_C_braces_length >= MAX_EXTERN_C_BRACES) 232122180Skan { 233122180Skan fprintf (stderr, 234122180Skan "Internal error: out-of-bounds index\n"); 235122180Skan exit (FATAL_EXIT_CODE); 236122180Skan } 23718334Speter goto new_statement; 23818334Speter } 23918334Speter } 24018334Speter else 24150397Sobrien continue; 24218334Speter break; 24318334Speter } 24450397Sobrien /* This may be the name of a variable or function. */ 24590075Sobrien prev_id = *token; 24618334Speter break; 24718334Speter } 24890075Sobrien token = get_a_token (pfile); 24918334Speter } 25018334Speter} 251