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