genhooks.c 10.4 KB
Newer Older
1 2
/* Process target.def to create initialization macros definition in
   target-hooks-def.h and documentation in target-hooks.texi.
Jakub Jelinek committed
3
   Copyright (C) 2009-2015 Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
#include "bconfig.h"
#include "system.h"
#include "errors.h"

24
struct hook_desc { const char *doc, *type, *name, *param, *init, *docname; };
25
static struct hook_desc hook_array[] = {
26 27
#define HOOK_VECTOR_1(NAME, FRAGMENT)	\
  { 0, 0, #NAME, 0, 0, HOOK_TYPE },
28
#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) \
29
  { DOC, #TYPE, HOOK_PREFIX #NAME, 0, #INIT, HOOK_TYPE },
30
#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) \
31
  { DOC, #TYPE, HOOK_PREFIX #NAME, #PARAMS, #INIT, HOOK_TYPE },
32
#define DEFHOOK_UNDOC(NAME, DOC, TYPE, PARAMS, INIT) \
33
  { "*", #TYPE, HOOK_PREFIX #NAME, #PARAMS, #INIT, HOOK_TYPE },
34
#include "target.def"
35
#include "c-family/c-target.def"
36
#include "common/common-target.def"
37 38 39
#undef DEFHOOK
};

Mike Stump committed
40
/* For each @Fcode in the first paragraph of the documentation string DOC,
41 42 43 44 45 46 47 48 49 50 51 52 53 54
   print an @findex directive.  HOOK_NAME is the name of the hook this bit of
   documentation pertains to.  */
static void
emit_findices (const char *doc, const char *hook_name)
{
  const char *end = strstr (doc, "\n\n");
  const char *fcode;

  while ((fcode = strstr (doc, "@Fcode{")) && (!end || fcode < end))
    {
      fcode += strlen ("@Fcode{");
      doc = strchr (fcode, '}');
      if (!doc)
	fatal ("Malformed @Fcode for hook %s\n", hook_name);
55
      printf ("@findex %.*s\n", (int) (doc - fcode), fcode);
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
      doc = fcode;
    }
}

/* Return an upper-case copy of IN.  */
static char *
upstrdup (const char *in)
{
  char *p, *ret = xstrdup (in);
  for (p = ret; *p; p++)
    *p = TOUPPER (*p);
  return ret;
}

/* Struct for 'start hooks' which start a sequence of consecutive hooks
   that are defined in target.def and to be documented in tm.texi.  */
struct s_hook
{
  char *name;
  int pos;
};

static hashval_t
s_hook_hash (const void *p)
{
  const struct s_hook *s_hook = (const struct s_hook *)p;
  return htab_hash_string (s_hook->name);
}

static int
s_hook_eq_p (const void *p1, const void *p2)
{
  return (strcmp (((const struct s_hook *) p1)->name, 
		  ((const struct s_hook *) p2)->name) == 0);
}

/* Read the documentation file with name IN_FNAME, perform substitutions
Joseph Myers committed
93
   to incorporate information from hook_array, and emit the result on stdout.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
   Hooks defined with DEFHOOK / DEFHOOKPOD are emitted at the place of a
   matching @hook in the input file; if there is no matching @hook, the
   hook is emitted after the hook that precedes it in target.def .
   Usually, the emitted hook documentation starts with the hook
   signature, followed by the string from the doc field.
   The documentation is bracketed in @deftypefn / @deftypevr and a matching
   @end.
   While emitting the doc field, @Fcode is translated to @code, and an
   @findex entry is added to the affected paragraph.
   If the doc field starts with '*', the leading '*' is stripped, and the doc
   field is otherwise emitted unaltered; no function signature/
   @deftypefn/deftypevr/@end is emitted.
   In particular, a doc field of "*" means not to emit any ocumentation for
   this target.def / hook_array entry at all (there might be documentation
   for this hook in the file named IN_FNAME, though).
   A doc field of 0 is used to append the hook signature after the previous
   hook's signture, so that one description can be used for a group of hooks.
   When the doc field is "", @deftypefn/@deftypevr and the hook signature
   is emitted, but not the matching @end.  This allows all the free-form
   documentation to be placed in IN_FNAME, to work around GPL/GFDL
   licensing incompatibility issues.  */
