118334Speter/* gen-protos.c - massages a list of prototypes, for use by fixproto.
290075Sobrien   Copyright (C) 1993, 1994, 1995, 1996, 1998,
3169689Skan   1999, 2003, 2004, 2005 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
19132718Skan#include "bconfig.h"
2050397Sobrien#include "system.h"
21132718Skan#include "coretypes.h"
22132718Skan#include "tm.h"
2318334Speter#include "scan.h"
24169689Skan#include "errors.h"
2518334Speter
2650397Sobrienint verbose = 0;
2750397Sobrien
28132718Skanstatic void add_hash (const char *);
29132718Skanstatic int parse_fn_proto (char *, char *, struct fn_decl *);
3090075Sobrien
3118334Speter#define HASH_SIZE 2503 /* a prime */
3250397Sobrienint hash_tab[HASH_SIZE];
3350397Sobrienint next_index;
3490075Sobrienint collisions;
3518334Speter
3650397Sobrienstatic void
37132718Skanadd_hash (const char *fname)
3850397Sobrien{
3950397Sobrien  int i, i0;
4018334Speter
4150397Sobrien  /* NOTE:  If you edit this, also edit lookup_std_proto in fix-header.c !! */
4290075Sobrien  i = hashstr (fname, strlen (fname)) % HASH_SIZE;
4350397Sobrien  i0 = i;
4450397Sobrien  if (hash_tab[i] != 0)
4550397Sobrien    {
4690075Sobrien      collisions++;
4750397Sobrien      for (;;)
4850397Sobrien	{
4950397Sobrien	  i = (i+1) % HASH_SIZE;
50169689Skan	  gcc_assert (i != i0);
5150397Sobrien	  if (hash_tab[i] == 0)
5250397Sobrien	    break;
5350397Sobrien	}
5450397Sobrien    }
5550397Sobrien  hash_tab[i] = next_index;
5618334Speter
5750397Sobrien  next_index++;
5850397Sobrien}
5918334Speter
6050397Sobrien/* Given a function prototype, fill in the fields of FN.
6150397Sobrien   The result is a boolean indicating if a function prototype was found.
6250397Sobrien
6350397Sobrien   The input string is modified (trailing NULs are inserted).
6450397Sobrien   The fields of FN point to the input string.  */
6550397Sobrien
6650397Sobrienstatic int
67132718Skanparse_fn_proto (char *start, char *end, struct fn_decl *fn)
6818334Speter{
6990075Sobrien  char *ptr;
7050397Sobrien  int param_nesting = 1;
7150397Sobrien  char *param_start, *param_end, *decl_start, *name_start, *name_end;
7250397Sobrien
7350397Sobrien  ptr = end - 1;
7450397Sobrien  while (*ptr == ' ' || *ptr == '\t') ptr--;
7550397Sobrien  if (*ptr-- != ';')
7650397Sobrien    {
7750397Sobrien      fprintf (stderr, "Funny input line: %s\n", start);
7850397Sobrien      return 0;
7950397Sobrien    }
8050397Sobrien  while (*ptr == ' ' || *ptr == '\t') ptr--;
8150397Sobrien  if (*ptr != ')')
8250397Sobrien    {
8350397Sobrien      fprintf (stderr, "Funny input line: %s\n", start);
8450397Sobrien      return 0;
8550397Sobrien    }
8650397Sobrien  param_end = ptr;
8750397Sobrien  for (;;)
8850397Sobrien    {
8950397Sobrien      int c = *--ptr;
9050397Sobrien      if (c == '(' && --param_nesting == 0)
9150397Sobrien	break;
9250397Sobrien      else if (c == ')')
9350397Sobrien	param_nesting++;
9450397Sobrien    }
9550397Sobrien  param_start = ptr+1;
9650397Sobrien
9750397Sobrien  ptr--;
9850397Sobrien  while (*ptr == ' ' || *ptr == '\t') ptr--;
9950397Sobrien
10052284Sobrien  if (!ISALNUM ((unsigned char)*ptr))
10150397Sobrien    {
10250397Sobrien      if (verbose)
10350397Sobrien	fprintf (stderr, "%s: Can't handle this complex prototype: %s\n",
10450397Sobrien		 progname, start);
10550397Sobrien      return 0;
10650397Sobrien    }
10750397Sobrien  name_end = ptr+1;
10850397Sobrien
10990075Sobrien  while (ISIDNUM (*ptr))
11090075Sobrien    --ptr;
11150397Sobrien  name_start = ptr+1;
11250397Sobrien  while (*ptr == ' ' || *ptr == '\t') ptr--;
11350397Sobrien  ptr[1] = 0;
11450397Sobrien  *param_end = 0;
11550397Sobrien  *name_end = 0;
11650397Sobrien
11750397Sobrien  decl_start = start;
11850397Sobrien  if (strncmp (decl_start, "typedef ", 8) == 0)
11950397Sobrien    return 0;
12050397Sobrien  if (strncmp (decl_start, "extern ", 7) == 0)
12150397Sobrien    decl_start += 7;
12250397Sobrien
12350397Sobrien  fn->fname = name_start;
12450397Sobrien  fn->rtype = decl_start;
12550397Sobrien  fn->params = param_start;
12650397Sobrien  return 1;
12718334Speter}
12818334Speter
12918334Speterint
130132718Skanmain (int argc ATTRIBUTE_UNUSED, char **argv)
13118334Speter{
13218334Speter  FILE *inf = stdin;
13318334Speter  FILE *outf = stdout;
13450397Sobrien  int i;
13550397Sobrien  sstring linebuf;
13650397Sobrien  struct fn_decl fn_decl;
13718334Speter
13850397Sobrien  i = strlen (argv[0]);
13950397Sobrien  while (i > 0 && argv[0][i-1] != '/') --i;
14050397Sobrien  progname = &argv[0][i];
14150397Sobrien
142169689Skan  /* Unlock the stdio streams.  */
143169689Skan  unlock_std_streams ();
144169689Skan
14550397Sobrien  INIT_SSTRING (&linebuf);
14650397Sobrien
14718334Speter  fprintf (outf, "struct fn_decl std_protos[] = {\n");
14818334Speter
14950397Sobrien  /* A hash table entry of 0 means "unused" so reserve it.  */
15052284Sobrien  fprintf (outf, "  {\"\", \"\", \"\", 0},\n");
15150397Sobrien  next_index = 1;
152132718Skan
15318334Speter  for (;;)
15418334Speter    {
15518334Speter      int c = skip_spaces (inf, ' ');
15650397Sobrien
15718334Speter      if (c == EOF)
15818334Speter	break;
15918334Speter      linebuf.ptr = linebuf.base;
16018334Speter      ungetc (c, inf);
16118334Speter      c = read_upto (inf, &linebuf, '\n');
16218334Speter      if (linebuf.base[0] == '#') /* skip cpp command */
16318334Speter	continue;
16418334Speter      if (linebuf.base[0] == '\0') /* skip empty line */
16518334Speter	continue;
16618334Speter
16750397Sobrien      if (! parse_fn_proto (linebuf.base, linebuf.ptr, &fn_decl))
16818334Speter	continue;
16918334Speter
17050397Sobrien      add_hash (fn_decl.fname);
17118334Speter
17252284Sobrien      fprintf (outf, "  {\"%s\", \"%s\", \"%s\", 0},\n",
17350397Sobrien	       fn_decl.fname, fn_decl.rtype, fn_decl.params);
17418334Speter
17518334Speter      if (c == EOF)
17618334Speter	break;
17718334Speter    }
17852284Sobrien  fprintf (outf, "  {0, 0, 0, 0}\n};\n");
17918334Speter
18018334Speter
18118334Speter  fprintf (outf, "#define HASH_SIZE %d\n", HASH_SIZE);
18218334Speter  fprintf (outf, "short hash_tab[HASH_SIZE] = {\n");
18318334Speter  for (i = 0; i < HASH_SIZE; i++)
18418334Speter    fprintf (outf, "  %d,\n", hash_tab[i]);
18518334Speter  fprintf (outf, "};\n");
18618334Speter
18790075Sobrien  fprintf (stderr, "gen-protos: %d entries %d collisions\n",
18890075Sobrien	   next_index, collisions);
189132718Skan
19018334Speter  return 0;
19118334Speter}
192