home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d167 / cdecl.lha / CDecl / cdecl.c < prev    next >
C/C++ Source or Header  |  1988-11-22  |  26KB  |  1,048 lines

  1. /*
  2.  * cdecl - ANSI C and C++ declaration composer & decoder
  3.  *
  4.  *    originally written
  5.  *        Graham Ross
  6.  *        once at tektronix!tekmdp!grahamr
  7.  *        now at Context, Inc.
  8.  *
  9.  *    modified to provide hints for unsupported types
  10.  *    added argument lists for functions
  11.  *    added 'explain cast' grammar
  12.  *    added #ifdef for 'create program' feature
  13.  *        ???? (sorry, I lost your name and login)
  14.  *
  15.  *    conversion to ANSI C
  16.  *        David Wolverton
  17.  *        ihnp4!houxs!daw
  18.  *
  19.  *    merged D. Wolverton's ANSI C version w/ ????'s version
  20.  *    added function prototypes
  21.  *    added C++ declarations
  22.  *    made type combination checking table driven
  23.  *    added checks for void variable combinations
  24.  *    made 'create program' feature a runtime option
  25.  *    added file parsing as well as just stdin
  26.  *    added help message at beginning
  27.  *    added prompts when on a TTY or in interactive mode
  28.  *    added getopt() usage
  29.  *    added -a, -r, -p, -c, -d, -D, -V, -i and -+ options
  30.  *    delinted
  31.  *    added #defines for those without getopt or void
  32.  *    added 'set options' command
  33.  *    added 'quit/exit' command
  34.  *    added synonyms
  35.  *        Tony Hansen
  36.  *        attmail!tony, ihnp4!pegasus!hansen
  37.  *
  38.  *    added extern, register, static
  39.  *    added links to explain, cast, declare
  40.  *    separately developed ANSI C support
  41.  *        Merlyn LeRoy
  42.  *        merlyn@rose3.rosemount.com
  43.  *
  44.  *    merged versions from LeRoy
  45.  *    added tmpfile() support
  46.  *    allow more parts to be missing during explanations
  47.  *        Tony Hansen
  48.  *        attmail!tony, ihnp4!pegasus!hansen
  49.  */
  50.  
  51. char cdeclsccsid[] = "@(#)cdecl.c    2.4 3/31/88";
  52.  
  53. #include <stdio.h>
  54. #include <ctype.h>
  55. #ifdef AMIGA
  56.  
  57. char *strcat(), *strncat(), *strcpy(), *strncpy(), index(), rindex();
  58. char *strchr(), *strrchr(), *strpbrk(), *strtok();
  59. int strcmp(), strncmp(), strlen(), strspn(), strcspn();
  60.  
  61. char *malloc();
  62. extern free(), exit(), perror();
  63.  
  64. #include <errno.h>
  65. #else /* AMIGA not defined */
  66. #if __STDC__ || defined(DOS)
  67. # include <stdlib.h>
  68. # include <stddef.h>
  69. # include <string.h>
  70. # include <stdarg.h>
  71. #else
  72. # ifndef NOVARARGS
  73. #  include <varargs.h>
  74. # endif /* ndef NOVARARGS */
  75. char *malloc();
  76. void free(), exit(), perror();
  77. # ifdef BSD
  78. #  include <strings.h>
  79.    extern int errno;
  80. #  define strrchr rindex
  81. #  define NOTMPFILE
  82. # else
  83. #  include <string.h>
  84. #  include <errno.h>
  85. # endif /* BSD */
  86. # ifdef NOVOID
  87. #  define void int
  88. # endif /* NOVOID */
  89. #endif /* __STDC__ || DOS */
  90.  
  91. #endif /* AMIGA */
  92.  
  93. #define    MB_SHORT    0001
  94. #define    MB_LONG        0002
  95. #define    MB_UNSIGNED    0004
  96. #define MB_INT        0010
  97. #define MB_CHAR        0020
  98. #define MB_FLOAT    0040
  99. #define MB_DOUBLE    0100
  100. #define MB_VOID        0200
  101. #define    MB_SIGNED    0400
  102.  
  103. #define NullCP ((char*)NULL)
  104. #ifdef dodebug
  105. # define Debug(x) do { if (DebugFlag) (void) fprintf x; } while (0)
  106. #else
  107. # define Debug(x) /* nothing */
  108. #endif
  109.  
  110. #if __STDC__
  111.   char *ds(char *), *cat(char *, ...), *visible(int);
  112.   int getopt(int,char **,char *);
  113.   int main(int, char **);
  114.   int yywrap(void);
  115.   int dostdin(void);
  116.   void mbcheck(void), dohelp(void), usage(void);
  117.   void prompt(void), doprompt(void), noprompt(void);
  118.   void unsupp(char *, char *);
  119.   void notsupported(char *, char *, char *);
  120.   void yyerror(char *);
  121.   void doset(char *);
  122.   void dodeclare(char*, char*, char*, char*, char*);
  123.   void docast(char*, char*, char*, char*);
  124.   void dodexplain(char*, char*, char*, char*);
  125.   void docexplain(char*, char*, char*, char*);
  126.   void setprogname(char *);
  127.   int dotmpfile(int, char**), dofileargs(int, char**);
  128. #else
  129.   char *ds(), *cat(), *visible();
  130.   int getopt();
  131.   void mbcheck(), dohelp(), usage();
  132.   void prompt(), doprompt(), noprompt();
  133.   void unsupp(), notsupported();
  134.   void yyerror();
  135.   void doset(), dodeclare(), docast(), dodexplain(), docexplain();
  136.   void setprogname();
  137.   int dotmpfile(), dofileargs();
  138. #endif /* __STDC__ */
  139.   FILE *tmpfile();
  140.  
  141. /* variables used during parsing */
  142. unsigned modbits = 0;
  143. int arbdims = 1;
  144. char *savedname = 0;
  145. char unknown_name[] = "unknown_name";
  146. char prev = 0;        /* the current type of the variable being examined */
  147.             /*    values    type                   */
  148.             /*    p    pointer                   */
  149.             /*    r    reference               */
  150.             /*    f    function               */
  151.             /*    a    array (of arbitrary dimensions)    */
  152.             /*    A    array with dimensions           */
  153.             /*    n    name                   */
  154.             /*    v    void                   */
  155.             /*    s    struct | class               */
  156.             /*    t    simple type (int, long, etc.)       */
  157.  
  158. /* options */
  159. int RitchieFlag = 0;        /* -r, assume Ritchie PDP C language */
  160. int MkProgramFlag = 0;        /* -c, output {} and ; after declarations */
  161. int PreANSIFlag = 0;        /* -p, assume pre-ANSI C language */
  162. int CplusplusFlag = 0;        /* -+, assume C++ language */
  163. int OnATty = 0;            /* stdin is coming from a terminal */
  164. int Interactive = 0;        /* -i, overrides OnATty */
  165. int KeywordName = 0;        /* $0 is a keyword (declare, explain, cast) */
  166. char *progname = "cdecl";    /* $0 */
  167.  
  168. #if dodebug
  169. int DebugFlag = 0;        /* -d, output debugging trace info */
  170. #endif
  171.  
  172. #ifdef doyydebug        /* compile in yacc trace statements */
  173. #define YYDEBUG 1
  174. #endif /* doyydebug */
  175.  
  176. #include "cdgram.c"
  177. #include "cdlex.c"
  178.  
  179. /* definitions (and abbreviations) for type combinations cross check table */
  180. #define ALWAYS    0    /* combo always okay */
  181. #define _    ALWAYS
  182. #define NEVER    1    /* combo never allowed */
  183. #define X    NEVER
  184. #define RITCHIE    2    /* combo not allowed in Ritchie compiler */
  185. #define R    RITCHIE
  186. #define PREANSI    3    /* combo not allowed in Pre-ANSI compiler */
  187. #define P    PREANSI
  188. #define ANSI    4    /* combo not allowed anymore in ANSI compiler */
  189. #define A    ANSI
  190.  
  191. /* This is an lower left triangular array. If we needed */
  192. /* to save 9 bytes, the "long" row can be removed. */
  193. char crosscheck[9][9] = {
  194.     /*            L, I, S, C, V, U, S, F, D, */
  195.     /* long */        _, _, _, _, _, _, _, _, _,
  196.     /* int */        _, _, _, _, _, _, _, _, _,
  197.     /* short */        X, _, _, _, _, _, _, _, _,
  198.     /* char */        X, X, X, _, _, _, _, _, _,
  199.     /* void */        X, X, X, X, _, _, _, _, _,
  200.     /* unsigned */    R, _, R, R, X, _, _, _, _,
  201.     /* signed */    P, P, P, P, X, X, _, _, _,
  202.     /* float */        A, X, X, X, X, X, X, _, _,
  203.     /* double */    P, X, X, X, X, X, X, X, _
  204. };
  205.  
  206. /* the names and bits checked for each row in the above array */
  207. struct
  208.     {
  209.     char *name;
  210.     int bit;
  211.     } crosstypes[9] =
  212.     {
  213.         { "long",        MB_LONG        },
  214.         { "int",        MB_INT        },
  215.         { "short",        MB_SHORT    },
  216.         { "char",        MB_CHAR        },
  217.         { "void",        MB_VOID        },
  218.         { "unsigned",    MB_UNSIGNED    },
  219.         { "signed",        MB_SIGNED    },
  220.         { "float",        MB_FLOAT    },
  221.         { "double",        MB_DOUBLE    }
  222.     };
  223.  
  224. /* Run through the crosscheck array looking */
  225. /* for unsupported combinations of types. */
  226. void mbcheck()
  227. {
  228.     register int i, j, restrict;
  229.     char *t1, *t2;
  230.  
  231.     /* Loop through the types */
  232.     /* (skip the "long" row) */
  233.     for (i = 1; i < 9; i++)
  234.     {
  235.     /* if this type is in use */
  236.     if ((modbits & crosstypes[i].bit) != 0)
  237.         {
  238.         /* check for other types also in use */
  239.         for (j = 0; j < i; j++)
  240.         {
  241.         /* this type is not in use */
  242.         if (!(modbits & crosstypes[j].bit))
  243.             continue;
  244.         /* check the type of restriction */
  245.         restrict = crosscheck[i][j];
  246.         if (restrict == ALWAYS)
  247.             continue;
  248.         t1 = crosstypes[i].name;
  249.         t2 = crosstypes[j].name;
  250.         if (restrict == NEVER)
  251.             {
  252.             notsupported("", t1, t2);
  253.             }
  254.         else if (restrict == RITCHIE)
  255.             {
  256.             if (RitchieFlag)
  257.             notsupported(" (Ritchie Compiler)", t1, t2);
  258.             }
  259.         else if (restrict == PREANSI)
  260.             {
  261.             if (PreANSIFlag || RitchieFlag)
  262.             notsupported(" (Pre-ANSI Compiler)", t1, t2);
  263.             }
  264.         else if (restrict == ANSI)
  265.             {
  266.             if (!RitchieFlag && !PreANSIFlag)
  267.             notsupported(" (ANSI Compiler)", t1, t2);
  268.             }
  269.         else
  270.             {
  271.             (void) fprintf (stderr,
  272.             "%s: Internal error in crosscheck[%d,%d]=%d!\n",
  273.             progname, i, j, restrict);
  274.             exit(1); /* NOTREACHED */
  275.             }
  276.         }
  277.         }
  278.     }
  279. }
  280.  
  281. /* undefine these as they are no longer needed */
  282. #undef _
  283. #undef ALWAYS
  284. #undef X
  285. #undef NEVER
  286. #undef R
  287. #undef RITCHIE
  288. #undef P
  289. #undef PREANSI
  290. #undef A
  291. #undef ANSI
  292.  
  293. /* Write out a message about something */
  294. /* being unsupported, possibly with a hint. */
  295. void unsupp(s,hint)
  296. char *s,*hint;
  297. {
  298.     notsupported("", s, NullCP);
  299.     if (hint)
  300.     (void) fprintf(stderr, "\t(maybe you mean \"%s\")\n", hint);
  301. }
  302.  
  303. /* Write out a message about something */
  304. /* being unsupported on a particular compiler. */
  305. void notsupported(compiler, type1, type2)
  306. char *compiler, *type1, *type2;
  307. {
  308.     if (type2)
  309.     (void) fprintf(stderr,
  310.         "Warning: Unsupported in%s C%s -- '%s' with '%s'\n",
  311.         compiler, CplusplusFlag ? "++" : "", type1, type2);
  312.     else
  313.     (void) fprintf(stderr,
  314.         "Warning: Unsupported in%s C%s -- '%s'\n",
  315.         compiler, CplusplusFlag ? "++" : "", type1);
  316. }
  317.  
  318. /* Called by the yacc grammar */
  319. void yyerror(s)
  320. char *s;
  321. {
  322.     (void) printf("%s\n",s);
  323.     Debug((stdout, "yychar=%d\n", yychar));
  324. }
  325.  
  326. /* Called by the yacc grammar */
  327. int yywrap()
  328. {
  329.     return 1;
  330. }
  331.  
  332. /*
  333.  * Support for dynamic strings:
  334.  * cat() creates a string from the concatenation
  335.  * of a null terminated list of input strings.
  336.  * The input strings are free()'d by cat()
  337.  * (so they better have been malloc()'d).
  338.  *
  339.  * the different methods of <stdarg.h> and
  340.  * <vararg.h> are handled within these macros
  341.  */
  342. #ifdef AMIGA
  343. # define VA_DCL(type,var)        (var) type var;
  344. # define VA_START(list,var,type)    (list = (va_list)&(var) , (var))
  345. # define va_arg(list,type)        ((type *)(list += sizeof(type)))[0]
  346. # define va_end(p)            /* nothing */
  347. typedef char *va_list;
  348. #else
  349. #if __STDC__
  350. #  define VA_DCL(type,var)        (type var,...)
  351. #  define VA_START(list,var,type)    ((va_start(list,var)) , (var))
  352. #else
  353. #if defined(DOS)
  354. #  define VA_DCL(type,var)        (var,...) type var;
  355. #  define VA_START(list,var,type)    ((va_start(list,var)) , (var))
  356. #else
  357. #ifndef NOVARARGS
  358. # define VA_DCL(type,var)        (va_alist) va_dcl
  359. # define VA_START(list,var,type)    ((va_start(list)) , va_arg(list,type))
  360. #else
  361.    /*
  362.     *    it is assumed here that machines which don't have either
  363.     *    <varargs.h> or <stdarg.h> will put its arguments on
  364.     *    the stack in the "usual" way and consequently can grab
  365.     *    the arguments using the "take the address of the first
  366.     *    parameter and increment by sizeof" trick.
  367.     */
  368. # define VA_DCL(type,var)        (var) type var;
  369. # define VA_START(list,var,type)    (list = (va_list)&(var) , (var))
  370. # define va_arg(list,type)        ((type *)(list += sizeof(type)))[-1]
  371. # define va_end(p)            /* nothing */
  372. typedef char *va_list;
  373. #endif /* NOVARARGS */
  374. #endif /* DOS */
  375. #endif /* __STDC__ */
  376. #endif /* AMIGA */
  377.  
  378. /* VARARGS */
  379. char *cat
  380. VA_DCL(char*, s1)
  381. {
  382.     register char *newstr;
  383.     register unsigned len = 1;
  384.     char *str;
  385.     va_list args;
  386.  
  387.     /* find the length which needs to be allocated */
  388.     str = VA_START(args, s1, char*);
  389.     for ( ; str; str = va_arg(args, char*))
  390.     len += strlen(str);
  391.     va_end(args);
  392.  
  393.     /* allocate it */
  394.     newstr = malloc(len);
  395.     if (newstr == 0)
  396.     {
  397.     (void) fprintf (stderr, "%s: out of malloc space within cat()!\n",
  398.         progname);
  399.     exit(1);
  400.     }
  401.     newstr[0] = '\0';
  402.  
  403.     /* copy in the strings */
  404.     str = VA_START(args, s1, char*);
  405.     for ( ; str; str = va_arg(args, char*))
  406.     {
  407.     (void) strcat(newstr,str);
  408.     free(str);
  409.     }
  410.     va_end(args);
  411.  
  412.     Debug((stderr, "\tcat created '%s'\n", newstr));
  413.     return newstr;
  414. }
  415.  
  416. /*
  417.  * ds() makes a malloc()'d string from one that's not.
  418.  */
  419. char *ds(s)
  420. char *s;
  421. {
  422.     register char *p = malloc((unsigned)(strlen(s)+1));
  423.  
  424.     if (p)
  425.     (void) strcpy(p,s);
  426.     else
  427.     {
  428.     (void) fprintf (stderr, "%s: malloc() failed!\n", progname);
  429.     exit(1);
  430.     }
  431.     return p;
  432. }
  433.  
  434. /* return a visible representation of a character */
  435. char *visible(c)
  436. int c;
  437. {
  438.     static char buf[5];
  439.  
  440.     c &= 0377;
  441.     if (isprint(c))
  442.     {
  443.     buf[0] = c;
  444.     buf[1] = '\0';
  445.     }
  446.     else
  447.     (void) sprintf(buf,"\\%03o",c);
  448.     return buf;
  449. }
  450.  
  451. #ifdef NOTMPFILE
  452. /* provide a conservative version of tmpfile() */
  453. /* for those systems without it. */
  454. /* tmpfile() returns a FILE* of a file opened */
  455. /* for read&write. It is supposed to be */
  456. /* automatically removed when it gets closed, */
  457. /* but here we provide a separate rmtmpfile() */
  458. /* function to perform that function. */
  459. /* Also provide several possible file names to */
  460. /* try for opening. */
  461. static char *file4tmpfile = 0;
  462.  
  463. FILE *tmpfile()
  464. {
  465.  
  466. #ifdef AMIGA
  467.     static char *listtmpfiles[] =
  468.     {
  469.     ":T/cdeclXXXXXX",
  470.     "ram:cdeclXXXXXX",
  471.     "ram:cdeclXXXXXX",
  472.     "ram:cdeclXXXXXX",
  473.     0
  474.     };
  475. #else
  476.     static char *listtmpfiles[] =
  477.     {
  478.     "/usr/tmp/cdeclXXXXXX",
  479.     "/tmp/cdeclXXXXXX",
  480.     "/cdeclXXXXXX",
  481.     "cdeclXXXXXX",
  482.     0
  483.     };
  484. #endif
  485.  
  486.     char **listp = listtmpfiles;
  487.     for ( ; *listp; listp++)
  488.     {
  489.     FILE *retfp;
  490.     (void) mktemp(*listp);
  491.     retfp = fopen(*listp, "w+");
  492.     if (!retfp)
  493.         continue;
  494.     file4tmpfile = *listp;
  495.     return retfp;
  496.     }
  497.  
  498.     return 0;
  499. }
  500.  
  501. void rmtmpfile()
  502. {
  503.     if (file4tmpfile)
  504.     (void) unlink(file4tmpfile);
  505. }
  506. #else
  507. /* provide a mock rmtmpfile() for normal systems */
  508. # define rmtmpfile()    /* nothing */
  509. #endif /* NOTMPFILE */
  510.  
  511. #ifndef NOGETOPT
  512. extern int optind;
  513. #else
  514. /* This is a miniature version of getopt() which will */
  515. /* do just barely enough for us to get by below. */
  516. /* Options are not allowed to be bunched up together. */
  517. /* Option arguments are not supported. */
  518. int optind = 1;
  519.  
  520. int getopt(argc,argv,optstring)
  521. char **argv;
  522. char *optstring;
  523. {
  524.     int ret;
  525.     char *p;
  526.  
  527.     if ((argv[optind][0] != '-')
  528. #ifdef DOS
  529.     && (argv[optind][0] != '/')
  530. #endif /* DOS */
  531.     )
  532.     return EOF;
  533.  
  534.     ret = argv[optind][1];
  535.     optind++;
  536.  
  537.     for (p = optstring; *p; p++)
  538.     if (*p == ret)
  539.         return ret;
  540.  
  541.     (void) fprintf (stderr, "%s: illegal option -- %s\n",
  542.     progname, visible(ret));
  543.  
  544.     return '?';
  545. }
  546. #endif
  547.  
  548. /* the help messages */
  549. struct helpstruct
  550.     {
  551.     char *text;    /* generic text */
  552.     char *cpptext;    /* C++ specific text */
  553.     } helptext[] =
  554.     {    /* up-to 23 lines of help text so it fits on (24x80) screens */
  555. /*  1 */{ "[] means optional; {} means 1 or more; <> means defined elsewhere", 0 },
  556. /*  2 */{ "  commands are separated by ';' and newlines", 0 },
  557. /*  3 */{ "command:", 0 },
  558. /*  4 */{ "  declare <name> as <english>", 0 },
  559. /*  5 */{ "  cast <name> into <english>", 0 },
  560. /*  6 */{ "  explain <gibberish>", 0 },
  561. /*  7 */{ "  set or set options", 0 },
  562. /*  8 */{ "  help, ?", 0 },
  563. /*  9 */{ "  quit or exit", 0 },
  564. /* 10 */{ "english:", 0 },
  565. /* 11 */{ "  function [( <decl-list> )] returning <english>", 0 },
  566. /* 12 */{ "  array [<number>] of <english>", 0 },
  567. /* 13 */{ "  [{ const | volatile | noalias }] pointer to <english>",
  568.       "  [{const|volatile}] {pointer|reference} to [member of class <name>] <english>" },
  569. /* 14 */{ "  <type>", 0 },
  570. /* 15 */{ "type:", 0 },
  571. /* 16 */{ "  {[<storage-class>] [{<modifier>}] [<C-type>]}", 0 },
  572. /* 17 */{ "  { struct | union | enum } <name>",
  573.       "  {struct|class|union|enum} <name>" },
  574. /* 18 */{ "decllist: a comma separated list of <name>, <english> or <name> as <english>", 0 },
  575. /* 19 */{ "name: a C identifier", 0 },
  576. /* 20 */{ "gibberish: a C declaration, like 'int *x', or cast, like '(int *)x'", 0 },
  577. /* 21 */{ "storage-class: extern, static, auto, register", 0 },
  578. /* 22 */{ "C-type: int, char, float, double, or void", 0 },
  579. /* 23 */{ "modifier: short, long, signed, unsigned, const, volatile, or noalias",
  580.       "modifier: short, long, signed, unsigned, const, or volatile" },
  581.     { 0, 0 }
  582.     };
  583.  
  584. /* Print out the help text */
  585. void dohelp()
  586. {
  587.     register struct helpstruct *p;
  588.     register char *fmt = CplusplusFlag ? " %s\n" : "\t%s\n";
  589.  
  590.     for (p = helptext; p->text; p++)
  591.     if (CplusplusFlag && p->cpptext)
  592.         (void) printf(fmt, p->cpptext);
  593.     else
  594.         (void) printf(fmt, p->text);
  595. }
  596.  
  597. /* Tell how to invoke cdecl. */
  598. void usage()
  599. {
  600.     (void) fprintf (stderr, "Usage: %s [-r|-p|-a|-+] [-ci%s%s] [files...]\n",
  601.     progname,
  602. #ifdef dodebug
  603.     "d",
  604. #else
  605.     "",
  606. #endif /* dodebug */
  607. #ifdef doyydebug
  608.     "D"
  609. #else
  610.     ""
  611. #endif /* doyydebug */
  612.     );
  613.     (void) fprintf (stderr, "\t-r Check against Ritchie PDP C Compiler\n");
  614.     (void) fprintf (stderr, "\t-p Check against Pre-ANSI C Compiler\n");
  615.     (void) fprintf (stderr, "\t-a Check against ANSI C Compiler%s\n",
  616.     CplusplusFlag ? "" : " (the default)");
  617.     (void) fprintf (stderr, "\t-+ Check against C++ Compiler%s\n",
  618.     CplusplusFlag ? " (the default)" : "");
  619.     (void) fprintf (stderr, "\t-c Create compilable output (include ; and {})\n");
  620.     (void) fprintf (stderr, "\t-i Force interactive mode\n");
  621. #ifdef dodebug
  622.     (void) fprintf (stderr, "\t-d Turn on debugging mode\n");
  623. #endif /* dodebug */
  624. #ifdef doyydebug
  625.     (void) fprintf (stderr, "\t-D Turn on YACC debugging mode\n");
  626. #endif /* doyydebug */
  627.     exit(1);
  628.     /* NOTREACHED */
  629. }
  630.  
  631. /* Manage the prompts. */
  632. static int prompting = 1;
  633.  
  634. void doprompt() { prompting = 1; }
  635. void noprompt() { prompting = 0; }
  636.  
  637. void prompt()
  638. {
  639.     if ((OnATty || Interactive) && prompting) {
  640.     (void) printf("%s> ", progname);
  641.     (void) fflush(stdout);
  642.     }
  643. }
  644.  
  645. /* Save away the name of the program from argv[0] */
  646. void setprogname(argv0)
  647. char *argv0;
  648. {
  649. #ifdef DOS
  650.     char *dot;
  651. #endif /* DOS */
  652.  
  653.     progname = strrchr(argv0, '/');
  654.  
  655. #ifdef DOS
  656.     if (!progname)
  657.     progname = strrchr(argv0, '\\');
  658. #endif /* DOS */
  659.  
  660.     if (progname)
  661.     progname++;
  662.     else
  663.     progname = argv0;
  664.  
  665. #ifdef DOS
  666.     dot = strchr(progname, '.');
  667.     if (dot)
  668.     *dot = '\0';
  669.     for (dot = progname; *dot; dot++)
  670.     *dot = tolower(*dot);
  671. #endif /* DOS */
  672. }
  673.  
  674. /* Run down the list of keywords to see if the */
  675. /* program is being called named as one of them */
  676. /* or the first argument is one of them. */
  677. int namedkeyword(argn)
  678. char *argn;
  679. {
  680.     static char *cmdlist[] =
  681.     {
  682.     "explain", "declare", "cast", "help", "?", "set", 0
  683.     };
  684.  
  685.     /* first check the program name */
  686.     char **cmdptr = cmdlist;
  687.     for ( ; *cmdptr; cmdptr++)
  688.     if (strcmp(*cmdptr, progname) == 0)
  689.         {
  690.         KeywordName = 1;
  691.         return 1;
  692.         }
  693.  
  694.     /* now check $1 */
  695.     for (cmdptr = cmdlist; *cmdptr; cmdptr++)
  696.     if (strcmp(*cmdptr, argn) == 0)
  697.         return 1;
  698.  
  699.     /* nope, must be file name arguments */
  700.     return 0;
  701. }
  702.  
  703. /* Read from standard input, turning */
  704. /* on prompting if necessary. */
  705. int dostdin()
  706. {
  707.     int ret;
  708.     OnATty = isatty(0);
  709.     if (OnATty || Interactive)
  710.     {
  711.     (void) printf("Type `help' or `?' for help\n");
  712.     prompt();
  713.     }
  714.  
  715.     yyin = stdin;
  716.     ret = yyparse();
  717.     OnATty = 0;
  718.     return ret;
  719. }
  720.  
  721. /* Write the arguments into a file */
  722. /* and treat that file as the input. */
  723. int dotmpfile(argc, argv)
  724. int argc;
  725. char **argv;
  726. {
  727.     int ret = 0;
  728.     FILE *tmpfp = tmpfile();
  729.     if (!tmpfp)
  730.     {
  731.     int sverrno = errno;
  732.     (void) fprintf (stderr, "%s: cannot open temp file\n",
  733.         progname);
  734.     errno = sverrno;
  735.     perror(progname);
  736.     return 1;
  737.     }
  738.  
  739.     if (KeywordName)
  740.     if (fputs(progname, tmpfp) == EOF)
  741.         {
  742.         int sverrno;
  743.     errwrite:
  744.         sverrno = errno;
  745.         (void) fprintf (stderr, "%s: error writing to temp file\n",
  746.         progname);
  747.         errno = sverrno;
  748.         perror(progname);
  749.         (void) fclose(tmpfp);
  750.         rmtmpfile();
  751.         return 1;
  752.         }
  753.  
  754.     for ( ; optind < argc; optind++)
  755.     if (fprintf(tmpfp, " %s", argv[optind]) == EOF)
  756.         goto errwrite;
  757.  
  758.     if (putc('\n', tmpfp) == EOF)
  759.     goto errwrite;
  760.  
  761.     rewind(tmpfp);
  762.     yyin = tmpfp;
  763.     ret += yyparse();
  764.     (void) fclose(tmpfp);
  765.     rmtmpfile();
  766.  
  767.     return ret;
  768. }
  769.  
  770. /* Read each of the named files for input. */
  771. int dofileargs(argc, argv)
  772. int argc;
  773. char **argv;
  774. {
  775.     FILE *ifp;
  776.     int ret = 0;
  777.  
  778.     for ( ; optind < argc; optind++)
  779.     if (strcmp(argv[optind], "-") == 0)
  780.         ret += dostdin();
  781.  
  782.     else if ((ifp = fopen(argv[optind], "r")) == NULL)
  783.         {
  784.         int sverrno = errno;
  785.         (void) fprintf (stderr, "%s: cannot open %s\n",
  786.         progname, argv[optind]);
  787.         errno = sverrno;
  788.         perror(argv[optind]);
  789.         ret++;
  790.         }
  791.  
  792.     else
  793.         {
  794.         yyin = ifp;
  795.         ret += yyparse();
  796.         }
  797.  
  798.     return ret;
  799. }
  800.  
  801. /* print out a cast */
  802. void docast(name, left, right, type)
  803. char *name, *left, *right, *type;
  804. {
  805.     int lenl = strlen(left), lenr = strlen(right);
  806.  
  807.     if (prev == 'f')
  808.         unsupp("Cast into function",
  809.             "cast into pointer to function");
  810.     else if (prev=='A' || prev=='a')
  811.         unsupp("Cast into array","cast into pointer");
  812.     (void) printf("(%s%*s%s)%s\n",
  813.         type, lenl+lenr?lenl+1:0,
  814.         left, right, name ? name : "expression");
  815.     free(left);
  816.     free(right);
  817.     free(type);
  818.     if (name)
  819.         free(name);
  820. }
  821.  
  822. /* print out a declaration */
  823. void dodeclare(name, storage, left, right, type)
  824. char *name, *storage, *left, *right, *type;
  825. {
  826.     if (prev == 'v')
  827.         unsupp("Variable of type void",
  828.             "variable of type pointer to void");
  829.  
  830.     if (*storage == 'r')
  831.     switch (prev)
  832.         {
  833.         case 'f': unsupp("Register function", NullCP); break;
  834.         case 'A':
  835.         case 'a': unsupp("Register array", NullCP); break;
  836.         case 's': unsupp("Register struct/class", NullCP); break;
  837.         }
  838.  
  839.     if (*storage)
  840.         (void) printf("%s ", storage);
  841.     (void) printf("%s %s%s%s",
  842.         type, left,
  843.     name ? name : (prev == 'f') ? "f" : "var", right);
  844.     if (MkProgramFlag) {
  845.         if ((prev == 'f') && (*storage != 'e'))
  846.             (void) printf(" { }\n");
  847.         else
  848.             (void) printf(";\n");
  849.     } else {
  850.         (void) printf("\n");
  851.     }
  852.     free(storage);
  853.     free(left);
  854.     free(right);
  855.     free(type);
  856.     if (name)
  857.         free(name);
  858. }
  859.  
  860. void dodexplain(storage, constvol, type, decl)
  861. char *storage, *constvol, *type, *decl;
  862. {
  863.     if (type && (strcmp(type, "void") == 0))
  864.     if (prev == 'n')
  865.         unsupp("Variable of type void",
  866.            "variable of type pointer to void");
  867.     else if (prev == 'a')
  868.         unsupp("array of type void",
  869.            "array of type pointer to void");
  870.     else if (prev == 'r')
  871.         unsupp("reference to type void",
  872.            "pointer to void");
  873.  
  874.     if (*storage == 'r')
  875.     switch (prev)
  876.         {
  877.         case 'f': unsupp("Register function", NullCP); break;
  878.         case 'A':
  879.         case 'a': unsupp("Register array", NullCP); break;
  880.         case 's': unsupp("Register struct/union/enum/class", NullCP); break;
  881.         }
  882.  
  883.     (void) printf("declare %s as ", savedname);
  884.     if (*storage)
  885.         (void) printf("%s ", storage);
  886.     (void) printf("%s", decl);
  887.     if (*constvol)
  888.         (void) printf("%s ", constvol);
  889.     (void) printf("%s\n", type ? type : "int");
  890. }
  891.  
  892. void docexplain(constvol, type, cast, name)
  893. char *constvol, *type, *cast, *name;
  894. {
  895.     if (strcmp(type, "void") == 0)
  896.     if (prev == 'a')
  897.         unsupp("array of type void",
  898.            "array of type pointer to void");
  899.     else if (prev == 'r')
  900.         unsupp("reference to type void",
  901.            "pointer to void");
  902.     (void) printf("cast %s into %s", name, cast);
  903.     if (strlen(constvol) > 0)
  904.         (void) printf("%s ", constvol);
  905.     (void) printf("%s\n",type);
  906. }
  907.  
  908. /* Do the appropriate things for the "set" command. */
  909. void doset(opt)
  910. char *opt;
  911. {
  912.     if (strcmp(opt, "create") == 0)
  913.     { MkProgramFlag = 1; }
  914.     else if (strcmp(opt, "nocreate") == 0)
  915.     { MkProgramFlag = 0; }
  916.     else if (strcmp(opt, "interactive") == 0)
  917.     { Interactive = 1; }
  918.     else if (strcmp(opt, "nointeractive") == 0)
  919.     { Interactive = 0; OnATty = 0; }
  920.     else if (strcmp(opt, "ritchie") == 0)
  921.     { CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; }
  922.     else if (strcmp(opt, "preansi") == 0)
  923.     { CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; }
  924.     else if (strcmp(opt, "ansi") == 0)
  925.     { CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; }
  926.     else if (strcmp(opt, "cplusplus") == 0)
  927.     { CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; }
  928. #ifdef dodebug
  929.     else if (strcmp(opt, "debug") == 0)
  930.     { DebugFlag = 1; }
  931.     else if (strcmp(opt, "nodebug") == 0)
  932.     { DebugFlag = 0; }
  933. #endif /* dodebug */
  934. #ifdef doyydebug
  935.     else if (strcmp(opt, "yydebug") == 0)
  936.     { yydebug = 1; }
  937.     else if (strcmp(opt, "noyydebug") == 0)
  938.     { yydebug = 0; }
  939. #endif /* doyydebug */
  940.     else
  941.     {
  942.     if ((strcmp(opt, unknown_name) != 0) &&
  943.         (strcmp(opt, "options") != 0))
  944.         (void) printf("Unknown set option: '%s'\n", opt);
  945.  
  946.     (void) printf("Valid set options (and command line equivalents) are:\n");
  947.     (void) printf("\toptions\n");
  948.     (void) printf("\tcreate (-c), nocreate\n");
  949.     (void) printf("\tinteractive (-i), nointeractive\n");
  950.     (void) printf("\tritchie (-r), preansi (-p), ansi (-a) or cplusplus (-+)\n");
  951. #ifdef dodebug
  952.     (void) printf("\tdebug (-d), nodebug\n");
  953. #endif /* dodebug */
  954. #ifdef doyydebug
  955.     (void) printf("\tyydebug (-D), noyydebug\n");
  956. #endif /* doyydebug */
  957.  
  958.     (void) printf("\nCurrent set values are:\n");
  959.     (void) printf("\t%screate\n", MkProgramFlag ? "   " : " no");
  960.     (void) printf("\t%sinteractive\n",
  961.         (OnATty || Interactive) ? "   " : " no");
  962.     if (RitchieFlag)
  963.         (void) printf("\t   ritchie\n");
  964.     else
  965.         (void) printf("\t(noritchie)\n");
  966.     if (PreANSIFlag)
  967.         (void) printf("\t   preansi\n");
  968.     else
  969.         (void) printf("\t(nopreansi)\n");
  970.     if (!RitchieFlag && !PreANSIFlag && !CplusplusFlag)
  971.         (void) printf("\t   ansi\n");
  972.     else
  973.         (void) printf("\t(noansi)\n");
  974.     if (CplusplusFlag)
  975.         (void) printf("\t   cplusplus\n");
  976.     else
  977.         (void) printf("\t(nocplusplus)\n");
  978. #ifdef dodebug
  979.     (void) printf("\t%sdebug\n", DebugFlag ? "   " : " no");
  980. #endif /* dodebug */
  981. #ifdef doyydebug
  982.     (void) printf("\t%syydebug\n", yydebug ? "   " : " no");
  983. #endif /* doyydebug */
  984.     }
  985. }
  986.  
  987. void versions()
  988. {
  989.     (void) printf("Version:\n\t%s\n\t%s\n\t%s\n",
  990.     cdeclsccsid, cdgramsccsid, cdlexsccsid);
  991.     exit(0);
  992. }
  993.  
  994. int main(argc, argv)
  995. char **argv;
  996. {
  997.     int c, ret = 0;
  998.  
  999.     setprogname(argv[0]);
  1000. #ifdef DOS
  1001.     if (strcmp(progname, "cppdecl") == 0)
  1002. #else
  1003.     if (strcmp(progname, "c++decl") == 0)
  1004. #endif /* DOS */
  1005.     CplusplusFlag = 1;
  1006.  
  1007.     while ((c = getopt(argc, argv, "cirpa+dDV")) != EOF)
  1008.     switch (c)
  1009.         {
  1010.         case 'c': MkProgramFlag=1; break;
  1011.         case 'i': Interactive=1; break;
  1012.  
  1013.         /* The following are mutually exclusive. */
  1014.         /* Only the last one set prevails. */
  1015.         case 'r': CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; break;
  1016.         case 'p': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; break;
  1017.         case 'a': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; break;
  1018.         case '+': CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; break;
  1019.  
  1020. #ifdef dodebug
  1021.         case 'd': DebugFlag=1; break;
  1022. #endif /* dodebug */
  1023. #ifdef doyydebug
  1024.         case 'D': yydebug=1; break;
  1025. #endif /* doyydebug */
  1026.         case 'V': versions(); break;
  1027.         case '?': usage(); break;
  1028.         }
  1029.  
  1030.     /* Run down the list of arguments, parsing each one. */
  1031.  
  1032.     /* Use standard input if no file names or "-" is found. */
  1033.     if (optind == argc)
  1034.     ret += dostdin();
  1035.  
  1036.     /* If called as explain, declare or cast, or first */
  1037.     /* argument is one of those, use the command line */
  1038.     /* as the input. */
  1039.     else if (namedkeyword(argv[optind]))
  1040.     ret += dotmpfile(argc, argv);
  1041.  
  1042.     else
  1043.     ret += dofileargs(argc, argv);
  1044.  
  1045.     exit(ret);
  1046.     /* NOTREACHED */
  1047. }
  1048.