[comp.sources.unix] v11i040: Inline code expander for C, Part02/04

rs@uunet.UU.NET (Rich Salz) (09/16/87)

Submitted-by: seismo!omepd!mcg@uunet.UU.NET
Posting-number: Volume 11, Issue 40
Archive-name: inline/Part02

# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have original permissions).
# This archive contains the following files:
#	./inline.1
#	./inline.h
#	./tokens.h
#	./inline.c
#	./declare.c
#
if `test ! -s ./inline.1`
then
echo "writing ./inline.1"
sed 's/^X//' > ./inline.1 << '\Rogue\Monster\'
X.TH INLINE 1 
X.\" $Header: inline.1,v 1.8 87/06/24 13:21:28 mcg Rel $
X.SH NAME
Xinline \- C preprocessor for inline functions
X.SH SYNOPSIS
X.B inline
X[
X.B \-w
X] [
X.B \-e
X] [
X.B \-s
X] [
X.B \-n
X] [
X.B \-d
X] [
X.B \-2
X] [
X.B \-S [ em
X]
X]
X[ infile ] [ outfile ]
X.SH DESCRIPTION
X.I Inline
Xis a
Xpreprocessor that accepts C language programs
Xcontaining the additional storage-class keyword
X\fBinline\fR applied to function declarations, and
Xgenerates identical C programs that (usually) have the
Xfunctions so marked expanded where they are called.
XInput code lacking the
X.B inline
Xkeyword is output unchanged.
XThus
X.I inline
Xallows C programmers a feature similar to that provided
Xby the C++ language.
XHowever, while the specifications are the same, the
X.I inline
Xprogram works substantially differently from currently
Ximplemented C++ compilers.
XCurrent C++ compilers rewrite
Xinline functions into expressions, thus prohibiting loops in them, but
Xallowing their use in contexts such as control statements of looping
Xconstructs.
X.I Inline
Xnormally
Xreformats
Xinline functions into code concealed in local blocks, adds
Xvariables for parameter and return values, and changes
X.B return
Xstatements into
X.BR goto s.
XThis allows use of all normal C constructs within inlines.
XThis rewriting is appropriate in all contexts except when
Xinline functions are called in the control parts of
X.B for
Xand
X.B while
Xloops, and in a few other cases.
XIn these cases, the C++ style expansion is used, and the procedures are
Xrewritten as expressions when
Xpossible (that is, when they lack loops, switches, and goto's).
X.PP
X.I Inline
Xemits
X.B extern
X(or, optionally,
X.BR static )
Xpredeclarations for
Xinline functions, so that unexpanded instances are compiled correctly,
Xand can be supplied externally.
XAdditionally, options are provided to emit the bodies of any unexpanded
Xfunctions as static procedures at the end of a module, or to emit
Xthe bodies of all inline functions alone, allowing inline functions to
Xbe collected into a library.
X.PP
XIn normal operation,
X.I inline
Xfunctions must be declared before they are used (like C++).
XThe \-2 (two-pass) option relaxes this requirement, at a 30% penalty in
Xprocessing time.
X.PP
XThe following options are provided:
X.IP \-w
Xsupress warning messages about unexpandable instances of inline functions.
X.IP \-e
Xemit predeclarations as
X.BR extern s,
Xand do not dump bodies of unexpanded functions (default).
X.IP \-s
Xemit predeclarations as
X.BR static s,
Xand dump bodies of unexpanded functions.
X.IP \-n
Xemit no predeclarations at all, and do not
Xdump bodies of unexpanded functions.
XThis allows the gathering of
X.B inline
Xfunctions into a library, to resolve unexpanded
Xreferences and any instances where the address
Xof an
X.B inline
Xwas taken.
X.IP \-d
Xdo not emit the main program, only dump the
Xbodies of all inlines (incompatible with \-e, \-s, and \-n).
X.IP \-2
Xprocess the file in two passes.  This allows inline functions to be
Xdeclared after their use.  For this option, standard input is not
Xaccepted.
X.IP \-S
Xemit (on the standard error output) statistics
Xabout the expansion process.
X.IP \-Se
Xemit extended statistics, giving expansion statistics
Xfor each
X.BR inline .
X.IP \-Sm
Xemit statistics about the memory usage of the program (if the program is
Xcompiled to collect these statistics).
X.PP
XIf no input file is specified, the standard input is assumed,
Xand likewise for the standard output.
X.SH BUGS/CAVEATS
X.I Inline
Xdoes not perform predictably when given incorrect C programs.
XIt is easy to test a program that contains inlines with the
Xcommand:
X.sp
X.nf
X.na
X	cc -c -Dinline=static file.c
X.fi
X.ad
X.PP
XWhen multiple inline functions are present in a single expression,
Xthe order in which the functions are executed in the inline code
Xis sometimes different from the order in which they would have been
Xcalled had they not been expanded.
XIn particular, all functions in the expression will be evaluated,
Xleft-to-right, before the operations in the expression are performed.
XThis is correct for most C operators,
X.I except
Xthe comma, boolean-or (||), and boolean-and (&&) operators.
XInline handles all but the comma operator correctly, expressionizing
Xcalls on the right side of the conditional operators.
X.PP
XWhile
X.I inline
Xattempts to pass preprocessor defines through without change,
Xit is strongly suggested that
X.I inline
Xbe executed
Xon code that has already been processed by
Xthe C preprocessor /lib/cpp.
X.PP
X.I Inline
Xdoes not recognize certain degenerate cases of function declarations
Xand calls, in particular:
X.sp
X.nf
X.na
X	(foo)(arg);
X.fi
X.ad
X.I Inline
Xalso does not correctly handle inline functions which take the address of
Xlabels, or which use labels other than in \fBgoto\fR statements, both
Xextremely distasteful (and probably illegal) practices.
X.SH "SEE ALSO"
Xcc(1), cpp(1)
X.SH NOTE
X.I Inline
Xsource code
Xis Copyright, 1986, 1987 by S. McGeady, all rights reserved.
X.br
XThe binaries for the VAX version of this program and this manual page are
Xin the public domain.
X.SH AUTHOR
XS. McGeady
X.br
X3714 SE 26th Ave.
X.br
XPortland, OR 97202
X.br
X(503) 235-2462
\Rogue\Monster\
else
  echo "will not over write ./inline.1"
fi
chmod 444 ./inline.1
if [ `wc -c ./inline.1 | awk '{printf $1}'` -ne 5093 ]
then
echo `wc -c ./inline.1 | awk '{print "Got " $1 ", Expected " 5093}'`
fi
if `test ! -s ./inline.h`
then
echo "writing ./inline.h"
sed 's/^X//' > ./inline.h << '\Rogue\Monster\'
X/*
X * inline code expander
X *
X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved
X */
X
X/* $Header: inline.h,v 1.13 87/06/18 15:27:08 mcg Rel $ */
X
X
X#include <stdio.h>
X
X#define	NFORMALS	30	/* max number of formal params */
X#define	NINLINE		400	/* max number of inline decl's */
X#define	NEXPAND		20	/* max number of expansions per stmt */
X#define	NTYPEDEF	50	/* max number of typedefs per scope */
X#define	NSCOPE		20	/* max scoping depth */
X#define	NLOCALS		200	/* max # of local vars */
X
X#define	NIL		((char *) 0)
X#define	NILP(t)		((t) 0)
X#define	NILTOK		NILP(struct token *)
X
X/* token flags */
X
X#define	TNOEXPAND	0x01
X#define	TNEEDEXPR	0x02
X#define	TAUTO		0x04	/* an auto identifier */
X#define	TINLINE		0x10
X
Xstruct token {
X	int	t_tok;		/* token type */
X	short	t_flags;	/* flag word */
X	short	t_num;		/* number for id expansion */
X	short	t_level;	/* brace level */
X	short	t_paren;	/* paren level */
X	int	t_line;		/* line this token occured on */
X	char	*t_id;		/* identifier of this token, if any */
X	struct token *t_next;	/* next token in this list */
X};
X
Xstruct toklist {
X	struct token *tl_head;	/* pointer to head token */
X	struct token *tl_tail;	/* pointer to last token in the list */
X};
X
X#define	SDECL		0	/* declaration */
X#define	SFORMAL		1	/* formal list */
X#define	SOPARAMDECL	2	/* old-style param declaration */
X#define	SBODY		3	/* body */
X#define	SDECLBODY	4	/* declaration of formals & return */
X#define	SEXPRDECL	5	/* expression form declarations */
X#define	SEXPRBODY	6	/* expression form body */
X#define	NSTATES		7
X
X/*
X * flags
X */
X
X#define	NEEDRETVAL	1
X
X/*
X * formal info
X */
X
X#define	I_LVALUE	1	/* formal is used as an lvalue */
X#define	I_SUB_OK	2	/* ok to substitute an actual here */
X#define	I_EXPR		4	/* successfully rewrote as an expression */
X
Xstruct inline_node {
X	char	 	*i_id;			/* ptr to identifier token */
X	struct toklist	i_text;			/* saved text of original */
X	struct toklist	i_tl[NSTATES];		/* token lists for sections */
X	char		*i_formals[NFORMALS];	/* list of formals */
X	int		i_formalinfo[NFORMALS];	/* info about formals */
X	int		i_flags;		/* misc flags */
X	int		i_nformals;		/* number of formals */
X	int		i_storclass;		/* storage class of inline */
X	int		i_line;			/* line number */
X	int		i_mem;			/* memory pool for storage */
X	int		i_exprmem;		/* pool for expression store */
X	int		i_nseen;		/* # of calls seen */
X	int		i_nexpand;		/* # of calls expanded */
X};
X
X
Xstruct expand_node {
X	struct inline_node *e_node; /* ptr to inline node for this expansion */
X	int		e_multiple; /* more than one call to this inline */
X	struct toklist	e_actuals[NFORMALS]; /* actuals for this call */
X	int		e_nactuals; /* number of actuals */
X};
X
Xstruct typelist {
X	char type_mem;
X	char *type_id[NTYPEDEF];
X};
X
Xstruct locallist {
X	char	*l_id;
X	long	l_scopes;
X};
X
Xextern int line;
Xextern int debug;
Xextern int errs;
Xextern int nowarn;
Xextern int forward_decl;
Xextern char *myname;
Xextern char *infile;
Xextern char *outfile;
Xextern struct typelist *typeid[];
X
Xextern struct token *gettok();
Xextern struct inline_node *isinline();
Xextern struct inline_node *mknode();
X
X/* token manipulation routines */
Xextern struct token *skipws();
Xextern struct token *newtok();
Xextern struct token *duptok();
Xextern struct token *instok();
X
X/* miscellany */
Xextern char *itoa();
Xextern char *mkstr();
Xextern char *MALLOC();
Xextern char *getmem();
X
Xextern struct inline_node *nodelist[];
\Rogue\Monster\
else
  echo "will not over write ./inline.h"
fi
chmod 444 ./inline.h
if [ `wc -c ./inline.h | awk '{printf $1}'` -ne 3395 ]
then
echo `wc -c ./inline.h | awk '{print "Got " $1 ", Expected " 3395}'`
fi
if `test ! -s ./tokens.h`
then
echo "writing ./tokens.h"
sed 's/^X//' > ./tokens.h << '\Rogue\Monster\'
X
X/* $Header: tokens.h,v 1.5 87/06/24 13:11:37 mcg Rel $ */
X
X
X#define	T_EOT		0
X
X/*
X * reserved words
X */
X
X#define T_AUTO		1	/* auto */
X#define T_BREAK		2	/* break */
X#define T_CASE		3	/* case */
X#define T_CHAR		4	/* char */
X#define T_CONST		5	/* const */
X#define T_CONTINUE	6	/* continue */
X#define T_DEFAULT	7	/* default */
X#define T_DO		8	/* do */
X#define T_DOUBLE	9	/* double */
X#define T_ELSE		10
X#define T_ENUM		11
X#define T_EXTERN	12
X#define T_FLOAT		13
X#define T_FOR		14
X#define T_GOTO		15
X#define T_IF		16
X#define T_INT		17
X#define T_LONG		18
X#define T_REGISTER	19
X#define T_RETURN	20
X#define T_SHORT		21
X#define T_SIGNED	22
X#define T_SIZEOF	23
X#define T_STATIC	24
X#define T_STRUCT	25
X#define T_SWITCH	26
X#define T_TYPEDEF	27
X#define T_UNION		28
X#define T_UNSIGNED	29
X#define T_VOID		30
X#define T_VOLATILE	31
X#define T_WHILE		32
X
X
X#define T_ELLIPSES	33	/* ... */
X#define T_EQ		34	/* = */
X#define T_COMMA		35	/* , */
X#define T_LBRACE	36	/* { */
X#define T_RBRACE	37	/* } */
X#define T_SEMIC		38	/* ; */
X#define T_RS_EQ		39	/* <<= */
X#define T_LS_EQ		40	/* >>= */
X#define T_ADD_EQ	41	/* += */	
X#define T_SUB_EQ	42	/* -= */
X#define T_MUL_EQ	43	/* *= */
X#define T_DIV_EQ	44	/* /= */
X#define T_MOD_EQ	45	/* %= */
X#define T_AND_EQ	46	/* &= */
X#define T_XOR_EQ	47	/* ^= */
X#define T_OR_EQ		48	/* |= */
X#define T_RS 		49	/* >> */
X#define T_LS		50	/* << */
X#define T_INC		51	/* ++ */
X#define T_DEC		52	/* -- */
X#define T_PTR 		53	/* -> */
X#define T_CAND 		54	/* && */
X#define T_COR		55	/* || */
X#define T_LE 		56	/* <= */
X#define T_GE 		57	/* >= */
X#define T_CEQ		58	/* == */
X#define T_NE 		59	/* != */
X#define	T_COLON		60	/* : */
X				/* 61 missing */
X#define	T_LPAREN	62	/* ( */
X#define	T_RPAREN	63	/* ) */
X#define	T_LSQ		64	/* [ */
X#define	T_RSQ		65	/* ] */
X#define	T_DOT		66	/* . */
X#define	T_AMPER		67	/* & */
X#define	T_NOT		68	/* ! */
X#define	T_TILDE		69	/* ~ */
X#define	T_MINUS		70	/* - */
X#define	T_PLUS		71	/* + */
X#define	T_STAR		72	/* * */
X#define	T_DIV		73	/* / */
X#define	T_MOD		74	/* % */
X#define	T_LT		75	/* < */
X#define	T_GT		76	/* > */
X#define T_XOR		77	/* ^ */
X#define	T_OR		78	/* | */
X#define	T_QUEST		79	/* ? */
X
X#define T_INLINE	80	/* the 'inline' keyword */
X#define T_IDENT		81	/* an identifier */
X#define	T_TYPE_ID	82	/* a type identifier */
X#define T_WS		83	/* whitespace and comments */
X#define	T_NUM		84	/* a constant */
X#define	T_STR		85	/* string */
X#define	T_CPP		86	/* a preprocessor-style '#' line */
X#define	T_CHARCONST	87	/* a character constant */
X#define	T_COMMENT	88	/* a comment */
X#define	T_STRTAG	89	/* a structure or union tag */
X#define	T_LABEL		90	/* a label */
X
X#define T_ACTUAL	91	/* an actual parameter */
X#define T_RETVAL	92
X#define	T_ARGLIST	93	/* a substitutable argument list */
X#define	T_RETLAB	94
X#define	T_FORMAL	95
\Rogue\Monster\
else
  echo "will not over write ./tokens.h"
fi
chmod 444 ./tokens.h
if [ `wc -c ./tokens.h | awk '{printf $1}'` -ne 2763 ]
then
echo `wc -c ./tokens.h | awk '{print "Got " $1 ", Expected " 2763}'`
fi
if `test ! -s ./inline.c`
then
echo "writing ./inline.c"
sed 's/^X//' > ./inline.c << '\Rogue\Monster\'
X/*
X * inline substituter for C
X *
X * s. mcgeady - 10/25/86
X */
X
X/*
X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved
X */
X
X/* $Header: inline.c,v 1.20 87/06/24 13:11:30 mcg Rel $ */
X
X#include <stdio.h>
X#include "tokens.h"
X#include "inline.h"
X
X#define	strrchr rindex
Xextern char *strrchr();
X
X#define	LOGFILE	"/c/mcg/.inline_use"
X
X/*
X * global data declarations
X */
X
Xstruct typelist *typeid[NSCOPE];
X
Xstatic struct locallist locals[NLOCALS];
Xstatic int expanded = 0;
X
Xstruct inline_node *nodelist[NINLINE] = {0};
X
Xint forward_decl = T_EXTERN;
Xchar *myname;
Xchar *infile = NIL;
Xchar *outfile = NIL;
Xint debug = 0;
Xint stats = 0;
Xint mstats = 0;
Xint dumpinline = 0;
Xint noexpand = 0;
Xint errs = 0;
Xint nowarn = 0;
Xint twopass = 0;
Xint pass = 0;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	register int mem;
X	struct toklist prog;
X	register int r;
X
X#ifdef LOGFILE
X	logusage(argc,argv);
X#endif
X	if (!(myname = strrchr(argv[0],'/'))) {
X		myname = argv[0];
X	} else {
X		myname++;
X	}
X
X	while (--argc) {
X		++argv;
X		if ((*argv)[0] == '-') {
X			switch((*argv)[1]) {
X			case 'w':	/* supress warnings */
X				nowarn++;
X				break;
X			case 'x':	/* debug */
X				debug++;
X				if ((*argv)[2] != '\0') {
X					debug = (*argv)[2] - '0';
X				}
X				break;
X			case 'S':	/* stats */
X				stats = 1;
X				for (r = 2; (*argv)[r] != '\0'; r++) {
X					switch((*argv)[r]) {
X					case 'e':	/* expansion stats */
X						stats++;
X						break;
X					case 'm':	/* memory stats */
X						mstats++;
X						break;
X					}
X				}
X				break;
X			case 'e':	/* externals */
X				dumpinline = 0;
X				break;
X			case 's':	/* static */
X				forward_decl = T_STATIC;
X				dumpinline = 1;
X				break;
X			case 'n':	/* none */
X				dumpinline = 0;
X				forward_decl = 0;
X				break;
X			case 'd':	/* dump inlines */
X				noexpand++;
X				forward_decl = 0;
X				dumpinline = 2;
X				break;
X
X			case '2':
X				twopass++;
X				break;
X
X			default:
X				error(0,"bad switch %s", *argv);
X				break;
X			}
X		} else {	/* a filename */
X			if (!infile) {
X				infile = *argv;
X				if (!freopen(infile,"r",stdin)) {
X					error(0,"cannot open %s", *argv);
X					exit(1);
X				}
X			} else if (!outfile) {
X				outfile = *argv;
X				if (!freopen(outfile,"w",stdout)) {
X					error(0,"cannot create %s", *argv);
X					exit(1);
X				}
X			} else {
X				error(0,"usage: %s [flags] [infile] [outfile]", myname);
X				exit(1);
X			}
X		}
X	}
X
X	if (twopass) {
X		if (dumpinline == 2) {
X			warn(0, "two pass operations nonsensical with -d - twopass disabled");
X			twopass = 0;
X		}
X		if (infile == NIL) {
X			error(0, "two pass operation requires a named input file");
X			exit(1);
X		}
X	}
X	pushscope(0);
X	while(1) {
X		mem = openpool();
X		expanded = 0;
X		prog.tl_head = prog.tl_tail = NILTOK;
X		r = doproc(mem,&prog);
X		if (!noexpand || r >= 0)
X			prtoklist(&prog,expanded,stdout);
X		(void) closepool(mem);
X		if (r == 0) {	/* end of file */
X			if (twopass && (pass == 0)) {
X				fclose(stdin);
X				popscope(0);
X				pushscope(0);
X				if (!freopen(infile,"r",stdin)) {
X					error(0,"cannot reopen %s", infile);
X					exit(1);
X				}
X				pass = 1;
X				continue;
X			}
X			break;
X		}
X	}
X	if (dumpinline) {
X		dump(dumpinline);
X	}
X	/* print memory allocator stats */
X	if (mstats) {
X		memstats();
X	}
X	if (stats) {
X		prstats(stats);
X	}
X	return(errs);
X}
X
X/*
X * handle a procedure - return 0 on EOF
X */
X
Xdoproc(mem,prog)
Xregister int mem;
Xstruct toklist *prog;
X{
X	register struct token *tok = NILTOK;
X	register struct token *last = NILTOK;/* last **non-whitespace** token */
X	register struct token *savtok = NILTOK;
X	register struct token *decltok = NILTOK;
X	register int state = 0;
X	register int inlined = 0;
X	int seenquest = 0;
X	int seengoto = 0;
X	int scope = 0;
X	int i;
X
X#define	STYPEDEF	1		/* a typedef declaration */
X#define	SSTRUCTDECL	2		/* a structure declaration */
X#define	SSTRUCTTAG	3		/* as above, but have seen struct tag */
X#define	SSTRUCTBODY	4		/* in the structure body */
X#define	SSTRUCTREF	5		/* saw a "." or "->" */
X
X	clearlocals();
X
X	while((tok && tok->t_tok != T_WS ? last = tok: 0), tok = gettok(mem)) {
X
X		addtok(prog,tok);
X
X		switch(tok->t_tok) {
X		case T_WS:
X			continue;
X
X		case T_QUEST:
X			seenquest++;
X			continue;
X
X		case T_COLON:
X			if (!seenquest && (last->t_tok == T_IDENT)) {
X				/* a label */
X				last->t_tok = T_LABEL;
X			}
X			if (seenquest) seenquest--;
X			continue;
X
X		case T_GOTO:
X			seengoto++;
X			continue;
X
X		case T_SEMIC:
X			seengoto = 0;
X			if (state == STYPEDEF) {
X				if (tok->t_level <= savtok->t_level) {
X					dotypedef(savtok);
X					state = 0;
X					decltok = savtok = NILTOK;
X				}
X				continue;
X			}
X			if (state == SSTRUCTBODY && (tok->t_level > savtok->t_level)) {
X				continue;
X			}
X			if (state) {
X				state = 0;
X			}
X			if (tok->t_level > 0 && decltok &&
X			    decltok->t_tok != T_EXTERN) {
X				/* a declaration line */
X				if (!twopass || ((pass == 0) && inlined) || ((pass == 1) && !inlined)) {
X					dolocals(mem,decltok,tok,inlined);
X				}
X			}
X			decltok = NILTOK;
X
X			continue;
X
X		case T_LBRACE:
X			scope++;
X			if (state == SSTRUCTDECL || state == SSTRUCTTAG) {
X				state = SSTRUCTBODY;
X				continue;
X			}
X			if (state) {	/* typedef or struct body */
X				continue;
X			}
X			if (scope-1 == 0) {
X				if (!inlined && !(twopass && (pass == 0)))
X					doargs(mem,prog->tl_head,tok);
X				decltok = NILTOK;
X			}
X			continue;
X
X		case T_RBRACE:
X			scope--;
X			if (state == SSTRUCTBODY) {
X				if (tok->t_level <= savtok->t_level) {
X					state = 0;
X					decltok = savtok;
X					savtok = NILTOK;
X				}
X				continue;
X			}
X			if (scope != 0) {
X				clearscope(scope);
X				continue;
X			}
X			if (!state) {
X				if (isdecl(prog)) {
X					if (twopass && pass == 1) {
X						/* NIL it out */
X						prog->tl_head = prog->tl_tail = NILTOK;
X					} else {
X						dodecl(prog,dumpinline);
X					}
X				} else if (!noexpand) {
X					if (twopass && (pass == 0)) {
X						prog->tl_head = prog->tl_tail = NILTOK;
X					} else {
X						expanded += doinline(mem,prog);
X					}
X				}
X			}
X			clearlocals();
X			/* this is the only way out of doproc() except EOF */
X			break;
X
X		case T_INLINE:
X			inlined++;
X			continue;
X
X		case T_TYPEDEF:
X			savtok = tok;
X			state = STYPEDEF;
X			continue;
X
X		case T_STRUCT:
X		case T_UNION:
X			savtok = tok;
X			if (tok->t_level > 0) {
X				decltok = savtok;
X			}
X			state = SSTRUCTDECL;
X			continue;
X
X		case T_DOT:
X		case T_PTR:
X			state = SSTRUCTREF;
X			continue;
X
X		case T_IDENT:
X			switch(state) {
X			case SSTRUCTBODY:
X			case STYPEDEF:
X			case SSTRUCTTAG:
X				continue;
X
X			case SSTRUCTREF:
X				state = 0;
X				continue;
X
X			case SSTRUCTDECL:
X				tok->t_tok = T_STRTAG;
X				state = SSTRUCTTAG;
X				continue;
X			}
X			if (seengoto) {
X				tok->t_tok = T_LABEL;
X				continue;
X			}
X			if (scope > 0 && !decltok && islocal(tok->t_id,scope)) {
X				tok->t_flags |= TAUTO;
X				if (inlined) {
X					tok->t_flags |= TINLINE;
X					tok->t_num = deflevel(tok->t_id,scope);
X				}
X			}
X			continue;
X
X		default:
X			if (state == SSTRUCTBODY || state == STYPEDEF) {
X				continue;
X			}
X			if (tok->t_level > 0 && !decltok &&
X			    (istype(tok) || isstoreclass(tok)) && 
X			    (last->t_tok == T_SEMIC || last->t_tok == T_LBRACE)) {
X		
X				decltok = tok;
X			}
X			continue;
X		}
X
X		break;
X	}
X	if (!tok) return(0);
X	return(1);
X}
X
Xdoargs(mem,begin,end)
Xint mem;
Xregister struct token *begin, *end;
X{
X	register struct token *tp = begin;
X
X	/* first find an identifier */
X	while(tp && tp->t_tok != T_IDENT) {
X		tp = tp->t_next;
X	}
X	if (!tp) return;
X
X	/* then find level 0 left paren */
X	while(tp && (tp->t_tok != T_LPAREN || tp->t_paren > 0)) {
X		tp = tp->t_next;
X	}
X	if (!tp) return;
X
X	for ( ; tp && tp != end; tp = tp->t_next) {
X		if ((tp->t_tok == T_IDENT) && (tp->t_level >= begin->t_level)) {
X			if (addlocal(tp->t_id,1) < 0) {
X				error(tp->t_line, "too many local variables");
X			} else {
X				tp->t_flags |= TAUTO;
X			}
X		}
X	}
X}
X
Xdolocals(mem,begin,end,inlined)
Xint mem;
Xregister struct token *begin, *end;
Xint inlined;
X{
X	register int skip = 0;
X	register struct token *tp;
X	register int i;
X
X	for (tp = begin->t_next; tp && tp != end; tp = tp->t_next) {
X		if (skip) {
X			if (tp->t_tok == T_SEMIC ||
X			    (tp->t_tok == T_COMMA &&
X			    (tp->t_paren <= skip-1))) {
X				skip = 0;
X			} else if ((tp->t_tok == T_IDENT) &&
X				   islocal(tp->t_id,tp->t_level)) {
X				tp->t_flags |= TAUTO;
X				if (inlined) {
X					tp->t_num = deflevel(tp->t_id,tp->t_level);
X					tp->t_flags |= TINLINE;
X				}
X			}
X			continue;
X		}
X		if (tp->t_tok == T_EQ) {
X			skip = tp->t_paren+1;
X			continue;
X		} else if ((tp->t_tok == T_IDENT) &&
X			   (tp->t_level >= begin->t_level)) {
X
X			if (addlocal(tp->t_id,tp->t_level) < 0) {
X				error(tp->t_line, "too many local variables");
X				continue;
X			}
X			tp->t_flags |= TAUTO;
X			if (inlined) {
X				tp->t_flags |= TINLINE;
X				tp->t_num = tp->t_level;
X			}
X		}
X	}
X}
X
Xstatic int scopemask[] = {
X		0x0001,		/* scope 1 */
X		0x0003,		/* scope 2 */
X		0x0007,		/* scope 3 */
X		0x000f,		/* scope 4 */
X		0x001f,		/* scope 5 */
X		0x003f,		/* scope 6 */
X		0x007f,		/* scope 7 */
X		0x00ff,		/* scope 8 */
X		0x01ff,		/* scope 9 */
X		0x03ff,		/* scope 10 */
X		0x07ff,		/* scope 11 */
X		0x0fff,		/* scope 12 */
X		0x1fff,		/* scope 13 */
X		0x3fff,		/* scope 14 */
X		0x7fff,		/* scope 15 */
X		0xffff,		/* scope 16 */
X		0x1ffff,	/* scope 17 */
X		0x3ffff,	/* scope 18 */
X		0x7ffff,	/* scope 19 */
X		0xfffff		/* scope 20 */
X};
X
X
X
Xaddlocal(s,scope)
Xregister char *s;
Xregister int scope;
X{
X	register struct locallist *p;
X	register char *rs;
X	register int i = 0;
X
X	if (scope > NSCOPE) return(-1);
X
X	for (rs = s; *rs != '\0'; i += *rs++)
X		;
X
X	i %= NLOCALS;
X
X	for (p = &locals[i]; p >= locals; p--) {
X		if (p->l_id == NIL) {
X			p->l_id = s;
X			p->l_scopes |= (1<<(scope-1));
X			return(0);
X		} else if (strcmp(s,p->l_id) == 0) {
X			p->l_scopes |= (1<<(scope-1));
X			return(1);
X		}
X	}
X	for (p = &locals[i+1]; p < &locals[NLOCALS]; p++) {
X		if (p->l_id == NIL) {
X			p->l_id = s;
X			p->l_scopes |= (1<<(scope-1));
X			return(0);
X		} else if (strcmp(s,p->l_id) == 0) {
X			p->l_scopes |= (1<<(scope-1));
X			return(1);
X		}
X	}
X	return(-1);
X}
X
Xislocal(s,scope)
Xregister char *s;
Xregister int scope;
X{
X	register struct locallist *p;
X	register char *rs;
X	register int i = 0;
X
X	for (rs = s; *rs != '\0'; i += *rs++)
X		;
X
X	i %= NLOCALS;
X
X	for (p = &locals[i]; p >= locals; p--) {
X		if (p->l_id == NIL) {
X			return(0);
X		} else if ((strcmp(s,p->l_id) == 0) &&
X			    p->l_scopes&scopemask[scope-1]) {
X			return(1);
X		}
X	}
X	for (p = &locals[i+1]; p < &locals[NLOCALS]; p++) {
X		if (p->l_id == NIL) {
X			return(0);
X		} else if ((strcmp(s,p->l_id) == 0) &&
X			   p->l_scopes&scopemask[scope-1]) {
X			return(1);
X		}
X	}
X	return(0);
X}
X
X
Xdeflevel(s,scope)
Xregister char *s;
Xregister int scope;
X{
X	register struct locallist *p;
X	register char *rs;
X	register int i = 0;
X
X	for (rs = s; *rs != '\0'; i += *rs++)
X		;
X
X	i %= NLOCALS;
X
X	for (p = &locals[i]; p >= locals; p--) {
X		if (p->l_id == NIL) {
X			return(0);
X		} else if ((strcmp(s,p->l_id) == 0) &&
X			    p->l_scopes&scopemask[scope-1]) {
X			goto end;
X		}
X	}
X	for (p = &locals[i+1]; p < &locals[NLOCALS]; p++) {
X		if (p->l_id == NIL) {
X			return(0);
X		} else if ((strcmp(s,p->l_id) == 0) &&
X			   p->l_scopes&scopemask[scope-1]) {
X			goto end;
X		}
X	}
X	return(0);
X
X    end:
X	if (scope < 1 || scope > NSCOPE) {
X		return(0);
X	}
X	for (i = scope-1; i >= 0; i--) {
X		if (p->l_scopes&(1<<i)) {
X			return(i+1);
X		}
X	}
X	return(0);
X}
X
Xclearlocals() {
X	register int i;
X
X	for (i = 0; i < NLOCALS; i++) {
X		locals[i].l_id = NIL;
X		locals[i].l_scopes = 0;
X	}
X}
X
Xclearscope(scope)
Xregister int scope;
X{
X	register int i;
X
X	for (i = 0; i < NLOCALS; i++) {
X		if (locals[i].l_id != NIL) {
X			locals[i].l_scopes &= scopemask[scope-1];
X		}
X	}
X}
X
Xstruct inline_node *
Xisinline(id)
Xregister char *id;
X{
X	register int i;
X
X	for(i=0; (i < NINLINE) && (nodelist[i] != NILP(struct inline_node *)); i++) {
X		if (nodelist[i]->i_id && strcmp(nodelist[i]->i_id, id) == 0) {
X			return(nodelist[i]);
X		}
X	}
X	return((struct inline_node *) 0);
X}
X
X
Xpushscope(level)
X{
X	register int mem;
X	register int i;
X
X	if (level >= NSCOPE) {
X		error(line, "internal - push of invalid scope level");
X		return;
X	}
X	mem = openpool();
X	typeid[level] = (struct typelist *) getmem(mem,1,sizeof(struct typelist));
X	if (typeid[level] == NILP(struct typelist *)) {
X		error(line, "internal - out of memory");
X		return;
X	}
X	typeid[level]->type_mem = mem;
X	for (i = 0; i < NTYPEDEF; i++) {
X		typeid[level]->type_id[i] = NIL;
X	}
X	return;
X}
X
Xpopscope(level)
X{
X#ifdef notdef
X	if (level == 0) {
X		error(line, "internal - pop of scope 0\n");
X		return;
X	}
X#endif
X	if (level >= NSCOPE) {
X		error(line, "internal - invalid scope depth");
X		return;
X	}
X
X	(void) closepool(typeid[level]->type_mem);
X	typeid[level] = NILP(struct typelist *);
X	return;
X}
X
Xdump(n)
Xint n;
X{
X	register int i;
X	struct token tok;
X
X	if (n < 1) return;
X
X	for (i = 0; (i < NINLINE) && (nodelist[i] != NILP(struct inline_node *)); i++) {
X		if (n > 1 || (nodelist[i]->i_nseen > nodelist[i]->i_nexpand)) {
X			if (nodelist[i]->i_text.tl_head->t_tok == T_INLINE) {
X				nodelist[i]->i_text.tl_head =
X					nodelist[i]->i_text.tl_head->t_next;
X			}
X
X			if (forward_decl) {
X				tok.t_tok = forward_decl;
X				prtok(&tok,0,stdout);
X			}
X			prtoklist(&nodelist[i]->i_text,0,stdout);
X			printf("\n\n");
X		}
X	}
X}
X
X
Xprstats(n)
Xint n;
X{
X	register int i;
X	int nseen = 0;
X	int nnode = 0;
X	int nexpand = 0;
X
X	for(i=0; (i < NINLINE) && (nodelist[i] != NILP(struct inline_node *)); i++) {
X		nnode++;
X		nseen += nodelist[i]->i_nseen;
X		nexpand += nodelist[i]->i_nexpand;
X		if (n > 1) {
X			fprintf(stderr,
X				"inline %s(): %d expansions in %d occurences\n",
X				nodelist[i]->i_id,nodelist[i]->i_nexpand,
X				nodelist[i]->i_nseen);
X		}
X	}
X	fprintf(stderr, "%d nodes, %d expansions in %d occurences\n",
X			nnode, nexpand, nseen);
X}
X
X#ifdef LOGFILE
X
X#include <pwd.h>
Xextern char *ctime();
X
Xlogusage(argc,argv)
Xint argc;
Xchar **argv;
X{
X	FILE *f;
X	struct passwd *pw;
X	char *name, *t;
X	long now;
X
X	if (f = fopen(LOGFILE,"a")) {
X		setpwent();
X		pw = getpwuid(getuid());
X		endpwent();
X		if (pw) {
X			name = pw->pw_name;
X			/* don't log the author */
X			if (strcmp(name,"mcg") == 0) {
X				fclose(f);
X				return;
X			}
X		} else {
X			name = "???";
X		}
X		now = time(0);
X		t = ctime(&now);
X		t[strlen(t)-1] = '\0';
X		t += 4;
X		fprintf(f,"%s [%s]", pw->pw_name, t);
X		if (argc > 1) {
X			fprintf(f," (");
X			while(--argc) {
X				fprintf(f,"%s", *argv);
X				argv++;
X				if (argc) fprintf(f," ");
X			}
X			fprintf(f,")");
X		}
X		fprintf(f,"\n");
X		fclose(f);
X	}
X	return;
X}
X
X#endif
\Rogue\Monster\
else
  echo "will not over write ./inline.c"