static void
emit_documentation (const char *in_fname)
{
  int i, j;
  char buf[1000];
  htab_t start_hooks = htab_create (99, s_hook_hash, s_hook_eq_p, (htab_del) 0);
  FILE *f;

  /* Enter all the start hooks in start_hooks.  */
  f = fopen (in_fname, "r");
  if (!f)
    {
      perror ("");
      fatal ("Couldn't open input file");
    }
  while (fscanf (f, "%*[^@]"), buf[0] = '\0',
	 fscanf (f, "@%5[^ \n]", buf) != EOF)
    {
      void **p;
      struct s_hook *shp;

      if (strcmp (buf, "hook") != 0)
	continue;
      buf[0] = '\0';
      fscanf (f, "%999s", buf);
      shp = XNEW (struct s_hook);
      shp->name = upstrdup (buf);
      shp->pos = -1;
      p = htab_find_slot (start_hooks, shp, INSERT);
      if (*p != HTAB_EMPTY_ENTRY)
	fatal ("Duplicate placement for hook %s\n", shp->name);
      *(struct s_hook **) p = shp;
    }
  fclose (f);
  /* For each hook in hook_array, if it is a start hook, store its position.  */
  for (i = 0; i < (int) (sizeof hook_array / sizeof hook_array[0]); i++)
    {
      struct s_hook sh, *shp;
      void *p;

      if (!hook_array[i].doc || strcmp (hook_array[i].doc, "*") == 0)
	continue;
      sh.name = upstrdup (hook_array[i].name);
      p = htab_find (start_hooks, &sh);
      if (p)
	{
	  shp = (struct s_hook *) p;
	  if (shp->pos >= 0)
	    fatal ("Duplicate hook %s\n", sh.name);
	  shp->pos = i;
	}
166
      else
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
	fatal ("No place specified to document hook %s\n", sh.name);
      free (sh.name);
    }
  /* Copy input file to stdout, substituting @hook directives with the
     corresponding hook documentation sequences.  */
  f = fopen (in_fname, "r");
  if (!f)
    {
      perror ("");
      fatal ("Couldn't open input file");
    }
  for (;;)
    {
      struct s_hook sh, *shp;
      int c = getc (f);
      char *name;

      if (c == EOF)
	break;
      if (c != '@')
	{
	  putchar (c);
	  continue;
	}
      buf[0] = '\0';
      fscanf (f, "%5[^ \n]", buf);
      if (strcmp (buf, "hook") != 0)
	{
	  printf ("@%s", buf);
	  continue;
	}
      fscanf (f, "%999s", buf);
      sh.name = name = upstrdup (buf);
      shp = (struct s_hook *) htab_find (start_hooks, &sh);
      if (!shp || shp->pos < 0)
	fatal ("No documentation for hook %s\n", sh.name);
      i = shp->pos;
      do
	{
	  const char *q, *e;
	  const char *deftype;
	  const char *doc, *fcode, *p_end;

	  /* A leading '*' means to output the documentation string without
	     further processing.  */
	  if (*hook_array[i].doc == '*')
	    printf ("%s", hook_array[i].doc + 1);
	  else
	    {
	      if (i != shp->pos)
		printf ("\n\n");
	      emit_findices (hook_array[i].doc, name);

	      /* Print header.  Function-valued hooks have a parameter list, 
		 unlike POD-valued ones.  */
	      deftype = hook_array[i].param ? "deftypefn" : "deftypevr";
223
	      printf ("@%s {%s} ", deftype, hook_array[i].docname);
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
	      if (strchr (hook_array[i].type, ' '))
		printf ("{%s}", hook_array[i].type);
	      else
		printf ("%s", hook_array[i].type);
	      printf (" %s", name);
	      if (hook_array[i].param)
		{
		  /* Print the parameter list, with the parameter names
		     enclosed in @var{}.  */
		  printf (" ");
		  for (q = hook_array[i].param; (e = strpbrk (q, " *,)"));
		       q = e + 1)
		    /* Type names like 'int' are followed by a space, sometimes
		       also by '*'.  'void' should appear only in "(void)".  */
		    if (*e == ' ' || *e == '*' || *q == '(')
239
		      printf ("%.*s", (int) (e - q + 1), q);
240
		    else
241
		      printf ("@var{%.*s}%c", (int) (e - q), q, *e);
242 243 244 245 246 247 248 249 250
		}
	      /* POD-valued hooks sometimes come in groups with common
		 documentation.*/
	      for (j = i + 1;
		   j < (int) (sizeof hook_array / sizeof hook_array[0])
		   && hook_array[j].doc == 0 && hook_array[j].type; j++)
		{
		  char *namex = upstrdup (hook_array[j].name);

251 252 253
		  printf ("\n@%sx {%s} {%s} %s",
			  deftype, hook_array[j].docname,
			  hook_array[j].type, namex);
254 255 256 257 258 259 260 261 262 263 264 265 266
		}
	      if (hook_array[i].doc[0])
		{
		  printf ("\n");
		  /* Print each documentation paragraph in turn.  */
		  for (doc = hook_array[i].doc; *doc; doc = p_end)
		    {
		      /* Find paragraph end.  */
		      p_end = strstr (doc, "\n\n");
		      p_end = (p_end ? p_end + 2 : doc + strlen (doc));
		      /* Print paragraph, emitting @Fcode as @code.  */
		      for (; (fcode = strstr (doc, "@Fcode{")) && fcode < p_end;
			   doc = fcode + 2)
267 268
			printf ("%.*s@", (int) (fcode - doc), doc);
		      printf ("%.*s", (int) (p_end - doc), doc);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
		      /* Emit function indices for next paragraph.  */
		      emit_findices (p_end, name);
		    }
		  printf ("\n@end %s", deftype);
		}
	    }
	  if (++i >= (int) (sizeof hook_array / sizeof hook_array[0])
	      || !hook_array[i].doc)
	    break;
	  free (name);
	  sh.name = name = upstrdup (hook_array[i].name);
	}
      while (!htab_find (start_hooks, &sh));
      free (name);
    }
}

