home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / TOP / USR / SRC / cpp.decus.t.Z / cpp.decus.t / cpp6.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-23  |  27.0 KB  |  970 lines

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