/* 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. */ #include "proj.h" #define FFEINTRIN_DOC 1 #include "intrin.h" 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); 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. */ ffeintrinImp cg_imp; /* Unique code-generation code. */ #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,GFRT,CONTROL) #define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) #include "intrin.def" #undef DEFNAME #undef DEFGEN #undef DEFSPEC #undef DEFIMP #undef DEFIMQ }; 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,GFRT,CONTROL) #define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) #include "intrin.def" #undef DEFNAME #undef DEFGEN #undef DEFSPEC #undef DEFIMP #undef DEFIMQ }; 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,GFRT,CONTROL) \ { NAME, FFEINTRIN_imp ## CODE, FFECOM_gfrt ## GFRT, CONTROL }, #define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) \ { NAME, FFEINTRIN_imp ## CGIMP, FFECOM_gfrt ## GFRT, CONTROL }, #elif 1 /* FFECOM_targetCURRENT == FFECOM_targetFFE */ #define DEFIMP(CODE,NAME,GFRT,CONTROL) \ { NAME, FFEINTRIN_imp ## CODE, CONTROL }, #define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) \ { NAME, FFEINTRIN_imp ## CGIMP, CONTROL }, #else #error #endif #include "intrin.def" #undef DEFNAME #undef DEFGEN #undef DEFSPEC #undef DEFIMP #undef DEFIMQ }; 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,GFRT,CONTROL) #define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) #include "intrin.def" #undef DEFGEN #undef DEFSPEC #undef DEFIMP #undef DEFIMQ }; static char *descriptions[FFEINTRIN_imp] = { #define DEFDOC(IMP,SUMMARY,DESCRIPTION) [FFEINTRIN_imp ## IMP] DESCRIPTION, #include "intdoc.h" #undef DEFDOC }; static char *summaries[FFEINTRIN_imp] = { #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"; 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; 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; for (i = 0; i < ARRAY_SIZE (gens[gen].specs); ++i) { ffeintrinSpec spec; if ((spec = gens[gen].specs[i]) == FFEINTRIN_specNONE) continue; if (specs[spec].implementation == FFEINTRIN_impNONE) continue; dumpif (specs[spec].family); dumpimp (menu, name, name_uc, i, specs[spec].family, specs[spec].implementation); dumpendif (); } } static void dumpspec (int menu, char *name, char *name_uc, ffeintrinSpec spec) { if (specs[spec].implementation == FFEINTRIN_impNONE) return; dumpif (specs[spec].family); dumpimp (menu, name, name_uc, 0, specs[spec].family, specs[spec].implementation); dumpendif (); } static void dumpimp (int menu, char *name, char *name_uc, size_t genno, ffeintrinFamily family, ffeintrinImp imp) { char *c = imps[imp].control; bool subr = (c[0] == '-'); char *argc; char *argi; int colon = (c[2] == ':') ? 2 : 3; int argno; if (menu) { printf ("* %s Intrinsic", name); if (genno) printf (" (Form %s)", imps[imp].name); printf ("::"); if (summaries[imp] != NULL) { #define INDENT_SUMMARY 24 int spaces = INDENT_SUMMARY - 14 - strlen (name); char *c = summaries[imp]; if (genno != 0) spaces -= (8 + strlen (imps[imp].name)); if (spaces < 1) spaces = 1; while (spaces--) fputc (' ', stdout); 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); 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); ++c; } } printf ("\n"); return; } printf ("@node %s Intrinsic", name); if (genno) printf (" (Form %s)", imps[imp].name); printf ("\n@subsubsection %s Intrinsic", name); if (genno) printf (" (Form %s)", imps[imp].name); printf ("\n@cindex %s intrinsic\n@cindex intrinsics, %s\n @noindent @example %s%s(", name, name, (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; 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; } }