home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 243_01 / cpp6.c < prev    next >
C/C++ Source or Header  |  1990-05-14  |  43KB  |  1,206 lines

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