/* Emit #defines to stdout (this will be redirected to generate
   target-hook-def.h) which set target hooks initializer macros
288 289
   to their default values.  These should only be emitted for hooks
   whose type is given by DOCNAME.  */
290
static void
291
emit_init_macros (const char *docname)
292 293 294 295 296 297 298 299 300 301 302
{
  int i;
  const int MAX_NEST = 2;
  int print_nest, nest = 0;

  for (print_nest = 0; print_nest <= MAX_NEST; print_nest++)
    {
      for (i = 0; i < (int) (sizeof hook_array / sizeof hook_array[0]); i++)
	{
	  char *name = upstrdup (hook_array[i].name);

303 304 305
	  if (strcmp (hook_array[i].docname, docname) != 0)
	    continue;

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	  if (!hook_array[i].type)
	    {
	      if (*name)
		{
		  if (nest && nest == print_nest)
		    printf ("    %s, \\\n", name);
		  nest++;
		  if (nest > MAX_NEST)
		    fatal ("Unexpected nesting of %s\n", name);
		  if (nest == print_nest)
		    printf ("\n#define %s \\\n  { \\\n", name);
		}
	      else
		{
		  if (nest == print_nest)
		    printf ("  }\n");
		  nest--;
		}
	      continue;
	    }
	  if (0 == print_nest)
	    {
	      /* Output default definitions of target hooks.  */
	      printf ("#ifndef %s\n#define %s %s\n#endif\n",
		      name, name, hook_array[i].init);
	    }
	  if (nest == print_nest)
	    printf ("    %s, \\\n", name);
	}
    }
}

int
main (int argc, char **argv)
{
341 342
  progname = "genhooks";

343 344
  if (argc >= 3)
    emit_documentation (argv[2]);
345
  else
346
    emit_init_macros (argv[1]);
347 348
  return 0;
}