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