3398 lines
69 KiB
C
3398 lines
69 KiB
C
/* Copyright (c) 1984 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)cpp.c 1.1 94/10/31 SMI"; /* from S5R3.1 1.41 */
|
|
#endif
|
|
|
|
|
|
#ifdef FLEXNAMES
|
|
# define NCPS 128
|
|
#else
|
|
# define NCPS 8
|
|
#endif
|
|
int ncps = NCPS; /* default name length */
|
|
|
|
# include "stdio.h"
|
|
# include "ctype.h"
|
|
#ifdef SUNPRO
|
|
# include <sys/file.h>
|
|
# include <vroot.h>
|
|
# include <report.h>
|
|
#endif
|
|
#ifdef BROWSER
|
|
# include <sys/types.h>
|
|
# include <sys/stat.h>
|
|
# include "cb_cpp_protocol.h"
|
|
# include "cb_line_id.h"
|
|
#else
|
|
#include "-DBROWSER should be left ON!"
|
|
#endif
|
|
/* C command - C preprocessor */
|
|
|
|
#define STATIC
|
|
|
|
#define CLASSCODE 27 /* exit status if #class seen */
|
|
|
|
#define READ "r"
|
|
#define WRITE "w"
|
|
#define SALT '#'
|
|
|
|
# define PAGESIZ 8192
|
|
|
|
/*
|
|
* The last token printed on the "# linenumber filename" lines.
|
|
*/
|
|
#define NOINCL "" /* Has nothing to do with an include file */
|
|
#define PUSHINCL "1" /* Have just entered an include file */
|
|
#define POPINCL "2" /* Have just exited an include file */
|
|
|
|
char *pbeg, *pbuf, *pend;
|
|
char *outp, *inp;
|
|
char *newp;
|
|
char cinit;
|
|
|
|
int cxref = 0;
|
|
char *xcopy();
|
|
FILE *outfp;
|
|
static int ready = 0;
|
|
int xline;
|
|
int predefining = 1;
|
|
int default_include = 1;
|
|
|
|
/* 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 | mc68000 | sparc | i386
|
|
# 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 + PAGESIZ + PAGESIZ + NCPS ];
|
|
|
|
# define MAXNEST 12 /* max number of nested #include's */
|
|
# define MAXFRE 14 /* max buffers of macro pushback */
|
|
|
|
# define SBSIZE 65536
|
|
|
|
char *sbf = NULL;
|
|
char *savch = NULL;
|
|
|
|
char *malloc(), *calloc();
|
|
|
|
# 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 */
|
|
|
|
#ifdef BROWSER
|
|
# define CBCHUNK_POWER 9 /* Line id blocks as a power of 2 */
|
|
# define CBCHUNK_SIZE ( 1 << CBCHUNK_POWER ) /* No. line id blocks/chunk */
|
|
# define CBCHUNK_MASK ( CBCHUNK_SIZE - 1 ) /* Mask of low order bits */
|
|
Cb_line_id cbchunks[ PAGESIZ / CBCHUNK_SIZE ];
|
|
int cbcount = 0; /* Number of line ids to flush */
|
|
#endif
|
|
|
|
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 *realnames[ MAXNEST ];
|
|
STATIC char *dirnams[ MAXNEST ]; /* actual directory of #include files */
|
|
STATIC FILE *fins[ MAXNEST ];
|
|
STATIC int lineno[ MAXNEST ];
|
|
#ifdef BROWSER
|
|
STATIC int cbhashes[ MAXNEST ]; /* Current hash value for line */
|
|
STATIC int cblengths[ MAXNEST ]; /* Current lengths for line */
|
|
#endif
|
|
|
|
#ifdef SUNPRO
|
|
STATIC pathcellpt dirs= NULL;
|
|
#else
|
|
STATIC char *dirs[ MAXINC ]; /* -I and <> directories */
|
|
#endif
|
|
STATIC char *dfltdir = (char *) 0; /* user-supplied default (like /usr/include) */
|
|
char *copy(), *subst(), *trmdir(), *strchr(), *strrchr();
|
|
char *chkend();
|
|
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 ignoreline; /* ignore "#line" entries */
|
|
STATIC int passcom; /* don't delete comments */
|
|
STATIC int eolcom; /* allow // ... \n comments */
|
|
STATIC int incomm; /* set while in comment so that EOF can be detected */
|
|
STATIC int rflag; /* allow macro recursion */
|
|
STATIC int mflag; /* generate makefile dependencies */
|
|
STATIC char *infile; /* name of .o file to build dependencies from */
|
|
STATIC FILE *mout; /* file to place dependencies on */
|
|
STATIC int print_incs; /* set to print out included filenames */
|
|
STATIC int port_flag; /* set to check for unportable constructs */
|
|
STATIC int ifno;
|
|
STATIC int exfail;
|
|
#ifdef BROWSER
|
|
STATIC int cbflag; /* Pass code browser info to ccom */
|
|
STATIC int cbsuppress; /* Suppress code browser info */
|
|
STATIC char *cbmacend; /* End of macro expansion (or NULL) */
|
|
STATIC int cbifline; /* Lineno for last #if */
|
|
STATIC int cbifsay; /* Lineno for last sayline() */
|
|
STATIC int cbfirst = 1; /* First time through sayline */
|
|
STATIC char cbsuffix; /* Suffix for source file */
|
|
STATIC int cbinsubst = 0; /* 1 => inside of subst() */
|
|
STATIC int cbversionsend = 1; /* 1 => send version number */
|
|
#endif
|
|
|
|
struct symtab
|
|
{
|
|
char *name;
|
|
char *value;
|
|
struct symtab *next; /* pointer to next chain entry */
|
|
} *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 %s\n"
|
|
# define ERRFORM "*%c* %s, line "
|
|
# else
|
|
# define symsiz 500
|
|
# define LINEFORM "# %d \"%s\" %s\n"
|
|
# define ERRFORM "*%c* \"%s\", line "
|
|
# endif
|
|
STATIC struct symtab *stab[ symsiz ];
|
|
|
|
#define BKTINC 50 /* max space obtainable by calloc */
|
|
#define ELEMSIZ sizeof(struct symtab)
|
|
|
|
STATIC struct symtab *sfree = NULL; /* pointer to next free space */
|
|
STATIC int nfree = 0; /* number of free cells */
|
|
|
|
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 *lneloc;
|
|
STATIC struct symtab *ulnloc;
|
|
STATIC struct symtab *uflloc;
|
|
STATIC struct symtab *clsloc;
|
|
STATIC struct symtab *idtloc;
|
|
STATIC struct symtab *pragloc;
|
|
STATIC int trulvl;
|
|
STATIC int flslvl;
|
|
STATIC char *expanding_params;
|
|
#define MAX_DEPTH 500 /* max of trulvl + flslvl */
|
|
#define SEEN_ELSE 0x1
|
|
#define TRUE_ELIF 0x2
|
|
STATIC char ifelstk[MAX_DEPTH];
|
|
|
|
sayline( incl )
|
|
char *incl;
|
|
{
|
|
if ( pflag == 0 )
|
|
{
|
|
#ifdef BROWSER
|
|
/*
|
|
* The code browser generates more saylines, hence a more
|
|
* compact representation used. Also the first sayline for
|
|
* a file contains the file timestamp.
|
|
*/
|
|
if ( cbflag )
|
|
{
|
|
if ( ( incl[0] == '\0' ) && ( !cbfirst ) )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_LINENO, fout );
|
|
cbputlineno( fout, lineno[ifno] );
|
|
}
|
|
else
|
|
{
|
|
if ( cbfirst )
|
|
cbfirst = 0;
|
|
else
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_SAYLINE, fout );
|
|
}
|
|
fprintf( fout, "# %d \"%s\" %s\n",
|
|
lineno[ifno], fnames[ifno], incl );
|
|
}
|
|
if ( cbversionsend )
|
|
{
|
|
cbversionsend = 0;
|
|
fprintf( fout, "%c%c%d%c", CB_CHR_PREFIX,
|
|
CB_CHR_VERSION,
|
|
CB_CPP_PROTOCOL_VERSION,
|
|
CB_CHR_END_ID );
|
|
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
fprintf( fout, LINEFORM,
|
|
lineno[ifno], fnames[ifno], incl );
|
|
}
|
|
}
|
|
|
|
/* data structure guide
|
|
/*
|
|
/* most of the scanning takes place in the buffer:
|
|
/*
|
|
/* (low address) (high address)
|
|
/* pbeg pbuf pend
|
|
/* | <-- PAGESIZ chars --> | <-- PAGESIZ 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 )
|
|
#ifdef BROWSER
|
|
{
|
|
if ( ( cbmacend != NULL ) && ( outp >= cbmacend ) &&
|
|
( *inp != '\0' ) && ( !cbinsubst ) )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_MACRO_REF_END, fout );
|
|
cbmacend = NULL;
|
|
}
|
|
return;
|
|
}
|
|
#else
|
|
return;
|
|
#endif
|
|
#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( NOINCL );
|
|
*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
|
|
if ( p1 < inp )
|
|
p1 += fwrite( p1, sizeof( char ), inp - p1, f );
|
|
outp = p1;
|
|
#ifdef BROWSER
|
|
/*
|
|
* Do not output CB_CHR_MACRO_REF_END when the input buffer is empty.
|
|
* It may be the case that a compiler lexeme splits (such as "->")
|
|
* across the buffer boundary. Some compilers can not cope with
|
|
* code browser information in the middle of lexemes.
|
|
*/
|
|
if ( ( cbmacend != NULL ) && ( outp >= cbmacend ) &&
|
|
( *inp != '\0' ) && ( !cbinsubst ) )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_MACRO_REF_END, fout );
|
|
cbmacend = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef BROWSER
|
|
cbflushids()
|
|
{
|
|
register int i, count;
|
|
|
|
dump();
|
|
count = cbcount;
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_LINE_ID, fout );
|
|
putc( count & 255, fout );
|
|
putc( count >> 8, fout );
|
|
i = 0;
|
|
while ( count > 0 )
|
|
count -= fwrite( cbchunks[ i++ ], sizeof( Cb_line_id_rec ),
|
|
( count >= CBCHUNK_SIZE ) ?
|
|
CBCHUNK_SIZE : count, fout );
|
|
cbcount = count;
|
|
}
|
|
|
|
/*
|
|
* Pre-scan the buffer and compute line id's for the code browser.
|
|
*/
|
|
cbprescan()
|
|
{
|
|
register char c, *p;
|
|
register int length, hash, count;
|
|
register Cb_line_id line_id;
|
|
Cb_line_id chunk;
|
|
|
|
if ( cbcount > 0 )
|
|
{
|
|
perror( "line ids for -cb flag are messed up" );
|
|
exit( 2 );
|
|
}
|
|
p = pbuf;
|
|
hash = cbhashes[ifno];
|
|
length = cblengths[ifno];
|
|
count = 0;
|
|
for ( ;; )
|
|
{
|
|
if ( ( ( c = *p++ ) == '\0' ) && ( p >= pend ) )
|
|
{
|
|
cbhashes[ifno] = hash;
|
|
cblengths[ifno] = length;
|
|
cbcount = count;
|
|
return;
|
|
}
|
|
else if ( c == '\n' )
|
|
{
|
|
if ( ( count & CBCHUNK_MASK ) == 0 )
|
|
{
|
|
if ( cbchunks[ count >> CBCHUNK_POWER ] == 0 )
|
|
{
|
|
chunk = (Cb_line_id_rec *) malloc(
|
|
CBCHUNK_SIZE * sizeof( Cb_line_id_rec ) );
|
|
if ( chunk == NULL )
|
|
{
|
|
perror( "Out of memory" );
|
|
exit( 1 );
|
|
}
|
|
cbchunks[ count >> CBCHUNK_POWER ] =
|
|
chunk;
|
|
}
|
|
chunk = cbchunks[ count >> CBCHUNK_POWER ];
|
|
}
|
|
line_id = &chunk[ count & CBCHUNK_MASK ];
|
|
line_id->hash = hash;
|
|
line_id->length = length;
|
|
line_id->is_inactive = 0;
|
|
count++;
|
|
hash = 0;
|
|
length = 0;
|
|
}
|
|
else
|
|
{
|
|
hash += c;
|
|
length++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
#ifdef BROWSER
|
|
register int d;
|
|
#endif
|
|
|
|
dump();
|
|
np = pbuf - ( p - inp );
|
|
op = inp;
|
|
#ifdef BROWSER
|
|
if ( cbmacend != NULL )
|
|
d = cbmacend - p;
|
|
#endif
|
|
if ( bob( np + 1 ) )
|
|
{
|
|
pperror( "token too long" );
|
|
np = pbeg;
|
|
p = inp + PAGESIZ;
|
|
}
|
|
macdam += np - inp;
|
|
outp = inp = np;
|
|
while ( op < p )
|
|
*np++ = *op++;
|
|
p = np;
|
|
#ifdef BROWSER
|
|
if ( cbmacend != NULL )
|
|
cbmacend = p + d;
|
|
#endif
|
|
for ( ;; )
|
|
{
|
|
/* retrieve hunk of pushed-back macro text */
|
|
if ( mactop > inctop[ifno] )
|
|
{
|
|
op = instack[ --mactop ];
|
|
np = pbuf;
|
|
do
|
|
{
|
|
while ( *np++ = *op++ )
|
|
;
|
|
}
|
|
while ( op < endbuf[mactop] );
|
|
pend = np - 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 ( 0 < ( ninbuf = fread( pbuf, sizeof( char ), PAGESIZ, fin ) ) )
|
|
{
|
|
pend = pbuf + ninbuf;
|
|
*pend = '\0';
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
cbprescan();
|
|
#endif
|
|
return( p );
|
|
}
|
|
if ( ferror( fin ) )
|
|
{
|
|
fprintf( stderr, "cpp: Error reading ");
|
|
perror( realnames[ifno] );
|
|
exit(2);
|
|
}
|
|
/* 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 )
|
|
{
|
|
if ( !passcom )
|
|
--flslvl;
|
|
pperror( "missing */" );
|
|
}
|
|
if ( expanding_params ) {
|
|
pperror( "%s: argument mismatch",
|
|
expanding_params );
|
|
--flslvl;
|
|
}
|
|
if ( trulvl +flslvl > 0 )
|
|
pperror( "missing #endif" );
|
|
inp = p;
|
|
dump();
|
|
if ( fout && ferror( fout ) )
|
|
{
|
|
perror( "cpp: Can't write output file" );
|
|
if ( exfail < CLASSCODE - 1 )
|
|
++exfail;
|
|
}
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( cbmacend != NULL ) )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_MACRO_REF_END, fout );
|
|
cbmacend = NULL;
|
|
}
|
|
#endif
|
|
exit( exfail ? ( exfail ==
|
|
CLASSCODE ? CLASSCODE : 2 ) : 0 );
|
|
}
|
|
fclose( fin );
|
|
fin = fins[--ifno];
|
|
#ifdef SUNPRO
|
|
add_dir_to_path(dirnams[ifno], &dirs, 0);
|
|
#else
|
|
dirs[0] = dirnams[ifno];
|
|
#endif
|
|
#ifdef BROWSER
|
|
if ( cbcount > 0 )
|
|
cbflushids();
|
|
#endif
|
|
sayline( POPINCL );
|
|
if ( cxref )
|
|
fprintf(outfp, "\"%s\"\n", fnames[ifno]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define BEG 0
|
|
#define LF 1
|
|
|
|
char *
|
|
cotoken( p )
|
|
register char *p;
|
|
{
|
|
register int c, i;
|
|
char quoc;
|
|
static int state = BEG;
|
|
|
|
if ( state != BEG )
|
|
goto prevlf;
|
|
for ( ;; )
|
|
{
|
|
again:
|
|
#ifdef BROWSER
|
|
if ( ( cbmacend != NULL ) && ( p >= cbmacend ) )
|
|
{
|
|
dump(); /* Force out end macro reference. */
|
|
}
|
|
#endif
|
|
while ( !isspc( *p++ ) )
|
|
;
|
|
switch ( *( inp = p - 1 ) )
|
|
{
|
|
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 == '/' && eolcom )
|
|
{
|
|
p++;
|
|
incomm++;
|
|
if ( !passcom )
|
|
{
|
|
inp = p - 2;
|
|
dump();
|
|
++flslvl;
|
|
}
|
|
for ( ;; )
|
|
{
|
|
while (*p && *p != '\n')
|
|
p++;
|
|
if ( p[0] == '\n' )
|
|
{
|
|
goto endcpluscom;
|
|
}
|
|
else if ( eob( p ) )
|
|
{
|
|
if ( !passcom )
|
|
{
|
|
inp = p;
|
|
p = refill( p );
|
|
}
|
|
else if ( (p - inp) >= BUFSIZ ) /* split long comment */
|
|
{
|
|
inp = p;
|
|
refill( p );
|
|
}
|
|
else
|
|
p = refill( p );
|
|
}
|
|
else
|
|
++p; /* ignore null byte */
|
|
}
|
|
endcpluscom:
|
|
if ( !passcom )
|
|
{
|
|
outp = inp = p;
|
|
--flslvl;
|
|
}
|
|
incomm--;
|
|
break;
|
|
}
|
|
else 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 ) >= PAGESIZ )
|
|
{
|
|
*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 ) >= PAGESIZ )
|
|
{
|
|
*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++ ) )
|
|
;
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( p[-1] == CB_CHR_PREFIX ) &&
|
|
( flslvl == 0 ) )
|
|
{
|
|
inp = p;
|
|
dump();
|
|
putc( CB_CHR_CONTROL_A, fout );
|
|
}
|
|
|
|
#endif
|
|
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;
|
|
int reallineno;
|
|
|
|
dump();
|
|
reallineno = 0;
|
|
for ( ii = sizeof(int) / sizeof(char); --ii >= 0; )
|
|
{
|
|
if ( eob( p ) )
|
|
p = refill( p );
|
|
reallineno |= ( *p++ & 0xFF ) << ( ii * 8 );
|
|
}
|
|
lineno[ifno] = reallineno;
|
|
putc('\n', fout);
|
|
sayline( NOINCL );
|
|
inp = outp = p;
|
|
break;
|
|
}
|
|
case '\n':
|
|
newline:
|
|
#ifdef BROWSER
|
|
if ( cbcount > 0 )
|
|
cbflushids();
|
|
#endif
|
|
++lineno[ifno];
|
|
if ( isslo )
|
|
{
|
|
state=LF;
|
|
return( p );
|
|
}
|
|
prevlf:
|
|
state = BEG;
|
|
for ( ;; )
|
|
{
|
|
/*
|
|
* ignore formfeeds and vertical tabs
|
|
* which may be just before the SALT
|
|
*/
|
|
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;
|
|
}
|
|
}
|
|
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 <= PAGESIZ 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] )
|
|
{
|
|
p = refill( p );
|
|
p = inp = pend;
|
|
dump();
|
|
}
|
|
}
|
|
if ( fretop > 0 )
|
|
np = bufstack[--fretop];
|
|
else
|
|
{
|
|
np = savch;
|
|
savch += PAGESIZ;
|
|
if ( savch >= sbf + SBSIZE )
|
|
{
|
|
allocsbf();
|
|
np = savch;
|
|
savch += PAGESIZ;
|
|
}
|
|
*savch++ = '\0';
|
|
}
|
|
instack[mactop] = np;
|
|
op = pend - PAGESIZ;
|
|
if ( op < p )
|
|
op = p;
|
|
for ( ;; ) /* out with old */
|
|
{
|
|
while ( *np++ = *op++ )
|
|
;
|
|
if ( eob( op ) )
|
|
break;
|
|
}
|
|
endbuf[mactop++] = np; /* mark end of saved text */
|
|
np = pbuf + PAGESIZ;
|
|
op = pend - PAGESIZ;
|
|
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;
|
|
#ifdef BROWSER
|
|
if ( cbmacend != NULL )
|
|
cbmacend += d;
|
|
#endif
|
|
return( p + d );
|
|
}
|
|
|
|
char *
|
|
doincl( p )
|
|
register char *p;
|
|
{
|
|
int filok, inctype;
|
|
register char *cp;
|
|
char **dirp, *nfil;
|
|
char filname[PAGESIZ];
|
|
#ifdef SUNPRO
|
|
char translated[1000];
|
|
char symbol[256];
|
|
int fd;
|
|
#endif
|
|
#ifdef BROWSER
|
|
struct stat status;
|
|
char *namep;
|
|
#endif
|
|
|
|
p = skipbl( p );
|
|
#ifdef BROWSER
|
|
namep = inp;
|
|
#endif
|
|
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 */
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( flslvl == 0 ) && ( cbmacend == NULL ) )
|
|
cbputid( fout, CB_CHR_INCLUDE_SYSTEM,
|
|
xcopy( namep, inp + 1 ) );
|
|
#endif
|
|
}
|
|
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';
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( flslvl == 0 ) && ( cbmacend == NULL ) )
|
|
cbputid( fout, CB_CHR_INCLUDE_LOCAL,
|
|
xcopy( namep, inp ) );
|
|
#endif
|
|
}
|
|
else if ( inp[-1] == '\'' ) /* single quotes for quiche eaters */
|
|
{
|
|
inctype = 0;
|
|
# ifdef gimpel
|
|
while ( inp < p )
|
|
{
|
|
if ( *inp == '.' && !intss() )
|
|
*inp = '#';
|
|
*cp++ = *inp++;
|
|
}
|
|
# else
|
|
while ( inp < p )
|
|
*cp++ = *inp++;
|
|
# endif
|
|
if ( *--cp == '\'' )
|
|
*cp = '\0';
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( flslvl == 0 ) && ( cbmacend == NULL ) )
|
|
cbputid( fout, CB_CHR_INCLUDE_LOCAL,
|
|
xcopy( namep, inp ) );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* This is not an error if we're skipping */
|
|
if (!flslvl)
|
|
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 - PAGESIZ )
|
|
{
|
|
allocsbf();
|
|
nfil = savch;
|
|
}
|
|
|
|
/* check for #include "/usr/include/..." */
|
|
if (strncmp(filname, "/usr/include/", 13) == 0)
|
|
ppwarn("#include of /usr/include/... may be non-portable");
|
|
|
|
filok = 0;
|
|
if (inctype >= nd)
|
|
{
|
|
pperror( "Can't find include file %s", filname );
|
|
return(p);
|
|
}
|
|
#ifdef BROWSER
|
|
if ( cbcount > 0 )
|
|
cbflushids();
|
|
#endif
|
|
#ifdef SUNPRO
|
|
if ((fd= open_vroot(filname, O_RDONLY, 0, dirs + inctype, VROOT_DEFAULT)) >= 0)
|
|
{ char *path;
|
|
|
|
fins[ifno + 1] = fdopen(fd, "r");
|
|
filok = 1;
|
|
fin = fins[++ifno];
|
|
get_vroot_path(NULL, &path, NULL);
|
|
(void)strcpy(translated, path);
|
|
if ( print_incs )
|
|
fprintf( stderr, "%s\n", translated );
|
|
}
|
|
#else
|
|
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;
|
|
}
|
|
}
|
|
#endif
|
|
if ( filok == 0 )
|
|
pperror( "Can't find include file %s", filname );
|
|
else
|
|
{
|
|
#ifdef SUNPRO
|
|
fnames[ifno] = cp = copy(translated);
|
|
report_dependency(cp);
|
|
#else
|
|
fnames[ifno] = cp = nfil;
|
|
#endif
|
|
#ifdef BROWSER
|
|
cbhashes[ifno] = 0;
|
|
cblengths[ifno] = 0;
|
|
#endif
|
|
lineno[ifno] = 1;
|
|
realnames[ifno] = fnames[ifno];
|
|
while ( *cp++)
|
|
;
|
|
savch = cp;
|
|
#ifdef SUNPRO
|
|
dirnams[ifno] = trmdir( copy(translated ) );
|
|
add_dir_to_path(dirnams[ifno], &dirs, 0);
|
|
#else
|
|
dirnams[ifno] = dirs[0] = trmdir( copy( nfil ) );
|
|
#endif
|
|
sayline( PUSHINCL );
|
|
if ( mflag )
|
|
fprintf( mout, "%s: %s\n", infile, fnames[ifno] );
|
|
if ( cxref )
|
|
fprintf(outfp, "\"%s\"\n", fnames[ifno]);
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
if ( cbmacend != NULL )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_MACRO_REF_END, fout );
|
|
cbmacend = NULL;
|
|
}
|
|
}
|
|
#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[PAGESIZ]; /* space for formal names */
|
|
|
|
passcom=0; /* delete comments in all but body of macro */
|
|
|
|
if ( savch > sbf + SBSIZE - PAGESIZ )
|
|
allocsbf();
|
|
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 */
|
|
passcom = sav_passcom; /* restore to "real" value */
|
|
return( p );
|
|
}
|
|
np = slookup( pin, p, 1 );
|
|
if ( oldval = np->value ) /* was previously defined */
|
|
savch = oldsavch;
|
|
if ( cxref )
|
|
def(np->name, lineno[ifno]);
|
|
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 */
|
|
{
|
|
if ( cxref )
|
|
newf(np->name, lineno[ifno]);
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
cbputid( fout, CB_CHR_MACRO_DEF_W_FORMALS, np->name );
|
|
#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;
|
|
if ( cxref )
|
|
def(*(pf-1), lineno[ifno]);
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
cbputid( fout, CB_CHR_MACRO_FORMAL_DEF,
|
|
*(pf - 1) );
|
|
#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 */
|
|
#ifdef BROWSER
|
|
if ( cbflag && !cbsuppress )
|
|
cbputid( fout, CB_CHR_MACRO_DEF_WO_FORMALS, np->name );
|
|
#endif
|
|
}
|
|
/*
|
|
* 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 */
|
|
{
|
|
putc( '\n', fout );
|
|
continue;
|
|
}
|
|
if ( *pin == '\n' )
|
|
break;
|
|
#ifdef BROWSER
|
|
if ( cbflag && !cbsuppress &&
|
|
( ( *pin == '"' ) ||
|
|
( ( *pin == '\'' ) && ( cbsuffix == 'p' ) ) ) )
|
|
cbputid( fout, CB_CHR_MACRO_STRING_IN_DEF,
|
|
xcopy( pin, p ) );
|
|
#endif
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* skip // comment ivan Feb 1989
|
|
*/
|
|
|
|
if ( eolcom && *pin == '/' && pin[1] == '/' )
|
|
{
|
|
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 )
|
|
{
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
c = CB_CHR_MACRO_NON_FORMAL_REF;
|
|
#endif
|
|
for ( qf = pf; --qf >= formal; )
|
|
{
|
|
if ( equfrm( *qf, pin, p ) )
|
|
{
|
|
#ifndef NO_MACRO_FORMAL
|
|
if ( cxref )
|
|
ref(*qf, lineno[ifno]);
|
|
#endif
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
c = CB_CHR_MACRO_FORMAL_REF;
|
|
cbputid( fout, c, *qf );
|
|
}
|
|
#endif
|
|
*psav++ = qf - formal + 1;
|
|
*psav++ = WARN;
|
|
pin = p;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef BROWSER
|
|
if ( cbflag &&
|
|
( c == CB_CHR_MACRO_NON_FORMAL_REF ) )
|
|
cbputid( fout, c, xcopy( pin, p ) );
|
|
#endif
|
|
}
|
|
/* 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++;
|
|
}
|
|
}
|
|
}
|
|
#ifdef BROWSER
|
|
else if ( cbflag && !cbsuppress &&
|
|
isid( *pin ) && !isdigit( *pin ) )
|
|
cbputid( fout, CB_CHR_MACRO_NON_FORMAL_REF,
|
|
xcopy( pin, p ) );
|
|
#endif
|
|
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;
|
|
#ifdef BROWSER
|
|
if ( cbflag && !cbsuppress )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_MACRO_DEF_END, fout );
|
|
}
|
|
#endif
|
|
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
|
|
|
|
void
|
|
control( p ) /* find and handle preprocessor control lines */
|
|
register char *p;
|
|
{
|
|
register struct symtab *np;
|
|
int save_passcom;
|
|
#ifdef BROWSER
|
|
int cbline, cbflslvl = flslvl, cbkludge = 0;
|
|
#endif
|
|
|
|
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 == 0 )
|
|
++trulvl;
|
|
else
|
|
++flslvl;
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( flslvl <= 1 ) )
|
|
cbputid( fout,
|
|
( flslvl == 0) ?
|
|
CB_CHR_IFNDEF_UNDEFD :
|
|
CB_CHR_IFNDEF_DEFD,
|
|
xcopy( inp, p ) );
|
|
#endif
|
|
if ( trulvl + flslvl >= MAX_DEPTH )
|
|
pperror( "#if, #ifdef, #ifndef nesting too deep" );
|
|
else
|
|
ifelstk[trulvl + flslvl] =
|
|
flslvl ? 0 : TRUE_ELIF;
|
|
if ( cxref )
|
|
ref(xcopy(inp, p), lineno[ifno]);
|
|
p = chkend( p, 1 );
|
|
}
|
|
else if ( np == ifdloc ) /* ifdef */
|
|
{
|
|
LOOKUP(1/*skipbl*/, 0/*flag*/); /* sets "np" */
|
|
if ( flslvl == 0 && np != 0 )
|
|
++trulvl;
|
|
else
|
|
++flslvl;
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( flslvl <= 1 ) )
|
|
cbputid( fout,
|
|
( flslvl == 0) ?
|
|
CB_CHR_IFDEF_DEFD :
|
|
CB_CHR_IFDEF_UNDEFD,
|
|
xcopy( inp, p ) );
|
|
#endif
|
|
if ( trulvl + flslvl >= MAX_DEPTH )
|
|
pperror( "#if, #ifdef, #ifndef nesting too deep" );
|
|
else
|
|
ifelstk[trulvl + flslvl] =
|
|
flslvl ? 0 : TRUE_ELIF;
|
|
if ( cxref )
|
|
ref(xcopy(inp, p), lineno[ifno]);
|
|
p = chkend( p, 1 );
|
|
}
|
|
else if ( np == eifloc ) /* endif */
|
|
{
|
|
if ( flslvl )
|
|
{
|
|
if ( --flslvl == 0 )
|
|
sayline( NOINCL );
|
|
}
|
|
else if ( trulvl )
|
|
--trulvl;
|
|
else
|
|
pperror( "If-less endif", 0 );
|
|
p = chkend( p, 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;
|
|
if ( cxref )
|
|
xline = lineno[ifno];
|
|
if ( ifelstk[trulvl + flslvl + 1] == 0 )
|
|
{
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
sayline( NOINCL );
|
|
cbifsay = lineno[ifno];
|
|
cbflslvl = 0;
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_END_INACTIVE, fout );
|
|
putc( CB_CHR_PREFIX,
|
|
fout );
|
|
putc( CB_CHR_IF,
|
|
fout );
|
|
}
|
|
#endif BROWSER
|
|
if ( yyparse() )
|
|
{
|
|
++trulvl;
|
|
ifelstk[trulvl + flslvl] =
|
|
TRUE_ELIF;
|
|
sayline( NOINCL );
|
|
}
|
|
else
|
|
++flslvl;
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
putc( CB_CHR_PREFIX,
|
|
fout );
|
|
putc( ( flslvl == 0 ) ?
|
|
CB_CHR_IF_END_ACTIVE :
|
|
CB_CHR_IF_END_INACTIVE,
|
|
fout );
|
|
}
|
|
#endif BROWSER
|
|
}
|
|
else
|
|
++flslvl;
|
|
#ifdef BROWSER
|
|
if ( lineno[ifno] != cbifsay + 1 )
|
|
{
|
|
/* Fix for non-cb mode too! */
|
|
--lineno[ifno];
|
|
sayline( NOINCL );
|
|
++lineno[ifno];
|
|
}
|
|
cbifsay = cbifline = 0;
|
|
#endif BROWSER
|
|
p = newp;
|
|
}
|
|
}
|
|
else if ( trulvl )
|
|
{
|
|
++flslvl;
|
|
--trulvl;
|
|
#ifdef BROWSER
|
|
cbkludge++;
|
|
#endif BROWSER
|
|
}
|
|
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( NOINCL );
|
|
}
|
|
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 */
|
|
{
|
|
++flslvl;
|
|
p = skipbl( p ); /* inp -> start of undef id */
|
|
--flslvl;
|
|
if ( cxref )
|
|
ref(xcopy(inp, p), lineno[ifno]);
|
|
if ( flslvl == 0 )
|
|
{
|
|
LOOKUP(0/*skipbl*/, DROP); /* sets "np" */
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( flslvl == 0 ) )
|
|
cbputid( fout, CB_CHR_UNDEF,
|
|
xcopy( inp, p ) );
|
|
#endif
|
|
p = chkend( p, 1 );
|
|
}
|
|
else
|
|
p = chkend( p, 2 );
|
|
}
|
|
else if ( np == ifloc ) /* if */
|
|
{
|
|
#if tgp
|
|
pperror( " IF not implemented, true assumed", 0 );
|
|
if ( flslvl == 0 )
|
|
++trulvl;
|
|
else
|
|
++flslvl;
|
|
#else
|
|
# ifdef BROWSER
|
|
int cbtemp;
|
|
|
|
cbifsay = cbifline = lineno[ifno];
|
|
cbtemp = 0;
|
|
if ( cbflag && ( flslvl == 0 ) )
|
|
{
|
|
cbtemp = 1;
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_IF, fout );
|
|
}
|
|
# endif
|
|
newp = p;
|
|
if ( cxref )
|
|
xline = lineno[ifno];
|
|
if ( flslvl == 0 && yyparse() )
|
|
++trulvl;
|
|
else
|
|
++flslvl;
|
|
# ifdef BROWSER
|
|
if ( cbtemp )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( ( flslvl == 0 ) ? CB_CHR_IF_END_ACTIVE :
|
|
CB_CHR_IF_END_INACTIVE, fout );
|
|
}
|
|
if ( lineno[ifno] != cbifsay + 1 )
|
|
{
|
|
--lineno[ifno];
|
|
sayline( NOINCL );
|
|
++lineno[ifno];
|
|
}
|
|
cbifsay = cbifline = 0;
|
|
# endif
|
|
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 && ignoreline == 0 )
|
|
{
|
|
register char *s;
|
|
register int ln;
|
|
|
|
outp = inp = p;
|
|
do_line:
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_POUND_LINE, fout );
|
|
}
|
|
#endif
|
|
*--outp = '#';
|
|
/*
|
|
* make sure that the whole
|
|
* directive has been read
|
|
*/
|
|
s = p;
|
|
while ( *s && *s != '\n' )
|
|
s++;
|
|
if ( eob( s ) )
|
|
(void)refill( s );
|
|
/*
|
|
* eat the line number
|
|
*/
|
|
s = p = 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' )
|
|
{
|
|
register char *t = savch;
|
|
|
|
if ( *s != '"' )
|
|
*t++ = *s;
|
|
for ( ;; )
|
|
{
|
|
if ( *++s == '"' )
|
|
break;
|
|
else if ( *s == '\n' || *s == '\0' )
|
|
break;
|
|
*t++ = *s;
|
|
}
|
|
*t++ = '\0';
|
|
if ( strcmp( savch, fnames[ifno] ) )
|
|
{
|
|
fnames[ifno] = savch;
|
|
savch = t;
|
|
}
|
|
}
|
|
/*
|
|
* push it all along to be eventually printed
|
|
*/
|
|
save_passcom = passcom;
|
|
passcom = 0;
|
|
while ( *inp != '\n' )
|
|
p = cotoken( p );
|
|
passcom = save_passcom;
|
|
continue;
|
|
}
|
|
}
|
|
else if ( clsloc != 0 && np == clsloc ) /* class */
|
|
exfail = CLASSCODE; /* return value */
|
|
else if ( np == pragloc || np == idtloc ) /* pragma, ident */
|
|
{
|
|
register char *s;
|
|
/* pass it through unfiltered */
|
|
s = p;
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( np == idtloc) )
|
|
{
|
|
char * startp, * endp;
|
|
++flslvl;
|
|
if ( *p != '\n' )
|
|
p = cotoken( p );
|
|
startp = p;
|
|
while ( (*p != '\n' ) && ( p[-1] != '\n' ) &&
|
|
( ( *p != '/' ) || ( p[1] != '*' ) ) )
|
|
p = cotoken( p );
|
|
if ( p[-1] == '\n' )
|
|
p--;
|
|
endp = p;
|
|
while ( ( *startp == ' ' ) ||
|
|
( *startp == '\t' ) )
|
|
startp++;
|
|
while ( ( endp[-1] == ' ' ) ||
|
|
( endp[-1] == '\t' ) )
|
|
endp--;
|
|
if ( endp > startp )
|
|
cbputid( fout, CB_CHR_IDENT,
|
|
xcopy( startp, endp ) );
|
|
--flslvl;
|
|
}
|
|
if ( cbflag )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_SAYLINE, fout );
|
|
}
|
|
#endif
|
|
while ( *s && *s != '\n' )
|
|
s++;
|
|
if ( eob( s ) )
|
|
p = refill( s );
|
|
save_passcom = passcom;
|
|
passcom = 0;
|
|
while ( *inp != '\n' )
|
|
p = cotoken( p );
|
|
passcom = save_passcom;
|
|
#ifdef BROWSER
|
|
if (cbflag)
|
|
{
|
|
dump();
|
|
}
|
|
#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 */
|
|
#ifdef BROWSER
|
|
cbline = lineno[ifno];
|
|
#endif
|
|
++flslvl;
|
|
while ( *inp != '\n' )
|
|
{
|
|
outp = inp = p;
|
|
p = cotoken( p );
|
|
}
|
|
--flslvl;
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( cbline + 1 != lineno[ifno] ) )
|
|
{
|
|
--lineno[ifno];
|
|
sayline( NOINCL );
|
|
++lineno[ifno];
|
|
}
|
|
if ( cbflag && ( cbflslvl != flslvl ) )
|
|
{
|
|
if ( ( cbflslvl == 1 ) && ( flslvl == 0 ) )
|
|
{
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_END_INACTIVE, fout );
|
|
}
|
|
if ( ( cbflslvl == 0 ) && ( flslvl == 1 ) )
|
|
{
|
|
if ( cbkludge )
|
|
{
|
|
/* Make #elif look inactive: */
|
|
lineno[ifno] -= 2;
|
|
sayline( NOINCL );
|
|
lineno[ifno] += 2;
|
|
cbkludge = 0;
|
|
}
|
|
putc( CB_CHR_PREFIX, fout );
|
|
putc( CB_CHR_START_INACTIVE, fout );
|
|
}
|
|
cbflslvl = flslvl;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
struct symtab *
|
|
stsym( s )
|
|
register char *s;
|
|
{
|
|
char buf[PAGESIZ];
|
|
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] && 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;
|
|
}
|
|
|
|
/* getspace is used to get the next available space from the */
|
|
/* free list; if there is no free space, it will allocate */
|
|
/* a new block of BKTINC elements */
|
|
struct symtab *
|
|
getspace()
|
|
{
|
|
register struct symtab *bp;
|
|
|
|
if ( nfree == 0 )
|
|
{
|
|
sfree = (struct symtab *)calloc( BKTINC, ELEMSIZ );
|
|
if ( sfree == NULL )
|
|
{
|
|
pperror( "too many defines", 0 );
|
|
exit( exfail ? (exfail ==
|
|
CLASSCODE ? CLASSCODE : 2) : 0 );
|
|
}
|
|
nfree = BKTINC;
|
|
}
|
|
|
|
bp = sfree;
|
|
sfree++;
|
|
nfree--;
|
|
return (bp);
|
|
}
|
|
|
|
struct symtab *
|
|
lookup( namep, enterf )
|
|
char *namep;
|
|
{
|
|
register char *np, *snp;
|
|
register int c, i;
|
|
register struct symtab *sp;
|
|
struct symtab *prev;
|
|
|
|
/* namep had better not be too long (currently, <=ncps chars) */
|
|
np = namep;
|
|
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];
|
|
prev = sp;
|
|
while ( sp )
|
|
{
|
|
snp = sp->name;
|
|
np = namep;
|
|
while ( *snp++ == *np )
|
|
if ( *np++ == '\0' )
|
|
{
|
|
if ( enterf == DROP )
|
|
{
|
|
sp->name[0] = DROP;
|
|
sp->value = 0;
|
|
}
|
|
/* symbol already in symbol table; return a */
|
|
/* pointer to it */
|
|
return( lastsym = sp );
|
|
}
|
|
prev = sp;
|
|
sp = sp->next;
|
|
}
|
|
if ( enterf == 1 )
|
|
{
|
|
/* Since symbol is not in the symbol table */
|
|
/* get a bucket for it and put the bucket */
|
|
/* in the symbol table */
|
|
sp = getspace();
|
|
sp->name = namep;
|
|
sp->value = 0;
|
|
sp->next = NULL;
|
|
if ( prev )
|
|
prev->next = sp;
|
|
else
|
|
stab[c] = sp;
|
|
}
|
|
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 && 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;
|
|
int wasfast = 0;
|
|
char *actual[MAXFRM]; /* actual[n] is text of nth actual */
|
|
char acttxt[PAGESIZ]; /* space for actuals */
|
|
int hadactuals;
|
|
#ifdef BROWSER
|
|
char cbchr;
|
|
int cbline, cbsayline;
|
|
#endif
|
|
|
|
vp = sp->value;
|
|
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;
|
|
if ( cxref )
|
|
ref(macnam, lineno[ifno]);
|
|
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++ )
|
|
;
|
|
}
|
|
#ifdef BROWSER
|
|
cbinsubst = 1;
|
|
cbchr = CB_CHR_MACRO_REF_WO_FORMALS_DEFD;
|
|
cbsayline = cbline = lineno[ifno];
|
|
#endif
|
|
if ( 0 != ( params = *--vp & 0xFF ) ) /*definition calls for params */
|
|
{
|
|
register char **pa;
|
|
int dparams; /* parameters in definition */
|
|
|
|
#ifdef BROWSER
|
|
cbchr = CB_CHR_MACRO_REF_W_FORMALS_DEFD;
|
|
#endif
|
|
ca = acttxt;
|
|
pa = actual;
|
|
if ( params == 0xFF ) /* #define foo() ... */
|
|
params = 1;
|
|
dparams = params;
|
|
if ( !isslo )
|
|
{
|
|
sloscan();
|
|
wasfast++;
|
|
}
|
|
++flslvl; /* no expansion during search for actuals */
|
|
expanding_params= sp->name; /* who's being expanded? */
|
|
|
|
plvl = 0;
|
|
maclin = lineno[ifno];
|
|
macfil = fnames[ifno];
|
|
hadactuals = 1;
|
|
do
|
|
{
|
|
p = skipbl( p );
|
|
}
|
|
while ( *inp == '\n' ); /* skip \n too */
|
|
|
|
expanding_params= 0;
|
|
|
|
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;
|
|
}
|
|
#ifdef BROWSER
|
|
if ( cbflag && ( inp >= cbmacend ) &&
|
|
( ( *inp == '"') ||
|
|
( ( *inp == '\'' ) &&
|
|
( cbsuffix == 'p' ) ) ||
|
|
( isid( *inp ) &&
|
|
!isdigit( *inp ) ) ) )
|
|
{
|
|
char c;
|
|
|
|
if (cbsayline != lineno[ifno] )
|
|
{
|
|
cbsayline = lineno[ifno];
|
|
sayline( NOINCL );
|
|
}
|
|
if ( ( *inp == '"' ) ||
|
|
( ( *inp == '\'' ) &&
|
|
( cbsuffix == 'p' ) ) )
|
|
c = CB_CHR_MACRO_STRING_ACTUAL;
|
|
else
|
|
c = CB_CHR_MACRO_ACTUAL_REF;
|
|
cbputid( fout, c,
|
|
xcopy( inp, p ) );
|
|
}
|
|
#endif
|
|
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[PAGESIZ] ) {
|
|
pperror( "%s: actuals too long", sp->name );
|
|
ca = &acttxt[PAGESIZ];
|
|
}
|
|
}
|
|
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 */
|
|
}
|
|
/* 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;
|
|
if ( wasfast )
|
|
fasscan();
|
|
} else
|
|
hadactuals = 0;
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
if ( cbmacend == NULL )
|
|
{
|
|
if ( cbifsay != 0 )
|
|
{
|
|
sayline( NOINCL );
|
|
cbputid( fout, cbchr, macnam );
|
|
}
|
|
else if ( cbline != lineno[ifno] )
|
|
{
|
|
cbsayline = lineno[ifno];
|
|
lineno[ifno] = cbline;
|
|
sayline( NOINCL );
|
|
cbputid( fout, cbchr, macnam );
|
|
lineno[ifno] = cbsayline;
|
|
/* Embedded lf code does not always work */
|
|
sayline( NOINCL );
|
|
}
|
|
else
|
|
cbputid( fout, cbchr, macnam );
|
|
}
|
|
if (p > cbmacend )
|
|
cbmacend = p;
|
|
}
|
|
#endif
|
|
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;
|
|
}
|
|
if ( hadactuals && 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;
|
|
}
|
|
#ifdef BROWSER
|
|
cbinsubst = 0;
|
|
#endif
|
|
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, *new;
|
|
|
|
old = new = savch;
|
|
while ( *new++ = *s++ )
|
|
;
|
|
savch = new;
|
|
return( old );
|
|
}
|
|
|
|
allocsbf()
|
|
{
|
|
sbf = (char *)malloc(SBSIZE);
|
|
if (sbf == NULL)
|
|
{
|
|
pperror( "out of buffer space" );
|
|
exit(1);
|
|
}
|
|
savch = sbf;
|
|
*savch++ = '\0';
|
|
}
|
|
|
|
yywrap()
|
|
{
|
|
return( 1 );
|
|
}
|
|
|
|
main( argc, argv )
|
|
char *argv[];
|
|
{
|
|
register int i, c;
|
|
register char *p;
|
|
char *tf, *cp;
|
|
int forclass = 0; /* 1 if C-with-classes selected */
|
|
#ifdef SUNPRO
|
|
char *p1, *p2;
|
|
struct symtab *sp;
|
|
char dashi[1024];
|
|
#endif
|
|
#ifdef BROWSER
|
|
struct stat status;
|
|
#endif
|
|
|
|
dashi[0] = '\0';
|
|
/* initialize hash table */
|
|
for (i = 0; i < symsiz; i++)
|
|
stab[i] = NULL;
|
|
|
|
# if gcos
|
|
if ( setjmp( env ) )
|
|
return( exfail ? ( exfail == CLASSCODE ? CLASSCODE : 2 ) : 0 );
|
|
# endif
|
|
allocsbf();
|
|
if (port_flag)
|
|
p = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
else
|
|
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] = "";
|
|
#ifdef SUNPRO
|
|
dirnams[0] = ".";
|
|
add_dir_to_path(dirnams[0], &dirs, 0);
|
|
#else
|
|
dirnams[0] = dirs[0] = ".";
|
|
#endif
|
|
realnames[ifno] = "standard input";
|
|
# endif
|
|
# if ibm
|
|
fnames[ifno = 0] = "";
|
|
realnames[ifno] = "standard input";
|
|
# endif
|
|
# if gcos
|
|
if ( inquire( stdin, _TTY ) )
|
|
freopen( "*src", "rt", stdin );
|
|
# endif
|
|
# if gimpel || gcos
|
|
fnames[ifno = 0] = (char *) inquire( stdin, _FILENAME );
|
|
realnames[ifno] = fnames[ifno];
|
|
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':
|
|
mflag++;
|
|
pflag++;
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
perror( "-M disables -cb" );
|
|
cbflag = 0;
|
|
}
|
|
#endif
|
|
continue;
|
|
case 'P':
|
|
ignoreline++;
|
|
pflag++;
|
|
#ifdef BROWSER
|
|
if ( cbflag )
|
|
{
|
|
perror( "-P disables -cb" );
|
|
cbflag = 0;
|
|
}
|
|
#endif
|
|
continue;
|
|
case 'E':
|
|
continue;
|
|
case 'R':
|
|
++rflag;
|
|
continue;
|
|
case 'C':
|
|
passcom++;
|
|
continue;
|
|
case 'B':
|
|
eolcom++;
|
|
continue;
|
|
case 'F':
|
|
if ((outfp = fopen(argv[++i],"w")) == NULL)
|
|
{
|
|
fprintf(stderr, "Can't open ");
|
|
perror(argv[i]);
|
|
exit(1);
|
|
}
|
|
++cxref;
|
|
continue;
|
|
case 'D':
|
|
/* This option is dealt with later. */
|
|
continue;
|
|
case 'U':
|
|
/* This option is dealt with later. */
|
|
continue;
|
|
case 'n':
|
|
if (strcmp(argv[i], "-noinclude") == 0) {
|
|
default_include = 0;
|
|
} else {
|
|
pperror( "unknown flag %s", argv[i] );
|
|
}
|
|
continue;
|
|
case 'u':
|
|
if (strcmp(argv[i], "-undef") == 0) {
|
|
predefining = 0;
|
|
} else {
|
|
pperror( "unknown flag %s", argv[i] );
|
|
}
|
|
continue;
|
|
case 'I':
|
|
if ( nd > MAXINC - 4 )
|
|
pperror( "excessive -I file (%s) ignored", argv[i] );
|
|
else
|
|
#ifdef SUNPRO
|
|
add_dir_to_path(argv[i] + 2, &dirs, nd++);
|
|
strcat(dashi, argv[i]);
|
|
strcat(dashi, " ");
|
|
#else
|
|
dirs[nd++] = argv[i] + 2;
|
|
#endif
|
|
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;
|
|
#ifdef BROWSER
|
|
case 'c':
|
|
if ( strncmp( argv[i], "-cb" , 3 ) == 0 )
|
|
{
|
|
if ( pflag )
|
|
perror( "-P and - M disable -cb" );
|
|
else
|
|
{
|
|
( fastab + COFF )[CB_CHR_PREFIX] |= QB;
|
|
++cbflag;
|
|
}
|
|
cbsuffix = argv[i][strlen( argv[i] ) - 1];
|
|
}
|
|
else
|
|
pperror( "unknown flag %s", argv[i] );
|
|
continue;
|
|
#endif
|
|
case 'W': /* enable C with classes */
|
|
forclass = 1;
|
|
continue;
|
|
case 'p':
|
|
port_flag++; /* reject #endif FOO, $ in identifiers */
|
|
ncps = 8; /* restrict names to 8 characters */
|
|
continue;
|
|
default:
|
|
pperror( "unknown flag %s", argv[i] );
|
|
continue;
|
|
}
|
|
default:
|
|
if ( fin == stdin )
|
|
{
|
|
#ifdef SUNPRO
|
|
int fd;
|
|
fd = open_vroot(argv[i], O_RDONLY, 0, NULL, VROOT_DEFAULT);
|
|
if ((fd < 0) || ( NULL == ( fin = fdopen( fd, READ ) ) ) )
|
|
#else
|
|
if ( NULL == ( fin = fopen( argv[i], READ ) ) )
|
|
#endif
|
|
{
|
|
fprintf( stderr, "cpp: ");
|
|
perror( argv[i] );
|
|
exit(2);
|
|
}
|
|
fnames[ifno] = copy( argv[i] );
|
|
realnames[ifno] = fnames[ifno];
|
|
infile = copy( argv[i] );
|
|
if ( cxref )
|
|
fprintf(outfp,"\"%s\"\n", fnames[ifno]);
|
|
#ifdef BROWSER
|
|
cbsuffix = argv[i][strlen( argv[i] ) - 1];
|
|
#endif
|
|
#ifdef SUNPRO
|
|
if (dashi[0] != '\0')
|
|
dashi[strlen(dashi)-1] = '\0';
|
|
report_search_path(dashi);
|
|
dirnams[ifno] = trmdir( argv[i] );
|
|
add_dir_to_path(dirnams[ifno], &dirs, 0);
|
|
#else
|
|
dirs[0] = dirnams[ifno] = trmdir( argv[i] );
|
|
#endif
|
|
# 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 )
|
|
{
|
|
if ( NULL == ( fout = fopen( argv[i], WRITE ) ) )
|
|
{
|
|
fprintf( stderr, "cpp: Can't create ");
|
|
perror( argv[i] );
|
|
exit(2);
|
|
}
|
|
else
|
|
fclose( stdout );
|
|
# endif
|
|
}
|
|
else
|
|
pperror( "extraneous name %s", argv[i] );
|
|
}
|
|
}
|
|
|
|
if ( mflag )
|
|
{
|
|
if ( infile == NULL )
|
|
{
|
|
fprintf( stderr,
|
|
"cpp: no input file specified with -M flag\n" );
|
|
exit(8);
|
|
}
|
|
tf = strrchr( infile, '.' );
|
|
if ( tf == NULL )
|
|
{
|
|
fprintf( stderr, "cpp: missing component name on %s\n",
|
|
infile );
|
|
exit(8);
|
|
}
|
|
tf[1] = 'o';
|
|
tf = strrchr( infile, '/' );
|
|
if ( tf != NULL )
|
|
infile = tf + 1;
|
|
mout = fout;
|
|
if ( NULL == ( fout = fopen( "/dev/null", "w" ) ) )
|
|
{
|
|
perror( "cpp: Can't open /dev/null" );
|
|
exit(8);
|
|
}
|
|
}
|
|
|
|
fins[ifno] = fin;
|
|
exfail = 0;
|
|
/* after user -I files here are the standard include libraries */
|
|
/* use user-supplied default first */
|
|
if (dfltdir != (char *) 0) {
|
|
# ifdef SUNPRO
|
|
add_dir_to_path(dfltdir, &dirs, nd++);
|
|
scan_vroot_first();
|
|
# else
|
|
dirs[nd++] = dfltdir;
|
|
# endif
|
|
} else {
|
|
if (default_include) {
|
|
# if unix
|
|
# ifdef SUNPRO
|
|
add_dir_to_path("/usr/include", &dirs, nd++);
|
|
scan_vroot_first();
|
|
# else
|
|
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
|
|
} /* default_include */
|
|
}
|
|
|
|
# ifdef SUNPRO
|
|
/* add_dir_to_path appends a null dirname */
|
|
# else
|
|
dirs[nd++] = 0;
|
|
# endif
|
|
|
|
# ifdef BROWSER
|
|
cbsuppress = 1;
|
|
# endif
|
|
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" );
|
|
pragloc = ppsym( "pragma" );
|
|
for ( i = sizeof( macbit ) / sizeof( macbit[0] ); --i >= 0; )
|
|
macbit[i] = 0;
|
|
if (predefining) {
|
|
# if unix
|
|
(void) stsym( "unix" );
|
|
# endif
|
|
# if sun
|
|
(void) stsym( "sun" );
|
|
# endif
|
|
# if mc68000
|
|
(void) stsym( "mc68000" );
|
|
# endif
|
|
/* processors */
|
|
# if mc68010
|
|
(void) stsym( "mc68010" );
|
|
# elif mc68020
|
|
(void) stsym( "mc68020" );
|
|
# elif sparc
|
|
(void) stsym( "sparc" );
|
|
# elif i386
|
|
(void) stsym( "i386" );
|
|
# endif
|
|
|
|
}
|
|
# ifdef sun
|
|
/*
|
|
* varargs hack: defining __BUILTIN_VA_ARG_INCR enables
|
|
* the compiler to treat the va_arg() macro as a compile
|
|
* time intrinsic. [assumes that 4.1 ccom and cpp are
|
|
* installed together]
|
|
*/
|
|
(void) stsym( "__BUILTIN_VA_ARG_INCR" );
|
|
# endif
|
|
|
|
tf = fnames[ifno]; /* do the -D and -U options now */
|
|
fnames[ifno] = "command line";
|
|
lineno[ifno] = 1;
|
|
for ( i = 1; i < argc; i++ )
|
|
{
|
|
if ( argv[i][0] == '-' && argv[i][1] == 'D' )
|
|
{
|
|
cp = &argv[i][2];
|
|
/* ignore plain "-D" (no argument) */
|
|
if ( *cp )
|
|
stsym( cp );
|
|
}
|
|
}
|
|
for ( i = 1; i < argc; i++ )
|
|
{
|
|
if ( argv[i][0] == '-' && argv[i][1] == 'U' )
|
|
{
|
|
cp = &argv[i][2];
|
|
if ( p = strchr( cp, '=' ) )
|
|
*p = '\0';
|
|
/*
|
|
* Truncate to ncps characters if needed.
|
|
*/
|
|
if ( strlen( cp ) > ncps )
|
|
(cp)[ncps] = '\0';
|
|
lookup( cp, DROP );
|
|
}
|
|
}
|
|
|
|
ulnloc = stsym( "__LINE__" );
|
|
uflloc = stsym( "__FILE__" );
|
|
fnames[ifno] = tf;
|
|
#ifdef BROWSER
|
|
cbsuppress = 0;
|
|
#endif
|
|
pbeg = buffer + ncps;
|
|
pbuf = pbeg + PAGESIZ;
|
|
pend = pbuf + PAGESIZ;
|
|
|
|
trulvl = 0;
|
|
flslvl = 0;
|
|
lineno[0] = 1;
|
|
sayline( NOINCL );
|
|
if ( mflag )
|
|
fprintf( mout, "%s: %s\n", infile, fnames[ifno] );
|
|
outp = inp = pend;
|
|
if ( cxref )
|
|
ready = 1;
|
|
control( pend );
|
|
if ( fout && ferror( fout ) )
|
|
{
|
|
perror( "cpp: Can't write output file" );
|
|
if ( exfail < CLASSCODE - 1 )
|
|
++exfail;
|
|
}
|
|
exit( exfail ? ( exfail == CLASSCODE ? CLASSCODE : 2 ) : 0 );
|
|
}
|
|
|
|
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;
|
|
{
|
|
#ifdef BROWSER
|
|
/* The code browser needs an xcopy that never truncates. */
|
|
static char name[NCPS + 1];
|
|
static char *buffer = name;
|
|
static int size = NCPS;
|
|
int len;
|
|
|
|
len = ptr2 - ptr1;
|
|
if ( len > size )
|
|
{
|
|
size = len;
|
|
buffer = malloc( size + 1 );
|
|
}
|
|
bcopy(ptr1, buffer, len);
|
|
buffer[len] = '\0';
|
|
return buffer;
|
|
#else
|
|
static char name[NCPS+1];
|
|
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.
|
|
*/
|
|
|
|
static char *
|
|
chkend( p, ntoken )
|
|
char * p;
|
|
int ntoken; /* number of tokens at which to warn */
|
|
{
|
|
int extratokens = 0;
|
|
int save_passcom = passcom;
|
|
|
|
if (eolcom) passcom = 1; /* ignore comments in this context */
|
|
else passcom=0;
|
|
++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 (port_flag && ++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 );
|
|
}
|