/* 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 # include # include #endif #ifdef BROWSER # include # include # 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 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 ); }