xref: /netbsd-src/external/gpl3/gcc/dist/gcc/genhooks.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Process target.def to create initialization macros definition in
2    target-hooks-def.h and documentation in target-hooks.texi.
3    Copyright (C) 2009-2022 Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 #include "bconfig.h"
21 #include "system.h"
22 #include "errors.h"
23 
24 struct hook_desc { const char *doc, *type, *name, *param, *init, *docname; };
25 static struct hook_desc hook_array[] = {
26 #define HOOK_VECTOR_1(NAME, FRAGMENT)	\
27   { 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 #include "d/d-target.def"
38 #undef DEFHOOK
39 };
40 
41 /* Return an upper-case copy of IN.  */
42 static char *
upstrdup(const char * in)43 upstrdup (const char *in)
44 {
45   char *p, *ret = xstrdup (in);
46   for (p = ret; *p; p++)
47     *p = TOUPPER (*p);
48   return ret;
49 }
50 
51 /* Struct for 'start hooks' which start a sequence of consecutive hooks
52    that are defined in target.def and to be documented in tm.texi.  */
53 struct s_hook
54 {
55   char *name;
56   int pos;
57 };
58 
59 static hashval_t
s_hook_hash(const void * p)60 s_hook_hash (const void *p)
61 {
62   const struct s_hook *s_hook = (const struct s_hook *)p;
63   return htab_hash_string (s_hook->name);
64 }
65 
66 static int
s_hook_eq_p(const void * p1,const void * p2)67 s_hook_eq_p (const void *p1, const void *p2)
68 {
69   return (strcmp (((const struct s_hook *) p1)->name,
70 		  ((const struct s_hook *) p2)->name) == 0);
71 }
72 
73 /* Read the documentation file with name IN_FNAME, perform substitutions
74    to incorporate information from hook_array, and emit the result on stdout.
75    Hooks defined with DEFHOOK / DEFHOOKPOD are emitted at the place of a
76    matching @hook in the input file; if there is no matching @hook, the
77    hook is emitted after the hook that precedes it in target.def .
78    Usually, the emitted hook documentation starts with the hook
79    signature, followed by the string from the doc field.
80    The documentation is bracketed in @deftypefn / @deftypevr and a matching
81    @end.
82    While emitting the doc field, an @findex entry is added
83    to the affected paragraph.
84    If the doc field starts with '*', the leading '*' is stripped, and the doc
85    field is otherwise emitted unaltered; no function signature/
86    @deftypefn/deftypevr/@end is emitted.
87    In particular, a doc field of "*" means not to emit any ocumentation for
88    this target.def / hook_array entry at all (there might be documentation
89    for this hook in the file named IN_FNAME, though).
90    A doc field of 0 is used to append the hook signature after the previous
91    hook's signture, so that one description can be used for a group of hooks.
92    When the doc field is "", @deftypefn/@deftypevr and the hook signature
93    is emitted, but not the matching @end.  This allows all the free-form
94    documentation to be placed in IN_FNAME, to work around GPL/GFDL
95    licensing incompatibility issues.  */
96 static void
emit_documentation(const char * in_fname)97 emit_documentation (const char *in_fname)
98 {
99   int i, j;
100   char buf[1000];
101   htab_t start_hooks = htab_create (99, s_hook_hash, s_hook_eq_p, (htab_del) 0);
102   FILE *f;
103 
104   /* Enter all the start hooks in start_hooks.  */
105   f = fopen (in_fname, "r");
106   if (!f)
107     {
108       perror ("");
109       fatal ("Couldn't open input file");
110     }
111   while (fscanf (f, "%*[^@]"), buf[0] = '\0',
112 	 fscanf (f, "@%5[^ \n]", buf) != EOF)
113     {
114       void **p;
115       struct s_hook *shp;
116 
117       if (strcmp (buf, "hook") != 0)
118 	continue;
119       buf[0] = '\0';
120       fscanf (f, "%999s", buf);
121       shp = XNEW (struct s_hook);
122       shp->name = upstrdup (buf);
123       shp->pos = -1;
124       p = htab_find_slot (start_hooks, shp, INSERT);
125       if (*p != HTAB_EMPTY_ENTRY)
126 	fatal ("Duplicate placement for hook %s\n", shp->name);
127       *(struct s_hook **) p = shp;
128     }
129   fclose (f);
130   /* For each hook in hook_array, if it is a start hook, store its position.  */
131   for (i = 0; i < (int) (sizeof hook_array / sizeof hook_array[0]); i++)
132     {
133       struct s_hook sh, *shp;
134       void *p;
135 
136       if (!hook_array[i].doc || strcmp (hook_array[i].doc, "*") == 0)
137 	continue;
138       sh.name = upstrdup (hook_array[i].name);
139       p = htab_find (start_hooks, &sh);
140       if (p)
141 	{
142 	  shp = (struct s_hook *) p;
143 	  if (shp->pos >= 0)
144 	    fatal ("Duplicate hook %s\n", sh.name);
145 	  shp->pos = i;
146 	}
147       else
148 	fatal ("No place specified to document hook %s\n", sh.name);
149       free (sh.name);
150     }
151   /* Copy input file to stdout, substituting @hook directives with the
152      corresponding hook documentation sequences.  */
153   f = fopen (in_fname, "r");
154   if (!f)
155     {
156       perror ("");
157       fatal ("Couldn't open input file");
158     }
159   for (;;)
160     {
161       struct s_hook sh, *shp;
162       int c = getc (f);
163       char *name;
164 
165       if (c == EOF)
166 	break;
167       if (c != '@')
168 	{
169 	  putchar (c);
170 	  continue;
171 	}
172       buf[0] = '\0';
173       fscanf (f, "%5[^ \n]", buf);
174       if (strcmp (buf, "hook") != 0)
175 	{
176 	  printf ("@%s", buf);
177 	  continue;
178 	}
179       fscanf (f, "%999s", buf);
180       sh.name = name = upstrdup (buf);
181       shp = (struct s_hook *) htab_find (start_hooks, &sh);
182       if (!shp || shp->pos < 0)
183 	fatal ("No documentation for hook %s\n", sh.name);
184       i = shp->pos;
185       do
186 	{
187 	  const char *q, *e;
188 	  const char *deftype;
189 	  const char *doc, *p_end;
190 
191 	  /* A leading '*' means to output the documentation string without
192 	     further processing.  */
193 	  if (*hook_array[i].doc == '*')
194 	    printf ("%s", hook_array[i].doc + 1);
195 	  else
196 	    {
197 	      if (i != shp->pos)
198 		printf ("\n\n");
199 
200 	      /* Print header.  Function-valued hooks have a parameter list,
201 		 unlike POD-valued ones.  */
202 	      deftype = hook_array[i].param ? "deftypefn" : "deftypevr";
203 	      printf ("@%s {%s} ", deftype, hook_array[i].docname);
204 	      if (strchr (hook_array[i].type, ' '))
205 		printf ("{%s}", hook_array[i].type);
206 	      else
207 		printf ("%s", hook_array[i].type);
208 	      printf (" %s", name);
209 	      if (hook_array[i].param)
210 		{
211 		  /* Print the parameter list, with the parameter names
212 		     enclosed in @var{}.  */
213 		  printf (" ");
214 		  for (q = hook_array[i].param; (e = strpbrk (q, " *,)"));
215 		       q = e + 1)
216 		    /* Type names like 'int' are followed by a space, sometimes
217 		       also by '*'.  'void' should appear only in "(void)".  */
218 		    if (*e == ' ' || *e == '*' || *q == '(')
219 		      printf ("%.*s", (int) (e - q + 1), q);
220 		    else
221 		      printf ("@var{%.*s}%c", (int) (e - q), q, *e);
222 		}
223 	      /* POD-valued hooks sometimes come in groups with common
224 		 documentation.*/
225 	      for (j = i + 1;
226 		   j < (int) (sizeof hook_array / sizeof hook_array[0])
227 		   && hook_array[j].doc == 0 && hook_array[j].type; j++)
228 		{
229 		  char *namex = upstrdup (hook_array[j].name);
230 
231 		  printf ("\n@%sx {%s} {%s} %s",
232 			  deftype, hook_array[j].docname,
233 			  hook_array[j].type, namex);
234 		}
235 	      if (hook_array[i].doc[0])
236 		{
237 		  printf ("\n");
238 		  /* Print each documentation paragraph in turn.  */
239 		  for (doc = hook_array[i].doc; *doc; doc = p_end)
240 		    {
241 		      /* Find paragraph end.  */
242 		      p_end = strstr (doc, "\n\n");
243 		      p_end = (p_end ? p_end + 2 : doc + strlen (doc));
244 		      printf ("%.*s", (int) (p_end - doc), doc);
245 		    }
246 		  printf ("\n@end %s", deftype);
247 		}
248 	    }
249 	  if (++i >= (int) (sizeof hook_array / sizeof hook_array[0])
250 	      || !hook_array[i].doc)
251 	    break;
252 	  free (name);
253 	  sh.name = name = upstrdup (hook_array[i].name);
254 	}
255       while (!htab_find (start_hooks, &sh));
256       free (name);
257     }
258 }
259 
260 /* Emit #defines to stdout (this will be redirected to generate
261    target-hook-def.h) which set target hooks initializer macros
262    to their default values.  These should only be emitted for hooks
263    whose type is given by DOCNAME.  */
264 static void
emit_init_macros(const char * docname)265 emit_init_macros (const char *docname)
266 {
267   int i;
268   const int MAX_NEST = 2;
269   int print_nest, nest = 0;
270 
271   for (print_nest = 0; print_nest <= MAX_NEST; print_nest++)
272     {
273       for (i = 0; i < (int) (sizeof hook_array / sizeof hook_array[0]); i++)
274 	{
275 	  char *name = upstrdup (hook_array[i].name);
276 
277 	  if (strcmp (hook_array[i].docname, docname) != 0)
278 	    continue;
279 
280 	  if (!hook_array[i].type)
281 	    {
282 	      if (*name)
283 		{
284 		  if (nest && nest == print_nest)
285 		    printf ("    %s, \\\n", name);
286 		  nest++;
287 		  if (nest > MAX_NEST)
288 		    fatal ("Unexpected nesting of %s\n", name);
289 		  if (nest == print_nest)
290 		    printf ("\n#define %s \\\n  { \\\n", name);
291 		}
292 	      else
293 		{
294 		  if (nest == print_nest)
295 		    printf ("  }\n");
296 		  nest--;
297 		}
298 	      continue;
299 	    }
300 	  if (print_nest == 0)
301 	    {
302 	      /* Output default definitions of target hooks.  */
303 	      printf ("#ifndef %s\n#define %s %s\n#endif\n",
304 		      name, name, hook_array[i].init);
305 	    }
306 	  if (nest == print_nest)
307 	    printf ("    %s, \\\n", name);
308 	}
309     }
310 }
311 
312 int
main(int argc,char ** argv)313 main (int argc, char **argv)
314 {
315   progname = "genhooks";
316 
317   if (argc >= 3)
318     emit_documentation (argv[2]);
319   else
320     emit_init_macros (argv[1]);
321   return 0;
322 }
323