home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume11
/
inline
/
part02
< prev
next >
Wrap
Text File
|
1987-09-14
|
46KB
|
1,955 lines
Subject: v11i040: Inline code expander for C, Part02/04
Newsgroups: comp.sources.unix
Sender: sources
Approved: rs@uunet.UU.NET
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 line
exit