1*8e2a856bSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*8e2a856bSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*8e2a856bSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*8e2a856bSAndrew Rist * distributed with this work for additional information 6*8e2a856bSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*8e2a856bSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*8e2a856bSAndrew Rist * "License"); you may not use this file except in compliance 9*8e2a856bSAndrew Rist * with the License. You may obtain a copy of the License at 10*8e2a856bSAndrew Rist * 11*8e2a856bSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*8e2a856bSAndrew Rist * 13*8e2a856bSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*8e2a856bSAndrew Rist * software distributed under the License is distributed on an 15*8e2a856bSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*8e2a856bSAndrew Rist * KIND, either express or implied. See the License for the 17*8e2a856bSAndrew Rist * specific language governing permissions and limitations 18*8e2a856bSAndrew Rist * under the License. 19*8e2a856bSAndrew Rist * 20*8e2a856bSAndrew Rist *************************************************************/ 21*8e2a856bSAndrew Rist 22*8e2a856bSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include <stdio.h> 25cdf0e10cSrcweir #include <ctype.h> 26cdf0e10cSrcweir #include "cppdef.h" 27cdf0e10cSrcweir #include "cpp.h" 28cdf0e10cSrcweir 29cdf0e10cSrcweir FILE *pCppOut = NULL; 30cdf0e10cSrcweir FILE *pCppIn = NULL; 31cdf0e10cSrcweir 32cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 33cdf0e10cSrcweir FILE *pDefOut = NULL; /* ER evtl. #define's dump */ 34cdf0e10cSrcweir #endif 35cdf0e10cSrcweir 36cdf0e10cSrcweir #ifdef B200 37cdf0e10cSrcweir /* BP, 25.07.91, einzige Moeglichkeit unter BC Stack und Heap festzusetzen */ 38cdf0e10cSrcweir extern unsigned _stklen = 24000; 39cdf0e10cSrcweir extern unsigned _heaplen = 30000; 40cdf0e10cSrcweir #endif 41cdf0e10cSrcweir 42cdf0e10cSrcweir 43cdf0e10cSrcweir 44cdf0e10cSrcweir /* 45cdf0e10cSrcweir * Commonly used global variables: 46cdf0e10cSrcweir * line is the current input line number. 47cdf0e10cSrcweir * wrongline is set in many places when the actual output 48cdf0e10cSrcweir * line is out of sync with the numbering, e.g, 49cdf0e10cSrcweir * when expanding a macro with an embedded newline. 50cdf0e10cSrcweir * 51cdf0e10cSrcweir * token holds the last identifier scanned (which might 52cdf0e10cSrcweir * be a candidate for macro expansion). 53cdf0e10cSrcweir * errors is the running cpp error counter. 54cdf0e10cSrcweir * infile is the head of a linked list of input files (extended by 55cdf0e10cSrcweir * #include and macros being expanded). infile always points 56cdf0e10cSrcweir * to the current file/macro. infile->parent to the includer, 57cdf0e10cSrcweir * etc. infile->fd is NULL if this input stream is a macro. 58cdf0e10cSrcweir */ 59cdf0e10cSrcweir int line; /* Current line number */ 60cdf0e10cSrcweir int wrongline; /* Force #line to compiler */ 61cdf0e10cSrcweir char token[IDMAX + 1]; /* Current input token */ 62cdf0e10cSrcweir int errors; /* cpp error counter */ 63cdf0e10cSrcweir FILEINFO *infile = NULL; /* Current input file */ 64cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 65cdf0e10cSrcweir int debug; /* TRUE if debugging now */ 66cdf0e10cSrcweir int bDumpDefs; /* TRUE if #define's dump req. */ 67cdf0e10cSrcweir #ifdef EVALDEFS 68cdf0e10cSrcweir int bIsInEval; /* TRUE if #define eval now */ 69cdf0e10cSrcweir char EvalBuf[NEVALBUF + 1]; /* evaluation buffer */ 70cdf0e10cSrcweir int nEvalOff = 0; /* offset to free buffer pos */ 71cdf0e10cSrcweir #endif 72cdf0e10cSrcweir #endif 73cdf0e10cSrcweir /* 74cdf0e10cSrcweir * This counter is incremented when a macro expansion is initiated. 75cdf0e10cSrcweir * If it exceeds a built-in value, the expansion stops -- this tests 76cdf0e10cSrcweir * for a runaway condition: 77cdf0e10cSrcweir * #define X Y 78cdf0e10cSrcweir * #define Y X 79cdf0e10cSrcweir * X 80cdf0e10cSrcweir * This can be disabled by falsifying rec_recover. (Nothing does this 81cdf0e10cSrcweir * currently: it is a hook for an eventual invocation flag.) 82cdf0e10cSrcweir */ 83cdf0e10cSrcweir int recursion; /* Infinite recursion counter */ 84cdf0e10cSrcweir int rec_recover = TRUE; /* Unwind recursive macros */ 85cdf0e10cSrcweir 86cdf0e10cSrcweir /* 87cdf0e10cSrcweir * instring is set TRUE when a string is scanned. It modifies the 88cdf0e10cSrcweir * behavior of the "get next character" routine, causing all characters 89cdf0e10cSrcweir * to be passed to the caller (except <DEF_MAGIC>). Note especially that 90cdf0e10cSrcweir * comments and \<newline> are not removed from the source. (This 91cdf0e10cSrcweir * prevents cpp output lines from being arbitrarily long). 92cdf0e10cSrcweir * 93cdf0e10cSrcweir * inmacro is set by #define -- it absorbs comments and converts 94cdf0e10cSrcweir * form-feed and vertical-tab to space, but returns \<newline> 95cdf0e10cSrcweir * to the caller. Strictly speaking, this is a bug as \<newline> 96cdf0e10cSrcweir * shouldn't delimit tokens, but we'll worry about that some other 97cdf0e10cSrcweir * time -- it is more important to prevent infinitly long output lines. 98cdf0e10cSrcweir * 99cdf0e10cSrcweir * instring and inmarcor are parameters to the get() routine which 100cdf0e10cSrcweir * were made global for speed. 101cdf0e10cSrcweir */ 102cdf0e10cSrcweir int instring = FALSE; /* TRUE if scanning string */ 103cdf0e10cSrcweir int inmacro = FALSE; /* TRUE if #defining a macro */ 104cdf0e10cSrcweir 105cdf0e10cSrcweir /* 106cdf0e10cSrcweir * work[] and workp are used to store one piece of text in a temporay 107cdf0e10cSrcweir * buffer. To initialize storage, set workp = work. To store one 108cdf0e10cSrcweir * character, call save(c); (This will fatally exit if there isn't 109cdf0e10cSrcweir * room.) To terminate the string, call save(EOS). Note that 110cdf0e10cSrcweir * the work buffer is used by several subroutines -- be sure your 111cdf0e10cSrcweir * data won't be overwritten. The extra byte in the allocation is 112cdf0e10cSrcweir * needed for string formal replacement. 113cdf0e10cSrcweir */ 114cdf0e10cSrcweir char work[NWORK + 1]; /* Work buffer */ 115cdf0e10cSrcweir char *workp; /* Work buffer pointer */ 116cdf0e10cSrcweir 117cdf0e10cSrcweir /* 118cdf0e10cSrcweir * keepcomments is set TRUE by the -C option. If TRUE, comments 119cdf0e10cSrcweir * are written directly to the output stream. This is needed if 120cdf0e10cSrcweir * the output from cpp is to be passed to lint (which uses commands 121cdf0e10cSrcweir * embedded in comments). cflag contains the permanent state of the 122cdf0e10cSrcweir * -C flag. keepcomments is always falsified when processing #control 123cdf0e10cSrcweir * commands and when compilation is supressed by a false #if 124cdf0e10cSrcweir * 125cdf0e10cSrcweir * If eflag is set, CPP returns "success" even if non-fatal errors 126cdf0e10cSrcweir * were detected. 127cdf0e10cSrcweir * 128cdf0e10cSrcweir * If nflag is non-zero, no symbols are predefined except __LINE__. 129cdf0e10cSrcweir * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols 130cdf0e10cSrcweir * are predefined. 131cdf0e10cSrcweir */ 132cdf0e10cSrcweir int keepcomments = FALSE; /* Write out comments flag */ 133cdf0e10cSrcweir int cflag = FALSE; /* -C option (keep comments) */ 134cdf0e10cSrcweir int eflag = FALSE; /* -E option (never fail) */ 135cdf0e10cSrcweir int nflag = 0; /* -N option (no predefines) */ 136cdf0e10cSrcweir 137cdf0e10cSrcweir /* 138cdf0e10cSrcweir * ifstack[] holds information about nested #if's. It is always 139cdf0e10cSrcweir * accessed via *ifptr. The information is as follows: 140cdf0e10cSrcweir * WAS_COMPILING state of compiling flag at outer level. 141cdf0e10cSrcweir * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else. 142cdf0e10cSrcweir * TRUE_SEEN set TRUE when #if or #elif succeeds 143cdf0e10cSrcweir * ifstack[0] holds the compiling flag. It is TRUE if compilation 144cdf0e10cSrcweir * is currently enabled. Note that this must be initialized TRUE. 145cdf0e10cSrcweir */ 146cdf0e10cSrcweir char ifstack[BLK_NEST] = { TRUE }; /* #if information */ 147cdf0e10cSrcweir char *ifptr = ifstack; /* -> current ifstack[] */ 148cdf0e10cSrcweir 149cdf0e10cSrcweir /* 150cdf0e10cSrcweir * incdir[] stores the -i directories (and the system-specific 151cdf0e10cSrcweir * #include <...> directories. 152cdf0e10cSrcweir */ 153cdf0e10cSrcweir char *incdir[NINCLUDE]; /* -i directories */ 154cdf0e10cSrcweir char **incend = incdir; /* -> free space in incdir[] */ 155cdf0e10cSrcweir 156cdf0e10cSrcweir /* 157cdf0e10cSrcweir * This is the table used to predefine target machine and operating 158cdf0e10cSrcweir * system designators. It may need hacking for specific circumstances. 159cdf0e10cSrcweir * Note: it is not clear that this is part of the Ansi Standard. 160cdf0e10cSrcweir * The -N option supresses preset definitions. 161cdf0e10cSrcweir */ 162cdf0e10cSrcweir char *preset[] = { /* names defined at cpp start */ 163cdf0e10cSrcweir #ifdef MACHINE 164cdf0e10cSrcweir MACHINE, 165cdf0e10cSrcweir #endif 166cdf0e10cSrcweir #ifdef SYSTEM 167cdf0e10cSrcweir SYSTEM, 168cdf0e10cSrcweir #endif 169cdf0e10cSrcweir #ifdef COMPILER 170cdf0e10cSrcweir COMPILER, 171cdf0e10cSrcweir #endif 172cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 173cdf0e10cSrcweir "decus_cpp", /* Ourselves! */ 174cdf0e10cSrcweir #endif 175cdf0e10cSrcweir NULL /* Must be last */ 176cdf0e10cSrcweir }; 177cdf0e10cSrcweir 178cdf0e10cSrcweir /* 179cdf0e10cSrcweir * The value of these predefined symbols must be recomputed whenever 180cdf0e10cSrcweir * they are evaluated. The order must not be changed. 181cdf0e10cSrcweir */ 182cdf0e10cSrcweir char *magic[] = { /* Note: order is important */ 183cdf0e10cSrcweir "__LINE__", 184cdf0e10cSrcweir "__FILE__", 185cdf0e10cSrcweir NULL /* Must be last */ 186cdf0e10cSrcweir }; 187cdf0e10cSrcweir 188cdf0e10cSrcweir static char *sharpfilename = NULL; 189cdf0e10cSrcweir 190cdf0e10cSrcweir int nRunde = 0; 191cdf0e10cSrcweir 192cdf0e10cSrcweir void InitCpp1() 193cdf0e10cSrcweir { 194cdf0e10cSrcweir int i; 195cdf0e10cSrcweir /* BP */ 196cdf0e10cSrcweir /* in der LIB-Version muessen alle Variablen initialisiert werden */ 197cdf0e10cSrcweir 198cdf0e10cSrcweir line = wrongline = errors = recursion = 0; 199cdf0e10cSrcweir for( i = 0; i < IDMAX; i++ ) 200cdf0e10cSrcweir token[ i ] = 0; 201cdf0e10cSrcweir 202cdf0e10cSrcweir for( i = 0; i < NWORK; i++ ) 203cdf0e10cSrcweir work[ i ] = 0; 204cdf0e10cSrcweir 205cdf0e10cSrcweir for( i = 0; i < NINCLUDE; i++ ) 206cdf0e10cSrcweir incdir[ i ] = NULL; 207cdf0e10cSrcweir 208cdf0e10cSrcweir workp = NULL; 209cdf0e10cSrcweir for( i = 0; i < BLK_NEST; i++ ) 210cdf0e10cSrcweir ifstack[ i ] = TRUE; 211cdf0e10cSrcweir ifptr = ifstack; 212cdf0e10cSrcweir 213cdf0e10cSrcweir pCppOut = stdout; 214cdf0e10cSrcweir pCppIn = stdin; 215cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 216cdf0e10cSrcweir debug = 0; 217cdf0e10cSrcweir bDumpDefs = 0; 218cdf0e10cSrcweir pDefOut = stdout; 219cdf0e10cSrcweir #ifdef EVALDEFS 220cdf0e10cSrcweir bIsInEval = 0; 221cdf0e10cSrcweir for( i = 0; i < NEVALBUF; i++ ) 222cdf0e10cSrcweir EvalBuf[ i ] = 0; 223cdf0e10cSrcweir nEvalOff = 0; 224cdf0e10cSrcweir #endif 225cdf0e10cSrcweir #endif 226cdf0e10cSrcweir rec_recover = TRUE; 227cdf0e10cSrcweir infile = NULL; 228cdf0e10cSrcweir instring = inmacro = keepcomments = cflag = eflag = FALSE; 229cdf0e10cSrcweir nflag = 0; 230cdf0e10cSrcweir incend = incdir; 231cdf0e10cSrcweir sharpfilename = NULL; 232cdf0e10cSrcweir /* BP */ 233cdf0e10cSrcweir } 234cdf0e10cSrcweir 235cdf0e10cSrcweir int MAIN(int argc, char** argv) 236cdf0e10cSrcweir { 237cdf0e10cSrcweir register int i; 238cdf0e10cSrcweir char **useargv, **pfargv; 239cdf0e10cSrcweir 240cdf0e10cSrcweir 241cdf0e10cSrcweir if( nRunde == 0 ) 242cdf0e10cSrcweir { 243cdf0e10cSrcweir pCppIn = stdin; 244cdf0e10cSrcweir pCppOut = stdout; 245cdf0e10cSrcweir } 246cdf0e10cSrcweir 247cdf0e10cSrcweir nRunde++; 248cdf0e10cSrcweir InitCpp1(); 249cdf0e10cSrcweir InitCpp2(); 250cdf0e10cSrcweir InitCpp3(); 251cdf0e10cSrcweir InitCpp4(); 252cdf0e10cSrcweir InitCpp5(); 253cdf0e10cSrcweir InitCpp6(); 254cdf0e10cSrcweir 255cdf0e10cSrcweir #if HOST == SYS_VMS 256cdf0e10cSrcweir argc = getredirection(argc, argv); /* vms >file and <file */ 257cdf0e10cSrcweir #endif 258cdf0e10cSrcweir initdefines(); /* O.S. specific def's */ 259cdf0e10cSrcweir if ( argv[argc-1][0] == '@' ) 260cdf0e10cSrcweir { 261cdf0e10cSrcweir i = readoptions( argv[1], &pfargv ); /* Command file */ 262cdf0e10cSrcweir useargv=pfargv; 263cdf0e10cSrcweir } 264cdf0e10cSrcweir else 265cdf0e10cSrcweir { 266cdf0e10cSrcweir i = dooptions(argc, argv); /* Command line -flags */ 267cdf0e10cSrcweir useargv=argv; 268cdf0e10cSrcweir } 269cdf0e10cSrcweir switch (i) { 270cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 271cdf0e10cSrcweir case 4: 272cdf0e10cSrcweir if ( bDumpDefs ) 273cdf0e10cSrcweir { 274cdf0e10cSrcweir /* 275cdf0e10cSrcweir * Get defBase file, "-" means use stdout. 276cdf0e10cSrcweir */ 277cdf0e10cSrcweir if (!streq(useargv[3], "-")) { 278cdf0e10cSrcweir #if HOST == SYS_VMS 279cdf0e10cSrcweir /* 280cdf0e10cSrcweir * On vms, reopen stdout with "vanilla rms" attributes. 281cdf0e10cSrcweir */ 282cdf0e10cSrcweir if ((i = creat(useargv[3], 0, "rat=cr", "rfm=var")) == -1 283cdf0e10cSrcweir || dup2(i, fileno(stdout)) == -1) { 284cdf0e10cSrcweir #else 285cdf0e10cSrcweir /* alt if (freopen(useargv[3], "w", stdout) == NULL) { */ 286cdf0e10cSrcweir 287cdf0e10cSrcweir pDefOut = fopen( useargv[3], "w" ); 288cdf0e10cSrcweir if( pDefOut == NULL ) { 289cdf0e10cSrcweir #endif 290cdf0e10cSrcweir perror(useargv[3]); 291cdf0e10cSrcweir cerror("Can't open output file \"%s\"", useargv[3]); 292cdf0e10cSrcweir exit(IO_ERROR); 293cdf0e10cSrcweir } 294cdf0e10cSrcweir } /* Continue by opening output */ 295cdf0e10cSrcweir } 296cdf0e10cSrcweir /* OSL_DEBUG_LEVEL > 1 */ 297cdf0e10cSrcweir #endif 298cdf0e10cSrcweir case 3: 299cdf0e10cSrcweir /* 300cdf0e10cSrcweir * Get output file, "-" means use stdout. 301cdf0e10cSrcweir */ 302cdf0e10cSrcweir if (!streq(useargv[2], "-")) { 303cdf0e10cSrcweir #if HOST == SYS_VMS 304cdf0e10cSrcweir /* 305cdf0e10cSrcweir * On vms, reopen stdout with "vanilla rms" attributes. 306cdf0e10cSrcweir */ 307cdf0e10cSrcweir if ((i = creat(useargv[2], 0, "rat=cr", "rfm=var")) == -1 308cdf0e10cSrcweir || dup2(i, fileno(stdout)) == -1) { 309cdf0e10cSrcweir #else 310cdf0e10cSrcweir /* alt if (freopen(useargv[2], "w", stdout) == NULL) { */ 311cdf0e10cSrcweir 312cdf0e10cSrcweir pCppOut = fopen( useargv[2], "w" ); 313cdf0e10cSrcweir if( pCppOut == NULL ) { 314cdf0e10cSrcweir #endif 315cdf0e10cSrcweir perror(useargv[2]); 316cdf0e10cSrcweir cerror("Can't open output file \"%s\"", useargv[2]); 317cdf0e10cSrcweir exit(IO_ERROR); 318cdf0e10cSrcweir } 319cdf0e10cSrcweir } /* Continue by opening input */ 320cdf0e10cSrcweir case 2: /* One file -> stdin */ 321cdf0e10cSrcweir /* 322cdf0e10cSrcweir * Open input file, "-" means use stdin. 323cdf0e10cSrcweir */ 324cdf0e10cSrcweir if (!streq(useargv[1], "-")) { 325cdf0e10cSrcweir /* alt: if (freopen(useargv[1], "r", stdin) == NULL) { */ 326cdf0e10cSrcweir pCppIn = fopen( useargv[1], "r" ); 327cdf0e10cSrcweir if( pCppIn == NULL) { 328cdf0e10cSrcweir perror(useargv[1]); 329cdf0e10cSrcweir cerror("Can't open input file \"%s\"", useargv[1]); 330cdf0e10cSrcweir exit(IO_ERROR); 331cdf0e10cSrcweir } 332cdf0e10cSrcweir strcpy(work, useargv[1]); /* Remember input filename */ 333cdf0e10cSrcweir break; 334cdf0e10cSrcweir } /* Else, just get stdin */ 335cdf0e10cSrcweir case 0: /* No args? */ 336cdf0e10cSrcweir case 1: /* No files, stdin -> stdout */ 337cdf0e10cSrcweir #if (HOST == SYS_UNIX) || (HOST == SYS_UNKNOWN) 338cdf0e10cSrcweir work[0] = EOS; /* Unix can't find stdin name */ 339cdf0e10cSrcweir #else 340cdf0e10cSrcweir fgetname(stdin, work); /* Vax-11C, Decus C know name */ 341cdf0e10cSrcweir #endif 342cdf0e10cSrcweir break; 343cdf0e10cSrcweir 344cdf0e10cSrcweir default: 345cdf0e10cSrcweir exit(IO_ERROR); /* Can't happen */ 346cdf0e10cSrcweir } 347cdf0e10cSrcweir /* if ( pfargv ) 348cdf0e10cSrcweir { 349cdf0e10cSrcweir for ( j=0;j++;j < PARALIMIT ) 350cdf0e10cSrcweir { 351cdf0e10cSrcweir if (pfargv[j]!=0) 352cdf0e10cSrcweir free(pfargv[j]); 353cdf0e10cSrcweir } 354cdf0e10cSrcweir free(pfargv); 355cdf0e10cSrcweir } 356cdf0e10cSrcweir */ 357cdf0e10cSrcweir 358cdf0e10cSrcweir setincdirs(); /* Setup -I include directories */ 359cdf0e10cSrcweir addfile( pCppIn, work); /* "open" main input file */ 360cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 361cdf0e10cSrcweir if (debug > 0 || bDumpDefs) 362cdf0e10cSrcweir dumpdef("preset #define symbols"); 363cdf0e10cSrcweir #endif 364cdf0e10cSrcweir if( pCppIn != stdin ) 365cdf0e10cSrcweir rewind( pCppIn ); 366cdf0e10cSrcweir 367cdf0e10cSrcweir cppmain(); /* Process main file */ 368cdf0e10cSrcweir 369cdf0e10cSrcweir if ((i = (ifptr - &ifstack[0])) != 0) { 370cdf0e10cSrcweir #if OLD_PREPROCESSOR 371cdf0e10cSrcweir ciwarn("Inside #ifdef block at end of input, depth = %d", i); 372cdf0e10cSrcweir #else 373cdf0e10cSrcweir cierror("Inside #ifdef block at end of input, depth = %d", i); 374cdf0e10cSrcweir #endif 375cdf0e10cSrcweir } 376cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 377cdf0e10cSrcweir if( pDefOut != stdout && pDefOut != stderr ) 378cdf0e10cSrcweir fclose( pDefOut ); 379cdf0e10cSrcweir #endif 380cdf0e10cSrcweir if( pCppOut != stdout && pCppOut != stderr ) 381cdf0e10cSrcweir fclose( pCppOut ); 382cdf0e10cSrcweir 383cdf0e10cSrcweir if (errors > 0) { 384cdf0e10cSrcweir fprintf(stderr, (errors == 1) 385cdf0e10cSrcweir ? "%d error in preprocessor\n" 386cdf0e10cSrcweir : "%d errors in preprocessor\n", errors); 387cdf0e10cSrcweir if (!eflag) 388cdf0e10cSrcweir exit(IO_ERROR); 389cdf0e10cSrcweir } 390cdf0e10cSrcweir #ifdef NOMAIN /* BP */ /* kein exit im der LIB-Version */ 391cdf0e10cSrcweir return( IO_NORMAL ); 392cdf0e10cSrcweir #else 393cdf0e10cSrcweir exit(IO_NORMAL); /* No errors or -E option set */ 394cdf0e10cSrcweir #endif 395cdf0e10cSrcweir 396cdf0e10cSrcweir } 397cdf0e10cSrcweir 398cdf0e10cSrcweir FILE_LOCAL 399cdf0e10cSrcweir void cppmain() 400cdf0e10cSrcweir /* 401cdf0e10cSrcweir * Main process for cpp -- copies tokens from the current input 402cdf0e10cSrcweir * stream (main file, include file, or a macro) to the output 403cdf0e10cSrcweir * file. 404cdf0e10cSrcweir */ 405cdf0e10cSrcweir { 406cdf0e10cSrcweir register int c; /* Current character */ 407cdf0e10cSrcweir register int counter; /* newlines and spaces */ 408cdf0e10cSrcweir 409cdf0e10cSrcweir /* 410cdf0e10cSrcweir * Explicitly output a #line at the start of cpp output so 411cdf0e10cSrcweir * that lint (etc.) knows the name of the original source 412cdf0e10cSrcweir * file. If we don't do this explicitly, we may get 413cdf0e10cSrcweir * the name of the first #include file instead. 414cdf0e10cSrcweir * We also seem to need a blank line following that first #line. 415cdf0e10cSrcweir */ 416cdf0e10cSrcweir #ifdef EVALDEFS 417cdf0e10cSrcweir if ( !bIsInEval ) 418cdf0e10cSrcweir #endif 419cdf0e10cSrcweir { 420cdf0e10cSrcweir sharp(); 421cdf0e10cSrcweir PUTCHAR('\n'); 422cdf0e10cSrcweir } 423cdf0e10cSrcweir /* 424cdf0e10cSrcweir * This loop is started "from the top" at the beginning of each line 425cdf0e10cSrcweir * wrongline is set TRUE in many places if it is necessary to write 426cdf0e10cSrcweir * a #line record. (But we don't write them when expanding macros.) 427cdf0e10cSrcweir * 428cdf0e10cSrcweir * The counter variable has two different uses: at 429cdf0e10cSrcweir * the start of a line, it counts the number of blank lines that 430cdf0e10cSrcweir * have been skipped over. These are then either output via 431cdf0e10cSrcweir * #line records or by outputting explicit blank lines. 432cdf0e10cSrcweir * When expanding tokens within a line, the counter remembers 433cdf0e10cSrcweir * whether a blank/tab has been output. These are dropped 434cdf0e10cSrcweir * at the end of the line, and replaced by a single blank 435cdf0e10cSrcweir * within lines. 436cdf0e10cSrcweir */ 437cdf0e10cSrcweir for (;;) { 438cdf0e10cSrcweir counter = 0; /* Count empty lines */ 439cdf0e10cSrcweir for (;;) { /* For each line, ... */ 440cdf0e10cSrcweir while (type[(c = get())] == SPA) /* Skip leading blanks */ 441cdf0e10cSrcweir ; /* in this line. */ 442cdf0e10cSrcweir if (c == '\n') /* If line's all blank, */ 443cdf0e10cSrcweir ++counter; /* Do nothing now */ 444cdf0e10cSrcweir else if (c == '#') { /* Is 1st non-space '#' */ 445cdf0e10cSrcweir keepcomments = FALSE; /* Don't pass comments */ 446cdf0e10cSrcweir counter = control(counter); /* Yes, do a #command */ 447cdf0e10cSrcweir keepcomments = (cflag && compiling); 448cdf0e10cSrcweir } 449cdf0e10cSrcweir else if (c == EOF_CHAR) /* At end of file? */ 450cdf0e10cSrcweir { 451cdf0e10cSrcweir break; 452cdf0e10cSrcweir } 453cdf0e10cSrcweir else if (!compiling) { /* #ifdef false? */ 454cdf0e10cSrcweir skipnl(); /* Skip to newline */ 455cdf0e10cSrcweir counter++; /* Count it, too. */ 456cdf0e10cSrcweir } 457cdf0e10cSrcweir else { 458cdf0e10cSrcweir break; /* Actual token */ 459cdf0e10cSrcweir } 460cdf0e10cSrcweir } 461cdf0e10cSrcweir if (c == EOF_CHAR) /* Exit process at */ 462cdf0e10cSrcweir break; /* End of file */ 463cdf0e10cSrcweir /* 464cdf0e10cSrcweir * If the loop didn't terminate because of end of file, we 465cdf0e10cSrcweir * know there is a token to compile. First, clean up after 466cdf0e10cSrcweir * absorbing newlines. counter has the number we skipped. 467cdf0e10cSrcweir */ 468cdf0e10cSrcweir if ((wrongline && infile->fp != NULL) || counter > 4) 469cdf0e10cSrcweir sharp(); /* Output # line number */ 470cdf0e10cSrcweir else { /* If just a few, stuff */ 471cdf0e10cSrcweir while (--counter >= 0) /* them out ourselves */ 472cdf0e10cSrcweir PUTCHAR('\n'); 473cdf0e10cSrcweir } 474cdf0e10cSrcweir /* 475cdf0e10cSrcweir * Process each token on this line. 476cdf0e10cSrcweir */ 477cdf0e10cSrcweir unget(); /* Reread the char. */ 478cdf0e10cSrcweir for (;;) { /* For the whole line, */ 479cdf0e10cSrcweir do { /* Token concat. loop */ 480cdf0e10cSrcweir for (counter = 0; (type[(c = get())] == SPA);) { 481cdf0e10cSrcweir #if COMMENT_INVISIBLE 482cdf0e10cSrcweir if (c != COM_SEP) 483cdf0e10cSrcweir counter++; 484cdf0e10cSrcweir #else 485cdf0e10cSrcweir counter++; /* Skip over blanks */ 486cdf0e10cSrcweir #endif 487cdf0e10cSrcweir } 488cdf0e10cSrcweir if (c == EOF_CHAR || c == '\n') 489cdf0e10cSrcweir goto end_line; /* Exit line loop */ 490cdf0e10cSrcweir else if (counter > 0) /* If we got any spaces */ 491cdf0e10cSrcweir PUTCHAR(' '); /* Output one space */ 492cdf0e10cSrcweir c = macroid(c); /* Grab the token */ 493cdf0e10cSrcweir } while (type[c] == LET && catenate()); 494cdf0e10cSrcweir if (c == EOF_CHAR || c == '\n') /* From macro exp error */ 495cdf0e10cSrcweir goto end_line; /* Exit line loop */ 496cdf0e10cSrcweir switch (type[c]) { 497cdf0e10cSrcweir case LET: 498cdf0e10cSrcweir fputs(token, pCppOut); /* Quite ordinary token */ 499cdf0e10cSrcweir #ifdef EVALDEFS 500cdf0e10cSrcweir { 501cdf0e10cSrcweir int len; 502cdf0e10cSrcweir if ( bIsInEval 503cdf0e10cSrcweir && nEvalOff + (len=strlen(token)) < NEVALBUF ) 504cdf0e10cSrcweir { 505cdf0e10cSrcweir strcpy( &EvalBuf[nEvalOff], token ); 506cdf0e10cSrcweir nEvalOff += len; 507cdf0e10cSrcweir } 508cdf0e10cSrcweir } 509cdf0e10cSrcweir #endif 510cdf0e10cSrcweir break; 511cdf0e10cSrcweir 512cdf0e10cSrcweir 513cdf0e10cSrcweir case DIG: /* Output a number */ 514cdf0e10cSrcweir case DOT: /* Dot may begin floats */ 515cdf0e10cSrcweir #ifdef EVALDEFS 516cdf0e10cSrcweir if ( bIsInEval ) 517cdf0e10cSrcweir scannumber(c, outputEval); 518cdf0e10cSrcweir else 519cdf0e10cSrcweir scannumber(c, output); 520cdf0e10cSrcweir #else 521cdf0e10cSrcweir scannumber(c, output); 522cdf0e10cSrcweir #endif 523cdf0e10cSrcweir break; 524cdf0e10cSrcweir 525cdf0e10cSrcweir case QUO: /* char or string const */ 526cdf0e10cSrcweir scanstring(c, output); /* Copy it to output */ 527cdf0e10cSrcweir break; 528cdf0e10cSrcweir 529cdf0e10cSrcweir default: /* Some other character */ 530cdf0e10cSrcweir cput(c); /* Just output it */ 531cdf0e10cSrcweir #ifdef EVALDEFS 532cdf0e10cSrcweir if ( bIsInEval && nEvalOff < NEVALBUF ) 533cdf0e10cSrcweir EvalBuf[nEvalOff++] = c; 534cdf0e10cSrcweir #endif 535cdf0e10cSrcweir break; 536cdf0e10cSrcweir } /* Switch ends */ 537cdf0e10cSrcweir } /* Line for loop */ 538cdf0e10cSrcweir end_line: if (c == '\n') { /* Compiling at EOL? */ 539cdf0e10cSrcweir PUTCHAR('\n'); /* Output newline, if */ 540cdf0e10cSrcweir if (infile->fp == NULL) /* Expanding a macro, */ 541cdf0e10cSrcweir wrongline = TRUE; /* Output # line later */ 542cdf0e10cSrcweir } 543cdf0e10cSrcweir } /* Continue until EOF */ 544cdf0e10cSrcweir #ifdef EVALDEFS 545cdf0e10cSrcweir if ( bIsInEval ) 546cdf0e10cSrcweir EvalBuf[nEvalOff++] = '\0'; 547cdf0e10cSrcweir #endif 548cdf0e10cSrcweir } 549cdf0e10cSrcweir 550cdf0e10cSrcweir void output(int c) 551cdf0e10cSrcweir /* 552cdf0e10cSrcweir * Output one character to stdout -- output() is passed as an 553cdf0e10cSrcweir * argument to scanstring() 554cdf0e10cSrcweir */ 555cdf0e10cSrcweir { 556cdf0e10cSrcweir #if COMMENT_INVISIBLE 557cdf0e10cSrcweir if (c != TOK_SEP && c != COM_SEP) 558cdf0e10cSrcweir #else 559cdf0e10cSrcweir if (c != TOK_SEP) 560cdf0e10cSrcweir #endif 561cdf0e10cSrcweir /* alt: PUTCHAR(c); */ 562cdf0e10cSrcweir PUTCHAR(c); 563cdf0e10cSrcweir } 564cdf0e10cSrcweir 565cdf0e10cSrcweir #ifdef EVALDEFS 566cdf0e10cSrcweir outputEval(c) 567cdf0e10cSrcweir int c; 568cdf0e10cSrcweir /* 569cdf0e10cSrcweir * Output one character to stdout -- output() is passed as an 570cdf0e10cSrcweir * argument to scanstring() 571cdf0e10cSrcweir */ 572cdf0e10cSrcweir { 573cdf0e10cSrcweir #if COMMENT_INVISIBLE 574cdf0e10cSrcweir if (c != TOK_SEP && c != COM_SEP) 575cdf0e10cSrcweir #else 576cdf0e10cSrcweir if (c != TOK_SEP) 577cdf0e10cSrcweir #endif 578cdf0e10cSrcweir /* alt: PUTCHAR(c); */ 579cdf0e10cSrcweir { 580cdf0e10cSrcweir PUTCHAR(c); 581cdf0e10cSrcweir if ( bIsInEval && nEvalOff < NEVALBUF ) 582cdf0e10cSrcweir EvalBuf[nEvalOff++] = c; 583cdf0e10cSrcweir } 584cdf0e10cSrcweir } 585cdf0e10cSrcweir #endif 586cdf0e10cSrcweir 587cdf0e10cSrcweir 588cdf0e10cSrcweir FILE_LOCAL 589cdf0e10cSrcweir void sharp() 590cdf0e10cSrcweir /* 591cdf0e10cSrcweir * Output a line number line. 592cdf0e10cSrcweir */ 593cdf0e10cSrcweir { 594cdf0e10cSrcweir register char *name; 595cdf0e10cSrcweir 596cdf0e10cSrcweir if (keepcomments) /* Make sure # comes on */ 597cdf0e10cSrcweir PUTCHAR('\n'); /* a fresh, new line. */ 598cdf0e10cSrcweir fprintf( pCppOut, "#%s %d", LINE_PREFIX, line); 599cdf0e10cSrcweir if (infile->fp != NULL) { 600cdf0e10cSrcweir name = (infile->progname != NULL) 601cdf0e10cSrcweir ? infile->progname : infile->filename; 602cdf0e10cSrcweir if (sharpfilename == NULL 603cdf0e10cSrcweir || (sharpfilename != NULL && !streq(name, sharpfilename)) ) { 604cdf0e10cSrcweir if (sharpfilename != NULL) 605cdf0e10cSrcweir free(sharpfilename); 606cdf0e10cSrcweir sharpfilename = savestring(name); 607cdf0e10cSrcweir fprintf( pCppOut, " \"%s\"", name); 608cdf0e10cSrcweir } 609cdf0e10cSrcweir } 610cdf0e10cSrcweir PUTCHAR('\n'); 611cdf0e10cSrcweir wrongline = FALSE; 612cdf0e10cSrcweir } 613