|
|
researchv10 Norman
/*#ident "@(#)cpp:common/cpp.c 1.44" */
#ifdef FLEXNAMES
# define NCPS 128
#else
# define NCPS 8
#endif
int ncps = NCPS; /* default name length */
# include <stdio.h>
# include <ctype.h>
# include <libc.h>
# include <sys/types.h> /* needed by stat.h */
# include <sys/stat.h> /* needed by option -M */
/* C command - C preprocessor */
/*
* See if necessary defines are given
*/
#if !defined( PD_MACH ) || !defined( PD_SYS )
# include "*** Must define PD_MACH and PD_SYS ***"
#endif
/*
* These defines are used to enter new machines and/or systems
* to the two lists. To create a new instance of cpp in a cross
* compilation environment, set PD_MY_MACH=\"your-new-machine\"
* and/or PD_MY_SYS=\"your-new-os\" and set PD_MACH=MAX_PD_MACH
* and PD_SYS=MAX_PD_SYS.
*/
#ifndef PD_MY_MACH
# define PD_MY_MACH 0
#endif
#ifndef PD_MY_SYS
# define PD_MY_SYS 0
#endif
#define STATIC
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define CLASSCODE 27 /* exit status if #class seen */
#define READ "r"
#define WRITE "w"
#define SALT '#'
#ifndef BUFSIZ
# define BUFSIZ 512
#endif
char *pbeg, *pbuf, *pend;
char *outp, *inp;
char *newp;
char cinit;
#ifdef CXREF
char *xcopy();
FILE *outfp;
static int ready = 0;
int xline;
#endif
/* some code depends on whether characters are sign or zero extended */
/* #if '\377' < 0 not used here, old cpp doesn't understand */
#if pdp11 | vax
# define COFF 128
#else
# define COFF 0
#endif
# if gcos
# define ALFSIZ 512 /* alphabet size */
# else
# define ALFSIZ 256 /* alphabet size */
# endif
char macbit[ ALFSIZ + 11 ];
char toktyp[ ALFSIZ ];
#define BLANK 1
#define IDENT 2
#define NUMBR 3
/* a superimposed code is used to reduce the number of calls to the
/* symbol table lookup routine. (if the kth character of an identifier
/* is 'a' and there are no macro names whose kth character is 'a'
/* then the identifier cannot be a macro name, hence there is no need
/* to look in the symbol table.) 'scw1' enables the test based on
/* single characters and their position in the identifier. 'scw2'
/* enables the test based on adjacent pairs of characters and their
/* position in the identifier. scw1 typically costs 1 indexed fetch,
/* an AND, and a jump per character of identifier, until the identifier
/* is known as a non-macro name or until the end of the identifier.
/* scw1 is inexpensive. scw2 typically costs 4 indexed fetches,
/* an add, an AND, and a jump per character of identifier, but it is also
/* slightly more effective at reducing symbol table searches.
/* scw2 usually costs too much because the symbol table search is
/* usually short; but if symbol table search should become expensive,
/* the code is here.
/* using both scw1 and scw2 is of dubious value.
*/
#define scw1 1
#define scw2 0
#if scw2
char t21[ ALFSIZ ], t22[ ALFSIZ ], t23[ ALFSIZ + NCPS ];
#endif
#if scw1
# define b0 1
# define b1 2
# define b2 4
# define b3 8
# define b4 16
# define b5 32
# define b6 64
# define b7 128
#endif
#define IB 1
#define SB 2
#define NB 4
#define CB 8
#define QB 16
#define WB 32
char fastab[ ALFSIZ ];
char slotab[ ALFSIZ ];
char *ptrtab;
#define isslo ( ptrtab == ( slotab + COFF ) )
#define isid(a) ( ( fastab + COFF )[a] & IB )
#define isspc(a) ( ptrtab[a] & SB )
#define isnum(a) ( ( fastab + COFF )[a] & NB )
#define iscom(a) ( ( fastab + COFF )[a] & CB )
#define isquo(a) ( ( fastab + COFF )[a] & QB )
#define iswarn(a) ( ( fastab + COFF )[a] & WB )
#define eob(a) ( ( a ) >= pend )
#define bob(a) ( pbeg >= ( a ) )
char buffer[ NCPS + BUFSIZ + BUFSIZ + NCPS ];
# define MAXNEST 12 /* max number of nested #include's */
# define MAXFRE 14 /* max buffers of macro pushback */
#ifdef pdp11
# define SBSIZE 24000
#else
/* The idea here is to define the buffer to have a certain size
** (the literal number) plus enough room for slop and taking side buffers
** out to hold processing interrupted by #include's. The cost of side
** buffers is particularly noticable on an Amdahl, where BUFSIZ is 4096.
*/
# define SBSIZE (21000 + (MAXFRE+1)*BUFSIZ)
#endif
char sbf[ SBSIZE ];
char *savch = sbf;
# define DROP '\376' /* special character not legal ASCII or EBCDIC */
# define WARN DROP
# define SAME 0
# define MAXINC 100 /* max number of directories for -I options */
# define MAXFRM 31 /* max number of formals/actuals to a macro */
static char warnc = WARN;
int mactop, fretop;
char *instack[ MAXFRE ], *bufstack[ MAXFRE ], *endbuf[ MAXFRE ];
int plvl; /* parenthesis level during scan for macro actuals */
int maclin; /* line number of macro call requiring actuals */
char *macfil; /* file name of macro call requiring actuals */
char *macnam; /* name of macro requiring actuals */
int maclvl; /* # calls since last decrease in nesting level */
char *macforw; /* pointer which must be exceeded to decrease nesting level */
int macdam; /* offset to macforw due to buffer shifting */
#if tgp
int tgpscan; /* flag for dump(); */
#endif
STATIC int inctop[ MAXNEST ];
STATIC char *fnames[ MAXNEST ];
STATIC char *fdates[ MAXNEST ]; /* for -M option */
STATIC char *dirnams[ MAXNEST ]; /* actual directory of #include files */
STATIC FILE *fins[ MAXNEST ];
STATIC int lineno[ MAXNEST ];
STATIC char *dirs[ MAXINC ]; /* -I and <> directories */
STATIC char *dfltdir = (char *) 0; /* user-supplied default (like /usr/include) */
char *copy(), *subst(), *trmdir(), *strchr();
char *chkend(), *getfdate(), *findfdate();
struct symtab *stsym();
STATIC FILE *fin = stdin;
STATIC FILE *fout = stdout;
STATIC int nd = 1;
STATIC int pflag; /* don't put out lines "# 12 foo.c" */
STATIC int mflag;
STATIC int passcom; /* don't delete comments */
STATIC int incomm; /* set while in comment so that EOF can be detected */
STATIC int rflag; /* allow macro recursion */
STATIC int print_incs; /* set to print out included filenames */
STATIC int ifno;
# define NPREDEF 20
STATIC char *prespc[ NPREDEF ];
STATIC char **predef = prespc;
STATIC char *punspc[ NPREDEF ];
STATIC char **prund = punspc;
STATIC int exfail;
struct symtab
{
char *name;
char *value;
} *lastsym, *lookup(), *slookup();
# if gcos
# include <setjmp.h>
static jmp_buf env;
# define main mainpp
# undef exit
# define exit(S) longjmp(env, 1)
# define symsiz 500
# define LINEFORM "# %d %s\n"
# define ERRFORM "*%c* %s, line "
# else
# define symsiz 2000
# define LINEFORM "# %d \"%s%s\"\n"
# define ERRFORM "*%c* \"%s%s\", line "
# endif
STATIC struct symtab stab[ symsiz ];
STATIC struct symtab *defloc;
STATIC struct symtab *udfloc;
STATIC struct symtab *incloc;
STATIC struct symtab *ifloc;
STATIC struct symtab *elsloc;
STATIC struct symtab *eifloc;
STATIC struct symtab *elifloc;
STATIC struct symtab *ifdloc;
STATIC struct symtab *ifnloc;
STATIC struct symtab *ysysloc;
STATIC struct symtab *varloc;
STATIC struct symtab *lneloc;
STATIC struct symtab *ulnloc;
STATIC struct symtab *uflloc;
STATIC struct symtab *clsloc;
STATIC struct symtab *idtloc;
STATIC struct symtab *pragmaloc;
STATIC int trulvl;
STATIC int flslvl;
#define MAX_DEPTH 500 /* max of trulvl + flslvl */
#define SEEN_ELSE 0x1
#define TRUE_ELIF 0x2
STATIC char ifelstk[MAX_DEPTH];
/*
* To facilitate the handling of different cpp's and cross cpp's,
* the sets of mutually exclusive predefined are placed into lists.
* The value used from these lists are set when building from the
* command line.
*/
#define MAX_PD_MACH 13 /* set so it is where PD_MY_MACH is at */
#define D_tss 0 /*define table indexes */
#define D_os 1
#define D_mert 2
#define D_RT 3
#define D_RES 4
#define D_interdata 5
#define D_pdp11 6
#define D_vax 7
#define D_u370 8
#define D_u3b 9
#define D_u3b5 10
#define D_u3b2 11
#define D_u3b20d 12
#define D_newmach MAX_PD_MACH
#define D_nomach MAX_PD_MACH
char *pdef_mach[MAX_PD_MACH+2] = /* choose using PD_MACH */
{
/*
* The following are ``machines'' for historical reasons only.
*/
"tss", "os", "mert",
"RT", "RES",
/* These are the currently supported machines */
"interdata", "pdp11", "vax",
"u370", "u3b", "u3b5",
"u3b2", "u3b20d",
PD_MY_MACH, /* for adding "own" machine */
0
};
#define MAX_PD_SYS 4 /* set so that it is where PD_MY_SYS is at */
#define D_unix 0
#define D_gcos 1
#define D_ibm 2
#define D_DMERT 3
#define D_newsys MAX_PD_SYS
#define D_nosys MAX_PD_SYS
char *pdef_sys[MAX_PD_SYS+2] = /* choose using PD_SYS */
{
"unix",
"gcos",
"ibm",
"DMERT",
PD_MY_SYS, /* for adding "own" system */
0
};
#if PD_MACH < 0 || PD_MACH > MAX_PD_MACH
# include "*** PD_MACH set illegally ***"
#endif
#if PD_SYS < 0 || PD_SYS > MAX_PD_SYS
# include "*** PD_SYS set illegally ***"
#endif
sayline()
{
if ( pflag == 0 )
fprintf( fout, LINEFORM, lineno[ifno], fnames[ifno] ,fdates[ifno] );
}
/* data structure guide
/*
/* most of the scanning takes place in the buffer:
/*
/* (low address) (high address)
/* pbeg pbuf pend
/* | <-- BUFSIZ chars --> | <-- BUFSIZ chars --> |
/* _______________________________________________________________________
/* |_______________________________________________________________________|
/* | | |
/* |<-- waiting -->| |<-- waiting -->
/* | to be |<-- current -->| to be
/* | written | token | scanned
/* | | |
/* outp inp p
/*
/* *outp first char not yet written to output file
/* *inp first char of current token
/* *p first char not yet scanned
/*
/* macro expansion: write from *outp to *inp (chars waiting to be written),
/* ignore from *inp to *p (chars of the macro call), place generated
/* characters in front of *p (in reverse order), update pointers,
/* resume scanning.
/*
/* symbol table pointers point to just beyond the end of macro definitions;
/* the first preceding character is the number of formal parameters.
/* the appearance of a formal in the body of a definition is marked by
/* 2 chars: the char WARN, and a char containing the parameter number.
/* the first char of a definition is preceded by a zero character.
/*
/* when macro expansion attempts to back up over the beginning of the
/* buffer, some characters preceding *pend are saved in a side buffer,
/* the address of the side buffer is put on 'instack', and the rest
/* of the main buffer is moved to the right. the end of the saved buffer
/* is kept in 'endbuf' since there may be nulls in the saved buffer.
/*
/* similar action is taken when an 'include' statement is processed,
/* except that the main buffer must be completely emptied. the array
/* element 'inctop[ifno]' records the last side buffer saved when
/* file 'ifno' was included. these buffers remain dormant while
/* the file is being read, and are reactivated at end-of-file.
/*
/* instack[0 : mactop] holds the addresses of all pending side buffers.
/* instack[inctop[ifno]+1 : mactop-1] holds the addresses of the side
/* buffers which are "live"; the side buffers instack[0 : inctop[ifno]]
/* are dormant, waiting for end-of-file on the current file.
/*
/* space for side buffers is obtained from 'savch' and is never returned.
/* bufstack[0:fretop-1] holds addresses of side buffers which
/* are available for use.
*/
dump()
{
/* write part of buffer which lies between outp and inp .
/* this should be a direct call to 'write', but the system slows
/* to a crawl if it has to do an unaligned copy. thus we buffer.
/*? this silly loop is 15% of the total time, thus even the 'putc'
/*? macro is too slow.
*/
register char *p1;
register FILE *f;
#if tgp
register char *p2;
#endif
if ( ( p1 = outp ) == inp || flslvl != 0 )
return;
#if tgp
# define MAXOUT 80
if ( !tgpscan ) /* scan again to insure <= MAXOUT
{ /* chars between linefeeds */
register char c, *pblank;
char savc, stopc, brk;
tgpscan = 1;
brk = stopc = pblank = 0;
p2 = inp;
savc = *p2;
*p2 = '\0';
while ( c = *p1++ )
{
if ( c == '\\' )
c = *p1++;
if ( stopc == c )
stopc = 0;
else if ( c == '"' || c == '\'' )
stopc = c;
if ( p1 - outp > MAXOUT && pblank != 0 )
{
*pblank++ = '\n';
inp = pblank;
dump();
brk = 1;
pblank = 0;
}
if ( c == ' ' && stopc == 0 )
pblank = p1 - 1;
}
if ( brk )
sayline();
*p2 = savc;
inp = p2;
p1 = outp;
tgpscan = 0;
}
#endif
f = fout;
# if gcos
/* filter out "$ program c" card if first line of input */
/* gmatch is a simple pattern matcher in the GCOS Standard Library */
{
static int gmfirst = 0;
if ( !gmfirst )
{
++gmfirst;
if ( gmatch( p1, "^$*program[ \t]*c*") )
p1 = strchr( p1, '\n' );
}
}
# endif
while (p1 < inp)
putc(*p1++, f);
outp = p1;
}
char *
refill( p )
register char *p;
{
/* dump buffer. save chars from inp to p. read into buffer at pbuf,
/* contiguous with p. update pointers, return new p.
*/
register char *np, *op;
register int ninbuf;
dump();
/* slide current token to left of pbuf */
ninbuf = p - inp;
np = pbuf - ninbuf;
if ( bob( np + 1 ) )
{
pperror( "token too long" );
np = pbeg;
p = inp + BUFSIZ;
}
macdam += np - inp;
memcpy(np, inp, ninbuf);
p = np + ninbuf; /* usually pbuf - ninbuf */
outp = inp = np;
for ( ;; )
{
/* retrieve hunk of pushed-back macro text */
if ( mactop > inctop[ifno] )
{
op = instack[ --mactop ];
memcpy(pbuf, op, endbuf[mactop] - op);
pend = pbuf + (endbuf[mactop] - op) - 1;
/* make buffer space avail for 'include' processing */
if ( fretop < MAXFRE )
bufstack[fretop++] = instack[mactop];
return( p );
}
else /* get more text from file(s) */
{
maclvl = 0;
#if NOTDEF
if ( 0 < ( ninbuf = fread( pbuf, sizeof( char ), BUFSIZ, fin ) ) )
{
#else
/*
* very much faster, but don't remove stdio completely for now
* in vague search for compatibility
*/
if ((ninbuf = read(fileno(fin), pbuf, BUFSIZ)) > 0) {
#endif
pend = pbuf + ninbuf;
*pend = '\0';
return( p );
}
/* end of #include file */
if ( ifno == 0 ) /* end of input */
{
if ( plvl != 0 )
{
int n = plvl, tlin = lineno[ifno];
char *tfil = fnames[ifno];
lineno[ifno] = maclin;
fnames[ifno] = macfil;
pperror( "%s: unterminated macro call",
macnam );
lineno[ifno] = tlin;
fnames[ifno] = tfil;
np = p;
/*shut off unterminated quoted string*/
*np++ = '\n';
/* supply missing parens */
while ( --n >= 0 )
*np++ = ')';
pend = np;
*np = '\0';
if ( plvl < 0 )
plvl = 0;
return( p );
}
if ( incomm ) {
pperror( "Unexpected EOF in comment" );
/* undo flslvl bump when comment started */
if (flslvl) --flslvl;
}
if ( trulvl +flslvl > 0 )
pperror( "Unexpected EOF within #if, #ifdef or #ifndef" );
inp = p;
dump();
if ( fout && ferror( fout ) )
pperror( "Problems with writing output file; probably out of temp space" );
exit( exfail ? ( exfail ==
CLASSCODE ? CLASSCODE : 2 ) : 0 );
}
fclose( fin );
fin = fins[--ifno];
dirs[0] = dirnams[ifno];
sayline();
#ifdef CXREF
fprintf(outfp, "\"%s\"\n", fnames[ifno]);
#endif
}
}
}
#define BEG 0
#define LF 1
char *
cotoken( p )
register char *p;
{
register int c, i;
char quoc;
static int state = BEG;
static int speakup = 0;
if ( state != BEG )
goto prevlf;
for ( ;; )
{
again:
while ( !isspc( c = *p++ ) )
;
inp = p - 1;
switch ( c )
{
case 0:
if ( eob( --p ) )
{
p = refill( p );
goto again;
}
else
++p; /* ignore null byte */
break;
case '|':
case '&':
for ( ;; ) /* sloscan only */
{
if ( *p++ == *inp )
break;
if ( eob( --p ) )
p = refill( p );
else
break;
}
break;
case '=':
case '!':
for ( ;; ) /* sloscan only */
{
if ( *p++ == '=' )
break;
if ( eob( --p ) )
p = refill( p );
else
break;
}
break;
case '<':
case '>':
for ( ;; ) /* sloscan only */
{
if ( *p++ == '=' || p[-2] == p[-1] )
break;
if ( eob( --p ) )
p = refill( p );
else
break;
}
break;
case '\\':
for ( ;; )
{
if ( *p++ == '\n' )
{
++lineno[ifno];
break;
}
if ( eob( --p ) )
p = refill( p );
else
{
++p;
break;
}
}
break;
case '/':
for ( ;; )
{
if ( *p++ == '*' ) /* comment */
{
incomm = 1;
if ( !passcom )
{
inp = p - 2;
dump();
++flslvl;
}
for ( ;; )
{
while ( !iscom( *p++ ) )
;
if ( p[-1] == '*' )
for ( ;; )
{
if ( *p++ == '/' )
goto endcom;
if ( eob( --p ) )
{
if ( !passcom )
{
inp = p;
p = refill( p );
}
/* split long comment */
else if ( ( p - inp ) >= BUFSIZ )
{
*p++ = '*';
*p++ = '/';
inp = p;
p = refill( p );
outp = inp = p -= 2;
*p++ = '/';
*p++ = '*';
}
else
p = refill( p );
}
else
break;
}
else if ( p[-1] == '\n' )
{
++lineno[ifno];
if ( !passcom && flslvl <= 1 )
putc( '\n', fout );
}
else if ( eob( --p ) )
{
if ( !passcom )
{
inp = p;
p = refill( p );
}
/* split long comment */
else if ( ( p - inp ) >= BUFSIZ )
{
*p++ = '*';
*p++ = '/';
inp = p;
p = refill( p );
outp = inp = p -= 2;
*p++ = '/';
*p++ = '*';
}
else
p = refill( p );
}
else
++p; /* ignore null byte */
}
endcom:
incomm = 0;
if ( !passcom )
{
outp = inp = p;
--flslvl;
goto again;
}
break;
}
if ( eob( --p ) )
p = refill( p );
else
break;
}
break;
# if gcos
case '`':
# endif
case '"':
case '\'':
quoc = p[-1];
for ( ;; )
{
while ( !isquo( *p++ ) )
;
if ( p[-1] == quoc )
break;
if ( p[-1] == '\n' ) /* bare \n terminates quotation */
{
--p;
break;
}
if ( p[-1] == '\\' )
for ( ;; )
{
if ( *p++ == '\n' ) /* escaped \n ignored */
{
++lineno[ifno];
break;
}
if ( eob( --p ) )
p = refill( p );
else
{
++p;
break;
}
}
else if ( eob( --p ) )
p = refill( p );
else
++p; /* it was a different quote character */
}
break;
case WARN:
{
int ii;
dump();
speakup = 0;
for ( ii = sizeof(int) / sizeof(char); --ii >= 0; )
{
if ( eob( p ) )
p = refill( p );
speakup |= ( *p++ & 0xFF ) << ( ii * 8 );
}
inp = outp = p;
break;
}
case '\n':
++lineno[ifno];
if ( isslo )
{
state=LF;
return( p );
}
prevlf:
if ( speakup )
{
inp = p;
dump();
lineno[ifno] = speakup + 1;
sayline();
speakup = 0;
}
state = BEG;
for ( ;; )
{
/*
* ignore formfeeds and vertical tabs
* which may be just before the SALT
*/
#if NOTDEF
if ( *p == '\f' || *p == '\v' )
{
register char *s = p;
while ( *++s == '\f' || *s == '\v' )
;
if ( *s == SALT )
{
/*
* get the SALT to the front!
*/
*s = *p;
*p = SALT;
}
}
#endif
if ( *p++ == SALT )
return( p );
if ( eob( inp = --p ) )
p = refill( p );
else
goto again;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for ( ;; )
{
while ( isnum( *p++ ) )
;
if ( eob( --p ) )
p = refill( p );
else
break;
}
break;
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '_':
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
#if scw1
# define tmac1( c, bit ) if ( !xmac1( c, bit, & ) ) \
goto nomac
# define xmac1( c, bit, op ) ( ( macbit + COFF )[c] op ( bit ) )
#else
# define tmac1( c, bit )
# define xmac1( c, bit, op )
#endif
#if scw2
# define tmac2( c0, c1, cpos ) if ( !xmac2( c0, c1, cpos, & ) ) \
goto nomac
# define xmac2( c0, c1, cpos, op ) \
( ( macbit + COFF )[ ( t21 + COFF )[c0] + \
( t22 + COFF )[c1]] op ( t23 + COFF + cpos )[c0] )
#else
# define tmac2( c0, c1, cpos )
# define xmac2( c0, c1, cpos, op )
#endif
if ( flslvl )
goto nomac;
for ( ;; )
{
c = p[-1];
tmac1( c, b0 );
i = *p++;
if ( !isid( i ) )
goto endid;
tmac1( i, b1 );
tmac2( c, i, 0 );
c = *p++;
if ( !isid( c ) )
goto endid;
tmac1( c, b2 );
tmac2( i, c, 1 );
i = *p++;
if ( !isid( i ) )
goto endid;
tmac1( i, b3 );
tmac2( c, i, 2 );
c = *p++;
if ( !isid( c ) )
goto endid;
tmac1( c, b4 );
tmac2( i, c, 3 );
i = *p++;
if ( !isid( i ) )
goto endid;
tmac1( i, b5 );
tmac2( c, i, 4 );
c = *p++;
if ( !isid( c ) )
goto endid;
tmac1( c, b6 );
tmac2( i, c, 5 );
i = *p++;
if ( !isid( i ) )
goto endid;
tmac1( i, b7 );
tmac2( c, i, 6 );
tmac2( i, 0, 7 );
while ( isid( *p++ ) )
;
if ( eob( --p ) )
{
refill( p );
p = inp + 1;
continue;
}
goto lokid;
endid:
if ( eob( --p ) )
{
refill( p );
p = inp + 1;
continue;
}
tmac2( p[-1], 0, -1 + ( p - inp ) );
lokid:
slookup( inp, p, 0 );
if ( newp )
{
p = newp;
goto again;
}
else
break;
nomac:
while ( isid( *p++ ) )
;
if ( eob( --p ) )
{
p = refill( p );
goto nomac;
}
else
break;
}
break;
} /* end of switch */
if ( isslo )
return( p );
} /* end of infinite loop */
}
char *
skipbl( p ) /* get next non-blank token */
register char *p;
{
do
{
outp = inp = p;
p = cotoken( p );
}
while ( ( toktyp + COFF )[*inp] == BLANK );
return( p );
}
char *
unfill( p )
register char *p;
{
/* take <= BUFSIZ chars from right end of buffer and put
/* them on instack. slide rest of buffer to the right,
/* update pointers, return new p.
*/
register char *np, *op;
register int d;
if ( mactop >= MAXFRE )
{
pperror( "%s: too much pushback", macnam );
p = inp = pend; /* begin flushing pushback */
dump();
while ( mactop > inctop[ifno] )
{
(void) refill( p );
p = inp = pend;
dump();
}
}
if ( fretop > 0 )
np = bufstack[--fretop];
else
{
np = savch;
savch += BUFSIZ;
if ( savch >= sbf + SBSIZE )
{
pperror( "no space" );
exit( exfail ? ( exfail == CLASSCODE ? CLASSCODE : 2 )
: 0 );
}
*savch++ = '\0';
}
instack[mactop] = np;
op = pend - BUFSIZ;
if ( op < p )
op = p;
memcpy(np, op, pend - op);
np += pend - op;
*np++ = 0;
endbuf[mactop++] = np; /* mark end of saved text */
np = pbuf + BUFSIZ;
op = pend - BUFSIZ;
pend = np;
if ( op < p )
op = p;
while ( outp < op ) /* slide over new */
*--np = *--op;
if ( bob( np ) )
pperror( "token too long" );
d = np - outp;
outp += d;
inp += d;
macdam += d;
return( p + d );
}
char *
doincl( p )
register char *p;
{
int filok, inctype;
register char *cp;
char **dirp, *nfil;
char filname[BUFSIZ];
p = skipbl( p );
cp = filname;
if ( *inp++ == '<' ) /* special <> syntax */
{
inctype = 1;
++flslvl; /* prevent macro expansion */
for ( ;; )
{
outp = inp = p;
p = cotoken( p );
if ( *inp == '\n' )
{
--p;
*cp = '\0';
break;
}
if ( *inp == '>' )
{
*cp = '\0';
break;
}
# ifdef gimpel
if ( *inp == '.' && !intss() )
*inp = '#';
# endif
while ( inp < p )
*cp++ = *inp++;
}
--flslvl; /* reenable macro expansion */
}
else if ( inp[-1] == '"' ) /* regular "" syntax */
{
inctype = 0;
# ifdef gimpel
while ( inp < p )
{
if ( *inp == '.' && !intss() )
*inp = '#';
*cp++ = *inp++;
}
# else
while ( inp < p )
*cp++ = *inp++;
# endif
if ( *--cp == '"' )
*cp = '\0';
}
else
{
int ppwarn(), pperror();
/* This is a warning if we're skipping, error if not. */
(*(flslvl ? ppwarn : pperror))( "bad include syntax", 0 );
inctype = 2;
}
/* flush current file to \n , then write \n */
p = chkend( p, 1 );
outp = inp = p;
dump();
if ( inctype == 2 || flslvl != 0 )
return( p );
/* look for included file */
if ( ifno + 1 >= MAXNEST )
{
pperror( "Unreasonable include nesting", 0 );
return( p );
}
if ( ( nfil = savch ) > sbf + SBSIZE - BUFSIZ )
{
pperror( "no space" );
exit( exfail ? ( exfail == CLASSCODE ? CLASSCODE : 2 ) : 0 );
}
/* check for #include "/usr/include/..." */
if (strncmp(filname, "/usr/include/", 13) == 0)
ppwarn("#include of /usr/include/... may be non-portable");
filok = 0;
for ( dirp = dirs + inctype; *dirp; ++dirp )
{
if (
# if gcos
strchr( filname, '/' )
# else
filname[0] == '/'
# endif
|| **dirp == '\0' )
{
strcpy( nfil, filname );
}
else
{
strcpy( nfil, *dirp );
# if unix || gcos || DMERT
strcat( nfil, "/" );
# endif
#ifdef ibm
# ifndef gimpel
strcat( nfil, "." );
# endif
#endif
strcat( nfil, filname );
}
if ( NULL != ( fins[ifno + 1] = fopen( nfil, READ ) ) )
{
filok = 1;
fin = fins[++ifno];
if ( print_incs )
fprintf( stderr, "%s\n", nfil );
break;
}
}
if ( filok == 0 )
pperror( "Can't find include file %s", filname );
else
{
lineno[ifno] = 1;
fnames[ifno] = cp = nfil;
while ( *cp++)
;
savch = cp;
fdates[ifno] = getfdate( fin );
dirnams[ifno] = dirs[0] = trmdir( copy( nfil ) );
sayline();
#ifdef CXREF
fprintf(outfp, "\"%s\"\n", fnames[ifno]);
#endif
/* save current contents of buffer */
while ( !eob( p ) )
p = unfill( p );
inctop[ifno] = mactop;
}
return( p );
}
equfrm( a, p1, p2 )
register char *a, *p1, *p2;
{
register char c;
int flag;
c = *p2;
*p2 = '\0';
flag = strcmp( a, p1 );
*p2 = c;
return( flag == SAME );
}
char *
dodef( p ) /* process '#define' */
char *p;
{
register char *pin, *psav, *cf;
char **pf, **qf;
int b, c, params;
int ex_blank; /* used to ignore extra blanks in token-string */
int sav_passcom = passcom; /* saved passcom, used to reset it */
struct symtab *np;
char *oldval, *oldsavch;
char *formal[MAXFRM]; /* formal[n] is name of nth formal */
char formtxt[BUFSIZ]; /* space for formal names */
if ( savch > sbf + SBSIZE - BUFSIZ )
{
pperror( "too much defining" );
return( p );
}
oldsavch = savch; /* to reclaim space if redefinition */
++flslvl; /* prevent macro expansion during 'define' */
p = skipbl( p );
pin = inp;
if ( ( toktyp + COFF )[*pin] != IDENT )
{
if (*pin == '\n') --lineno[ifno];
ppwarn( "illegal/missing macro name" );
if (*pin == '\n') ++lineno[ifno];
while ( *inp != '\n' )
p = skipbl( p );
--flslvl; /* restore expansion */
return( p );
}
np = slookup( pin, p, 1 );
if ( oldval = np->value ) /* was previously defined */
savch = oldsavch;
#ifdef CXREF
def(np->name, lineno[ifno]);
#endif
b = 1;
cf = pin;
while ( cf < p ) /* update macbit */
{
c = *cf++;
xmac1( c, b, |= );
b = ( b + b ) & 0xFF;
if ( cf != p )
xmac2( c, *cf, -1 + ( cf - pin ), |= );
else
xmac2( c, 0, -1 + ( cf - pin ), |= );
}
params = 0;
outp = inp = p;
p = cotoken( p );
pin = inp;
if ( *pin == '(' ) /* with parameters; identify the formals */
{
#ifdef CXREF
newf(np->name, lineno[ifno]);
#endif
cf = formtxt;
pf = formal;
for ( ;; )
{
p = skipbl( p );
pin = inp;
if ( *pin == '\n' )
{
--lineno[ifno];
--p;
pperror( "%s: missing )", np->name );
break;
}
if ( *pin == ')' )
break;
if ( *pin == ',' )
continue;
if ( ( toktyp + COFF )[*pin] != IDENT )
{
c = *p;
*p = '\0';
pperror( "bad formal: %s", pin );
*p = c;
}
else if ( pf >= &formal[MAXFRM] )
{
c = *p;
*p = '\0';
pperror( "too many formals: %s", pin );
*p = c;
}
else
{
*pf++ = cf;
while ( pin < p )
*cf++ = *pin++;
*cf++ = '\0';
++params;
#ifdef CXREF
def(*(pf-1), lineno[ifno]);
#endif
}
}
if ( params == 0 ) /* #define foo() ... */
--params;
}
else if ( *pin == '\n' )
{
--lineno[ifno];
--p;
}
else
p = inp; /* back up to scan non-blank next token */
/*
* remember beginning of macro body, so that we can
* warn if a redefinition is different from old value.
*/
oldsavch = psav = savch;
passcom = 1; /* make cotoken() return comments as tokens */
ex_blank = 1; /* must have some delimiter - might as well be blank */
for ( ;; ) /* accumulate definition until linefeed */
{
outp = inp = p;
p = cotoken( p );
pin = inp;
if ( *pin == '\\' && pin[1] == '\n' ) /* ignore escaped lf */
{
if ( !ex_blank ) /* replace it with a blank */
{
*psav++ = ' ';
ex_blank = 1;
}
putc( '\n', fout );
continue;
}
if ( *pin == '\n' )
break;
if ( ( toktyp + COFF )[*pin] == BLANK ) /* skip extra blanks */
{
if ( ex_blank )
continue;
*pin = ' '; /* force it to be a "real" blank */
ex_blank = 1;
}
else
ex_blank = 0;
if ( *pin == '/' && pin[1] == '*' ) /* skip comment */
{ /* except for \n's */
while ( pin < p )
if ( *pin++ == '\n' )
putc( '\n', fout );
continue;
}
if ( params ) /* mark the appearance of formals in the definiton */
{
if ( ( toktyp + COFF )[*pin] == IDENT )
{
for ( qf = pf; --qf >= formal; )
{
if ( equfrm( *qf, pin, p ) )
{
#ifdef CXREF
#ifndef NO_MACRO_FORMAL
ref(*qf, lineno[ifno]);
#endif
#endif
*psav++ = qf - formal + 1;
*psav++ = WARN;
pin = p;
break;
}
}
}
/* inside quotation marks, too */
else if ( *pin == '"' || *pin == '\''
# if gcos
|| *pin == '`'
# endif
)
{
char quoc = *pin;
for ( *psav++ = *pin++; pin < p && *pin != quoc; )
{
while ( pin < p && !isid( *pin ) )
{
if ( *pin == '\n'
&& pin[-1] == '\\' )
{
putc( '\n', fout );
psav--; /* no \ */
pin++; /* no \n */
}
else
*psav++ = *pin++;
}
cf = pin;
while ( cf < p && isid( *cf ) )
++cf;
for ( qf = pf; --qf >= formal; )
{
if ( equfrm( *qf, pin, cf ) )
{
*psav++ = qf - formal + 1;
*psav++ = WARN;
pin = cf;
break;
}
}
while ( pin < cf )
*psav++ = *pin++;
}
}
}
while ( pin < p )
if ( *pin == '\n' && pin[-1] == '\\' )
{
putc( '\n', fout );
psav--; /* no \ */
pin++; /* no \n */
}
else
*psav++ = *pin++;
}
passcom = sav_passcom; /* restore to "real" value */
if ( psav[-1] == ' ' ) /* if token-string ended with a blank */
psav--; /* then it is unnecessary - throw away */
*psav++ = params;
*psav++ = '\0';
if ( ( cf = oldval ) != NULL ) /* redefinition */
{
--cf; /* skip no. of params, which may be zero */
while ( *--cf ) /* go back to the beginning */
;
if ( 0 != strcmp( ++cf, oldsavch ) ) /* redefinition different from old */
{
--lineno[ifno];
ppwarn( "%s redefined", np->name );
++lineno[ifno];
np->value = psav - 1;
}
else
psav = oldsavch; /* identical redef.; reclaim space */
}
else
np->value = psav - 1;
--flslvl;
inp = pin;
savch = psav;
return( p );
}
#define fasscan() ptrtab = fastab + COFF
#define sloscan() ptrtab = slotab + COFF
/* this macro manages the lookup of a macro name and produces
** a warning if the name is missing
*/
#define LOOKUP(skipblank, flag) \
++flslvl; if (skipblank) p = skipbl(p); \
if ( ( toktyp + COFF )[*inp] != IDENT ) \
{ \
if (*inp == '\n') --lineno[ifno];\
ppwarn( "illegal/missing macro name" ); \
if (*inp == '\n') ++lineno[ifno];\
while ( *inp != '\n' ) \
p = skipbl( p ); \
--flslvl; \
continue; \
} \
np = slookup(inp,p,flag); --flslvl
control( p ) /* find and handle preprocessor control lines */
register char *p;
{
register struct symtab *np;
for ( ;; )
{
fasscan();
p = cotoken( p );
if ( *inp == '\n' )
++inp;
dump();
sloscan();
p = skipbl( p );
*--inp = SALT;
outp = inp;
++flslvl;
np = slookup( inp, p, 0 );
--flslvl;
if ( np == defloc ) /* define */
{
if ( flslvl == 0 )
{
p = dodef( p );
continue;
}
}
else if ( np == incloc ) /* include */
{
p = doincl( p );
continue;
}
else if ( np == ifnloc ) /* ifndef */
{
LOOKUP(1/*skipbl*/, 0/*flag*/); /* sets "np" */
if ( flslvl == 0 && np->value == 0 )
++trulvl;
else
++flslvl;
if ( trulvl + flslvl >= MAX_DEPTH )
pperror( "#if,ifdef,ifndef nesting too deep" );
else
ifelstk[trulvl + flslvl] =
flslvl ? 0 : TRUE_ELIF;
#ifdef CXREF
ref(xcopy(inp, p), lineno[ifno]);
#endif
p = chkend( p, 1 );
}
else if ( np == ifdloc ) /* ifdef */
{
LOOKUP(1/*skipbl*/, 0/*flag*/); /* sets "np" */
if ( flslvl == 0 && np->value != 0 )
++trulvl;
else
++flslvl;
if ( trulvl + flslvl >= MAX_DEPTH )
pperror( "#if,ifdef,ifndef nesting too deep" );
else
ifelstk[trulvl + flslvl] =
flslvl ? 0 : TRUE_ELIF;
#ifdef CXREF
ref(xcopy(inp, p), lineno[ifno]);
#endif
p = chkend( p, 1 );
}
else if ( np == eifloc ) /* endif */
{
if ( flslvl )
{
if ( --flslvl == 0 )
sayline();
}
else if ( trulvl )
--trulvl;
else
pperror( "If-less endif", 0 );
p = chkend( p, 2 ); /* research mod; summit uses 1 */
}
else if ( np == elifloc ) /* elif */
{
if ( ifelstk[trulvl + flslvl] & SEEN_ELSE )
pperror( "#elif following #else", 0 );
if ( flslvl )
{
if ( --flslvl != 0 )
++flslvl;
else
{
newp = p;
#ifdef CXREF
xline = lineno[ifno];
#endif
if ( ifelstk[trulvl + flslvl + 1] == 0
&& yyparse() )
{
++trulvl;
ifelstk[trulvl + flslvl] =
TRUE_ELIF;
sayline();
}
else
++flslvl;
p = newp;
}
}
else if ( trulvl )
{
++flslvl;
--trulvl;
}
else
pperror( "If-less elif", 0 );
}
else if ( np == elsloc ) /* else */
{
if ( ifelstk[trulvl + flslvl] & SEEN_ELSE )
pperror( "too many #else's", 0 );
if ( flslvl )
{
if ( --flslvl != 0 )
++flslvl;
else if ( ifelstk[trulvl + flslvl + 1] == 0 )
{
++trulvl;
sayline();
}
else
++flslvl;
}
else if ( trulvl )
{
++flslvl;
--trulvl;
}
else
pperror( "If-less else", 0 );
ifelstk[trulvl + flslvl] |= SEEN_ELSE;
p = chkend( p, 1 );
}
else if ( np == udfloc ) /* undefine */
{
if ( flslvl == 0 )
{
LOOKUP(1/*skipbl*/, DROP); /* sets "np" */
p = chkend( p, 1 );
}
else
p = chkend( p, 2 );
#ifdef CXREF
ref(xcopy(inp, p), lineno[ifno]);
#endif
}
else if ( np == ifloc ) /* if */
{
#if tgp
pperror( " IF not implemented, true assumed", 0 );
if ( flslvl == 0 )
++trulvl;
else
++flslvl;
#else
newp = p;
#ifdef CXREF
xline = lineno[ifno];
#endif
if ( flslvl == 0 && yyparse() )
++trulvl;
else
++flslvl;
p = newp;
if ( trulvl + flslvl >= MAX_DEPTH )
pperror( "#if,ifdef,ifndef nesting too deep" );
else
ifelstk[trulvl + flslvl] =
flslvl ? 0 : TRUE_ELIF;
#endif
}
else if ( np == lneloc ) /* line */
{
if ( flslvl == 0 && pflag == 0 )
{
register char *s;
register int ln;
outp = inp = p;
do_line:
*--outp = '#';
/*
* make sure that the whole
* directive has been read
*/
s = p;
while ( *s && *s != '\n' )
s++;
if ( eob( s ) )
p = refill( s );
/*
* eat the line number
*/
s = inp;
while ( ( toktyp + COFF )[*s] == BLANK )
s++;
ln = 0;
while ( isdigit( *s ) )
ln = ln * 10 + *s++ - '0';
if ( ln )
lineno[ifno] = ln - 1;
else
pperror( "bad number for #line" );
/*
* eat the optional "filename"
*/
while ( ( toktyp + COFF )[*s] == BLANK )
s++;
if ( *s != '\n' )
{
if ( *s != '"' )
pperror( "bad file for #line" );
else
{
register char *t = savch;
for ( ;; )
{
if ( *++s == '"' )
break;
else if ( *s == '\n' ||
*s == '\0' )
{
pperror( "bad file for #line" );
break;
}
*t++ = *s;
}
*t++ = '\0';
if ( strcmp( savch, fnames[ifno] ) )
{
fnames[ifno] = savch;
fdates[ifno] = findfdate( &fnames[ifno] );
savch = t;
}
}
}
/*
* push it all along to be eventually printed
*/
while ( *inp != '\n' )
p = cotoken( p );
continue;
}
}
else if ( np == clsloc ) /* class */
exfail = CLASSCODE; /* return value */
else if ( np == idtloc ) /* ident */
{
if ( pflag == 0 )
while ( *inp != '\n' ) /* just pass it along */
p = cotoken( p );
}
#ifdef PRAGMA
else if ( np == pragmaloc ) { /* pragma */
while ( *inp != '\n' ) /* pass it all along */
p = cotoken( p );
}
#endif
else if ( *++inp == '\n' ) /* allows blank line after # */
outp = inp;
else if ( isdigit( *inp ) ) /* pass thru line directives */
{
outp = p = inp;
goto do_line;
}
else
pperror( "undefined control", 0 );
/* flush to lf */
++flslvl;
while ( *inp != '\n' )
{
outp = inp = p;
p = cotoken( p );
}
--flslvl;
}
}
struct symtab *
stsym( s )
register char *s;
{
char buf[BUFSIZ];
register char *p;
/* make definition look exactly like end of #define line */
/* copy to avoid running off end of world when param list is at end */
p = buf;
while ( *p++ = *s++ )
;
p = buf;
while ( isid( *p++ ) ) /* skip first identifier */
;
if ( *--p == '=' )
{
*p++ = ' ';
while ( *p++ )
;
}
else
{
s = " 1";
while ( *p++ = *s++ )
;
}
pend = p;
*--p = '\n';
sloscan();
dodef( buf );
return( lastsym );
}
struct symtab *
ppsym( s ) /* kludge */
char *s;
{
register struct symtab *sp;
cinit = SALT;
*savch++ = SALT;
sp = stsym( s );
--sp->name;
cinit = 0;
return( sp );
}
int yy_errflag; /* TRUE when pperror called by yyerror() */
/* VARARGS1 */
pperror( s, x, y )
char *s;
{
if ( fnames[ifno][0] )
# if gcos
fprintf( stderr, ERRFORM, exfail >= 0 ? 'F' : 'W',fnames[ifno]);
# else
fprintf( stderr, "%s: ", fnames[ifno] );
# endif
fprintf( stderr, "%d: ", lineno[ifno] );
fprintf( stderr, s, x, y );
if ( yy_errflag )
fprintf( stderr, " (in preprocessor if)\n" );
else
fprintf( stderr, "\n" );
if ( exfail < CLASSCODE - 1 )
++exfail;
}
yyerror( s, a, b )
char *s;
{
yy_errflag = 1;
pperror( s, a, b );
yy_errflag = 0;
}
ppwarn( s, x )
char *s;
{
int fail = exfail;
exfail = -1;
pperror( s, x );
exfail = fail;
}
struct symtab *
lookup( namep, enterf )
char *namep;
{
register char *np, *snp;
register int c, i;
int around;
register struct symtab *sp;
/* namep had better not be too long (currently, <=ncps chars) */
np = namep;
around = 0;
i = cinit;
while ( c = *np++ )
i += i + c;
c = i; /* c=i for register usage on pdp11 */
c %= symsiz;
if ( c < 0 )
c += symsiz;
sp = &stab[c];
while ( snp = sp->name )
{
np = namep;
while ( *snp++ == *np )
if ( *np++ == '\0' )
{
if ( enterf == DROP )
{
sp->name[0] = DROP;
sp->value = 0;
}
return( lastsym = sp );
}
if ( --sp < &stab[0] )
if ( around )
{
pperror( "too many defines", 0 );
exit( exfail ? ( exfail ==
CLASSCODE ? CLASSCODE : 2 ) : 0 );
}
else
{
++around;
sp = &stab[symsiz - 1];
}
}
if ( enterf == 1 )
sp->name = namep;
return( lastsym = sp );
}
struct symtab *
slookup( p1, p2, enterf )
register char *p1, *p2;
int enterf;
{
register char *p3;
char c2, c3;
struct symtab *np;
c2 = *p2; /* mark end of token */
*p2 ='\0';
if ( ( p2 - p1 ) > ncps )
p3 = p1 + ncps;
else
p3 = p2;
c3 = *p3; /* truncate to ncps chars or less */
*p3 ='\0';
if ( enterf == 1 )
p1 = copy( p1 );
np = lookup( p1, enterf );
*p3 = c3;
*p2 = c2;
if ( np->value != 0 && flslvl == 0 )
newp = subst( p2, np );
else
newp = 0;
return( np );
}
char *
subst( p, sp )
register char *p;
struct symtab *sp;
{
static char match[] = "%s: argument mismatch";
register char *ca, *vp;
int params;
char *actual[MAXFRM]; /* actual[n] is text of nth actual */
char acttxt[BUFSIZ]; /* space for actuals */
if ( 0 == ( vp = sp->value ) )
return( p );
if ( ( p - macforw ) <= macdam )
{
if ( ++maclvl > symsiz && !rflag )
{
pperror( "%s: macro recursion", sp->name );
return( p );
}
}
else
maclvl = 0; /* level decreased */
macforw = p; /* new target for decrease in level */
macdam = 0;
macnam = sp->name;
#ifdef CXREF
ref(macnam, lineno[ifno]);
#endif
dump();
if ( sp == ulnloc )
{
vp = acttxt;
*vp++ = '\0';
sprintf( vp, "%d", lineno[ifno] );
while ( *vp++ )
;
}
else if ( sp == uflloc )
{
vp = acttxt;
*vp++ = '\0';
sprintf( vp, "\"%s\"", fnames[ifno] );
while ( *vp++ )
;
}
if ( 0 != ( params = *--vp & 0xFF ) ) /*definition calls for params */
{
register char **pa;
int dparams; /* parameters in definition */
ca = acttxt;
pa = actual;
if ( params == 0xFF ) /* #define foo() ... */
params = 0;
dparams = params;
sloscan();
++flslvl; /* no expansion during search for actuals */
plvl = -1;
maclin = lineno[ifno];
macfil = fnames[ifno];
do
{
p = skipbl( p );
}
while ( *inp == '\n' ); /* skip \n too */
if ( *inp == '(' )
{
for ( plvl = 1; plvl != 0; )
{
*ca++ = '\0';
for ( ;; )
{
outp = inp = p;
p = cotoken( p );
if ( *inp == '(' )
++plvl;
if ( *inp == ')' && --plvl == 0 )
{
if ( ca > acttxt+1 )
--params;
break;
}
if ( plvl == 1 && *inp == ',' )
{
--params;
break;
}
while ( inp < p )
{
/*
* toss newlines in arguments
* to macros - keep problems
* to a minimum.
* if a backslash is just
* before the newline, assume
* it is in a string and
* leave it in.
*/
if ( *inp == '\n'
&& inp[-1] != '\\' )
{
*inp = ' ';
}
*ca++ = *inp++;
}
if ( ca > &acttxt[BUFSIZ] )
pperror( "%s: actuals too long", sp->name );
}
if ( pa >= &actual[MAXFRM] )
ppwarn( match, sp->name );
else
*pa++ = ca;
}
}
else { /* should have seen (, because def
** had args
*/
ppwarn( match, sp->name );
p = inp; /* back up to current token */
}
if ( maclin != lineno[ifno] ) /* embedded linefeeds in macro call */
{
int i, j = lineno[ifno];
for ( i = sizeof( int ) / sizeof( char ); --i >= 0; )
{
if ( bob( p ) )
{
outp = inp = p;
p = unfill( p );
}
*--p = j;
j >>= 8;
}
if ( bob( p ) )
{
outp = inp = p;
p = unfill( p );
}
*--p = warnc;
}
/* def with one arg and use with zero args is special ok case */
if ( params < 0 || (params > 0 && dparams != 1) )
ppwarn( match, sp->name );
while ( --params >= 0 )
*pa++ = "" + 1; /* null string for missing actuals */
--flslvl;
fasscan();
}
for ( ;; ) /* push definition onto front of input stack */
{
while ( !iswarn( *--vp ) )
{
if ( bob( p ) )
{
outp = inp = p;
p = unfill( p );
}
*--p = *vp;
}
if ( *vp == warnc ) /* insert actual param */
{
ca = actual[*--vp - 1];
while ( *--ca )
{
if ( bob( p ) )
{
outp = inp = p;
p = unfill( p );
}
*--p = *ca;
}
}
else
break;
}
outp = inp = p;
return( p );
}
char *
trmdir( s )
register char *s;
{
register char *p = s;
while ( *p++ )
;
--p;
while ( p > s && *--p != '/' )
;
# if unix || DMERT
if ( p == s )
*p++ = '.';
# endif
*p = '\0';
return( s );
}
STATIC char *
copy( s )
register char *s;
{
register char *old;
old = savch;
while ( *savch++ = *s++ )
;
return( old );
}
yywrap()
{
return( 1 );
}
main( argc, argv )
char *argv[];
{
register int i, c;
register char *p;
char *tf, **cp2;
int forclass = 0; /* 1 if C-with-classes selected */
# if gcos
if ( setjmp( env ) )
return( exfail ? ( exfail == CLASSCODE ? CLASSCODE : 2 ) : 0 );
# endif
p = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
i = 0;
while ( c = *p++ )
{
( fastab + COFF )[c] |= IB | NB | SB;
( toktyp + COFF )[c] = IDENT;
#if scw2
/* 53 == 63-10; digits rarely appear in identifiers,
/* and can never be the first char of an identifier.
/* 11 == 53*53/sizeof(macbit) .
*/
++i;
( t21 + COFF )[c] = ( 53 * i ) / 11;
( t22 + COFF )[c] = i % 11;
#endif
}
p = "0123456789.";
while ( c = *p++ )
{
( fastab + COFF )[c] |= NB | SB;
( toktyp + COFF )[c] = NUMBR;
}
# if gcos
p = "\n\"'`/\\";
# else
p = "\n\"'/\\";
# endif
while ( c = *p++ )
( fastab + COFF )[c] |= SB;
# if gcos
p = "\n\"'`\\";
# else
p = "\n\"'\\";
# endif
while ( c = *p++ )
( fastab + COFF )[c] |= QB;
p = "*\n";
while ( c = *p++ )
( fastab + COFF)[c] |= CB;
( fastab + COFF )[warnc] |= WB | SB;
( fastab + COFF )['\0'] |= CB | QB | SB | WB;
for ( i = ALFSIZ; --i >= 0; )
slotab[i] = fastab[i] | SB;
p = " \t\v\f\r"; /* note no \n; */
while ( c = *p++ )
( toktyp + COFF )[c] = BLANK;
#if scw2
for ( ( t23 + COFF )[i = ALFSIZ + 7 - COFF] = 1; --i >= -COFF; )
if ( ( ( t23 + COFF )[i] = ( t23 + COFF + 1 )[i] << 1 ) == 0 )
( t23 + COFF )[i] = 1;
#endif
# if unix || DMERT
fnames[ifno = 0] = "";
fdates[ifno = 0] = "";
dirnams[0] = dirs[0] = ".";
# endif
# if ibm
fnames[ifno = 0] = "";
fdates[ifno = 0] = "";
# endif
# if gcos
if ( inquire( stdin, _TTY ) )
freopen( "*src", "rt", stdin );
# endif
# if gimpel || gcos
fnames[ifno = 0] = (char *) inquire( stdin, _FILENAME );
dirnams[0] = dirs[0] = trmdir( copy( fnames[0] ) );
# endif
for ( i = 1; i < argc; i++ )
{
switch ( argv[i][0] )
{
case '-':
# if gcos
/* case-independent on GCOS */
switch ( toupper( argv[i][1] ) )
# else
switch( argv[i][1] )
# endif
{
case 'M': /* research: filename+moddate*/
mflag++;
continue;
case 'P':
pflag++;
case 'E':
continue;
case 'R':
++rflag;
continue;
case 'C':
passcom++;
continue;
#ifdef CXREF
case 'F':
if ((outfp = fopen(argv[++i],"w")) == NULL)
{
fprintf(stderr, "Can't open %s\n",
argv[i]);
exit(1);
}
continue;
#endif
case 'D':
if ( predef > prespc + NPREDEF )
{
pperror( "too many -D options, ignoring %s", argv[i] );
continue;
}
/* ignore plain "-D" (no argument) */
if ( *( argv[i] + 2 ) )
*predef++ = argv[i] + 2;
continue;
case 'U':
if ( prund > punspc + NPREDEF )
{
pperror( "too many -U options, ignoring %s", argv[i] );
continue;
}
*prund++ = argv[i] + 2;
continue;
case 'I':
if ( nd > MAXINC - 4 )
pperror( "excessive -I file (%s) ignored", argv[i] );
else
dirs[nd++] = argv[i] + 2;
continue;
case 'Y':
dfltdir = argv[i] + 2;
continue;
case '\0':
continue;
case 'T':
ncps = 8; /* backward name compatabilty */
continue;
case 'H': /* print included filenames */
print_incs++;
continue;
case 'W': /* enable C with classes */
forclass = 1;
continue;
default:
pperror( "unknown flag %s", argv[i] );
continue;
}
default:
if ( fin == stdin )
{
if ( NULL == ( fin = fopen( argv[i], READ ) ) )
{
pperror( "No source file %s", argv[i] );
exit(2);
}
fnames[ifno] = copy( argv[i] );
fdates[ifno] = getfdate( fin );
#ifdef CXREF
fprintf(outfp,"\"%s\"\n", fnames[ifno]);
#endif
dirs[0] = dirnams[ifno] = trmdir( argv[i] );
# ifndef gcos
/* too dangerous to have file name in same syntactic position
be input or output file depending on file redirections,
so force output to stdout, willy-nilly
[i don't see what the problem is. jfr]
*/
}
else if ( fout == stdout )
{
static char _sobuf[BUFSIZ];
if ( NULL == ( fout = fopen( argv[i], WRITE ) ) )
{
pperror( "Can't create %s", argv[i] );
exit(2);
}
else
{
fclose( stdout );
setbuf( fout, _sobuf );
}
# endif
}
else
pperror( "extraneous name %s", argv[i] );
}
}
fins[ifno] = fin;
exfail = 0;
/* after user -I files here are the standard include libraries */
/* use user-supplied default first */
if (dfltdir != (char *) 0)
dirs[nd++] = dfltdir;
else {
# if unix || DMERT
# if defined(SGSINC) || defined(DMERT)
if ( strlen( SGSINC ) != 0 )
dirs[nd++] = SGSINC; /* For cross cpp's */
# endif
# ifdef USRINC
if ( strlen( USRINC ) != 0 )
dirs[nd++] = USRINC; /* usually /usr/include */
# endif
# if !defined( SGSINC ) && !defined( USRINC )
dirs[nd++] = "/usr/include";
# endif
# endif
# if gcos
dirs[nd++] = "cc/include";
# endif
# if ibm
# ifndef gimpel
dirs[nd++] = "BTL$CLIB";
# endif
# endif
# ifdef gimpel
dirs[nd++] = intss() ? "SYS3.C." : "";
# endif
# ifdef compool
dirs[nd++] = "/compool";
# endif
}
dirs[nd++] = 0;
defloc = ppsym( "define" );
udfloc = ppsym( "undef" );
incloc = ppsym( "include" );
elsloc = ppsym( "else" );
eifloc = ppsym( "endif" );
elifloc = ppsym( "elif" );
ifdloc = ppsym( "ifdef" );
ifnloc = ppsym( "ifndef" );
ifloc = ppsym( "if" );
lneloc = ppsym( "line" );
if (forclass) /* only when C with classes enabled */
clsloc = ppsym( "class" );
idtloc = ppsym( "ident" );
#ifdef PRAGMA
pragmaloc = ppsym( "pragma" );
#endif
for ( i = sizeof( macbit ) / sizeof( macbit[0] ); --i >= 0; )
macbit[i] = 0;
if ( pdef_mach[PD_MACH] )
ysysloc = stsym( pdef_mach[PD_MACH] );
if ( pdef_sys[PD_SYS] )
varloc = stsym( pdef_sys[PD_SYS] );
tf = fnames[ifno]; /* do the -D and -U options now */
fnames[ifno] = "command line";
lineno[ifno] = 1;
cp2 = prespc;
while ( cp2 < predef )
stsym( *cp2++ );
cp2 = punspc;
while ( cp2 < prund )
{
if ( p = strchr( *cp2, '=' ) )
*p = '\0';
/*
* Truncate to ncps characters if needed.
*/
if ( strlen( *cp2 ) > ncps )
(*cp2)[ncps] = '\0';
lookup( *cp2++, DROP );
}
ulnloc = stsym( "__LINE__" );
uflloc = stsym( "__FILE__" );
fnames[ifno] = tf;
pbeg = buffer + ncps;
pbuf = pbeg + BUFSIZ;
pend = pbuf + BUFSIZ;
trulvl = 0;
flslvl = 0;
lineno[0] = 1;
sayline();
outp = inp = pend;
#ifdef CXREF
ready = 1;
#endif
control( pend );
if ( fout && ferror( fout ) )
pperror( "Problems with output file; probably out of temp space" );
exit( exfail ? ( exfail == CLASSCODE ? CLASSCODE : 2 ) : 0 );
}
#ifdef CXREF
ref( name, line )
char *name;
int line;
{
#ifdef FLEXNAMES
fprintf(outfp, "R%s\t%05d\n", name, line);
#else
fprintf(outfp, "R%.8s\t%05d\n", name, line);
#endif
}
def( name, line )
char *name;
int line;
{
if (ready)
#ifdef FLEXNAMES
fprintf(outfp, "D%s\t%05d\n", name, line);
#else
fprintf(outfp, "D%.8s\t%05d\n", name, line);
#endif
}
newf( name, line )
char *name;
int line;
{
#ifdef FLEXNAMES
fprintf(outfp, "F%s\t%05d\n", name, line);
#else
fprintf(outfp, "F%.8s\t%05d\n", name, line);
#endif
}
char *
xcopy( ptr1, ptr2 )
register char *ptr1, *ptr2;
{
static char name[NCPS];
char *saveptr, ch;
register char *ptr3 = name;
/* locate end of name; save character there */
if ((ptr2 - ptr1) > ncps)
{
saveptr = ptr1 + ncps;
ch = *saveptr;
*saveptr = '\0';
}
else {
ch = *ptr2;
*ptr2 = '\0';
saveptr = ptr2;
}
while (*ptr3++ = *ptr1++) ; /* copy name */
*saveptr = ch; /* replace character */
return( name );
}
#endif
/* Scan over the end of a directive, making sure there's no
** residual junk.
**
** This code is a little messier than you might expect. To avoid bumping
** the line number when we hit the newline, print the message the first time
** we find we've got too many tokens.
*/
char *
chkend( p, ntoken )
char * p;
int ntoken; /* number of tokens at which to warn */
{
int extratokens = 0;
int save_passcom = passcom;
passcom = 0; /* ignore comments in this context */
++flslvl; /* don't expand anything */
/* if at newline, force rescan to do end-of-line stuff */
if (*inp == '\n')
p = inp;
for (;;) {
p = skipbl(p); /* get next token */
if (*inp == '\n')
break; /* reached end */
if(++extratokens == ntoken) /* hit number of extras; flag here */
ppwarn("extra tokens (ignored) after directive");
}
/* restore comment flag */
passcom = save_passcom;
--flslvl; /* back to previous expansion level */
return( p );
}
char *
getfdate( fin )
FILE *fin;
{
char date[ 10 ];
struct stat sb;
if ( !mflag )
return "";
fstat( fileno( fin ), &sb );
sprintf( date, "@%ld", sb.st_mtime );
return copy( date );
}
char *
findfdate( fname )
char *fname;
{
register char *s;
for ( s = fname; *s; s++ )
if ( *s == '@' ) {
*s++ = 0;
break;
}
return s;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.