18e2a856bSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 38e2a856bSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 48e2a856bSAndrew Rist * or more contributor license agreements. See the NOTICE file 58e2a856bSAndrew Rist * distributed with this work for additional information 68e2a856bSAndrew Rist * regarding copyright ownership. The ASF licenses this file 78e2a856bSAndrew Rist * to you under the Apache License, Version 2.0 (the 88e2a856bSAndrew Rist * "License"); you may not use this file except in compliance 98e2a856bSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 118e2a856bSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 138e2a856bSAndrew Rist * Unless required by applicable law or agreed to in writing, 148e2a856bSAndrew Rist * software distributed under the License is distributed on an 158e2a856bSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 168e2a856bSAndrew Rist * KIND, either express or implied. See the License for the 178e2a856bSAndrew Rist * specific language governing permissions and limitations 188e2a856bSAndrew Rist * under the License. 19cdf0e10cSrcweir * 208e2a856bSAndrew Rist *************************************************************/ 218e2a856bSAndrew Rist 228e2a856bSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include <stdio.h> 25cdf0e10cSrcweir #include <ctype.h> 26cdf0e10cSrcweir #include <string.h> 27cdf0e10cSrcweir #include "cppdef.h" 28cdf0e10cSrcweir #include "cpp.h" 29cdf0e10cSrcweir 30cdf0e10cSrcweir /*ER evaluate macros to pDefOut */ 31cdf0e10cSrcweir 32cdf0e10cSrcweir /* 33cdf0e10cSrcweir * skipnl() skips over input text to the end of the line. 34cdf0e10cSrcweir * skipws() skips over "whitespace" (spaces or tabs), but 35cdf0e10cSrcweir * not skip over the end of the line. It skips over 36cdf0e10cSrcweir * TOK_SEP, however (though that shouldn't happen). 37cdf0e10cSrcweir * scanid() reads the next token (C identifier) into token[]. 38cdf0e10cSrcweir * The caller has already read the first character of 39cdf0e10cSrcweir * the identifier. Unlike macroid(), the token is 40cdf0e10cSrcweir * never expanded. 41cdf0e10cSrcweir * macroid() reads the next token (C identifier) into token[]. 42cdf0e10cSrcweir * If it is a #defined macro, it is expanded, and 43cdf0e10cSrcweir * macroid() returns TRUE, otherwise, FALSE. 44cdf0e10cSrcweir * catenate() Does the dirty work of token concatenation, TRUE if it did. 45cdf0e10cSrcweir * scanstring() Reads a string from the input stream, calling 46cdf0e10cSrcweir * a user-supplied function for each character. 47cdf0e10cSrcweir * This function may be output() to write the 48cdf0e10cSrcweir * string to the output file, or save() to save 49cdf0e10cSrcweir * the string in the work buffer. 50cdf0e10cSrcweir * scannumber() Reads a C numeric constant from the input stream, 51cdf0e10cSrcweir * calling the user-supplied function for each 52cdf0e10cSrcweir * character. (output() or save() as noted above.) 53cdf0e10cSrcweir * save() Save one character in the work[] buffer. 54cdf0e10cSrcweir * savestring() Saves a string in malloc() memory. 55cdf0e10cSrcweir * getfile() Initialize a new FILEINFO structure, called when 56cdf0e10cSrcweir * #include opens a new file, or a macro is to be 57cdf0e10cSrcweir * expanded. 58cdf0e10cSrcweir * getmem() Get a specified number of bytes from malloc memory. 59cdf0e10cSrcweir * output() Write one character to stdout (calling PUTCHAR) -- 60cdf0e10cSrcweir * implemented as a function so its address may be 61cdf0e10cSrcweir * passed to scanstring() and scannumber(). 62cdf0e10cSrcweir * lookid() Scans the next token (identifier) from the input 63cdf0e10cSrcweir * stream. Looks for it in the #defined symbol table. 64cdf0e10cSrcweir * Returns a pointer to the definition, if found, or NULL 65cdf0e10cSrcweir * if not present. The identifier is stored in token[]. 66cdf0e10cSrcweir * defnedel() Define enter/delete subroutine. Updates the 67cdf0e10cSrcweir * symbol table. 68cdf0e10cSrcweir * get() Read the next byte from the current input stream, 69cdf0e10cSrcweir * handling end of (macro/file) input and embedded 70cdf0e10cSrcweir * comments appropriately. Note that the global 71cdf0e10cSrcweir * instring is -- essentially -- a parameter to get(). 72cdf0e10cSrcweir * cget() Like get(), but skip over TOK_SEP. 73cdf0e10cSrcweir * unget() Push last gotten character back on the input stream. 74cdf0e10cSrcweir * cerror(), cwarn(), cfatal(), cierror(), ciwarn() 75cdf0e10cSrcweir * These routines format an print messages to the user. 76cdf0e10cSrcweir * cerror & cwarn take a format and a single string argument. 77cdf0e10cSrcweir * cierror & ciwarn take a format and a single int (char) argument. 78cdf0e10cSrcweir * cfatal takes a format and a single string argument. 79cdf0e10cSrcweir */ 80*1dda6fa0Smseidel 81cdf0e10cSrcweir /* 82cdf0e10cSrcweir * This table must be rewritten for a non-Ascii machine. 83cdf0e10cSrcweir * 84cdf0e10cSrcweir * Note that several "non-visible" characters have special meaning: 85cdf0e10cSrcweir * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion. 86cdf0e10cSrcweir * Hex 1E TOK_SEP -- a delimiter for token concatenation 87cdf0e10cSrcweir * Hex 1F COM_SEP -- a zero-width whitespace for comment concatenation 88cdf0e10cSrcweir */ 89cdf0e10cSrcweir #if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D 90cdf0e10cSrcweir << error type table is not correct >> 91cdf0e10cSrcweir #endif 92cdf0e10cSrcweir 93cdf0e10cSrcweir #if OK_DOLLAR 94cdf0e10cSrcweir #define DOL LET 95cdf0e10cSrcweir #else 96cdf0e10cSrcweir #define DOL 000 97cdf0e10cSrcweir #endif 98cdf0e10cSrcweir 99cdf0e10cSrcweir #ifdef EBCDIC 100cdf0e10cSrcweir 101cdf0e10cSrcweir char type[256] = { /* Character type codes Hex */ 102cdf0e10cSrcweir END, 000, 000, 000, 000, SPA, 000, 000, /* 00 */ 103cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 08 */ 104cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */ 105cdf0e10cSrcweir 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */ 106cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 20 */ 107cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 28 */ 108cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 30 */ 109cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 38 */ 110cdf0e10cSrcweir SPA, 000, 000, 000, 000, 000, 000, 000, /* 40 */ 111cdf0e10cSrcweir 000, 000, 000, DOT, OP_LT,OP_LPA,OP_ADD, OP_OR, /* 48 .<(+| */ 112cdf0e10cSrcweir OP_AND, 000, 000, 000, 000, 000, 000, 000, /* 50 & */ 113cdf0e10cSrcweir 000, 000,OP_NOT, DOL,OP_MUL,OP_RPA, 000,OP_XOR, /* 58 !$*);^ */ 114cdf0e10cSrcweir OP_SUB,OP_DIV, 000, 000, 000, 000, 000, 000, /* 60 -/ */ 115cdf0e10cSrcweir 000, 000, 000, 000,OP_MOD, LET, OP_GT,OP_QUE, /* 68 ,%_>? */ 116cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 70 */ 117cdf0e10cSrcweir 000, 000,OP_COL, 000, 000, QUO, OP_EQ, QUO, /* 78 `:#@'=" */ 118cdf0e10cSrcweir 000, LET, LET, LET, LET, LET, LET, LET, /* 80 abcdefg */ 119cdf0e10cSrcweir LET, LET, 000, 000, 000, 000, 000, 000, /* 88 hi */ 120cdf0e10cSrcweir 000, LET, LET, LET, LET, LET, LET, LET, /* 90 jklmnop */ 121cdf0e10cSrcweir LET, LET, 000, 000, 000, 000, 000, 000, /* 98 qr */ 122cdf0e10cSrcweir 000,OP_NOT, LET, LET, LET, LET, LET, LET, /* A0 ~stuvwx */ 123cdf0e10cSrcweir LET, LET, 000, 000, 000, 000, 000, 000, /* A8 yz [ */ 124cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* B0 */ 125cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* B8 ] */ 126cdf0e10cSrcweir 000, LET, LET, LET, LET, LET, LET, LET, /* C0 {ABCDEFG */ 127cdf0e10cSrcweir LET, LET, 000, 000, 000, 000, 000, 000, /* C8 HI */ 128cdf0e10cSrcweir 000, LET, LET, LET, LET, LET, LET, LET, /* D0 }JKLMNOP */ 129cdf0e10cSrcweir LET, LET, 000, 000, 000, 000, 000, 000, /* D8 QR */ 130cdf0e10cSrcweir BSH, 000, LET, LET, LET, LET, LET, LET, /* E0 \ STUVWX */ 131cdf0e10cSrcweir LET, LET, 000, 000, 000, 000, 000, 000, /* E8 YZ */ 132cdf0e10cSrcweir DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* F0 01234567 */ 133cdf0e10cSrcweir DIG, DIG, 000, 000, 000, 000, 000, 000, /* F8 89 */ 134cdf0e10cSrcweir }; 135cdf0e10cSrcweir 136cdf0e10cSrcweir #else 137cdf0e10cSrcweir 138cdf0e10cSrcweir char type[256] = { /* Character type codes Hex */ 139cdf0e10cSrcweir END, 000, 000, 000, 000, 000, 000, 000, /* 00 */ 140cdf0e10cSrcweir 000, SPA, 000, 000, 000, 000, 000, 000, /* 08 */ 141cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */ 142cdf0e10cSrcweir 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */ 143cdf0e10cSrcweir SPA,OP_NOT, QUO, 000, DOL,OP_MOD,OP_AND, QUO, /* 20 !"#$%&' */ 144cdf0e10cSrcweir OP_LPA,OP_RPA,OP_MUL,OP_ADD, 000,OP_SUB, DOT,OP_DIV, /* 28 ()*+,-./ */ 145cdf0e10cSrcweir DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* 30 01234567 */ 146cdf0e10cSrcweir DIG, DIG,OP_COL, 000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */ 147cdf0e10cSrcweir 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */ 148cdf0e10cSrcweir LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */ 149cdf0e10cSrcweir LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */ 150cdf0e10cSrcweir LET, LET, LET, 000, BSH, 000,OP_XOR, LET, /* 58 XYZ[\]^_ */ 151cdf0e10cSrcweir 000, LET, LET, LET, LET, LET, LET, LET, /* 60 `abcdefg */ 152cdf0e10cSrcweir LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */ 153cdf0e10cSrcweir LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */ 154cdf0e10cSrcweir LET, LET, LET, 000, OP_OR, 000,OP_NOT, 000, /* 78 xyz{|}~ */ 155cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 156cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 157cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 158cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 159cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 160cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 161cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 162cdf0e10cSrcweir 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ 163cdf0e10cSrcweir }; 164cdf0e10cSrcweir 165cdf0e10cSrcweir #endif 166cdf0e10cSrcweir 167*1dda6fa0Smseidel 168cdf0e10cSrcweir /* 169cdf0e10cSrcweir * C P P S y m b o l T a b l e s 170cdf0e10cSrcweir */ 171cdf0e10cSrcweir 172cdf0e10cSrcweir /* 173cdf0e10cSrcweir * SBSIZE defines the number of hash-table slots for the symbol table. 174cdf0e10cSrcweir * It must be a power of 2. 175cdf0e10cSrcweir */ 176cdf0e10cSrcweir #ifndef SBSIZE 177cdf0e10cSrcweir #define SBSIZE 64 178cdf0e10cSrcweir #endif 179cdf0e10cSrcweir #define SBMASK (SBSIZE - 1) 180cdf0e10cSrcweir #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1) 181cdf0e10cSrcweir << error, SBSIZE must be a power of 2 >> 182cdf0e10cSrcweir #endif 183cdf0e10cSrcweir 184cdf0e10cSrcweir 185cdf0e10cSrcweir static DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */ 186cdf0e10cSrcweir 187cdf0e10cSrcweir void InitCpp6() 188cdf0e10cSrcweir { 189cdf0e10cSrcweir int i; 190cdf0e10cSrcweir for( i = 0; i < SBSIZE; i++ ) 191cdf0e10cSrcweir symtab[ i ] = NULL; 192cdf0e10cSrcweir } 193cdf0e10cSrcweir 194cdf0e10cSrcweir 195cdf0e10cSrcweir 196cdf0e10cSrcweir void skipnl() 197cdf0e10cSrcweir /* 198cdf0e10cSrcweir * Skip to the end of the current input line. 199cdf0e10cSrcweir */ 200cdf0e10cSrcweir { 201cdf0e10cSrcweir register int c; 202cdf0e10cSrcweir 203cdf0e10cSrcweir do { /* Skip to newline */ 204cdf0e10cSrcweir c = get(); 205cdf0e10cSrcweir } while (c != '\n' && c != EOF_CHAR); 206cdf0e10cSrcweir } 207cdf0e10cSrcweir 208cdf0e10cSrcweir int 209cdf0e10cSrcweir skipws() 210cdf0e10cSrcweir /* 211cdf0e10cSrcweir * Skip over whitespace 212cdf0e10cSrcweir */ 213cdf0e10cSrcweir { 214cdf0e10cSrcweir register int c; 215cdf0e10cSrcweir 216cdf0e10cSrcweir do { /* Skip whitespace */ 217cdf0e10cSrcweir c = get(); 218cdf0e10cSrcweir #if COMMENT_INVISIBLE 219cdf0e10cSrcweir } while (type[c] == SPA || c == COM_SEP); 220cdf0e10cSrcweir #else 221cdf0e10cSrcweir } while (type[c] == SPA); 222cdf0e10cSrcweir #endif 223cdf0e10cSrcweir return (c); 224cdf0e10cSrcweir } 225*1dda6fa0Smseidel 226cdf0e10cSrcweir void scanid(int c) 227cdf0e10cSrcweir /* 228cdf0e10cSrcweir * Get the next token (an id) into the token buffer. 229cdf0e10cSrcweir * Note: this code is duplicated in lookid(). 230cdf0e10cSrcweir * Change one, change both. 231cdf0e10cSrcweir */ 232cdf0e10cSrcweir { 233cdf0e10cSrcweir register char *bp; 234cdf0e10cSrcweir 235cdf0e10cSrcweir if (c == DEF_MAGIC) /* Eat the magic token */ 236cdf0e10cSrcweir c = get(); /* undefiner. */ 237cdf0e10cSrcweir bp = token; 238cdf0e10cSrcweir do { 239cdf0e10cSrcweir if (bp < &token[IDMAX]) /* token dim is IDMAX+1 */ 240cdf0e10cSrcweir *bp++ = (char)c; 241cdf0e10cSrcweir c = get(); 242cdf0e10cSrcweir } while (type[c] == LET || type[c] == DIG); 243cdf0e10cSrcweir unget(); 244cdf0e10cSrcweir *bp = EOS; 245cdf0e10cSrcweir } 246cdf0e10cSrcweir 247cdf0e10cSrcweir int 248cdf0e10cSrcweir macroid(int c) 249cdf0e10cSrcweir /* 250cdf0e10cSrcweir * If c is a letter, scan the id. if it's #defined, expand it and scan 251cdf0e10cSrcweir * the next character and try again. 252cdf0e10cSrcweir * 253cdf0e10cSrcweir * Else, return the character. If type[c] is a LET, the token is in token. 254cdf0e10cSrcweir */ 255cdf0e10cSrcweir { 256cdf0e10cSrcweir register DEFBUF *dp; 257cdf0e10cSrcweir 258cdf0e10cSrcweir if (infile != NULL && infile->fp != NULL) 259cdf0e10cSrcweir recursion = 0; 260cdf0e10cSrcweir while (type[c] == LET && (dp = lookid(c)) != NULL) { 261cdf0e10cSrcweir expand(dp); 262cdf0e10cSrcweir c = get(); 263cdf0e10cSrcweir } 264cdf0e10cSrcweir return (c); 265cdf0e10cSrcweir } 266*1dda6fa0Smseidel 267cdf0e10cSrcweir int 268cdf0e10cSrcweir catenate() 269cdf0e10cSrcweir /* 270cdf0e10cSrcweir * A token was just read (via macroid). 271cdf0e10cSrcweir * If the next character is TOK_SEP, concatenate the next token 272cdf0e10cSrcweir * return TRUE -- which should recall macroid after refreshing 273cdf0e10cSrcweir * macroid's argument. If it is not TOK_SEP, unget() the character 274cdf0e10cSrcweir * and return FALSE. 275cdf0e10cSrcweir */ 276cdf0e10cSrcweir { 277cdf0e10cSrcweir register int c; 278cdf0e10cSrcweir register char *token1; 279cdf0e10cSrcweir 280cdf0e10cSrcweir #if OK_CONCAT 281cdf0e10cSrcweir if (get() != TOK_SEP) { /* Token concatenation */ 282cdf0e10cSrcweir unget(); 283cdf0e10cSrcweir return (FALSE); 284cdf0e10cSrcweir } 285cdf0e10cSrcweir else { 286cdf0e10cSrcweir token1 = savestring(token); /* Save first token */ 287cdf0e10cSrcweir c = macroid(get()); /* Scan next token */ 288cdf0e10cSrcweir switch(type[c]) { /* What was it? */ 289cdf0e10cSrcweir case LET: /* An identifier, ... */ 290cdf0e10cSrcweir if (strlen(token1) + strlen(token) >= NWORK) 291cdf0e10cSrcweir cfatal("work buffer overflow doing %s #", token1); 292cdf0e10cSrcweir sprintf(work, "%s%s", token1, token); 293cdf0e10cSrcweir break; 294cdf0e10cSrcweir 295cdf0e10cSrcweir case DIG: /* A digit string */ 296cdf0e10cSrcweir strcpy(work, token1); 297cdf0e10cSrcweir workp = work + strlen(work); 298cdf0e10cSrcweir do { 299cdf0e10cSrcweir save(c); 300cdf0e10cSrcweir } while ((c = get()) != TOK_SEP); 301cdf0e10cSrcweir /* 302cdf0e10cSrcweir * The trailing TOK_SEP is no longer needed. 303cdf0e10cSrcweir */ 304cdf0e10cSrcweir save(EOS); 305cdf0e10cSrcweir break; 306cdf0e10cSrcweir 307cdf0e10cSrcweir default: /* An error, ... */ 308cdf0e10cSrcweir #if ! COMMENT_INVISIBLE 309cdf0e10cSrcweir if (isprint(c)) 310cdf0e10cSrcweir cierror("Strange character '%c' after #", c); 311cdf0e10cSrcweir else 312cdf0e10cSrcweir cierror("Strange character (%d.) after #", c); 313cdf0e10cSrcweir #endif 314cdf0e10cSrcweir strcpy(work, token1); 315cdf0e10cSrcweir unget(); 316cdf0e10cSrcweir break; 317cdf0e10cSrcweir } 318cdf0e10cSrcweir /* 319cdf0e10cSrcweir * work has the concatenated token and token1 has 320cdf0e10cSrcweir * the first token (no longer needed). Unget the 321cdf0e10cSrcweir * new (concatenated) token after freeing token1. 322cdf0e10cSrcweir * Finally, setup to read the new token. 323cdf0e10cSrcweir */ 324cdf0e10cSrcweir free(token1); /* Free up memory */ 325cdf0e10cSrcweir ungetstring(work); /* Unget the new thing, */ 326cdf0e10cSrcweir return (TRUE); 327cdf0e10cSrcweir } 328cdf0e10cSrcweir #else 329cdf0e10cSrcweir return (FALSE); /* Not supported */ 330cdf0e10cSrcweir #endif 331cdf0e10cSrcweir } 332*1dda6fa0Smseidel 333cdf0e10cSrcweir int 334cdf0e10cSrcweir scanstring(int delim, 335cdf0e10cSrcweir #ifndef _NO_PROTO 336cdf0e10cSrcweir void (*outfun)( int ) /* BP */ /* Output function */ 337cdf0e10cSrcweir #else 338cdf0e10cSrcweir void (*outfun)() /* BP */ 339cdf0e10cSrcweir #endif 340cdf0e10cSrcweir ) 341cdf0e10cSrcweir /* 342cdf0e10cSrcweir * Scan off a string. Warning if terminated by newline or EOF. 343cdf0e10cSrcweir * outfun() outputs the character -- to a buffer if in a macro. 344cdf0e10cSrcweir * TRUE if ok, FALSE if error. 345cdf0e10cSrcweir */ 346cdf0e10cSrcweir { 347cdf0e10cSrcweir register int c; 348cdf0e10cSrcweir 349cdf0e10cSrcweir instring = TRUE; /* Don't strip comments */ 350cdf0e10cSrcweir (*outfun)(delim); 351cdf0e10cSrcweir while ((c = get()) != delim 352cdf0e10cSrcweir && c != '\n' 353cdf0e10cSrcweir && c != EOF_CHAR) { 354cdf0e10cSrcweir 355cdf0e10cSrcweir if (c != DEF_MAGIC) 356cdf0e10cSrcweir (*outfun)(c); 357cdf0e10cSrcweir if (c == '\\') 358cdf0e10cSrcweir (*outfun)(get()); 359cdf0e10cSrcweir } 360cdf0e10cSrcweir instring = FALSE; 361cdf0e10cSrcweir if (c == delim) { 362cdf0e10cSrcweir (*outfun)(c); 363cdf0e10cSrcweir return (TRUE); 364cdf0e10cSrcweir } 365cdf0e10cSrcweir else { 366cdf0e10cSrcweir cerror("Unterminated string", NULLST); 367cdf0e10cSrcweir unget(); 368cdf0e10cSrcweir return (FALSE); 369cdf0e10cSrcweir } 370cdf0e10cSrcweir } 371*1dda6fa0Smseidel 372cdf0e10cSrcweir void scannumber(int c, 373cdf0e10cSrcweir #ifndef _NO_PROTO 374cdf0e10cSrcweir register void (*outfun)( int ) /* BP */ /* Output/store func */ 375cdf0e10cSrcweir #else 376cdf0e10cSrcweir register void (*outfun)() /* BP */ 377cdf0e10cSrcweir #endif 378cdf0e10cSrcweir ) 379cdf0e10cSrcweir /* 380cdf0e10cSrcweir * Process a number. We know that c is from 0 to 9 or dot. 381cdf0e10cSrcweir * Algorithm from Dave Conroy's Decus C. 382cdf0e10cSrcweir */ 383cdf0e10cSrcweir { 384cdf0e10cSrcweir register int radix; /* 8, 10, or 16 */ 385cdf0e10cSrcweir int expseen; /* 'e' seen in floater */ 386cdf0e10cSrcweir int signseen; /* '+' or '-' seen */ 387cdf0e10cSrcweir int octal89; /* For bad octal test */ 388cdf0e10cSrcweir int dotflag; /* TRUE if '.' was seen */ 389cdf0e10cSrcweir 390cdf0e10cSrcweir expseen = FALSE; /* No exponent seen yet */ 391cdf0e10cSrcweir signseen = TRUE; /* No +/- allowed yet */ 392cdf0e10cSrcweir octal89 = FALSE; /* No bad octal yet */ 393cdf0e10cSrcweir radix = 10; /* Assume decimal */ 394cdf0e10cSrcweir if ((dotflag = (c == '.')) != FALSE) { /* . something? */ 395cdf0e10cSrcweir (*outfun)('.'); /* Always out the dot */ 396cdf0e10cSrcweir if (type[(c = get())] != DIG) { /* If not a float numb, */ 397cdf0e10cSrcweir unget(); /* Rescan strange char */ 398cdf0e10cSrcweir return; /* All done for now */ 399cdf0e10cSrcweir } 400cdf0e10cSrcweir } /* End of float test */ 401cdf0e10cSrcweir else if (c == '0') { /* Octal or hex? */ 402cdf0e10cSrcweir (*outfun)(c); /* Stuff initial zero */ 403cdf0e10cSrcweir radix = 8; /* Assume it's octal */ 404cdf0e10cSrcweir c = get(); /* Look for an 'x' */ 405cdf0e10cSrcweir if (c == 'x' || c == 'X') { /* Did we get one? */ 406cdf0e10cSrcweir radix = 16; /* Remember new radix */ 407cdf0e10cSrcweir (*outfun)(c); /* Stuff the 'x' */ 408cdf0e10cSrcweir c = get(); /* Get next character */ 409cdf0e10cSrcweir } 410cdf0e10cSrcweir } 411cdf0e10cSrcweir for (;;) { /* Process curr. char. */ 412cdf0e10cSrcweir /* 413cdf0e10cSrcweir * Note that this algorithm accepts "012e4" and "03.4" 414cdf0e10cSrcweir * as legitimate floating-point numbers. 415cdf0e10cSrcweir */ 416cdf0e10cSrcweir if (radix != 16 && (c == 'e' || c == 'E')) { 417cdf0e10cSrcweir if (expseen) /* Already saw 'E'? */ 418cdf0e10cSrcweir break; /* Exit loop, bad nbr. */ 419cdf0e10cSrcweir expseen = TRUE; /* Set exponent seen */ 420cdf0e10cSrcweir signseen = FALSE; /* We can read '+' now */ 421cdf0e10cSrcweir radix = 10; /* Decimal exponent */ 422cdf0e10cSrcweir } 423cdf0e10cSrcweir else if (radix != 16 && c == '.') { 424cdf0e10cSrcweir if (dotflag) /* Saw dot already? */ 425cdf0e10cSrcweir break; /* Exit loop, two dots */ 426cdf0e10cSrcweir dotflag = TRUE; /* Remember the dot */ 427cdf0e10cSrcweir radix = 10; /* Decimal fraction */ 428cdf0e10cSrcweir } 429cdf0e10cSrcweir else if (c == '+' || c == '-') { /* 1.0e+10 */ 430cdf0e10cSrcweir if (signseen) /* Sign in wrong place? */ 431cdf0e10cSrcweir break; /* Exit loop, not nbr. */ 432cdf0e10cSrcweir /* signseen = TRUE; */ /* Remember we saw it */ 433cdf0e10cSrcweir } 434cdf0e10cSrcweir else { /* Check the digit */ 435cdf0e10cSrcweir switch (c) { 436cdf0e10cSrcweir case '8': case '9': /* Sometimes wrong */ 437cdf0e10cSrcweir octal89 = TRUE; /* Do check later */ 438cdf0e10cSrcweir case '0': case '1': case '2': case '3': 439cdf0e10cSrcweir case '4': case '5': case '6': case '7': 440cdf0e10cSrcweir break; /* Always ok */ 441cdf0e10cSrcweir 442cdf0e10cSrcweir case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 443cdf0e10cSrcweir case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 444cdf0e10cSrcweir if (radix == 16) /* Alpha's are ok only */ 445cdf0e10cSrcweir break; /* if reading hex. */ 446cdf0e10cSrcweir default: /* At number end */ 447cdf0e10cSrcweir goto done; /* Break from for loop */ 448cdf0e10cSrcweir } /* End of switch */ 449cdf0e10cSrcweir } /* End general case */ 450cdf0e10cSrcweir (*outfun)(c); /* Accept the character */ 451cdf0e10cSrcweir signseen = TRUE; /* Don't read sign now */ 452cdf0e10cSrcweir c = get(); /* Read another char */ 453cdf0e10cSrcweir } /* End of scan loop */ 454cdf0e10cSrcweir /* 455cdf0e10cSrcweir * When we break out of the scan loop, c contains the first 456cdf0e10cSrcweir * character (maybe) not in the number. If the number is an 457cdf0e10cSrcweir * integer, allow a trailing 'L' for long and/or a trailing 'U' 458cdf0e10cSrcweir * for unsigned. If not those, push the trailing character back 459cdf0e10cSrcweir * on the input stream. Floating point numbers accept a trailing 460cdf0e10cSrcweir * 'L' for "long double". 461cdf0e10cSrcweir */ 462cdf0e10cSrcweir done: if (dotflag || expseen) { /* Floating point? */ 463cdf0e10cSrcweir if (c == 'l' || c == 'L') { 464cdf0e10cSrcweir (*outfun)(c); 465cdf0e10cSrcweir c = get(); /* Ungotten later */ 466cdf0e10cSrcweir } 467cdf0e10cSrcweir } 468cdf0e10cSrcweir else { /* Else it's an integer */ 469cdf0e10cSrcweir /* 470cdf0e10cSrcweir * We know that dotflag and expseen are both zero, now: 471cdf0e10cSrcweir * dotflag signals "saw 'L'", and 472cdf0e10cSrcweir * expseen signals "saw 'U'". 473cdf0e10cSrcweir */ 474cdf0e10cSrcweir for (;;) { 475cdf0e10cSrcweir switch (c) { 476cdf0e10cSrcweir case 'l': 477cdf0e10cSrcweir case 'L': 478cdf0e10cSrcweir if (dotflag) 479cdf0e10cSrcweir goto nomore; 480cdf0e10cSrcweir dotflag = TRUE; 481cdf0e10cSrcweir break; 482cdf0e10cSrcweir 483cdf0e10cSrcweir case 'u': 484cdf0e10cSrcweir case 'U': 485cdf0e10cSrcweir if (expseen) 486cdf0e10cSrcweir goto nomore; 487cdf0e10cSrcweir expseen = TRUE; 488cdf0e10cSrcweir break; 489cdf0e10cSrcweir 490cdf0e10cSrcweir default: 491cdf0e10cSrcweir goto nomore; 492cdf0e10cSrcweir } 493cdf0e10cSrcweir (*outfun)(c); /* Got 'L' or 'U'. */ 494cdf0e10cSrcweir c = get(); /* Look at next, too. */ 495cdf0e10cSrcweir } 496cdf0e10cSrcweir } 497cdf0e10cSrcweir nomore: unget(); /* Not part of a number */ 498cdf0e10cSrcweir if (octal89 && radix == 8) 499cdf0e10cSrcweir cwarn("Illegal digit in octal number", NULLST); 500cdf0e10cSrcweir } 501*1dda6fa0Smseidel 502cdf0e10cSrcweir void save(int c) 503cdf0e10cSrcweir { 504cdf0e10cSrcweir if (workp >= &work[NWORK]) { 505cdf0e10cSrcweir work[NWORK-1] = '\0'; 506cdf0e10cSrcweir cfatal("Work buffer overflow: %s", work); 507cdf0e10cSrcweir } 508cdf0e10cSrcweir else *workp++ = (char)c; 509cdf0e10cSrcweir } 510cdf0e10cSrcweir 511cdf0e10cSrcweir char * 512cdf0e10cSrcweir savestring(char* text) 513cdf0e10cSrcweir /* 514cdf0e10cSrcweir * Store a string into free memory. 515cdf0e10cSrcweir */ 516cdf0e10cSrcweir { 517cdf0e10cSrcweir register char *result; 518cdf0e10cSrcweir 519cdf0e10cSrcweir result = getmem(strlen(text) + 1); 520cdf0e10cSrcweir strcpy(result, text); 521cdf0e10cSrcweir return (result); 522cdf0e10cSrcweir } 523cdf0e10cSrcweir 524cdf0e10cSrcweir FILEINFO * 525cdf0e10cSrcweir getfile(int bufsize, char* name) 526cdf0e10cSrcweir /* 527cdf0e10cSrcweir * Common FILEINFO buffer initialization for a new file or macro. 528cdf0e10cSrcweir */ 529cdf0e10cSrcweir { 530cdf0e10cSrcweir register FILEINFO *file; 531cdf0e10cSrcweir register int size; 532cdf0e10cSrcweir 533cdf0e10cSrcweir size = strlen(name); /* File/macro name */ 534cdf0e10cSrcweir file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size); 535cdf0e10cSrcweir file->parent = infile; /* Chain files together */ 536cdf0e10cSrcweir file->fp = NULL; /* No file yet */ 537cdf0e10cSrcweir file->filename = savestring(name); /* Save file/macro name */ 538cdf0e10cSrcweir file->progname = NULL; /* No #line seen yet */ 539cdf0e10cSrcweir file->unrecur = 0; /* No macro fixup */ 540cdf0e10cSrcweir file->bptr = file->buffer; /* Initialize line ptr */ 541cdf0e10cSrcweir file->buffer[0] = EOS; /* Force first read */ 542cdf0e10cSrcweir file->line = 0; /* (Not used just yet) */ 543cdf0e10cSrcweir if (infile != NULL) /* If #include file */ 544cdf0e10cSrcweir infile->line = line; /* Save current line */ 545cdf0e10cSrcweir infile = file; /* New current file */ 546cdf0e10cSrcweir line = 1; /* Note first line */ 547cdf0e10cSrcweir return (file); /* All done. */ 548cdf0e10cSrcweir } 549cdf0e10cSrcweir 550cdf0e10cSrcweir char * 551cdf0e10cSrcweir getmem(int size) 552cdf0e10cSrcweir /* 553cdf0e10cSrcweir * Get a block of free memory. 554cdf0e10cSrcweir */ 555cdf0e10cSrcweir { 556cdf0e10cSrcweir register char *result; 557cdf0e10cSrcweir 558cdf0e10cSrcweir if ((result = malloc((unsigned) size)) == NULL) 559cdf0e10cSrcweir cfatal("Out of memory", NULLST); 560cdf0e10cSrcweir return (result); 561cdf0e10cSrcweir } 562*1dda6fa0Smseidel 563cdf0e10cSrcweir 564cdf0e10cSrcweir DEFBUF * 565cdf0e10cSrcweir lookid(int c) 566cdf0e10cSrcweir /* 567cdf0e10cSrcweir * Look for the next token in the symbol table. Returns token in "token". 568cdf0e10cSrcweir * If found, returns the table pointer; Else returns NULL. 569cdf0e10cSrcweir */ 570cdf0e10cSrcweir { 571cdf0e10cSrcweir register int nhash; 572cdf0e10cSrcweir register DEFBUF *dp; 573cdf0e10cSrcweir register char *np; 574cdf0e10cSrcweir int temp = 0; 575cdf0e10cSrcweir int isrecurse; /* For #define foo foo */ 576cdf0e10cSrcweir 577cdf0e10cSrcweir np = token; 578cdf0e10cSrcweir nhash = 0; 579cdf0e10cSrcweir if (0 != (isrecurse = (c == DEF_MAGIC))) /* If recursive macro */ 580cdf0e10cSrcweir c = get(); /* hack, skip DEF_MAGIC */ 581cdf0e10cSrcweir do { 582cdf0e10cSrcweir if (np < &token[IDMAX]) { /* token dim is IDMAX+1 */ 583cdf0e10cSrcweir *np++ = (char)c; /* Store token byte */ 584cdf0e10cSrcweir nhash += c; /* Update hash value */ 585cdf0e10cSrcweir } 586cdf0e10cSrcweir c = get(); /* And get another byte */ 587cdf0e10cSrcweir } while (type[c] == LET || type[c] == DIG); 588cdf0e10cSrcweir unget(); /* Rescan terminator */ 589cdf0e10cSrcweir *np = EOS; /* Terminate token */ 590cdf0e10cSrcweir if (isrecurse) /* Recursive definition */ 591cdf0e10cSrcweir return (NULL); /* undefined just now */ 592cdf0e10cSrcweir nhash += (np - token); /* Fix hash value */ 593cdf0e10cSrcweir dp = symtab[nhash & SBMASK]; /* Starting bucket */ 594cdf0e10cSrcweir while (dp != (DEFBUF *) NULL) { /* Search symbol table */ 595cdf0e10cSrcweir if (dp->hash == nhash /* Fast precheck */ 596cdf0e10cSrcweir && (temp = strcmp(dp->name, token)) >= 0) 597cdf0e10cSrcweir break; 598cdf0e10cSrcweir dp = dp->link; /* Nope, try next one */ 599cdf0e10cSrcweir } 600cdf0e10cSrcweir return ((temp == 0) ? dp : NULL); 601cdf0e10cSrcweir } 602*1dda6fa0Smseidel 603cdf0e10cSrcweir DEFBUF * 604cdf0e10cSrcweir defendel(char* name, int delete) 605cdf0e10cSrcweir /* 606cdf0e10cSrcweir * Enter this name in the lookup table (delete = FALSE) 607cdf0e10cSrcweir * or delete this name (delete = TRUE). 608cdf0e10cSrcweir * Returns a pointer to the define block (delete = FALSE) 609cdf0e10cSrcweir * Returns NULL if the symbol wasn't defined (delete = TRUE). 610cdf0e10cSrcweir */ 611cdf0e10cSrcweir { 612cdf0e10cSrcweir register DEFBUF *dp; 613cdf0e10cSrcweir register DEFBUF **prevp; 614cdf0e10cSrcweir register char *np; 615cdf0e10cSrcweir int nhash; 616cdf0e10cSrcweir int temp; 617cdf0e10cSrcweir int size; 618cdf0e10cSrcweir 619cdf0e10cSrcweir for (nhash = 0, np = name; *np != EOS;) 620cdf0e10cSrcweir nhash += *np++; 621cdf0e10cSrcweir size = (np - name); 622cdf0e10cSrcweir nhash += size; 623cdf0e10cSrcweir prevp = &symtab[nhash & SBMASK]; 624cdf0e10cSrcweir while ((dp = *prevp) != (DEFBUF *) NULL) { 625cdf0e10cSrcweir if (dp->hash == nhash 626cdf0e10cSrcweir && (temp = strcmp(dp->name, name)) >= 0) { 627cdf0e10cSrcweir if (temp > 0) 628cdf0e10cSrcweir dp = NULL; /* Not found */ 629cdf0e10cSrcweir else { 630cdf0e10cSrcweir *prevp = dp->link; /* Found, unlink and */ 631cdf0e10cSrcweir if (dp->repl != NULL) /* Free the replacement */ 632cdf0e10cSrcweir free(dp->repl); /* if any, and then */ 633cdf0e10cSrcweir free((char *) dp); /* Free the symbol */ 634cdf0e10cSrcweir } 635cdf0e10cSrcweir break; 636cdf0e10cSrcweir } 637cdf0e10cSrcweir prevp = &dp->link; 638cdf0e10cSrcweir } 639cdf0e10cSrcweir if (!delete) { 640cdf0e10cSrcweir dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size); 641cdf0e10cSrcweir dp->link = *prevp; 642cdf0e10cSrcweir *prevp = dp; 643cdf0e10cSrcweir dp->hash = nhash; 644cdf0e10cSrcweir dp->repl = NULL; 645cdf0e10cSrcweir dp->nargs = 0; 646cdf0e10cSrcweir strcpy(dp->name, name); 647cdf0e10cSrcweir } 648cdf0e10cSrcweir return (dp); 649cdf0e10cSrcweir } 650cdf0e10cSrcweir 651cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 652cdf0e10cSrcweir 653cdf0e10cSrcweir void dumpdef(char *why) 654cdf0e10cSrcweir { 655cdf0e10cSrcweir register DEFBUF *dp; 656cdf0e10cSrcweir register DEFBUF **syp; 657cdf0e10cSrcweir FILE *pRememberOut = NULL; 658cdf0e10cSrcweir 659cdf0e10cSrcweir if ( bDumpDefs ) /*ER */ 660cdf0e10cSrcweir { 661cdf0e10cSrcweir pRememberOut = pCppOut; 662cdf0e10cSrcweir pCppOut = pDefOut; 663cdf0e10cSrcweir } 664cdf0e10cSrcweir fprintf( pCppOut, "CPP symbol table dump %s\n", why); 665cdf0e10cSrcweir for (syp = symtab; syp < &symtab[SBSIZE]; syp++) { 666cdf0e10cSrcweir if ((dp = *syp) != (DEFBUF *) NULL) { 667cdf0e10cSrcweir fprintf( pCppOut, "symtab[%d]\n", (syp - symtab)); 668cdf0e10cSrcweir do { 669cdf0e10cSrcweir dumpadef((char *) NULL, dp); 670cdf0e10cSrcweir } while ((dp = dp->link) != (DEFBUF *) NULL); 671cdf0e10cSrcweir } 672cdf0e10cSrcweir } 673cdf0e10cSrcweir if ( bDumpDefs ) 674cdf0e10cSrcweir { 675cdf0e10cSrcweir fprintf( pCppOut, "\n"); 676cdf0e10cSrcweir pCppOut = pRememberOut; 677cdf0e10cSrcweir } 678cdf0e10cSrcweir } 679cdf0e10cSrcweir 680cdf0e10cSrcweir void dumpadef(char *why, register DEFBUF *dp) 681cdf0e10cSrcweir { 682cdf0e10cSrcweir register char *cp; 683cdf0e10cSrcweir register int c; 684cdf0e10cSrcweir FILE *pRememberOut = NULL; 685cdf0e10cSrcweir 686cdf0e10cSrcweir /*ER dump #define's to pDefOut */ 687cdf0e10cSrcweir if ( bDumpDefs ) 688cdf0e10cSrcweir { 689cdf0e10cSrcweir pRememberOut = pCppOut; 690cdf0e10cSrcweir pCppOut = pDefOut; 691cdf0e10cSrcweir } 692cdf0e10cSrcweir fprintf( pCppOut, " \"%s\" [%d]", dp->name, dp->nargs); 693cdf0e10cSrcweir if (why != NULL) 694cdf0e10cSrcweir fprintf( pCppOut, " (%s)", why); 695cdf0e10cSrcweir if (dp->repl != NULL) { 696cdf0e10cSrcweir fprintf( pCppOut, " => "); 697cdf0e10cSrcweir for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) { 698cdf0e10cSrcweir #ifdef SOLAR 699cdf0e10cSrcweir if (c == DEL) { 700cdf0e10cSrcweir c = *cp++ & 0xFF; 701cdf0e10cSrcweir if( c == EOS ) break; 702cdf0e10cSrcweir fprintf( pCppOut, "<%%%d>", c - MAC_PARM); 703cdf0e10cSrcweir } 704cdf0e10cSrcweir #else 705cdf0e10cSrcweir if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) 706cdf0e10cSrcweir fprintf( pCppOut, "<%%%d>", c - MAC_PARM); 707cdf0e10cSrcweir #endif 708cdf0e10cSrcweir else if (isprint(c) || c == '\n' || c == '\t') 709cdf0e10cSrcweir PUTCHAR(c); 710cdf0e10cSrcweir else if (c < ' ') 711cdf0e10cSrcweir fprintf( pCppOut, "<^%c>", c + '@'); 712cdf0e10cSrcweir else 713cdf0e10cSrcweir fprintf( pCppOut, "<\\0%o>", c); 714cdf0e10cSrcweir } 715cdf0e10cSrcweir /*ER evaluate macros to pDefOut */ 716cdf0e10cSrcweir #ifdef EVALDEFS 717cdf0e10cSrcweir if ( bDumpDefs && !bIsInEval && dp->nargs <= 0 ) 718cdf0e10cSrcweir { 719cdf0e10cSrcweir FILEINFO *infileSave = infile; 720cdf0e10cSrcweir char *tokenSave = savestring( token ); 721cdf0e10cSrcweir char *workSave = savestring( work ); 722cdf0e10cSrcweir int lineSave = line; 723cdf0e10cSrcweir int wronglineSave = wrongline; 724cdf0e10cSrcweir int recursionSave = recursion; 725cdf0e10cSrcweir FILEINFO *file; 726cdf0e10cSrcweir EVALTYPE valEval; 727cdf0e10cSrcweir 728cdf0e10cSrcweir bIsInEval = 1; 729cdf0e10cSrcweir infile = NULL; /* start from scrap */ 730cdf0e10cSrcweir line = 0; 731cdf0e10cSrcweir wrongline = 0; 732cdf0e10cSrcweir *token = EOS; 733cdf0e10cSrcweir *work = EOS; 734cdf0e10cSrcweir recursion = 0; 735cdf0e10cSrcweir file = getfile( strlen( dp->repl ), dp->name ); 736cdf0e10cSrcweir strcpy( file->buffer, dp->repl ); 737cdf0e10cSrcweir fprintf( pCppOut, " ===> "); 738cdf0e10cSrcweir nEvalOff = 0; 739cdf0e10cSrcweir cppmain(); /* get() frees also *file */ 740cdf0e10cSrcweir valEval = 0; 741cdf0e10cSrcweir if ( 0 == evaluate( EvalBuf, &valEval ) ) 742cdf0e10cSrcweir { 743cdf0e10cSrcweir #ifdef EVALFLOATS 744cdf0e10cSrcweir if ( valEval != (EVALTYPE)((long)valEval ) ) 745cdf0e10cSrcweir fprintf( pCppOut, " ==eval=> %f", valEval ); 746cdf0e10cSrcweir else 747cdf0e10cSrcweir #endif 748cdf0e10cSrcweir fprintf( pCppOut, " ==eval=> %ld", (long)valEval ); 749cdf0e10cSrcweir } 750cdf0e10cSrcweir recursion = recursionSave; 751cdf0e10cSrcweir wrongline = wronglineSave; 752cdf0e10cSrcweir line = lineSave; 753cdf0e10cSrcweir strcpy( work, workSave ); 754cdf0e10cSrcweir free( workSave ); 755cdf0e10cSrcweir strcpy( token, tokenSave ); 756cdf0e10cSrcweir free( tokenSave ); 757cdf0e10cSrcweir infile = infileSave; 758cdf0e10cSrcweir bIsInEval = 0; 759cdf0e10cSrcweir } 760cdf0e10cSrcweir #endif 761cdf0e10cSrcweir } 762cdf0e10cSrcweir else { 763cdf0e10cSrcweir fprintf( pCppOut, ", no replacement."); 764cdf0e10cSrcweir } 765cdf0e10cSrcweir PUTCHAR('\n'); 766cdf0e10cSrcweir if ( bDumpDefs ) 767cdf0e10cSrcweir pCppOut = pRememberOut; 768cdf0e10cSrcweir } 769cdf0e10cSrcweir #endif 770*1dda6fa0Smseidel 771cdf0e10cSrcweir /* 772cdf0e10cSrcweir * G E T 773cdf0e10cSrcweir */ 774cdf0e10cSrcweir 775cdf0e10cSrcweir int 776cdf0e10cSrcweir get() 777cdf0e10cSrcweir /* 778cdf0e10cSrcweir * Return the next character from a macro or the current file. 779cdf0e10cSrcweir * Handle end of file from #include files. 780cdf0e10cSrcweir */ 781cdf0e10cSrcweir { 782cdf0e10cSrcweir register int c; 783cdf0e10cSrcweir register FILEINFO *file; 784cdf0e10cSrcweir register int popped; /* Recursion fixup */ 785cdf0e10cSrcweir 786cdf0e10cSrcweir popped = 0; 787cdf0e10cSrcweir get_from_file: 788cdf0e10cSrcweir if ((file = infile) == NULL) 789cdf0e10cSrcweir return (EOF_CHAR); 790cdf0e10cSrcweir newline: 791cdf0e10cSrcweir #if 0 792cdf0e10cSrcweir fprintf( pCppOut, "get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n", 793cdf0e10cSrcweir file->filename, recursion, line, 794cdf0e10cSrcweir file->bptr - file->buffer, file->buffer); 795cdf0e10cSrcweir #endif 796cdf0e10cSrcweir /* 797cdf0e10cSrcweir * Read a character from the current input line or macro. 798cdf0e10cSrcweir * At EOS, either finish the current macro (freeing temp. 799cdf0e10cSrcweir * storage) or read another line from the current input file. 800cdf0e10cSrcweir * At EOF, exit the current file (#include) or, at EOF from 801cdf0e10cSrcweir * the cpp input file, return EOF_CHAR to finish processing. 802cdf0e10cSrcweir */ 803cdf0e10cSrcweir if ((c = *file->bptr++ & 0xFF) == EOS) { 804cdf0e10cSrcweir /* 805cdf0e10cSrcweir * Nothing in current line or macro. Get next line (if 806cdf0e10cSrcweir * input from a file), or do end of file/macro processing. 807cdf0e10cSrcweir * In the latter case, jump back to restart from the top. 808cdf0e10cSrcweir */ 809cdf0e10cSrcweir if (file->fp == NULL) { /* NULL if macro */ 810cdf0e10cSrcweir popped++; 811cdf0e10cSrcweir recursion -= file->unrecur; 812cdf0e10cSrcweir if (recursion < 0) 813cdf0e10cSrcweir recursion = 0; 814cdf0e10cSrcweir infile = file->parent; /* Unwind file chain */ 815cdf0e10cSrcweir } 816cdf0e10cSrcweir else { /* Else get from a file */ 817cdf0e10cSrcweir if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) 818cdf0e10cSrcweir != NULL) { 819cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 820cdf0e10cSrcweir if (debug > 1) { /* Dump it to stdout */ 821cdf0e10cSrcweir fprintf( pCppOut, "\n#line %d (%s), %s", 822cdf0e10cSrcweir line, file->filename, file->buffer); 823cdf0e10cSrcweir } 824cdf0e10cSrcweir #endif 825cdf0e10cSrcweir goto newline; /* process the line */ 826cdf0e10cSrcweir } 827cdf0e10cSrcweir else { 828cdf0e10cSrcweir if( file->fp != stdin ) 829cdf0e10cSrcweir fclose(file->fp); /* Close finished file */ 830cdf0e10cSrcweir if ((infile = file->parent) != NULL) { 831cdf0e10cSrcweir /* 832cdf0e10cSrcweir * There is an "ungotten" newline in the current 833cdf0e10cSrcweir * infile buffer (set there by doinclude() in 834cdf0e10cSrcweir * cpp1.c). Thus, we know that the mainline code 835cdf0e10cSrcweir * is skipping over blank lines and will do a 836cdf0e10cSrcweir * #line at its convenience. 837cdf0e10cSrcweir */ 838cdf0e10cSrcweir wrongline = TRUE; /* Need a #line now */ 839cdf0e10cSrcweir } 840cdf0e10cSrcweir } 841cdf0e10cSrcweir } 842cdf0e10cSrcweir /* 843cdf0e10cSrcweir * Free up space used by the (finished) file or macro and 844cdf0e10cSrcweir * restart input from the parent file/macro, if any. 845cdf0e10cSrcweir */ 846cdf0e10cSrcweir free(file->filename); /* Free name and */ 847cdf0e10cSrcweir if (file->progname != NULL) /* if a #line was seen, */ 848cdf0e10cSrcweir free(file->progname); /* free it, too. */ 849cdf0e10cSrcweir free((char *) file); /* Free file space */ 850cdf0e10cSrcweir if (infile == NULL) /* If at end of file */ 851cdf0e10cSrcweir return (EOF_CHAR); /* Return end of file */ 852cdf0e10cSrcweir line = infile->line; /* Reset line number */ 853cdf0e10cSrcweir goto get_from_file; /* Get from the top. */ 854cdf0e10cSrcweir } 855cdf0e10cSrcweir /* 856cdf0e10cSrcweir * Common processing for the new character. 857cdf0e10cSrcweir */ 858cdf0e10cSrcweir if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete */ 859cdf0e10cSrcweir goto newline; /* from a file */ 860cdf0e10cSrcweir if (file->parent != NULL) { /* Macro or #include */ 861cdf0e10cSrcweir if (popped != 0) 862cdf0e10cSrcweir file->parent->unrecur += popped; 863cdf0e10cSrcweir else { 864cdf0e10cSrcweir recursion -= file->parent->unrecur; 865cdf0e10cSrcweir if (recursion < 0) 866cdf0e10cSrcweir recursion = 0; 867cdf0e10cSrcweir file->parent->unrecur = 0; 868cdf0e10cSrcweir } 869cdf0e10cSrcweir } 870cdf0e10cSrcweir #if (HOST == SYS_UNIX) 871cdf0e10cSrcweir /*ER*/ if (c == '\r') 872cdf0e10cSrcweir /*ER*/ return get(); /* DOS fuck */ 873cdf0e10cSrcweir #endif 874cdf0e10cSrcweir if (c == '\n') /* Maintain current */ 875cdf0e10cSrcweir ++line; /* line counter */ 876cdf0e10cSrcweir if (instring) /* Strings just return */ 877cdf0e10cSrcweir return (c); /* the character. */ 878cdf0e10cSrcweir else if (c == '/') { /* Comment? */ 879cdf0e10cSrcweir instring = TRUE; /* So get() won't loop */ 880cdf0e10cSrcweir /*MM c++ comments */ 881cdf0e10cSrcweir /*MM*/ c = get(); 882cdf0e10cSrcweir /*MM*/ if ((c != '*') && (c != '/')) { /* Next byte '*'? */ 883cdf0e10cSrcweir instring = FALSE; /* Nope, no comment */ 884cdf0e10cSrcweir unget(); /* Push the char. back */ 885cdf0e10cSrcweir return ('/'); /* Return the slash */ 886cdf0e10cSrcweir } 887cdf0e10cSrcweir if (keepcomments) { /* If writing comments */ 888cdf0e10cSrcweir PUTCHAR('/'); /* Write out the */ 889cdf0e10cSrcweir /* initializer */ 890cdf0e10cSrcweir /*MM*/ if( '*' == c ) 891cdf0e10cSrcweir PUTCHAR('*'); 892cdf0e10cSrcweir /*MM*/ else 893cdf0e10cSrcweir /*MM*/ PUTCHAR('/'); 894cdf0e10cSrcweir 895cdf0e10cSrcweir } 896cdf0e10cSrcweir /*MM*/ if( '*' == c ){ 897cdf0e10cSrcweir for (;;) { /* Eat a comment */ 898cdf0e10cSrcweir c = get(); 899cdf0e10cSrcweir test: if (keepcomments && c != EOF_CHAR) 900cdf0e10cSrcweir cput(c); 901cdf0e10cSrcweir switch (c) { 902cdf0e10cSrcweir case EOF_CHAR: 903cdf0e10cSrcweir cerror("EOF in comment", NULLST); 904cdf0e10cSrcweir return (EOF_CHAR); 905cdf0e10cSrcweir 906cdf0e10cSrcweir case '/': 907cdf0e10cSrcweir if ((c = get()) != '*') /* Don't let comments */ 908cdf0e10cSrcweir goto test; /* Nest. */ 909cdf0e10cSrcweir #ifdef STRICT_COMMENTS 910cdf0e10cSrcweir cwarn("Nested comments", NULLST); 911cdf0e10cSrcweir #endif 912cdf0e10cSrcweir /* Fall into * stuff */ 913cdf0e10cSrcweir case '*': 914cdf0e10cSrcweir if ((c = get()) != '/') /* If comment doesn't */ 915cdf0e10cSrcweir goto test; /* end, look at next */ 916cdf0e10cSrcweir instring = FALSE; /* End of comment, */ 917cdf0e10cSrcweir if (keepcomments) { /* Put out the comment */ 918cdf0e10cSrcweir cput(c); /* terminator, too */ 919cdf0e10cSrcweir } 920cdf0e10cSrcweir /* 921cdf0e10cSrcweir * A comment is syntactically "whitespace" -- 922cdf0e10cSrcweir * however, there are certain strange sequences 923cdf0e10cSrcweir * such as 924cdf0e10cSrcweir * #define foo(x) (something) 925cdf0e10cSrcweir * foo|* comment *|(123) 926cdf0e10cSrcweir * these are '/' ^ ^ 927cdf0e10cSrcweir * where just returning space (or COM_SEP) will cause 928cdf0e10cSrcweir * problems. This can be "fixed" by overwriting the 929cdf0e10cSrcweir * '/' in the input line buffer with ' ' (or COM_SEP) 930cdf0e10cSrcweir * but that may mess up an error message. 931cdf0e10cSrcweir * So, we peek ahead -- if the next character is 932cdf0e10cSrcweir * "whitespace" we just get another character, if not, 933cdf0e10cSrcweir * we modify the buffer. All in the name of purity. 934cdf0e10cSrcweir */ 935cdf0e10cSrcweir if (*file->bptr == '\n' 936cdf0e10cSrcweir || type[*file->bptr & 0xFF] == SPA) 937cdf0e10cSrcweir goto newline; 938cdf0e10cSrcweir #if COMMENT_INVISIBLE 939cdf0e10cSrcweir /* 940cdf0e10cSrcweir * Return magic (old-fashioned) syntactic space. 941cdf0e10cSrcweir */ 942cdf0e10cSrcweir return ((file->bptr[-1] = COM_SEP)); 943cdf0e10cSrcweir #else 944cdf0e10cSrcweir return ((file->bptr[-1] = ' ')); 945cdf0e10cSrcweir #endif 946cdf0e10cSrcweir 947cdf0e10cSrcweir case '\n': /* we'll need a #line */ 948cdf0e10cSrcweir if (!keepcomments) 949cdf0e10cSrcweir wrongline = TRUE; /* later... */ 950cdf0e10cSrcweir default: /* Anything else is */ 951cdf0e10cSrcweir break; /* Just a character */ 952cdf0e10cSrcweir } /* End switch */ 953cdf0e10cSrcweir } /* End comment loop */ 954cdf0e10cSrcweir } 955cdf0e10cSrcweir else{ /* c++ comment */ 956cdf0e10cSrcweir /*MM c++ comment*/ 957cdf0e10cSrcweir for (;;) { /* Eat a comment */ 958cdf0e10cSrcweir c = get(); 959cdf0e10cSrcweir if (keepcomments && c != EOF_CHAR) 960cdf0e10cSrcweir cput(c); 961cdf0e10cSrcweir if( EOF_CHAR == c ) 962cdf0e10cSrcweir return (EOF_CHAR); 963cdf0e10cSrcweir else if( '\n' == c ){ 964cdf0e10cSrcweir instring = FALSE; /* End of comment, */ 965cdf0e10cSrcweir return( c ); 966cdf0e10cSrcweir } 967cdf0e10cSrcweir } 968cdf0e10cSrcweir } 969cdf0e10cSrcweir } /* End if in comment */ 970cdf0e10cSrcweir else if (!inmacro && c == '\\') { /* If backslash, peek */ 971cdf0e10cSrcweir if ((c = get()) == '\n') { /* for a <nl>. If so, */ 972cdf0e10cSrcweir wrongline = TRUE; 973cdf0e10cSrcweir goto newline; 974cdf0e10cSrcweir } 975cdf0e10cSrcweir else { /* Backslash anything */ 976cdf0e10cSrcweir unget(); /* Get it later */ 977cdf0e10cSrcweir return ('\\'); /* Return the backslash */ 978cdf0e10cSrcweir } 979cdf0e10cSrcweir } 980cdf0e10cSrcweir else if (c == '\f' || c == VT) /* Form Feed, Vertical */ 981cdf0e10cSrcweir c = ' '; /* Tab are whitespace */ 982cdf0e10cSrcweir else if (c == 0xef) /* eat up UTF-8 BOM */ 983cdf0e10cSrcweir { 984cdf0e10cSrcweir if((c = get()) == 0xbb) 985cdf0e10cSrcweir { 986cdf0e10cSrcweir if((c = get()) == 0xbf) 987cdf0e10cSrcweir { 988cdf0e10cSrcweir c = get(); 989cdf0e10cSrcweir return c; 990cdf0e10cSrcweir } 991cdf0e10cSrcweir else 992cdf0e10cSrcweir { 993cdf0e10cSrcweir unget(); 994cdf0e10cSrcweir unget(); 995cdf0e10cSrcweir return 0xef; 996cdf0e10cSrcweir } 997cdf0e10cSrcweir } 998cdf0e10cSrcweir else 999cdf0e10cSrcweir { 1000cdf0e10cSrcweir unget(); 1001cdf0e10cSrcweir return 0xef; 1002cdf0e10cSrcweir } 1003cdf0e10cSrcweir } 1004cdf0e10cSrcweir return (c); /* Just return the char */ 1005cdf0e10cSrcweir } 1006*1dda6fa0Smseidel 1007cdf0e10cSrcweir void unget() 1008cdf0e10cSrcweir /* 1009cdf0e10cSrcweir * Backup the pointer to reread the last character. Fatal error 1010cdf0e10cSrcweir * (code bug) if we backup too far. unget() may be called, 1011cdf0e10cSrcweir * without problems, at end of file. Only one character may 1012cdf0e10cSrcweir * be ungotten. If you need to unget more, call ungetstring(). 1013cdf0e10cSrcweir */ 1014cdf0e10cSrcweir { 1015cdf0e10cSrcweir register FILEINFO *file; 1016cdf0e10cSrcweir 1017cdf0e10cSrcweir if ((file = infile) == NULL) 1018cdf0e10cSrcweir return; /* Unget after EOF */ 1019cdf0e10cSrcweir if (--file->bptr < file->buffer) 1020cdf0e10cSrcweir cfatal("Too much pushback", NULLST); 1021cdf0e10cSrcweir if (*file->bptr == '\n') /* Ungetting a newline? */ 1022cdf0e10cSrcweir --line; /* Unget the line number, too */ 1023cdf0e10cSrcweir } 1024cdf0e10cSrcweir 1025cdf0e10cSrcweir void ungetstring(char* text) 1026cdf0e10cSrcweir /* 1027cdf0e10cSrcweir * Push a string back on the input stream. This is done by treating 1028cdf0e10cSrcweir * the text as if it were a macro. 1029cdf0e10cSrcweir */ 1030cdf0e10cSrcweir { 1031cdf0e10cSrcweir register FILEINFO *file; 1032cdf0e10cSrcweir #ifndef ZTC /* BP */ 1033cdf0e10cSrcweir extern FILEINFO *getfile(); 1034cdf0e10cSrcweir #endif 1035cdf0e10cSrcweir file = getfile(strlen(text) + 1, ""); 1036cdf0e10cSrcweir strcpy(file->buffer, text); 1037cdf0e10cSrcweir } 1038cdf0e10cSrcweir 1039cdf0e10cSrcweir int 1040cdf0e10cSrcweir cget() 1041cdf0e10cSrcweir /* 1042cdf0e10cSrcweir * Get one character, absorb "funny space" after comments or 1043cdf0e10cSrcweir * token concatenation 1044cdf0e10cSrcweir */ 1045cdf0e10cSrcweir { 1046cdf0e10cSrcweir register int c; 1047cdf0e10cSrcweir 1048cdf0e10cSrcweir do { 1049cdf0e10cSrcweir c = get(); 1050cdf0e10cSrcweir #if COMMENT_INVISIBLE 1051cdf0e10cSrcweir } while (c == TOK_SEP || c == COM_SEP); 1052cdf0e10cSrcweir #else 1053cdf0e10cSrcweir } while (c == TOK_SEP); 1054cdf0e10cSrcweir #endif 1055cdf0e10cSrcweir return (c); 1056cdf0e10cSrcweir } 1057*1dda6fa0Smseidel 1058cdf0e10cSrcweir /* 1059cdf0e10cSrcweir * Error messages and other hacks. The first byte of severity 1060cdf0e10cSrcweir * is 'S' for string arguments and 'I' for int arguments. This 1061cdf0e10cSrcweir * is needed for portability with machines that have int's that 1062cdf0e10cSrcweir * are shorter than char *'s. 1063cdf0e10cSrcweir */ 1064cdf0e10cSrcweir 1065cdf0e10cSrcweir static void domsg(char* severity, char* format, void* arg) 1066cdf0e10cSrcweir /* 1067cdf0e10cSrcweir * Print filenames, macro names, and line numbers for error messages. 1068cdf0e10cSrcweir */ 1069cdf0e10cSrcweir { 1070cdf0e10cSrcweir register char *tp; 1071cdf0e10cSrcweir register FILEINFO *file; 1072cdf0e10cSrcweir 1073cdf0e10cSrcweir fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]); 1074cdf0e10cSrcweir if (*severity == 'S') 1075cdf0e10cSrcweir fprintf(stderr, format, (char *)arg); 1076cdf0e10cSrcweir else 1077cdf0e10cSrcweir fprintf(stderr, format, *((int *)arg) ); 1078cdf0e10cSrcweir putc('\n', stderr); 1079cdf0e10cSrcweir if ((file = infile) == NULL) 1080cdf0e10cSrcweir return; /* At end of file */ 1081cdf0e10cSrcweir if (file->fp != NULL) { 1082cdf0e10cSrcweir tp = file->buffer; /* Print current file */ 1083cdf0e10cSrcweir fprintf(stderr, "%s", tp); /* name, making sure */ 1084cdf0e10cSrcweir if (tp[strlen(tp) - 1] != '\n') /* there's a newline */ 1085cdf0e10cSrcweir putc('\n', stderr); 1086cdf0e10cSrcweir } 1087cdf0e10cSrcweir while ((file = file->parent) != NULL) { /* Print #includes, too */ 1088cdf0e10cSrcweir if (file->fp == NULL) 1089cdf0e10cSrcweir fprintf(stderr, "from macro %s\n", file->filename); 1090cdf0e10cSrcweir else { 1091cdf0e10cSrcweir tp = file->buffer; 1092cdf0e10cSrcweir fprintf(stderr, "from file %s, line %d:\n%s", 1093cdf0e10cSrcweir (file->progname != NULL) 1094cdf0e10cSrcweir ? file->progname : file->filename, 1095cdf0e10cSrcweir file->line, tp); 1096cdf0e10cSrcweir if (tp[strlen(tp) - 1] != '\n') 1097cdf0e10cSrcweir putc('\n', stderr); 1098cdf0e10cSrcweir } 1099cdf0e10cSrcweir } 1100cdf0e10cSrcweir } 1101cdf0e10cSrcweir 1102cdf0e10cSrcweir void cerror(char* format, char* sarg) 1103cdf0e10cSrcweir /* 1104cdf0e10cSrcweir * Print a normal error message, string argument. 1105cdf0e10cSrcweir */ 1106cdf0e10cSrcweir { 1107cdf0e10cSrcweir domsg("SError", format, sarg); 1108cdf0e10cSrcweir errors++; 1109cdf0e10cSrcweir } 1110cdf0e10cSrcweir 1111cdf0e10cSrcweir void cierror(char* format, int narg) 1112cdf0e10cSrcweir /* 1113cdf0e10cSrcweir * Print a normal error message, numeric argument. 1114cdf0e10cSrcweir */ 1115cdf0e10cSrcweir { 1116cdf0e10cSrcweir domsg("IError", format, &narg); 1117cdf0e10cSrcweir errors++; 1118cdf0e10cSrcweir } 1119cdf0e10cSrcweir 1120cdf0e10cSrcweir void cfatal(char* format, char* sarg) 1121cdf0e10cSrcweir /* 1122cdf0e10cSrcweir * A real disaster 1123cdf0e10cSrcweir */ 1124cdf0e10cSrcweir { 1125cdf0e10cSrcweir domsg("SFatal error", format, sarg); 1126cdf0e10cSrcweir exit(IO_ERROR); 1127cdf0e10cSrcweir } 1128cdf0e10cSrcweir 1129cdf0e10cSrcweir void cwarn(char* format, char* sarg) 1130cdf0e10cSrcweir /* 1131cdf0e10cSrcweir * A non-fatal error, string argument. 1132cdf0e10cSrcweir */ 1133cdf0e10cSrcweir { 1134cdf0e10cSrcweir domsg("SWarning", format, sarg); 1135cdf0e10cSrcweir } 1136cdf0e10cSrcweir 1137cdf0e10cSrcweir void ciwarn(char* format, int narg) 1138cdf0e10cSrcweir /* 1139cdf0e10cSrcweir * A non-fatal error, numeric argument. 1140cdf0e10cSrcweir */ 1141cdf0e10cSrcweir { 1142cdf0e10cSrcweir domsg("IWarning", format, &narg); 1143cdf0e10cSrcweir } 1144