fi
chmod 444 ./inline.c
if [ `wc -c ./inline.c | awk '{printf $1}'` -ne 14368 ]
then
echo `wc -c ./inline.c | awk '{print "Got " $1 ", Expected " 14368}'`
fi
if `test ! -s ./declare.c`
then
echo "writing ./declare.c"
sed 's/^X//' > ./declare.c << '\Rogue\Monster\'
X/*
X * inline code expander
X *
X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved
X */
X
X/* $Header: declare.c,v 1.10 87/06/24 13:11:05 mcg Rel $ */
X
X
X/*
X * process the declaration of an inline subroutine
X *
X * this involves storing away the declaration, formal parameter list,
X * formal parameter declarations, and body, and rewriting the body part
X * of the inline by adding formal parameter declarations at the top
X * with initialization templates, and replace return statements with
X * assignments to the return value template and jumps to the end
X * of the block
X */
X
X
X#include "inline.h"
X#include "tokens.h"
X
Xdodecl(list,save)
Xregister struct toklist *list;
Xregister int save;
X{
X	struct inline_node *node;
X	register int state = SDECL;
X	register int nextstate;
X	register struct token *t, *tok, *lasttok;
X	int retstmt = 0;
X	int sawretstmt = 0;
X	int structmember = 0;
X	int seenincdec = 0;
X	int i;
X	int mem;
X
X	/* note that this memory pool is permanent */
X	mem = openpool();	/* a memory pool for this guy */
X
X	node = mknode(mem);	/* no need to ever free this */
X
X	node->i_mem = mem;
X
X	/* add the node to the list */
X	for(i = 0; i < NINLINE; i++) {
X		if (nodelist[i] == NILP(struct inline_node *)) {
X			nodelist[i] = node;
X			break;
X		}
X	}
X	if (nodelist[i] != node){
X		error(list->tl_head->t_line,"too many inline's");
X		return;
X	}
X	state = SDECL;
X	nextstate = -1;
X	node->i_line = line;
X
X	lasttok = NILTOK;
X	for (tok = list->tl_head; tok != NILTOK; tok = tok->t_next) {
X		if (tok->t_tok == T_INLINE) {
X			break;
X		}
X		lasttok = tok;
X	}
X	if (tok == NILTOK) {
X		error(list->tl_head->t_line,"internal error in dodecl()");
X		return;
X	}
X	/* break the inline declaration off from the preceding stream */
X	if (lasttok) {
X		lasttok->t_next = NILTOK;
X	} else {
X		list->tl_head = NILTOK;
X		list->tl_tail = NILTOK;
X	}
X	for ( /* */ ; tok != NILTOK; tok = tok->t_next) {
X		/* put tokens on save list for possible dump later */
X		if (save) {
X			addtok(&node->i_text,duptok(mem,tok));
X		}
X
X		if (nextstate >= 0) {
X			state = nextstate;
X			nextstate = -1;
X		}
X		if ((retstmt == 1) && (tok->t_tok != T_WS) &&
X		    (tok->t_tok != T_SEMIC)) {
X			addtok(&node->i_tl[state], newtok(mem,T_RETVAL,NIL));
X			addtok(&node->i_tl[state], newtok(mem,T_WS," "));
X			addtok(&node->i_tl[state], newtok(mem,T_EQ,NIL));
X			addtok(&node->i_tl[state], newtok(mem,T_WS," "));
X			node->i_flags |= NEEDRETVAL;
X			retstmt++;
X		}
X		switch(tok->t_tok) {
X
X		case T_INLINE:
X			continue;
X
X		case T_LABEL:
X			if (state != SBODY) {
X				error(tok->t_line,"invalid label '%s:'",tok->t_id);
X			}
X			break;
X
X		case T_IDENT:
X			/* an identifier, what state are we in? */
X			if (!structmember) {
X				doident(state, seenincdec, tok, node, mem);
X			}
X			structmember = 0;
X			seenincdec = 0;
X			break;
X
X		case T_INC:	case T_DEC:	
X			seenincdec = 1;
X			break;
X
X		case T_LPAREN:
X			if ((state == SDECL) && (tok->t_paren == 0) &&
X			    (node->i_id != NIL)) {
X				state = SFORMAL;
X			}
X			break;
X
X		case T_RPAREN:
X			if ((state == SFORMAL) && (tok->t_paren == 0)) {
X				nextstate = SOPARAMDECL;
X			}
X			break;
X
X		case T_LBRACE:
X			if ((state == SFORMAL) || (state == SOPARAMDECL)) {
X				doformals(node);
X				state = SBODY;
X				nextstate = -1;
X			} else if (state != SBODY) {
X				error(tok->t_line,"no identifier found after 'inline'");
X
X				/* rewrite node eliminating 'inline' */
X			}
X			seenincdec = 0;
X			break;
X
X		case T_RBRACE:
X			if ((state == SBODY) && (tok->t_level == 0)) {
X				addtok(&node->i_tl[state], duptok(mem,tok));
X				if (sawretstmt) {
X					doretlab(&node->i_tl[state], node->i_id,mem);
X				}
X				/* add the extern or static decl for this */
X				if (forward_decl) {
X					struct toklist fdecl;
X
X					putdecl(node,&fdecl);
X					if (lasttok) {
X						(void) instok(lasttok,fdecl.tl_head);
X					} else {
X						list->tl_head = fdecl.tl_head;
X						list->tl_tail = fdecl.tl_tail;
X					}
X				}
X				node->i_exprmem = openpool();
X				if (rewrite(node,&node->i_tl[SBODY],1) > 0) {
X					node->i_flags |= I_EXPR;
X				} else {
X					closepool(node->i_exprmem);
X					node->i_exprmem = -1;
X				}
X				if (debug) {
X					debugnode(node);	/*DEBUG*/
X				}
X				return;	/* this is the only way out */
X			}
X			seenincdec = 0;
X			break;
X
X		case T_EXTERN:
X		case T_STATIC:
X			if (state == SDECL) {
X				node->i_storclass = tok->t_tok;
X			} else if (state != SBODY) {
X				error(tok->t_line,"illegal parameter declaration");
X			}
X			break;
X
X		case T_ELLIPSES:
X			error(tok->t_line,"inline routines can't be varargs");
X			break;
X
X		case T_RETURN:
X			addtok(&node->i_tl[state], t = newtok(mem,T_LBRACE,NIL));
X			t->t_level = tok->t_level;
X			retstmt = 1;
X			sawretstmt = 1;
X			seenincdec = 0;
X			continue;
X
X		case T_SEMIC:
X			if ((state == SBODY) && retstmt) {
X				doreturn(&node->i_tl[state], node->i_id,mem);
X				retstmt = 0;
X				addtok(&node->i_tl[state], duptok(mem,tok));
X				addtok(&node->i_tl[state], t = newtok(mem,T_RBRACE,NIL));
X				t->t_level = tok->t_level;
X				continue;
X			}
X			seenincdec = 0;
X			break;
X
X		case T_DOT:
X		case T_PTR:
X			structmember++;
X			break;
X
X		default:
X			break;
X		}
X
X		/* add the current token to the appropriate list */
X		addtok(&node->i_tl[state], duptok(mem,tok));
X	}
X	/*NOTREACHED*/
X	/* error(tok->t_line, "internal error in inline declaration"); */
X}
X
Xdoident(state,seenincdec,tok,node, mem)
Xint state, seenincdec;
Xregister struct token *tok;
Xregister struct inline_node *node;
Xint mem;
X{
X	register int i;
X
X	switch(state) {
X	case SDECL:	/* declaration */
X		if (node->i_id != NIL) {
X			error(tok->t_line, "too many identifiers on declaration line");
X			break;
X		}
X		if (isinline(tok->t_id)) {
X			error(tok->t_line, "redeclaration of inline '%s'", tok->t_id);
X			/* break; */
X		}
X		node->i_id = mkstr(mem,tok->t_id,0);
X		tok->t_tok = T_RETVAL;
X		break;
X
X	case SFORMAL:	/* formal parameter */
X		i = node->i_nformals++;
X		tok->t_tok = T_FORMAL;
X		node->i_formals[i] = mkstr(mem,tok->t_id,0);
X		break;
X
X	case SOPARAMDECL: /* old-style param declaration */
X		if (isformal(node,tok) < 0) {
X			error(tok->t_line,"parameter '%s' not in formal list",tok->t_id);
X		} else {
X			tok->t_tok = T_FORMAL;
X		}
X		break;
X	case SBODY:	/* found a formal in the body */
X		/*
X		 * if an identifier in the body matches
X		 * a formal, change it to be new formal name
X		 *
X		 * check to see if the formal is used as
X		 * an lvalue, which prevents various
X		 * optimizations we could otherwise perform 
X		 */
X
X		if ((i = isformal(node,tok)) >= 0) {
X			tok->t_tok = T_FORMAL;
X			if (seenincdec || isassigned(tok)) {
X				node->i_formalinfo[i] |= I_LVALUE;
X			}
X		} else if ((strcmp(node->i_id,tok->t_id) == 0) && iscall(tok)) {
X			error(tok->t_line, "recursive inline expansion");
X		}
X		break;
X	default:	/* somewhere else ?? */
X		break;
X	}
X}
X
X
Xdoreturn(list,id,mem)
Xstruct toklist *list;
Xchar *id;
X{
X	addtok(list, newtok(mem,T_SEMIC, NIL));
X	addtok(list, newtok(mem,T_WS, " "));
X	addtok(list, newtok(mem,T_GOTO, NIL));
X	addtok(list, newtok(mem,T_WS, " "));
X	addtok(list, newtok(mem,T_RETLAB, NIL));
X}
X
Xdoretlab(list,id,mem)
Xstruct toklist *list;
Xchar *id;
Xint mem;
X{
X	addtok(list, newtok(mem,T_WS,"\n"));
X	addtok(list, newtok(mem,T_RETLAB,NIL));
X	addtok(list, newtok(mem,T_COLON,NIL));
X	addtok(list, newtok(mem,T_SEMIC,NIL));
X	addtok(list, newtok(mem,T_WS,"\n"));
X}
X
Xputdecl(node,decl)
Xregister struct inline_node *node;
Xregister struct toklist *decl;
X{
X	register struct token *tl;
X
X	decl->tl_head = decl->tl_tail = NILTOK;
X
X	addtok(decl, newtok(node->i_mem,forward_decl,NIL));
X
X	for(tl = node->i_tl[SDECL].tl_head; tl != NILTOK; tl = tl->t_next) {
X		addtok(decl,duptok(node->i_mem,tl));
X		if (tl->t_tok == T_RETVAL) {
X			decl->tl_tail->t_tok = T_IDENT;
X		}
X	}
X	addtok(decl, newtok(node->i_mem,T_LPAREN,NIL));
X	addtok(decl, newtok(node->i_mem,T_RPAREN,NIL));
X	addtok(decl, newtok(node->i_mem,T_SEMIC,NIL));
X	addtok(decl, newtok(node->i_mem,T_WS, " /* forward decl */\n"));
X}
X
Xisassigned(tok)
Xregister struct token *tok;
X{
X	register struct token *t;
X
X	for (t = tok; t != NILTOK; t = t->t_next) {
X		switch(t->t_tok) {
X
X		case T_LPAREN:	case T_RPAREN:
X		case T_WS:	case T_COMMENT:
X		case T_FORMAL:
X			break;
X
X		case T_EQ:	case T_RS_EQ:	case T_LS_EQ:
X		case T_ADD_EQ:	case T_SUB_EQ:	case T_MUL_EQ:
X		case T_DIV_EQ:	case T_MOD_EQ:	case T_AND_EQ:
X		case T_XOR_EQ:	case T_OR_EQ:
X		case T_INC:	case T_DEC:	
X		case T_DOT:			/* structure, no chances */
X			return(1);
X
X		default:
X			return(0);
X		}
X	}
X	return(0);
X}
X
X/*
X * this is called when we see an opening brace indicating the beginning
X * of the body of a function.  we look through the stored function
X * declaration, build up the formal parameter list, and rewrite the
X * function declaration into a form that can be expanded inline:
X *
X * input:				becomes:
X *
X * old-style:
X *	inline foo() { ...			{ ...
X *
X *	inline foo(a,b,c) { ...			{ int a = T_ACTUAL,
X *						b = T_ACTUAL, c = T_ACTUAL;
X *						...
X *
X *	inline foo(a,b,c,d)			{ int a = T_ACTUAL;
X *	int a; float b; char c,d;		float b = T_ACTUAL
X *	{ ...					char c = T_ACTUAL, d = T_ACTUAL;
X *						...
X * new-style:
X *	inline foo(int a, float b, char c) {	{
X *	 ...					int a = T_ACTUAL;
X *						float b = T_ACTUAL;
X *						char c = T_ACTUAL;
X *						...
X *****
X *
X * NOTE:
X *
X * the above is how it would be done in the best of all possible worlds.
X * in practice, it turns out to be easier to issue separate initializations
X * for formals, like this:
X *
X * input:				Becomes:
X *
X *	inline foo(a,b) { ...			{ int a; int b;
X *						 int foo_ret;
X *						a = T_ACTUAL; b = T_ACTUAL;
X */
X
Xdoformals(node)
Xregister struct inline_node *node;
X{
X	register int new = 0;
X	register struct token *tl, *tok;
X	register struct toklist *paramdecl = &node->i_tl[SDECLBODY];
X	register int i;
X	int formal = -1;
X	int needsep = 0;
X	int gotformal[NFORMALS];
X	int parennest = 0;
X	int mem = node->i_mem;
X
X	/* determine what style of function declaration it is */
X	/* an old style parameter declaration */
X
X	tok = skipws(node->i_tl[SOPARAMDECL].tl_head);
X
X	if (tok == NILTOK) {
X		/* nothing other than whitespace in here */
X		paramdecl->tl_head = node->i_tl[SOPARAMDECL].tl_head;
X		paramdecl->tl_tail = node->i_tl[SOPARAMDECL].tl_tail;
X		node->i_tl[SOPARAMDECL].tl_head = NILTOK;
X		node->i_tl[SOPARAMDECL].tl_tail = NILTOK;
X	}
X
X	if (node->i_nformals == 0) {
X		/* no formal parameters */
X		return;
X	}
X	for (i = 0; i < NFORMALS; i++) {
X		gotformal[i] = 0;
X	}
X
X	if (node->i_tl[SOPARAMDECL].tl_head == NILTOK) {
X		/* either new style prototype declaration or args are all int */
X		for (tl = node->i_tl[SFORMAL].tl_head; tl != NILTOK; tl = tl->t_next) {
X			/* we see something other than id's, commas */
X			/* and parens, it's new-style declaration */
X			switch(tl->t_tok) {
X			case T_FORMAL:
X			case T_LPAREN:
X			case T_COMMA:
X			case T_RPAREN:
X				/* it's a new-style prototype */
X				new++;
X				tl = node->i_tl[SFORMAL].tl_head;
X				break;
X			default:
X				continue;
X			}
X			break;
X		}
X		if (!new) {	/* old style w/ args defaulted to int */
X			/* if it's old-style, then all args are 'int', so add that */
X			addtok(paramdecl,newtok(mem,T_INT,NIL));
X			addtok(paramdecl,newtok(mem,T_WS," "));
X			new = 1;
X			tl = node->i_tl[SFORMAL].tl_head;
X		}
X	} else {
X		/* loop through old-style param decl's, order them, and fill */
X		/* in those that have been defaulted */
X		for (tok = node->i_tl[SOPARAMDECL].tl_head; tok != NILTOK; tok = tok->t_next) {
X			if (tok->t_tok == T_FORMAL) {
X				if ((formal = isformal(node, tok)) >= 0) {
X					gotformal[formal] = 1;
X				} else {
X					error(tok->t_line, "parameter '%s' not in formal list",tok->t_id);
X				}
X			}
X		}
X		for (i = 0; i < node->i_nformals; i++) {
X			if (gotformal[i] == 0) {
X				addtok(&node->i_tl[SOPARAMDECL], newtok(mem,T_INT, NIL));
X				addtok(&node->i_tl[SOPARAMDECL], newtok(mem,T_WS, " "));
X				addtok(&node->i_tl[SOPARAMDECL], newtok(mem,T_FORMAL, node->i_formals[i]));
X				addtok(&node->i_tl[SOPARAMDECL], newtok(mem,T_SEMIC, NIL));
X				addtok(&node->i_tl[SOPARAMDECL], newtok(mem,T_WS, " "));
X				gotformal[i] = 1;
X			}
X		}
X		tl = node->i_tl[SOPARAMDECL].tl_head;
X	}
X
X
X	/*
X	 * loop through the formal declaration token list (or old style
X	 * parameter declaration list, if applicable)
X	 */
X	for ( /* tl init above */ ; tl != NILTOK; tl = tl->t_next) {
X		switch(tl->t_tok) {
X		case T_LPAREN:
X			if ((++parennest == 1) && new) {
X				continue;
X			}
X			break;
X
X		case T_SEMIC:
X			needsep = 0;
X			if (new) {
X				error(tl->t_line, "unexpected semicolon in new-style parameter list");
X			}
X			/*FALLTHROUGH*/
X		case T_RPAREN:
X			if (tl->t_tok == T_RPAREN) {
X				if (parennest >= 1) {
X					parennest--;
X				} else {
X					error(tl->t_line, "rparen error");
X					break;
X				}
X				if (new && (parennest > 0)) {
X					break;
X				}
X			}	
X			/*FALLTHROUGH*/
X		case T_COMMA:
X			if (formal >= 0) { /* seen a comma or semi-colon */
X
X				formal = -1;
X				/* haven't added the comma or semicolon */
X				if (tl->t_tok == T_SEMIC) {
X					addtok(paramdecl, newtok(mem,T_SEMIC, NIL));
X				} else {
X					needsep = 1;
X				}
X				continue;
X			}
X			break;	/* go ahead and add the token */
X
X		case T_FORMAL:
X			if (needsep) {
X				addtok(paramdecl,newtok(mem,T_COMMA,NIL));
X				needsep = 0;
X			}
X			addtok(paramdecl, tok = duptok(mem,tl));
X			if ((formal = isformal(node,tl)) < 0) {
X				error(tl->t_line,"parameter '%s' not in formals list", tl->t_id);
X			}
X			continue;
X
X		default:
X			break;
X		}
X		if (needsep) {
X			if (istype(tl) || isstoreclass(tl)) {
X				addtok(paramdecl,newtok(mem,T_SEMIC,NIL));
X				needsep = 0;
X			} else if (tl->t_tok == T_STAR) {
X				addtok(paramdecl,newtok(mem,T_COMMA,NIL));
X				needsep = 0;
X			}
X		}
X		addtok(paramdecl, tok = duptok(mem,tl));
X		/* don't put other tokens in init list */
X	}
X	if (needsep) {
X		addtok(paramdecl,newtok(mem,T_SEMIC,NIL));
X	}
X	addtok(paramdecl,newtok(mem,T_WS,"\n"));
X	return;
X}
X/*
X * return true if the argument tok is in the formal parameter list
X */
X
Xisformal(node,tok)
Xregister struct inline_node *node;
Xregister struct token *tok;
X{
X	register int i;
X
X	for(i=0; i < node->i_nformals; i++) {
X		if (strcmp(tok->t_id, node->i_formals[i]) == 0) {
X			return(i);
X		}
X	}
X	return(-1);
X}
X
Xisdecl(tl)
Xregister struct toklist *tl;
X{
X	register struct token *tok;
X
X	for (tok = tl->tl_head; tok != NILTOK; tok = tok->t_next) {
X		if (tok->t_tok == T_INLINE) {
X			return(1);
X		}
X	}
X	return(0);
X}
X
X
X/*
X * process a typedef line
X *
X * typedefs take the general form:
X *
X *	typedef base_type new_type;
X *
X *	however, one must watch for situations like:
X *
X *	typedef int newtype[DEFINE];
X *	typedef struct { int a; int b } newtype;
X *
X *	so the trick needs to be that the new type is the last identifier
X *	not embedded in braces or brackets;
X */
X
Xdotypedef(begin)
Xregister struct token *begin;
X{
X	register struct token *lastid = NILTOK;
X	register struct token *tl;
X	register char **p;
X	int level = -1;
X	int needbrack = 0;
X
X	for (tl = begin; tl != NILTOK; tl = tl->t_next) {
X		if (tl->t_tok == T_TYPEDEF) {
X			if (level >= 0) {
X				error(tl->t_line, "typedef within typedef");
X				return;
X			}
X			level = tl->t_level;
X			if ((level > NSCOPE) || (typeid[level] == NILP(struct typelist *))) {
X				error(tl->t_line, "bad level in dotypedef");
X				return;
X			}
X			continue;
X		}
X		if ((tl->t_tok == T_SEMIC) && (tl->t_level == level)) {
X			break;
X		}
X		if (tl->t_tok == T_LSQ) {
X			needbrack++;
X			continue;
X		}
X		if (needbrack) {
X			if (tl->t_tok == T_RSQ) {
X				needbrack--;
X			}
X			continue;
X		}
X		if ((tl->t_tok == T_IDENT) && (tl->t_level == level)) {
X			lastid = tl;
X		}
X	}
X	if (tl->t_tok != T_SEMIC) {
X		error(tl->t_line, "dotypedef terminated abnormally");
X	}
X	if (level < 0) {
X		error(tl->t_line, "internal error in dotypedef");
X		return;
X	}
X	if (lastid) {
X		lastid->t_tok = T_TYPE_ID;
X		for (p = typeid[level]->type_id; *p != NIL; p++) {
X			if (strcmp(lastid->t_id,*p) == 0) {
X				error(tl->t_line, "redeclaration of %s",*p);
X			}
X		}
X		if ((p-typeid[level]->type_id) < NTYPEDEF) {
X			*p = mkstr(typeid[level]->type_mem,lastid->t_id,0);
X		} else {
X			error(tl->t_line, "too many typedefs at scope level %d", level);
X		}
X	}
X}
X
\Rogue\Monster\
else
  echo "will not over write ./declare.c"
fi
chmod 444 ./declare.c
if [ `wc -c ./declare.c | awk '{printf $1}'` -ne 15931 ]
then
echo `wc -c ./declare.c | awk '{print "Got " $1 ", Expected " 15931}'`
fi
echo "Finished archive 3 of 3"
# if you want to concatenate archives, remove anything after this nline = nd