[comp.sources.unix] v14i091: New version of Cdecl, parse C declarations, Part02/02

rsalz@bbn.com (Rich Salz) (05/11/88)

Submitted-by: cbosgd!pegasus!hansen (Tony Hansen)
Posting-number: Volume 14, Issue 91
Archive-name: cdecl2/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  cdecl.c
# Wrapped by rsalz@fig.bbn.com on Mon May  9 20:40:48 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cdecl.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cdecl.c'\"
else
echo shar: Extracting \"'cdecl.c'\" \(25555 characters\)
sed "s/^X//" >'cdecl.c' <<'END_OF_FILE'
X/*
X * cdecl - ANSI C and C++ declaration composer & decoder
X *
X *	originally written
X *		Graham Ross
X *		once at tektronix!tekmdp!grahamr
X *		now at Context, Inc.
X *
X *	modified to provide hints for unsupported types
X *	added argument lists for functions
X *	added 'explain cast' grammar
X *	added #ifdef for 'create program' feature
X *		???? (sorry, I lost your name and login)
X *
X *	conversion to ANSI C
X *		David Wolverton
X *		ihnp4!houxs!daw
X *
X *	merged D. Wolverton's ANSI C version w/ ????'s version
X *	added function prototypes
X *	added C++ declarations
X *	made type combination checking table driven
X *	added checks for void variable combinations
X *	made 'create program' feature a runtime option
X *	added file parsing as well as just stdin
X *	added help message at beginning
X *	added prompts when on a TTY or in interactive mode
X *	added getopt() usage
X *	added -a, -r, -p, -c, -d, -D, -V, -i and -+ options
X *	delinted
X *	added #defines for those without getopt or void
X *	added 'set options' command
X *	added 'quit/exit' command
X *	added synonyms
X *		Tony Hansen
X *		attmail!tony, ihnp4!pegasus!hansen
X *
X *	added extern, register, static
X *	added links to explain, cast, declare
X *	separately developed ANSI C support
X *		Merlyn LeRoy
X *		merlyn@rose3.rosemount.com
X *
X *	merged versions from LeRoy
X *	added tmpfile() support
X *	allow more parts to be missing during explanations
X *		Tony Hansen
X *		attmail!tony, ihnp4!pegasus!hansen
X */
X
char cdeclsccsid[] = "@(#)cdecl.c	2.4 3/31/88";
X
X#include <stdio.h>
X#include <ctype.h>
X#if __STDC__ || defined(DOS)
X# include <stdlib.h>
X# include <stddef.h>
X# include <string.h>
X# include <stdarg.h>
X#else
X# ifndef NOVARARGS
X#  include <varargs.h>
X# endif /* ndef NOVARARGS */
char *malloc();
void free(), exit(), perror();
X# ifdef BSD
X#  include <strings.h>
X   extern int errno;
X#  define strrchr rindex
X#  define NOTMPFILE
X# else
X#  include <string.h>
X#  include <errno.h>
X# endif /* BSD */
X# ifdef NOVOID
X#  define void int
X# endif /* NOVOID */
X#endif /* __STDC__ || DOS */
X
X#define	MB_SHORT	0001
X#define	MB_LONG		0002
X#define	MB_UNSIGNED	0004
X#define MB_INT		0010
X#define MB_CHAR		0020
X#define MB_FLOAT	0040
X#define MB_DOUBLE	0100
X#define MB_VOID		0200
X#define	MB_SIGNED	0400
X
X#define NullCP ((char*)NULL)
X#ifdef dodebug
X# define Debug(x) do { if (DebugFlag) (void) fprintf x; } while (0)
X#else
X# define Debug(x) /* nothing */
X#endif
X
X#if __STDC__
X  char *ds(char *), *cat(char *, ...), *visible(int);
X  int getopt(int,char **,char *);
X  int main(int, char **);
X  int yywrap(void);
X  int dostdin(void);
X  void mbcheck(void), dohelp(void), usage(void);
X  void prompt(void), doprompt(void), noprompt(void);
X  void unsupp(char *, char *);
X  void notsupported(char *, char *, char *);
X  void yyerror(char *);
X  void doset(char *);
X  void dodeclare(char*, char*, char*, char*, char*);
X  void docast(char*, char*, char*, char*);
X  void dodexplain(char*, char*, char*, char*);
X  void docexplain(char*, char*, char*, char*);
X  void setprogname(char *);
X  int dotmpfile(int, char**), dofileargs(int, char**);
X#else
X  char *ds(), *cat(), *visible();
X  int getopt();
X  void mbcheck(), dohelp(), usage();
X  void prompt(), doprompt(), noprompt();
X  void unsupp(), notsupported();
X  void yyerror();
X  void doset(), dodeclare(), docast(), dodexplain(), docexplain();
X  void setprogname();
X  int dotmpfile(), dofileargs();
X#endif /* __STDC__ */
X  FILE *tmpfile();
X
X/* variables used during parsing */
unsigned modbits = 0;
int arbdims = 1;
char *savedname = 0;
char unknown_name[] = "unknown_name";
char prev = 0;		/* the current type of the variable being examined */
X			/*    values	type				   */
X			/*	p	pointer				   */
X			/*	r	reference			   */
X			/*	f	function			   */
X			/*	a	array (of arbitrary dimensions)    */
X			/*	A	array with dimensions		   */
X			/*	n	name				   */
X			/*	v	void				   */
X			/*	s	struct | class			   */
X			/*	t	simple type (int, long, etc.)	   */
X
X/* options */
int RitchieFlag = 0;		/* -r, assume Ritchie PDP C language */
int MkProgramFlag = 0;		/* -c, output {} and ; after declarations */
int PreANSIFlag = 0;		/* -p, assume pre-ANSI C language */
int CplusplusFlag = 0;		/* -+, assume C++ language */
int OnATty = 0;			/* stdin is coming from a terminal */
int Interactive = 0;		/* -i, overrides OnATty */
int KeywordName = 0;		/* $0 is a keyword (declare, explain, cast) */
char *progname = "cdecl";	/* $0 */
X
X#if dodebug
int DebugFlag = 0;		/* -d, output debugging trace info */
X#endif
X
X#ifdef doyydebug		/* compile in yacc trace statements */
X#define YYDEBUG 1
X#endif /* doyydebug */
X
X#include "cdgram.c"
X#include "cdlex.c"
X
X/* definitions (and abbreviations) for type combinations cross check table */
X#define ALWAYS	0	/* combo always okay */
X#define _	ALWAYS
X#define NEVER	1	/* combo never allowed */
X#define X	NEVER
X#define RITCHIE	2	/* combo not allowed in Ritchie compiler */
X#define R	RITCHIE
X#define PREANSI	3	/* combo not allowed in Pre-ANSI compiler */
X#define P	PREANSI
X#define ANSI	4	/* combo not allowed anymore in ANSI compiler */
X#define A	ANSI
X
X/* This is an lower left triangular array. If we needed */
X/* to save 9 bytes, the "long" row can be removed. */
char crosscheck[9][9] = {
X    /*			L, I, S, C, V, U, S, F, D, */
X    /* long */		_, _, _, _, _, _, _, _, _,
X    /* int */		_, _, _, _, _, _, _, _, _,
X    /* short */		X, _, _, _, _, _, _, _, _,
X    /* char */		X, X, X, _, _, _, _, _, _,
X    /* void */		X, X, X, X, _, _, _, _, _,
X    /* unsigned */	R, _, R, R, X, _, _, _, _,
X    /* signed */	P, P, P, P, X, X, _, _, _,
X    /* float */		A, X, X, X, X, X, X, _, _,
X    /* double */	P, X, X, X, X, X, X, X, _
X};
X
X/* the names and bits checked for each row in the above array */
struct
X    {
X    char *name;
X    int bit;
X    } crosstypes[9] =
X	{
X	    { "long",		MB_LONG		},
X	    { "int",		MB_INT		},
X	    { "short",		MB_SHORT	},
X	    { "char",		MB_CHAR		},
X	    { "void",		MB_VOID		},
X	    { "unsigned",	MB_UNSIGNED	},
X	    { "signed",		MB_SIGNED	},
X	    { "float",		MB_FLOAT	},
X	    { "double",		MB_DOUBLE	}
X	};
X
X/* Run through the crosscheck array looking */
X/* for unsupported combinations of types. */
void mbcheck()
X{
X    register int i, j, restrict;
X    char *t1, *t2;
X
X    /* Loop through the types */
X    /* (skip the "long" row) */
X    for (i = 1; i < 9; i++)
X	{
X	/* if this type is in use */
X	if ((modbits & crosstypes[i].bit) != 0)
X	    {
X	    /* check for other types also in use */
X	    for (j = 0; j < i; j++)
X		{
X		/* this type is not in use */
X		if (!(modbits & crosstypes[j].bit))
X		    continue;
X		/* check the type of restriction */
X		restrict = crosscheck[i][j];
X		if (restrict == ALWAYS)
X		    continue;
X		t1 = crosstypes[i].name;
X		t2 = crosstypes[j].name;
X		if (restrict == NEVER)
X		    {
X		    notsupported("", t1, t2);
X		    }
X		else if (restrict == RITCHIE)
X		    {
X		    if (RitchieFlag)
X			notsupported(" (Ritchie Compiler)", t1, t2);
X		    }
X		else if (restrict == PREANSI)
X		    {
X		    if (PreANSIFlag || RitchieFlag)
X			notsupported(" (Pre-ANSI Compiler)", t1, t2);
X		    }
X		else if (restrict == ANSI)
X		    {
X		    if (!RitchieFlag && !PreANSIFlag)
X			notsupported(" (ANSI Compiler)", t1, t2);
X		    }
X		else
X		    {
X		    (void) fprintf (stderr,
X			"%s: Internal error in crosscheck[%d,%d]=%d!\n",
X			progname, i, j, restrict);
X		    exit(1); /* NOTREACHED */
X		    }
X		}
X	    }
X	}
X}
X
X/* undefine these as they are no longer needed */
X#undef _
X#undef ALWAYS
X#undef X
X#undef NEVER
X#undef R
X#undef RITCHIE
X#undef P
X#undef PREANSI
X#undef A
X#undef ANSI
X
X/* Write out a message about something */
X/* being unsupported, possibly with a hint. */
void unsupp(s,hint)
char *s,*hint;
X{
X    notsupported("", s, NullCP);
X    if (hint)
X	(void) fprintf(stderr, "\t(maybe you mean \"%s\")\n", hint);
X}
X
X/* Write out a message about something */
X/* being unsupported on a particular compiler. */
void notsupported(compiler, type1, type2)
char *compiler, *type1, *type2;
X{
X    if (type2)
X	(void) fprintf(stderr,
X	    "Warning: Unsupported in%s C%s -- '%s' with '%s'\n",
X	    compiler, CplusplusFlag ? "++" : "", type1, type2);
X    else
X	(void) fprintf(stderr,
X	    "Warning: Unsupported in%s C%s -- '%s'\n",
X	    compiler, CplusplusFlag ? "++" : "", type1);
X}
X
X/* Called by the yacc grammar */
void yyerror(s)
char *s;
X{
X    (void) printf("%s\n",s);
X    Debug((stdout, "yychar=%d\n", yychar));
X}
X
X/* Called by the yacc grammar */
int yywrap()
X{
X    return 1;
X}
X
X/*
X * Support for dynamic strings:
X * cat() creates a string from the concatenation
X * of a null terminated list of input strings.
X * The input strings are free()'d by cat()
X * (so they better have been malloc()'d).
X *
X * the different methods of <stdarg.h> and
X * <vararg.h> are handled within these macros
X */
X#if __STDC__
X#  define VA_DCL(type,var)		(type var,...)
X#  define VA_START(list,var,type)	((va_start(list,var)) , (var))
X#else
X#if defined(DOS)
X#  define VA_DCL(type,var)		(var,...) type var;
X#  define VA_START(list,var,type)	((va_start(list,var)) , (var))
X#else
X#ifndef NOVARARGS
X# define VA_DCL(type,var)		(va_alist) va_dcl
X# define VA_START(list,var,type)	((va_start(list)) , va_arg(list,type))
X#else
X   /*
X    *	it is assumed here that machines which don't have either
X    *	<varargs.h> or <stdarg.h> will put its arguments on
X    *	the stack in the "usual" way and consequently can grab
X    *	the arguments using the "take the address of the first
X    *	parameter and increment by sizeof" trick.
X    */
X# define VA_DCL(type,var)		(var) type var;
X# define VA_START(list,var,type)	(list = (va_list)&(var) , (var))
X# define va_arg(list,type)		((type *)(list += sizeof(type)))[-1]
X# define va_end(p)			/* nothing */
typedef char *va_list;
X#endif /* NOVARARGS */
X#endif /* DOS */
X#endif /* __STDC__ */
X
X/* VARARGS */
char *cat
VA_DCL(char*, s1)
X{
X    register char *newstr;
X    register unsigned len = 1;
X    char *str;
X    va_list args;
X
X    /* find the length which needs to be allocated */
X    str = VA_START(args, s1, char*);
X    for ( ; str; str = va_arg(args, char*))
X	len += strlen(str);
X    va_end(args);
X
X    /* allocate it */
X    newstr = malloc(len);
X    if (newstr == 0)
X	{
X	(void) fprintf (stderr, "%s: out of malloc space within cat()!\n",
X	    progname);
X	exit(1);
X	}
X    newstr[0] = '\0';
X
X    /* copy in the strings */
X    str = VA_START(args, s1, char*);
X    for ( ; str; str = va_arg(args, char*))
X	{
X	(void) strcat(newstr,str);
X	free(str);
X	}
X    va_end(args);
X
X    Debug((stderr, "\tcat created '%s'\n", newstr));
X    return newstr;
X}
X
X/*
X * ds() makes a malloc()'d string from one that's not.
X */
char *ds(s)
char *s;
X{
X    register char *p = malloc((unsigned)(strlen(s)+1));
X
X    if (p)
X	(void) strcpy(p,s);
X    else
X	{
X	(void) fprintf (stderr, "%s: malloc() failed!\n", progname);
X	exit(1);
X	}
X    return p;
X}
X
X/* return a visible representation of a character */
char *visible(c)
int c;
X{
X    static char buf[5];
X
X    c &= 0377;
X    if (isprint(c))
X	{
X	buf[0] = c;
X	buf[1] = '\0';
X	}
X    else
X	(void) sprintf(buf,"\\%03o",c);
X    return buf;
X}
X
X#ifdef NOTMPFILE
X/* provide a conservative version of tmpfile() */
X/* for those systems without it. */
X/* tmpfile() returns a FILE* of a file opened */
X/* for read&write. It is supposed to be */
X/* automatically removed when it gets closed, */
X/* but here we provide a separate rmtmpfile() */
X/* function to perform that function. */
X/* Also provide several possible file names to */
X/* try for opening. */
static char *file4tmpfile = 0;
X
XFILE *tmpfile()
X{
X    static char *listtmpfiles[] =
X	{
X	"/usr/tmp/cdeclXXXXXX",
X	"/tmp/cdeclXXXXXX",
X	"/cdeclXXXXXX",
X	"cdeclXXXXXX",
X	0
X	};
X
X    char **listp = listtmpfiles;
X    for ( ; *listp; listp++)
X	{
X	FILE *retfp;
X	(void) mktemp(*listp);
X	retfp = fopen(*listp, "w+");
X	if (!retfp)
X	    continue;
X	file4tmpfile = *listp;
X	return retfp;
X	}
X
X    return 0;
X}
X
void rmtmpfile()
X{
X    if (file4tmpfile)
X	(void) unlink(file4tmpfile);
X}
X#else
X/* provide a mock rmtmpfile() for normal systems */
X# define rmtmpfile()	/* nothing */
X#endif /* NOTMPFILE */
X
X#ifndef NOGETOPT
extern int optind;
X#else
X/* This is a miniature version of getopt() which will */
X/* do just barely enough for us to get by below. */
X/* Options are not allowed to be bunched up together. */
X/* Option arguments are not supported. */
int optind = 1;
X
int getopt(argc,argv,optstring)
char **argv;
char *optstring;
X{
X    int ret;
X    char *p;
X
X    if ((argv[optind][0] != '-')
X#ifdef DOS
X	&& (argv[optind][0] != '/')
X#endif /* DOS */
X	)
X	return EOF;
X
X    ret = argv[optind][1];
X    optind++;
X
X    for (p = optstring; *p; p++)
X	if (*p == ret)
X	    return ret;
X
X    (void) fprintf (stderr, "%s: illegal option -- %s\n",
X	progname, visible(ret));
X
X    return '?';
X}
X#endif
X
X/* the help messages */
struct helpstruct
X    {
X	char *text;	/* generic text */
X	char *cpptext;	/* C++ specific text */
X    } helptext[] =
X    {	/* up-to 23 lines of help text so it fits on (24x80) screens */
X/*  1 */{ "[] means optional; {} means 1 or more; <> means defined elsewhere", 0 },
X/*  2 */{ "  commands are separated by ';' and newlines", 0 },
X/*  3 */{ "command:", 0 },
X/*  4 */{ "  declare <name> as <english>", 0 },
X/*  5 */{ "  cast <name> into <english>", 0 },
X/*  6 */{ "  explain <gibberish>", 0 },
X/*  7 */{ "  set or set options", 0 },
X/*  8 */{ "  help, ?", 0 },
X/*  9 */{ "  quit or exit", 0 },
X/* 10 */{ "english:", 0 },
X/* 11 */{ "  function [( <decl-list> )] returning <english>", 0 },
X/* 12 */{ "  array [<number>] of <english>", 0 },
X/* 13 */{ "  [{ const | volatile | noalias }] pointer to <english>",
X	  "  [{const|volatile}] {pointer|reference} to [member of class <name>] <english>" },
X/* 14 */{ "  <type>", 0 },
X/* 15 */{ "type:", 0 },
X/* 16 */{ "  {[<storage-class>] [{<modifier>}] [<C-type>]}", 0 },
X/* 17 */{ "  { struct | union | enum } <name>",
X	  "  {struct|class|union|enum} <name>" },
X/* 18 */{ "decllist: a comma separated list of <name>, <english> or <name> as <english>", 0 },
X/* 19 */{ "name: a C identifier", 0 },
X/* 20 */{ "gibberish: a C declaration, like 'int *x', or cast, like '(int *)x'", 0 },
X/* 21 */{ "storage-class: extern, static, auto, register", 0 },
X/* 22 */{ "C-type: int, char, float, double, or void", 0 },
X/* 23 */{ "modifier: short, long, signed, unsigned, const, volatile, or noalias",
X	  "modifier: short, long, signed, unsigned, const, or volatile" },
X	{ 0, 0 }
X    };
X
X/* Print out the help text */
void dohelp()
X{
X    register struct helpstruct *p;
X    register char *fmt = CplusplusFlag ? " %s\n" : "\t%s\n";
X
X    for (p = helptext; p->text; p++)
X	if (CplusplusFlag && p->cpptext)
X	    (void) printf(fmt, p->cpptext);
X	else
X	    (void) printf(fmt, p->text);
X}
X
X/* Tell how to invoke cdecl. */
void usage()
X{
X    (void) fprintf (stderr, "Usage: %s [-r|-p|-a|-+] [-ci%s%s] [files...]\n",
X	progname,
X#ifdef dodebug
X	"d",
X#else
X	"",
X#endif /* dodebug */
X#ifdef doyydebug
X	"D"
X#else
X	""
X#endif /* doyydebug */
X	);
X    (void) fprintf (stderr, "\t-r Check against Ritchie PDP C Compiler\n");
X    (void) fprintf (stderr, "\t-p Check against Pre-ANSI C Compiler\n");
X    (void) fprintf (stderr, "\t-a Check against ANSI C Compiler%s\n",
X	CplusplusFlag ? "" : " (the default)");
X    (void) fprintf (stderr, "\t-+ Check against C++ Compiler%s\n",
X	CplusplusFlag ? " (the default)" : "");
X    (void) fprintf (stderr, "\t-c Create compilable output (include ; and {})\n");
X    (void) fprintf (stderr, "\t-i Force interactive mode\n");
X#ifdef dodebug
X    (void) fprintf (stderr, "\t-d Turn on debugging mode\n");
X#endif /* dodebug */
X#ifdef doyydebug
X    (void) fprintf (stderr, "\t-D Turn on YACC debugging mode\n");
X#endif /* doyydebug */
X    exit(1);
X    /* NOTREACHED */
X}
X
X/* Manage the prompts. */
static int prompting = 1;
X
void doprompt() { prompting = 1; }
void noprompt() { prompting = 0; }
X
void prompt()
X{
X    if ((OnATty || Interactive) && prompting) {
X	(void) printf("%s> ", progname);
X	(void) fflush(stdout);
X    }
X}
X
X/* Save away the name of the program from argv[0] */
void setprogname(argv0)
char *argv0;
X{
X#ifdef DOS
X    char *dot;
X#endif /* DOS */
X
X    progname = strrchr(argv0, '/');
X
X#ifdef DOS
X    if (!progname)
X	progname = strrchr(argv0, '\\');
X#endif /* DOS */
X
X    if (progname)
X	progname++;
X    else
X	progname = argv0;
X
X#ifdef DOS
X    dot = strchr(progname, '.');
X    if (dot)
X	*dot = '\0';
X    for (dot = progname; *dot; dot++)
X	*dot = tolower(*dot);
X#endif /* DOS */
X}
X
X/* Run down the list of keywords to see if the */
X/* program is being called named as one of them */
X/* or the first argument is one of them. */
int namedkeyword(argn)
char *argn;
X{
X    static char *cmdlist[] =
X	{
X	"explain", "declare", "cast", "help", "?", "set", 0
X	};
X
X    /* first check the program name */
X    char **cmdptr = cmdlist;
X    for ( ; *cmdptr; cmdptr++)
X	if (strcmp(*cmdptr, progname) == 0)
X	    {
X	    KeywordName = 1;
X	    return 1;
X	    }
X
X    /* now check $1 */
X    for (cmdptr = cmdlist; *cmdptr; cmdptr++)
X	if (strcmp(*cmdptr, argn) == 0)
X	    return 1;
X
X    /* nope, must be file name arguments */
X    return 0;
X}
X
X/* Read from standard input, turning */
X/* on prompting if necessary. */
int dostdin()
X{
X    int ret;
X    OnATty = isatty(0);
X    if (OnATty || Interactive)
X	{
X	(void) printf("Type `help' or `?' for help\n");
X	prompt();
X	}
X
X    yyin = stdin;
X    ret = yyparse();
X    OnATty = 0;
X    return ret;
X}
X
X/* Write the arguments into a file */
X/* and treat that file as the input. */
int dotmpfile(argc, argv)
int argc;
char **argv;
X{
X    int ret = 0;
X    FILE *tmpfp = tmpfile();
X    if (!tmpfp)
X	{
X	int sverrno = errno;
X	(void) fprintf (stderr, "%s: cannot open temp file\n",
X	    progname);
X	errno = sverrno;
X	perror(progname);
X	return 1;
X	}
X
X    if (KeywordName)
X	if (fputs(progname, tmpfp) == EOF)
X	    {
X	    int sverrno;
X	errwrite:
X	    sverrno = errno;
X	    (void) fprintf (stderr, "%s: error writing to temp file\n",
X		progname);
X	    errno = sverrno;
X	    perror(progname);
X	    (void) fclose(tmpfp);
X	    rmtmpfile();
X	    return 1;
X	    }
X
X    for ( ; optind < argc; optind++)
X	if (fprintf(tmpfp, " %s", argv[optind]) == EOF)
X	    goto errwrite;
X
X    if (putc('\n', tmpfp) == EOF)
X	goto errwrite;
X
X    rewind(tmpfp);
X    yyin = tmpfp;
X    ret += yyparse();
X    (void) fclose(tmpfp);
X    rmtmpfile();
X
X    return ret;
X}
X
X/* Read each of the named files for input. */
int dofileargs(argc, argv)
int argc;
char **argv;
X{
X    FILE *ifp;
X    int ret = 0;
X
X    for ( ; optind < argc; optind++)
X	if (strcmp(argv[optind], "-") == 0)
X	    ret += dostdin();
X
X	else if ((ifp = fopen(argv[optind], "r")) == NULL)
X	    {
X	    int sverrno = errno;
X	    (void) fprintf (stderr, "%s: cannot open %s\n",
X		progname, argv[optind]);
X	    errno = sverrno;
X	    perror(argv[optind]);
X	    ret++;
X	    }
X
X	else
X	    {
X	    yyin = ifp;
X	    ret += yyparse();
X	    }
X
X    return ret;
X}
X
X/* print out a cast */
void docast(name, left, right, type)
char *name, *left, *right, *type;
X{
X    int lenl = strlen(left), lenr = strlen(right);
X
X    if (prev == 'f')
X	    unsupp("Cast into function",
X		    "cast into pointer to function");
X    else if (prev=='A' || prev=='a')
X	    unsupp("Cast into array","cast into pointer");
X    (void) printf("(%s%*s%s)%s\n",
X	    type, lenl+lenr?lenl+1:0,
X	    left, right, name ? name : "expression");
X    free(left);
X    free(right);
X    free(type);
X    if (name)
X        free(name);
X}
X
X/* print out a declaration */
void dodeclare(name, storage, left, right, type)
char *name, *storage, *left, *right, *type;
X{
X    if (prev == 'v')
X	    unsupp("Variable of type void",
X		    "variable of type pointer to void");
X
X    if (*storage == 'r')
X	switch (prev)
X	    {
X	    case 'f': unsupp("Register function", NullCP); break;
X	    case 'A':
X	    case 'a': unsupp("Register array", NullCP); break;
X	    case 's': unsupp("Register struct/class", NullCP); break;
X	    }
X
X    if (*storage)
X        (void) printf("%s ", storage);
X    (void) printf("%s %s%s%s",
X        type, left,
X	name ? name : (prev == 'f') ? "f" : "var", right);
X    if (MkProgramFlag) {
X	    if ((prev == 'f') && (*storage != 'e'))
X		    (void) printf(" { }\n");
X	    else
X		    (void) printf(";\n");
X    } else {
X	    (void) printf("\n");
X    }
X    free(storage);
X    free(left);
X    free(right);
X    free(type);
X    if (name)
X        free(name);
X}
X
void dodexplain(storage, constvol, type, decl)
char *storage, *constvol, *type, *decl;
X{
X    if (type && (strcmp(type, "void") == 0))
X	if (prev == 'n')
X	    unsupp("Variable of type void",
X		   "variable of type pointer to void");
X	else if (prev == 'a')
X	    unsupp("array of type void",
X		   "array of type pointer to void");
X	else if (prev == 'r')
X	    unsupp("reference to type void",
X		   "pointer to void");
X
X    if (*storage == 'r')
X	switch (prev)
X	    {
X	    case 'f': unsupp("Register function", NullCP); break;
X	    case 'A':
X	    case 'a': unsupp("Register array", NullCP); break;
X	    case 's': unsupp("Register struct/union/enum/class", NullCP); break;
X	    }
X
X    (void) printf("declare %s as ", savedname);
X    if (*storage)
X        (void) printf("%s ", storage);
X    (void) printf("%s", decl);
X    if (*constvol)
X	    (void) printf("%s ", constvol);
X    (void) printf("%s\n", type ? type : "int");
X}
X
void docexplain(constvol, type, cast, name)
char *constvol, *type, *cast, *name;
X{
X    if (strcmp(type, "void") == 0)
X	if (prev == 'a')
X	    unsupp("array of type void",
X		   "array of type pointer to void");
X	else if (prev == 'r')
X	    unsupp("reference to type void",
X		   "pointer to void");
X    (void) printf("cast %s into %s", name, cast);
X    if (strlen(constvol) > 0)
X	    (void) printf("%s ", constvol);
X    (void) printf("%s\n",type);
X}
X
X/* Do the appropriate things for the "set" command. */
void doset(opt)
char *opt;
X{
X    if (strcmp(opt, "create") == 0)
X	{ MkProgramFlag = 1; }
X    else if (strcmp(opt, "nocreate") == 0)
X	{ MkProgramFlag = 0; }
X    else if (strcmp(opt, "interactive") == 0)
X	{ Interactive = 1; }
X    else if (strcmp(opt, "nointeractive") == 0)
X	{ Interactive = 0; OnATty = 0; }
X    else if (strcmp(opt, "ritchie") == 0)
X	{ CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; }
X    else if (strcmp(opt, "preansi") == 0)
X	{ CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; }
X    else if (strcmp(opt, "ansi") == 0)
X	{ CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; }
X    else if (strcmp(opt, "cplusplus") == 0)
X	{ CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; }
X#ifdef dodebug
X    else if (strcmp(opt, "debug") == 0)
X	{ DebugFlag = 1; }
X    else if (strcmp(opt, "nodebug") == 0)
X	{ DebugFlag = 0; }
X#endif /* dodebug */
X#ifdef doyydebug
X    else if (strcmp(opt, "yydebug") == 0)
X	{ yydebug = 1; }
X    else if (strcmp(opt, "noyydebug") == 0)
X	{ yydebug = 0; }
X#endif /* doyydebug */
X    else
X	{
X	if ((strcmp(opt, unknown_name) != 0) &&
X	    (strcmp(opt, "options") != 0))
X	    (void) printf("Unknown set option: '%s'\n", opt);
X
X	(void) printf("Valid set options (and command line equivalents) are:\n");
X	(void) printf("\toptions\n");
X	(void) printf("\tcreate (-c), nocreate\n");
X	(void) printf("\tinteractive (-i), nointeractive\n");
X	(void) printf("\tritchie (-r), preansi (-p), ansi (-a) or cplusplus (-+)\n");
X#ifdef dodebug
X	(void) printf("\tdebug (-d), nodebug\n");
X#endif /* dodebug */
X#ifdef doyydebug
X	(void) printf("\tyydebug (-D), noyydebug\n");
X#endif /* doyydebug */
X
X	(void) printf("\nCurrent set values are:\n");
X	(void) printf("\t%screate\n", MkProgramFlag ? "   " : " no");
X	(void) printf("\t%sinteractive\n",
X	    (OnATty || Interactive) ? "   " : " no");
X	if (RitchieFlag)
X	    (void) printf("\t   ritchie\n");
X	else
X	    (void) printf("\t(noritchie)\n");
X	if (PreANSIFlag)
X	    (void) printf("\t   preansi\n");
X	else
X	    (void) printf("\t(nopreansi)\n");
X	if (!RitchieFlag && !PreANSIFlag && !CplusplusFlag)
X	    (void) printf("\t   ansi\n");
X	else
X	    (void) printf("\t(noansi)\n");
X	if (CplusplusFlag)
X	    (void) printf("\t   cplusplus\n");
X	else
X	    (void) printf("\t(nocplusplus)\n");
X#ifdef dodebug
X	(void) printf("\t%sdebug\n", DebugFlag ? "   " : " no");
X#endif /* dodebug */
X#ifdef doyydebug
X	(void) printf("\t%syydebug\n", yydebug ? "   " : " no");
X#endif /* doyydebug */
X	}
X}
X
void versions()
X{
X    (void) printf("Version:\n\t%s\n\t%s\n\t%s\n",
X	cdeclsccsid, cdgramsccsid, cdlexsccsid);
X    exit(0);
X}
X
int main(argc, argv)
char **argv;
X{
X    int c, ret = 0;
X
X    setprogname(argv[0]);
X#ifdef DOS
X    if (strcmp(progname, "cppdecl") == 0)
X#else
X    if (strcmp(progname, "c++decl") == 0)
X#endif /* DOS */
X	CplusplusFlag = 1;
X
X    while ((c = getopt(argc, argv, "cirpa+dDV")) != EOF)
X	switch (c)
X	    {
X	    case 'c': MkProgramFlag=1; break;
X	    case 'i': Interactive=1; break;
X
X	    /* The following are mutually exclusive. */
X	    /* Only the last one set prevails. */
X	    case 'r': CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; break;
X	    case 'p': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; break;
X	    case 'a': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; break;
X	    case '+': CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; break;
X
X#ifdef dodebug
X	    case 'd': DebugFlag=1; break;
X#endif /* dodebug */
X#ifdef doyydebug
X	    case 'D': yydebug=1; break;
X#endif /* doyydebug */
X	    case 'V': versions(); break;
X	    case '?': usage(); break;
X	    }
X
X    /* Run down the list of arguments, parsing each one. */
X
X    /* Use standard input if no file names or "-" is found. */
X    if (optind == argc)
X	ret += dostdin();
X
X    /* If called as explain, declare or cast, or first */
X    /* argument is one of those, use the command line */
X    /* as the input. */
X    else if (namedkeyword(argv[optind]))
X	ret += dotmpfile(argc, argv);
X
X    else
X	ret += dofileargs(argc, argv);
X
X    exit(ret);
X    /* NOTREACHED */
X}
END_OF_FILE
if test 25555 -ne `wc -c <'cdecl.c'`; then
    echo shar: \"'cdecl.c'\" unpacked with wrong size!
fi
# end of 'cdecl.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.