From b2f877e9db26ec43ff364a9ed1b43d2012023222 Mon Sep 17 00:00:00 2001
From: law <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Aug 1997 07:47:32 +0000
Subject: Initial revision

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@14772 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/f/intdoc.c | 1339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1339 insertions(+)
 create mode 100644 gcc/f/intdoc.c

(limited to 'gcc/f/intdoc.c')

diff --git a/gcc/f/intdoc.c b/gcc/f/intdoc.c
new file mode 100644
index 00000000000..ff9a6f9bb4f
--- /dev/null
+++ b/gcc/f/intdoc.c
@@ -0,0 +1,1339 @@
+/* intdoc.c
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   Contributed by James Craig Burley (burley@gnu.ai.mit.edu).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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 2, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* From f/proj.h, which uses #error -- not all C compilers
+   support that, and we want _this_ program to be compilable
+   by pretty much any C compiler.  */
+
+#include "assert.j"		/* Use gcc's assert.h. */
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#define FFEINTRIN_DOC 1
+#include "intrin.h"
+
+typedef enum
+  {
+#if !defined(false) || !defined(true)
+    false = 0, true = 1,
+#endif
+#if !defined(FALSE) || !defined(TRUE)
+    FALSE = 0, TRUE = 1,
+#endif
+    Doggone_Trailing_Comma_Dont_Work = 1
+  } bool;
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+char *family_name (ffeintrinFamily family);
+static void dumpif (ffeintrinFamily fam);
+static void dumpendif (void);
+static void dumpclearif (void);
+static void dumpem (void);
+static void dumpgen (int menu, char *name, char *name_uc,
+		     ffeintrinGen gen);
+static void dumpspec (int menu, char *name, char *name_uc,
+		      ffeintrinSpec spec);
+static void dumpimp (int menu, char *name, char *name_uc, size_t genno, ffeintrinFamily family,
+		     ffeintrinImp imp, ffeintrinSpec spec);
+static char *argument_info_ptr (ffeintrinImp imp, int argno);
+static char *argument_info_string (ffeintrinImp imp, int argno);
+static char *argument_name_ptr (ffeintrinImp imp, int argno);
+static char *argument_name_string (ffeintrinImp imp, int argno);
+#if 0
+static char *elaborate_if_complex (ffeintrinImp imp, int argno);
+static char *elaborate_if_maybe_complex (ffeintrinImp imp, int argno);
+static char *elaborate_if_real (ffeintrinImp imp, int argno);
+#endif
+static void print_type_string (char *c);
+
+int
+main (int argc, char **argv __attribute__ ((unused)))
+{
+  if (argc != 1)
+    {
+      fprintf (stderr, "\
+Usage: intdoc > intdoc.texi
+  Collects and dumps documentation on g77 intrinsics
+  to the file named intdoc.texi.\n");
+      exit (1);
+    }
+
+  dumpem ();
+  return 0;
+}
+
+struct _ffeintrin_name_
+  {
+    char *name_uc;
+    char *name_lc;
+    char *name_ic;
+    ffeintrinGen generic;
+    ffeintrinSpec specific;
+  };
+
+struct _ffeintrin_gen_
+  {
+    char *name;			/* Name as seen in program. */
+    ffeintrinSpec specs[2];
+  };
+
+struct _ffeintrin_spec_
+  {
+    char *name;			/* Uppercase name as seen in source code,
+				   lowercase if no source name, "none" if no
+				   name at all (NONE case). */
+    bool is_actualarg;		/* Ok to pass as actual arg if -pedantic. */
+    ffeintrinFamily family;
+    ffeintrinImp implementation;
+  };
+
+struct _ffeintrin_imp_
+  {
+    char *name;			/* Name of implementation. */
+#if 0	/* FFECOM_targetCURRENT == FFECOM_targetGCC */
+    ffecomGfrt gfrt;		/* gfrt index in library. */
+#endif	/* FFECOM_targetCURRENT == FFECOM_targetGCC */
+    char *control;
+  };
+
+static struct _ffeintrin_name_ names[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC) \
+  { UPPER, LOWER, MIXED, FFEINTRIN_ ## GEN, FFEINTRIN_ ## SPEC },
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_gen_ gens[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2) \
+  { NAME, { SPEC1, SPEC2, }, },
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_imp_ imps[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#if 0	/* FFECOM_targetCURRENT == FFECOM_targetGCC */
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+  { NAME, FFECOM_gfrt ## GFRT, CONTROL },
+#elif 1	/* FFECOM_targetCURRENT == FFECOM_targetFFE */
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+  { NAME, CONTROL },
+#else
+#error
+#endif
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_spec_ specs[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP) \
+  { NAME, CALLABLE, FAMILY, IMP, },
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+struct cc_pair { ffeintrinImp imp; char *text; };
+
+static char *descriptions[FFEINTRIN_imp] = { 0 };
+static struct cc_pair cc_descriptions[] = {
+#define DEFDOC(IMP,SUMMARY,DESCRIPTION) { FFEINTRIN_imp ## IMP, DESCRIPTION },
+#include "intdoc.h"
+#undef DEFDOC
+};
+
+static char *summaries[FFEINTRIN_imp] = { 0 };
+static struct cc_pair cc_summaries[] = {
+#define DEFDOC(IMP,SUMMARY,DESCRIPTION) { FFEINTRIN_imp ## IMP, SUMMARY },
+#include "intdoc.h"
+#undef DEFDOC
+};
+
+char *
+family_name (ffeintrinFamily family)
+{
+  switch (family)
+    {
+    case FFEINTRIN_familyF77:
+      return "familyF77";
+
+    case FFEINTRIN_familyASC:
+      return "familyASC";
+
+    case FFEINTRIN_familyMIL:
+      return "familyMIL";
+
+    case FFEINTRIN_familyGNU:
+      return "familyGNU";
+
+    case FFEINTRIN_familyF90:
+      return "familyF90";
+
+    case FFEINTRIN_familyVXT:
+      return "familyVXT";
+
+    case FFEINTRIN_familyFVZ:
+      return "familyFVZ";
+
+    case FFEINTRIN_familyF2C:
+      return "familyF2C";
+
+    case FFEINTRIN_familyF2U:
+      return "familyF2U";
+
+    case FFEINTRIN_familyBADU77:
+      return "familyBADU77";
+
+    default:
+      assert ("bad family" == NULL);
+      return "??";
+    }
+}
+
+static int in_ifset = 0;
+static ffeintrinFamily latest_family = FFEINTRIN_familyNONE;
+
+static void
+dumpif (ffeintrinFamily fam)
+{
+  assert (fam != FFEINTRIN_familyNONE);
+  if ((in_ifset != 2)
+      || (fam != latest_family))
+    {
+      if (in_ifset == 2)
+	printf ("@end ifset\n");
+      latest_family = fam;
+      printf ("@ifset %s\n", family_name (fam));
+    }
+  in_ifset = 1;
+}
+
+static void
+dumpendif ()
+{
+  in_ifset = 2;
+}
+
+static void
+dumpclearif ()
+{
+  if ((in_ifset == 2)
+      || (latest_family != FFEINTRIN_familyNONE))
+    printf ("@end ifset\n");
+  latest_family = FFEINTRIN_familyNONE;
+  in_ifset = 0;
+}
+
+static void
+dumpem ()
+{
+  int i;
+
+  for (i = 0; ((size_t) i) < ARRAY_SIZE (cc_descriptions); ++i)
+    {
+      assert (descriptions[cc_descriptions[i].imp] == NULL);
+      descriptions[cc_descriptions[i].imp] = cc_descriptions[i].text;
+    }
+
+  for (i = 0; ((size_t) i) < ARRAY_SIZE (cc_summaries); ++i)
+    {
+      assert (summaries[cc_summaries[i].imp] == NULL);
+      summaries[cc_summaries[i].imp] = cc_summaries[i].text;
+    }
+
+  printf ("@menu\n");
+  for (i = 0; ((size_t) i) < ARRAY_SIZE (names); ++i)
+    {
+      if (names[i].generic != FFEINTRIN_genNONE)
+	dumpgen (1, names[i].name_ic, names[i].name_uc,
+		 names[i].generic);
+      if (names[i].specific != FFEINTRIN_specNONE)
+	dumpspec (1, names[i].name_ic, names[i].name_uc,
+		  names[i].specific);
+    }
+  dumpclearif ();
+
+  printf ("@end menu\n\n");
+
+  for (i = 0; ((size_t) i) < ARRAY_SIZE (names); ++i)
+    {
+      if (names[i].generic != FFEINTRIN_genNONE)
+	dumpgen (0, names[i].name_ic, names[i].name_uc,
+		 names[i].generic);
+      if (names[i].specific != FFEINTRIN_specNONE)
+	dumpspec (0, names[i].name_ic, names[i].name_uc,
+		  names[i].specific);
+    }
+  dumpclearif ();
+}
+
+static void
+dumpgen (int menu, char *name, char *name_uc, ffeintrinGen gen)
+{
+  size_t i;
+  int total;
+
+  if (!menu)
+    {
+      for (total = 0, i = 0; i < ARRAY_SIZE (gens[gen].specs); ++i)
+	{
+	  if (gens[gen].specs[i] != FFEINTRIN_specNONE)
+	    ++total;
+	}
+    }
+
+  for (i = 0; i < ARRAY_SIZE (gens[gen].specs); ++i)
+    {
+      ffeintrinSpec spec;
+      size_t j;
+
+      if ((spec = gens[gen].specs[i]) == FFEINTRIN_specNONE)
+	continue;
+
+      dumpif (specs[spec].family);
+      dumpimp (menu, name, name_uc, i, specs[spec].family, specs[spec].implementation,
+	       spec);
+      if (!menu && (total > 0))
+	{
+	  if (total == 1)
+	    {
+	      printf ("\
+For information on another intrinsic with the same name:\n");
+	    }
+	  else
+	    {
+	      printf ("\
+For information on other intrinsics with the same name:\n");
+	    }
+	  for (j = 0; j < ARRAY_SIZE (gens[gen].specs); ++j)
+	    {
+	      if (j == i)
+		continue;
+	      if ((spec = gens[gen].specs[j]) == FFEINTRIN_specNONE)
+		continue;
+	      printf ("@xref{%s Intrinsic (%s)}.\n",
+		      name, specs[spec].name);
+	    }
+	  printf ("\n");
+	}
+      dumpendif ();
+    }
+}
+
+static void
+dumpspec (int menu, char *name, char *name_uc, ffeintrinSpec spec)
+{
+  dumpif (specs[spec].family);
+  dumpimp (menu, name, name_uc, 0, specs[spec].family, specs[spec].implementation,
+	   FFEINTRIN_specNONE);
+  dumpendif ();
+}
+
+static void
+dumpimp (int menu, char *name, char *name_uc, size_t genno, ffeintrinFamily family, ffeintrinImp imp,
+	 ffeintrinSpec spec)
+{
+  char *c;
+  bool subr;
+  char *argc;
+  char *argi;
+  int colon;
+  int argno;
+
+  assert ((imp != FFEINTRIN_impNONE) || !genno);
+
+  if (menu)
+    {
+      printf ("* %s Intrinsic",
+	      name);
+      if (spec != FFEINTRIN_specNONE)
+	printf (" (%s)", specs[spec].name);	/* See XYZZY1 below */
+      printf ("::");
+#define INDENT_SUMMARY 24
+      if ((imp == FFEINTRIN_impNONE)
+	  || (summaries[imp] != NULL))
+	{
+	  int spaces = INDENT_SUMMARY - 14 - strlen (name);
+	  char *c;
+
+	  if (spec != FFEINTRIN_specNONE)
+	    spaces -= (3 + strlen (specs[spec].name));	/* See XYZZY1 above */
+	  if (spaces < 1)
+	    spaces = 1;
+	  while (spaces--)
+	    fputc (' ', stdout);
+
+	  if (imp == FFEINTRIN_impNONE)
+	    {
+	      printf ("(Reserved for future use.)\n");
+	      return;
+	    }
+
+	  for (c = summaries[imp]; c[0] != '\0'; ++c)
+	    {
+	      if ((c[0] == '@')
+		  && (c[1] >= '0')
+	      && (c[1] <= '9'))
+		{
+		  int argno = c[1] - '0';
+
+		  c += 2;
+		  while ((c[0] >= '0')
+			 && (c[0] <= '9'))
+		    {
+		      argno = 10 * argno + (c[0] - '0');
+		      ++c;
+		    }
+		  assert (c[0] == '@');
+		  if (argno == 0)
+		    printf ("%s", name);
+		  else if (argno == 99)
+		    {	/* Yeah, this is a major kludge. */
+		      printf ("\n");
+		      spaces = INDENT_SUMMARY + 1;
+		      while (spaces--)
+			fputc (' ', stdout);
+		    }
+		  else
+		    printf ("%s", argument_name_string (imp, argno - 1));
+		}
+	      else
+		fputc (c[0], stdout);
+	    }
+	}
+      printf ("\n");
+      return;
+    }
+
+  printf ("@node %s Intrinsic", name);
+  if (spec != FFEINTRIN_specNONE)
+    printf (" (%s)", specs[spec].name);
+  printf ("\n@subsubsection %s Intrinsic", name);
+  if (spec != FFEINTRIN_specNONE)
+    printf (" (%s)", specs[spec].name);
+  printf ("\n@cindex %s intrinsic\n@cindex intrinsics, %s\n",
+	  name, name);
+
+  if (imp == FFEINTRIN_impNONE)
+    {
+      printf ("
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL %s} to use this name for an
+external procedure.
+
+",
+	      name);
+      return;
+    }
+
+  c = imps[imp].control;
+  subr = (c[0] == '-');
+  colon = (c[2] == ':') ? 2 : 3;
+
+  printf ("
+@noindent
+@example
+%s%s(",
+	  (subr ? "CALL " : ""), name);
+
+  fflush (stdout);
+
+  for (argno = 0; ; ++argno)
+    {
+      argc = argument_name_ptr (imp, argno);
+      if (argc == NULL)
+	break;
+      if (argno > 0)
+	printf (", ");
+      printf ("@var{%s}", argc);
+      argi = argument_info_string (imp, argno);
+      if ((argi[0] == '*')
+	  || (argi[0] == 'n')
+	  || (argi[0] == '+')
+      || (argi[0] == 'p'))
+	printf ("-1, @var{%s}-2, @dots{}, @var{%s}-n",
+		argc, argc);
+    }
+
+  printf (")
+@end example\n
+");
+
+  if (!subr)
+    {
+      int other_arg;
+      char *arg_string;
+      char *arg_info;
+
+      if ((c[colon + 1] >= '0')
+	  && (c[colon + 1] <= '9'))
+	{
+	  other_arg = c[colon + 1] - '0';
+	  arg_string = argument_name_string (imp, other_arg);
+	  arg_info = argument_info_string (imp, other_arg);
+	}
+      else
+	{
+	  other_arg = -1;
+	  arg_string = NULL;
+	  arg_info = NULL;
+	}
+
+      printf ("\
+@noindent
+%s: ", name);
+      print_type_string (c);
+      printf (" function");
+
+      if ((c[0] == 'R')
+	  && (c[1] == 'C'))
+	{
+	  assert (other_arg >= 0);
+
+	  if ((arg_info[0] == '?') || (arg_info[0] == '!') || (arg_info[0] == '+')
+	  || (arg_info[0] == '*') || (arg_info[0] == 'n') || (arg_info[0] == 'p'))
+	    ++arg_info;
+	  if ((arg_info[0] == 'F') || (arg_info[0] == 'N'))
+	    printf (".
+The exact type is @samp{REAL(KIND=1)} when argument @var{%s} is
+any type other than @code{COMPLEX}, or when it is @code{COMPLEX(KIND=1)}.
+When @var{%s} is any @code{COMPLEX} type other than @code{COMPLEX(KIND=1)},
+this intrinsic is valid only when used as the argument to
+@code{REAL()}, as explained below.\n\n",
+		    arg_string,
+		    arg_string);
+	  else
+	    printf (".
+This intrinsic is valid when argument @var{%s} is
+@code{COMPLEX(KIND=1)}.
+When @var{%s} is any other @code{COMPLEX} type,
+this intrinsic is valid only when used as the argument to
+@code{REAL()}, as explained below.\n\n",
+		    arg_string,
+		    arg_string);
+	}
+#if 0
+      else if ((c[0] == 'I')
+	       && (c[1] == 'p'))
+	printf (", the exact type being wide enough to hold a pointer
+on the target system (typically @code{INTEGER(KIND=1)} or @code{INTEGER(KIND=4)}).\n\n");
+#endif
+      else if ((c[1] == '=')
+	       && (c[colon + 1] >= '0')
+	       && (c[colon + 1] <= '9'))
+	{
+	  assert (other_arg >= 0);
+
+	  if ((arg_info[0] == '?') || (arg_info[0] == '!') || (arg_info[0] == '+')
+	  || (arg_info[0] == '*') || (arg_info[0] == 'n') || (arg_info[0] == 'p'))
+	    ++arg_info;
+
+	  if (((c[0] == arg_info[0])
+	       && ((c[0] == 'A') || (c[0] == 'C') || (c[0] == 'I')
+		   || (c[0] == 'L') || (c[0] == 'R')))
+	      || ((c[0] == 'R')
+		  && (arg_info[0] == 'C'))
+	      || ((c[0] == 'C')
+		  && (arg_info[0] == 'R')))
+	    printf (", the @samp{KIND=} value of the type being that of argument @var{%s}.\n\n",
+		    arg_string);
+	  else if ((c[0] == 'S')
+		   && ((arg_info[0] == 'C')
+		       || (arg_info[0] == 'F')
+		       || (arg_info[0] == 'N')))
+	    printf (".
+The exact type depends on that of argument @var{%s}---if @var{%s} is
+@code{COMPLEX}, this function's type is @code{REAL}
+with the same @samp{KIND=} value as the type of @var{%s}.
+Otherwise, this function's type is the same as that of @var{%s}.\n\n",
+		    arg_string, arg_string, arg_string, arg_string);
+	  else
+	    printf (", the exact type being that of argument @var{%s}.\n\n",
+		    arg_string);
+	}
+      else if ((c[1] == '=')
+	       && (c[colon + 1] == '*'))
+	printf (", the exact type being the result of cross-promoting the
+types of all the arguments.\n\n");
+      else if (c[1] == '=')
+	assert ("?0:?:" == NULL);
+      else
+	printf (".\n\n");
+    }
+
+  for (argno = 0, argc = &c[colon + 3]; *argc != '\0'; ++argno)
+    {
+      char optionality = '\0';
+      char extra = '\0';
+      char basic;
+      char kind;
+      int length;
+      int elements;
+
+      printf ("\
+@noindent
+@var{");
+      for (; ; ++argc)
+	{
+	  if (argc[0] == '=')
+	    break;
+	  printf ("%c", *argc);
+	}
+      printf ("}: ");
+
+      ++argc;
+      if ((*argc == '?')
+	  || (*argc == '!')
+	  || (*argc == '*')
+	  || (*argc == '+')
+	  || (*argc == 'n')
+	  || (*argc == 'p'))
+	optionality = *(argc++);
+      basic = *(argc++);
+      kind = *(argc++);
+      if (*argc == '[')
+	{
+	  length = *++argc - '0';
+	  if (*++argc != ']')
+	    length = 10 * length + (*(argc++) - '0');
+	  ++argc;
+	}
+      else
+	length = -1;
+      if (*argc == '(')
+	{
+	  elements = *++argc - '0';
+	  if (*++argc != ')')
+	    elements = 10 * elements + (*(argc++) - '0');
+	  ++argc;
+	}
+      else if (*argc == '&')
+	{
+	  elements = -1;
+	  ++argc;
+	}
+      else
+	elements = 0;
+      if ((*argc == '&')
+	  || (*argc == 'i')
+	  || (*argc == 'w')
+	  || (*argc == 'x'))
+	extra = *(argc++);
+      if (*argc == ',')
+	++argc;
+
+      switch (basic)
+	{
+	case '-':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("Any type");
+	      break;
+
+	    default:
+	      assert ("kind arg" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'A':
+	  assert ((kind == '1') || (kind == '*'));
+	  printf ("@code{CHARACTER");
+	  if (length != -1)
+	    printf ("*%d", length);
+	  printf ("}");
+	  break;
+
+	case 'C':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{COMPLEX}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{COMPLEX(KIND=%d)}", (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("Same @samp{KIND=} value as for @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    default:
+	      assert ("Ca" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'I':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{INTEGER}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{INTEGER(KIND=%d)}", (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("@code{INTEGER} with same @samp{KIND=} value as for @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    case 'p':
+	      printf ("@code{INTEGER} wide enough to hold a pointer");
+	      break;
+
+	    default:
+	      assert ("Ia" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'L':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{LOGICAL}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{LOGICAL(KIND=%d)}", (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("@code{LOGICAL} with same @samp{KIND=} value as for @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    default:
+	      assert ("La" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'R':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{REAL}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{REAL(KIND=%d)}", (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("@code{REAL} with same @samp{KIND=} value as for @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    default:
+	      assert ("Ra" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'B':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{INTEGER} or @code{LOGICAL}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{INTEGER(KIND=%d)} or @code{LOGICAL(KIND=%d)}",
+		      (kind - '0'), (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("Same type and @samp{KIND=} value as for @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    default:
+	      assert ("Ba" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'F':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{REAL} or @code{COMPLEX}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{REAL(KIND=%d)} or @code{COMPLEX(KIND=%d)}",
+		      (kind - '0'), (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("Same type as @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    default:
+	      assert ("Fa" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'N':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{INTEGER}, @code{REAL}, or @code{COMPLEX}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{INTEGER(KIND=%d)}, @code{REAL(KIND=%d)}, or @code{COMPLEX(KIND=%d)}",
+		      (kind - '0'), (kind - '0'), (kind - '0'));
+	      break;
+
+	    default:
+	      assert ("N1" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'S':
+	  switch (kind)
+	    {
+	    case '*':
+	      printf ("@code{INTEGER} or @code{REAL}");
+	      break;
+
+	    case '1': case '2': case '3': case '4': case '5':
+	    case '6': case '7': case '8': case '9':
+	      printf ("@code{INTEGER(KIND=%d)} or @code{REAL(KIND=%d)}",
+		      (kind - '0'), (kind - '0'));
+	      break;
+
+	    case 'A':
+	      printf ("@code{INTEGER} or @code{REAL} with same @samp{KIND=} value as for @var{%s}",
+		      argument_name_string (imp, 0));
+	      break;
+
+	    default:
+	      assert ("Sa" == NULL);
+	      break;
+	    }
+	  break;
+
+	case 'g':
+	  printf ("@samp{*@var{label}}, where @var{label} is the label
+of an executable statement");
+	  break;
+
+	case 's':
+	  printf ("Signal handler (@code{INTEGER FUNCTION} or @code{SUBROUTINE})
+or dummy/global @code{INTEGER(KIND=1)} scalar");
+	  break;
+
+	default:
+	  assert ("arg type?" == NULL);
+	  break;
+	}
+
+      switch (optionality)
+	{
+	case '\0':
+	  break;
+
+	case '!':
+	  printf ("; OPTIONAL (must be omitted if @var{%s} is @code{COMPLEX})",
+		  argument_name_string (imp, argno-1));
+	  break;
+
+	case '?':
+	  printf ("; OPTIONAL");
+	  break;
+
+	case '*':
+	  printf ("; OPTIONAL");
+	  break;
+
+	case 'n':
+	case '+':
+	  break;
+
+	case 'p':
+	  printf ("; at least two such arguments must be provided");
+	  break;
+
+	default:
+	  assert ("optionality!" == NULL);
+	  break;
+	}
+
+      switch (elements)
+	{
+	case -1:
+	  break;
+
+	case 0:
+	  if ((basic != 'g')
+	      && (basic != 's'))
+	    printf ("; scalar");
+	  break;
+
+	default:
+	  assert (extra != '\0');
+	  printf ("; DIMENSION(%d)", elements);
+	  break;
+	}
+
+      switch (extra)
+	{
+	case '\0':
+	  if ((basic != 'g')
+	      && (basic != 's'))
+	    printf ("; INTENT(IN)");
+	  break;
+
+	case 'i':
+	  break;
+
+	case '&':
+	  printf ("; cannot be a constant or expression");
+	  break;
+
+	case 'w':
+	  printf ("; INTENT(OUT)");
+	  break;
+
+	case 'x':
+	  printf ("; INTENT(INOUT)");
+	  break;
+	}
+
+      printf (".\n\n");
+    }
+
+  printf ("\
+@noindent
+Intrinsic groups: ");
+  switch (family)
+    {
+    case FFEINTRIN_familyF77:
+      printf ("(standard FORTRAN 77).");
+      break;
+
+    case FFEINTRIN_familyGNU:
+      printf ("@code{gnu}.");
+      break;
+
+    case FFEINTRIN_familyASC:
+      printf ("@code{f2c}, @code{f90}.");
+      break;
+
+    case FFEINTRIN_familyMIL:
+      printf ("@code{mil}, @code{f90}, @code{vxt}.");
+      break;
+
+    case FFEINTRIN_familyF90:
+      printf ("@code{f90}.");
+      break;
+
+    case FFEINTRIN_familyVXT:
+      printf ("@code{vxt}.");
+      break;
+
+    case FFEINTRIN_familyFVZ:
+      printf ("@code{f2c}, @code{vxt}.");
+      break;
+
+    case FFEINTRIN_familyF2C:
+      printf ("@code{f2c}.");
+      break;
+
+    case FFEINTRIN_familyF2U:
+      printf ("@code{unix}.");
+      break;
+
+    case FFEINTRIN_familyBADU77:
+      printf ("@code{badu77}.");
+      break;
+
+    default:
+      assert ("bad family" == NULL);
+      printf ("@code{???}.");
+      break;
+    }
+  printf ("\n\n");
+
+  if (descriptions[imp] != NULL)
+    {
+      char *c = descriptions[imp];
+
+      printf ("\
+@noindent
+Description:
+\n");
+
+      while (c[0] != '\0')
+	{
+	  if ((c[0] == '@')
+	      && (c[1] >= '0')
+	  && (c[1] <= '9'))
+	    {
+	      int argno = c[1] - '0';
+
+	      c += 2;
+	      while ((c[0] >= '0')
+		     && (c[0] <= '9'))
+		{
+		  argno = 10 * argno + (c[0] - '0');
+		  ++c;
+		}
+	      assert (c[0] == '@');
+	      if (argno == 0)
+		printf ("%s", name_uc);
+	      else
+		printf ("%s", argument_name_string (imp, argno - 1));
+	    }
+	  else
+	    fputc (c[0], stdout);
+	  ++c;
+	}
+
+      printf ("\n");
+    }
+}
+
+static char *
+argument_info_ptr (ffeintrinImp imp, int argno)
+{
+  char *c = imps[imp].control;
+  static char arginfos[8][32];
+  static int argx = 0;
+  int i;
+
+  if (c[2] == ':')
+    c += 5;
+  else
+    c += 6;
+
+  while (argno--)
+    {
+      while ((c[0] != ',') && (c[0] != '\0'))
+	++c;
+      if (c[0] != ',')
+	break;
+      ++c;
+    }
+
+  if (c[0] == '\0')
+    return NULL;
+
+  for (; (c[0] != '=') && (c[0] != '\0'); ++c)
+    ;
+
+  assert (c[0] == '=');
+
+  for (i = 0, ++c; (c[0] != ',') && (c[0] != '\0'); ++c, ++i)
+    arginfos[argx][i] = c[0];
+
+  arginfos[argx][i] = '\0';
+
+  c = &arginfos[argx][0];
+  ++argx;
+  if (((size_t) argx) >= ARRAY_SIZE (arginfos))
+    argx = 0;
+
+  return c;
+}
+
+static char *
+argument_info_string (ffeintrinImp imp, int argno)
+{
+  char *p;
+
+  p = argument_info_ptr (imp, argno);
+  assert (p != NULL);
+  return p;
+}
+
+static char *
+argument_name_ptr (ffeintrinImp imp, int argno)
+{
+  char *c = imps[imp].control;
+  static char argnames[8][32];
+  static int argx = 0;
+  int i;
+
+  if (c[2] == ':')
+    c += 5;
+  else
+    c += 6;
+
+  while (argno--)
+    {
+      while ((c[0] != ',') && (c[0] != '\0'))
+	++c;
+      if (c[0] != ',')
+	break;
+      ++c;
+    }
+
+  if (c[0] == '\0')
+    return NULL;
+
+  for (i = 0; (c[0] != '=') && (c[0] != '\0'); ++c, ++i)
+    argnames[argx][i] = c[0];
+
+  assert (c[0] == '=');
+  argnames[argx][i] = '\0';
+
+  c = &argnames[argx][0];
+  ++argx;
+  if (((size_t) argx) >= ARRAY_SIZE (argnames))
+    argx = 0;
+
+  return c;
+}
+
+static char *
+argument_name_string (ffeintrinImp imp, int argno)
+{
+  char *p;
+
+  p = argument_name_ptr (imp, argno);
+  assert (p != NULL);
+  return p;
+}
+
+static void
+print_type_string (char *c)
+{
+  char basic = c[0];
+  char kind = c[1];
+
+  switch (basic)
+    {
+    case 'A':
+      assert ((kind == '1') || (kind == '='));
+      if (c[2] == ':')
+	printf ("@code{CHARACTER*1}");
+      else
+	{
+	  assert (c[2] == '*');
+	  printf ("@code{CHARACTER*(*)}");
+	}
+      break;
+
+    case 'C':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{COMPLEX}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{COMPLEX(KIND=%d)}", (kind - '0'));
+	  break;
+
+	default:
+	  assert ("Ca" == NULL);
+	  break;
+	}
+      break;
+
+    case 'I':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{INTEGER}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{INTEGER(KIND=%d)}", (kind - '0'));
+	  break;
+
+	case 'p':
+	  printf ("@code{INTEGER(KIND=0)}");
+	  break;
+
+	default:
+	  assert ("Ia" == NULL);
+	  break;
+	}
+      break;
+
+    case 'L':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{LOGICAL}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{LOGICAL(KIND=%d)}", (kind - '0'));
+	  break;
+
+	default:
+	  assert ("La" == NULL);
+	  break;
+	}
+      break;
+
+    case 'R':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{REAL}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{REAL(KIND=%d)}", (kind - '0'));
+	  break;
+
+	case 'C':
+	  printf ("@code{REAL}");
+	  break;
+
+	default:
+	  assert ("Ra" == NULL);
+	  break;
+	}
+      break;
+
+    case 'B':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{INTEGER} or @code{LOGICAL}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{INTEGER(KIND=%d)} or @code{LOGICAL(KIND=%d)}",
+		  (kind - '0'), (kind - '0'));
+	  break;
+
+	default:
+	  assert ("Ba" == NULL);
+	  break;
+	}
+      break;
+
+    case 'F':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{REAL} or @code{COMPLEX}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{REAL(KIND=%d)} or @code{COMPLEX(KIND=%d)}",
+		  (kind - '0'), (kind - '0'));
+	  break;
+
+	default:
+	  assert ("Fa" == NULL);
+	  break;
+	}
+      break;
+
+    case 'N':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{INTEGER}, @code{REAL}, or @code{COMPLEX}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{INTEGER(KIND=%d)}, @code{REAL(KIND=%d)}, or @code{COMPLEX(KIND=%d)}",
+		  (kind - '0'), (kind - '0'), (kind - '0'));
+	  break;
+
+	default:
+	  assert ("N1" == NULL);
+	  break;
+	}
+      break;
+
+    case 'S':
+      switch (kind)
+	{
+	case '=':
+	  printf ("@code{INTEGER} or @code{REAL}");
+	  break;
+
+	case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  printf ("@code{INTEGER(KIND=%d)} or @code{REAL(KIND=%d)}",
+		  (kind - '0'), (kind - '0'));
+	  break;
+
+	default:
+	  assert ("Sa" == NULL);
+	  break;
+	}
+      break;
+
+    default:
+      assert ("arg type?" == NULL);
+      break;
+    }
+}
-- 
cgit v1.2.1