home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / cool.lha / ice / pisces / cpp / cpp6.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-04  |  30.8 KB  |  1,050 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.  * 21-Oct-85 RMS    Rename `token' to `tokenbuf'.
  19.  *            Dynamically allocate it, and make it as big as needed.
  20.  * 23-Oct-85 RMS    Fix bugs storing into tokenbuf as it gets bigger.
  21.  *             Change error msg to  cpp: "FILE", line LINE: MSG
  22.  * 24-Oct-85 RMS    Turn off warnings about / * inside a comment.
  23.  * 05-May-89 LGO    When in a macro, change \newline to just newline
  24.  * 19-Jan-90 DKM        Support for MVS and EBCDIC character set
  25.  */
  26.  
  27. #include    <stdio.h>
  28. #include    <ctype.h>
  29. #include    "cppdef.h"
  30. #include    "cpp.h"
  31.  
  32. /*
  33.  * skipnl()    skips over input text to the end of the line.
  34.  * skipws()    skips over "whitespace" (spaces or tabs), but
  35.  *        not skip over the end of the line.  It skips over
  36.  *        TOK_SEP, however (though that shouldn't happen).
  37.  * scanid()    reads the next token (C identifier) into tokenbuf.
  38.  *        The caller has already read the first character of
  39.  *        the identifier.  Unlike macroid(), the token is
  40.  *        never expanded.
  41.  * macroid()    reads the next token (C identifier) into tokenbuf.
  42.  *        If it is a #defined macro, it is expanded, and
  43.  *        macroid() returns TRUE, otherwise, FALSE.
  44.  * scanstring()    Reads a string from the input stream, calling
  45.  *        a user-supplied function for each character.
  46.  *        This function may be output() to write the
  47.  *        string to the output file, or save() to save
  48.  *        the string in the work buffer.
  49.  * scannumber()    Reads a C numeric constant from the input stream,
  50.  *        calling the user-supplied function for each
  51.  *        character.  (output() or save() as noted above.)
  52.  * save()    Save one character in the work[] buffer.
  53.  * savestring()    Saves a string in malloc() memory.
  54.  * getfile()    Initialize a new FILEINFO structure, called when
  55.  *        #include opens a new file, or a macro is to be
  56.  *        expanded.
  57.  * getmem()    Get a specified number of bytes from malloc memory.
  58.  * output()    Write one character to stdout (calling putchar) --
  59.  *        implemented as a function so its address may be
  60.  *        passed to scanstring() and scannumber().
  61.  * lookid()    Scans the next token (identifier) from the input
  62.  *        stream.  Looks for it in the #defined symbol table.
  63.  *        Returns a pointer to the definition, if found, or NULL
  64.  *        if not present.  The identifier is stored in tokenbuf.
  65.  * defnedel()    Define enter/delete subroutine.  Updates the
  66.  *        symbol table.
  67.  * get()    Read the next byte from the current input stream,
  68.  *        handling end of (macro/file) input and embedded
  69.  *        comments appropriately.  Note that the global
  70.  *        instring is -- essentially -- a parameter to get().
  71.  * cget()    Like get(), but skip over TOK_SEP.
  72.  * unget()    Push last gotten character back on the input stream.
  73.  * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
  74.  *        These routines format an print messages to the user.
  75.  *        cerror & cwarn take a format and a single string argument.
  76.  *        cierror & ciwarn take a format and a single int (char) argument.
  77.  *        cfatal takes a format and a single string argument.
  78.  */
  79.  
  80. /*
  81.  
  82.  *
  83.  * Note that several "non-visible" characters have special meaning
  84.  * and are defined in cpp.h.  
  85.  * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
  86.  * Hex 1E TOK_SEP   -- a delimiter for token concatenation
  87.  * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
  88.  */
  89. #if CHARSET == EBCDIC
  90. #if DEF_MAGIC != 0x19 || TOK_SEP != 0x1A || COM_SEP != 0x1B
  91.     << error type table isn't correct >>
  92. #endif
  93. #else
  94. #if DEF_MAGIC != 0x1D || TOK_SEP != 0x1E || COM_SEP != 0x1F
  95.     << error type table isn't correct >>
  96. #endif
  97. #endif
  98.  
  99. #if OK_DOLLAR
  100. #define    DOL    LET
  101. #else
  102. #define    DOL    000
  103. #endif
  104.  
  105. #if CHARSET == EBCDIC
  106.  
  107. char type[256] = {    /* Character type codes EBCDIC     Hex          */
  108.    END,   000,   000,   000,   000,   000,   000,   000, /* 00        */
  109.    000,   000,   000,   000,   000,   000,   000,   000, /* 08        */
  110.    000,   000,   000,   000,   000,   000,   000,   000, /* 10        */
  111.    000,   LET,   000,   SPA,   000,   000,   000,   000, /* 18       XXXX    */
  112.    000,   000,   000,   000,   000,   000,   000,   000, /* 20(reserved)*/
  113.    000,   000,   000,   000,   000,   000,   000,   000, /* 28(  for   )*/
  114.    000,   000,   000,   000,   000,   000,   000,   000, /* 30(MAC_PARM)*/
  115.    000,   000,   000,   000,   000,   000,   000,   000, /* 38( table  )*/
  116.    SPA,   000,   000,   000,   000,   000,   000,   000, /* 40             */
  117.    000,   000,   000,   DOT, OP_LT,OP_LPA,OP_ADD, OP_OR, /* 48    .<(+     */
  118. OP_AND,   000,   000,   000,   000,   000,   000,   000, /* 50 &           */
  119.    000,   000,OP_NOT,   DOL,OP_MUL,OP_RPA,   000,OP_XOR, /* 58   !$*);^    */
  120. OP_SUB,OP_DIV,   000,   000,   000,   000,   000,   000, /* 60 -/          */
  121.    000,   000, OP_OR,   000,OP_MOD,   LET, OP_GT,OP_QUE, /* 68   |,%_>?    */
  122.    000,   000,   000,   000,   000,   000,   000,   000, /* 70             */
  123.    000,   000,OP_COL,   000,   000,   QUO, OP_EQ,   QUO, /* 78   :#@'="    */
  124.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 80  abcdefg    */
  125.    LET,   LET,   000,   000,   000,   000,   000,   000, /* 88 hi          */
  126.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 90  jklmnop    */
  127.    LET,   LET,   000,   000,   000,   000,   000,   000, /* 98 qr         */
  128.    000,OP_NOT,   LET,   LET,   LET,   LET,   LET,   LET, /* A0  ~stuvwx */
  129.    LET,   LET,   000,   000,   000,   000,   000,   000, /* A8 yz   [     */
  130.    000,   000,   000,   000,   000,   000,   000,   000, /* B0            */
  131.    000,   000,   000,   000,   000,   000,   000,   000, /* B8      ]     */
  132.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* C0 {ABCDEFG    */
  133.    LET,   LET,   000,   000,   000,   000,   000,   000, /* C8 HI         */
  134.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* D0 }JKLMNOP    */
  135.    LET,   LET,   000,   000,   000,   000,   000,   000, /* D8 QR         */
  136.    BSH,   SPA,   LET,   LET,   LET,   LET,   LET,   LET, /* E0 \ STUVWX    */
  137.    LET,   LET,   000,   000,   000,   000,   000,   000, /* E8 YZ         */
  138.    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* F0 01234567    */
  139.    DIG,   DIG,   000,   000,   000,   000,   000,   000, /* F8 89         */
  140. };
  141.  
  142. #else   
  143.  
  144. char type[256] = {    /* Character type codes ASCII      Hex          */ 
  145.    END,   000,   000,   000,   000,   000,   000,   000, /* 00        */
  146.    000,   SPA,   000,   000,   000,   000,   000,   000, /* 08        */
  147.    000,   000,   000,   000,   000,   000,   000,   000, /* 10        */
  148.    000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18        */
  149.    SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&'    */
  150. OP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./    */
  151.    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567    */
  152.    DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>?    */
  153.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG    */
  154.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO    */
  155.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW    */
  156.    LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_    */
  157.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg    */
  158.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno    */
  159.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw    */
  160.    LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~    */
  161.    000,   000,   000,   000,   000,   000,   000,   000, /* 80(reserved)*/
  162.    000,   000,   000,   000,   000,   000,   000,   000, /* 88(   for  )*/
  163.    000,   000,   000,   000,   000,   000,   000,   000, /* 90(MAC_PARM)*/
  164.    000,   000,   000,   000,   000,   000,   000,   000, /* 98(  table )*/
  165.    000,   000,   000,   000,   000,   000,   000,   000, /* A0            */
  166.    000,   000,   000,   000,   000,   000,   000,   000, /* A8            */
  167.    000,   000,   000,   000,   000,   000,   000,   000, /* B0            */
  168.    000,   000,   000,   000,   000,   000,   000,   000, /* B8            */
  169.    000,   000,   000,   000,   000,   000,   000,   000, /* C0   not      */
  170.    000,   000,   000,   000,   000,   000,   000,   000, /* C8   used     */
  171.    000,   000,   000,   000,   000,   000,   000,   000, /* D0            */
  172.    000,   000,   000,   000,   000,   000,   000,   000, /* D8            */
  173.    000,   000,   000,   000,   000,   000,   000,   000, /* E0            */
  174.    000,   000,   000,   000,   000,   000,   000,   000, /* E8            */
  175.    000,   000,   000,   000,   000,   000,   000,   000, /* F0            */
  176.    000,   000,   000,   000,   000,   000,   000,   000, /* F8            */
  177. };
  178. #endif
  179.  
  180. skipnl()
  181. /*
  182.  * Skip to the end of the current input line.
  183.  */
  184. {
  185.     register int        c;
  186.  
  187.     do {                /* Skip to newline    */
  188.         c = get();
  189.     } while (c != '\n' && c != EOF_CHAR);
  190. }
  191.  
  192. int
  193. skipws()
  194. /*
  195.  * Skip over whitespace
  196.  */
  197. {
  198.     register int        c;
  199.  
  200.     do {                /* Skip whitespace    */
  201.         c = get();
  202. #if COMMENT_INVISIBLE
  203.     } while (type[c] == SPA || c == COM_SEP);
  204. #else
  205.     } while (type[c] == SPA);
  206. #endif
  207.     return (c);
  208. }
  209.  
  210. scanid(c)
  211. register int    c;                /* First char of id    */
  212. /*
  213.  * Get the next token (an id) into the token buffer.
  214.  * Note: this code is duplicated in lookid().
  215.  * Change one, change both.
  216.  */
  217. {
  218.     register int ct;
  219.  
  220.     if (c == DEF_MAGIC)            /* Eat the magic token    */
  221.         c = get();                /* undefiner.        */
  222.     ct = 0;
  223.     do
  224.       {
  225.         if (ct == tokenbsize)
  226.           tokenbuf = incmem (tokenbuf, 1 + (tokenbsize *= 2));
  227.         tokenbuf[ct++] = c;
  228.         c = get();
  229.       }
  230.     while (type[c] == LET || type[c] == DIG);
  231.     unget();
  232.     tokenbuf[ct] = EOS;
  233. }
  234.  
  235. int
  236. macroid(c)
  237. register int        c;
  238. /*
  239.  * If c is a letter, scan the id.  if it's #defined, expand it and scan
  240.  * the next character and try again.
  241.  *
  242.  * Else, return the character.  If type[c] is a LET, the token is in tokenbuf.
  243.  */
  244. {
  245.     register DEFBUF    *dp;
  246.  
  247.     if (infile != NULL && infile->fp != NULL)
  248.         recursion = 0;
  249.     while (type[c] == LET && (dp = lookid(c)) != NULL) {
  250.         expand(dp);
  251.         c = get();
  252.     }
  253.     return (c);
  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.       work[NWORK-1] = EOS;
  420.       cfatal("Work buffer overflow", NULLST);
  421.     }
  422.     else *workp++ = (char) 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.  
  449.     file = (FILEINFO *) getmem(sizeof (FILEINFO));
  450.     file->buffer = getmem(bufsize + 1);
  451.     file->bptr = file->buffer;        /* Initialize line ptr    */
  452.     file->buffer[0] = EOS;            /* Force first read    */
  453.     file->parent = infile;            /* Chain files together    */
  454.     file->fp = NULL;            /* No file yet        */
  455.     file->filename = savestring(name);    /* Save file/macro name    */
  456.     file->progname = NULL;            /* No #line seen yet    */
  457.     file->unrecur = 0;            /* No macro fixup    */
  458.     file->line = 0;                /* (Not used just yet)    */
  459.     if (infile != NULL)            /* If #include file    */
  460.         infile->line = line;        /* Save current line    */
  461.     infile = file;                /* New current file    */
  462.     line = 1;                /* Note first line    */
  463.     return (file);                /* All done.        */
  464. }
  465.  
  466. char *
  467. getmem(size)
  468. int        size;
  469. /*
  470.  * Get a block of free memory.
  471.  */
  472. {
  473.     register char    *result;
  474.     extern char    *malloc();
  475.  
  476.     if ((result = malloc((unsigned) size)) == NULL)
  477.         cfatal("Out of memory", NULLST);
  478.     return (result);
  479. }
  480.  
  481. char *
  482. incmem(obj,size)
  483. char        *obj;
  484. int        size;
  485. /*
  486.  * Get a block of free memory.
  487.  */
  488. {
  489.     register char    *result;
  490.     extern char    *realloc();
  491.  
  492.     if ((result = realloc(obj, (unsigned) size)) == NULL)
  493.         cfatal("Out of memory", NULLST);
  494.     return (result);
  495. }
  496.  
  497. /*
  498.  *            C P P   S y m b o l   T a b l e s
  499.  */
  500.  
  501. /*
  502.  * SBSIZE defines the number of hash-table slots for the symbol table.
  503.  * It must be a power of 2.
  504.  */
  505. #ifndef    SBSIZE
  506. #define    SBSIZE    64
  507. #endif
  508. #define    SBMASK    (SBSIZE - 1)
  509. #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
  510.     << error, SBSIZE must be a power of 2 >>
  511. #endif
  512.  
  513. static DEFBUF    *symtab[SBSIZE];    /* Symbol table queue headers    */
  514.  
  515. DEFBUF *
  516. lookid(c)
  517. int    c;                /* First character of token    */
  518. /*
  519.  * Look for the next token in the symbol table.  Returns token in tokenbuf.
  520.  * If found, returns the table pointer;  Else returns NULL.
  521.  */
  522. {
  523.     register int        nhash;
  524.     register DEFBUF        *dp;
  525.     register int        ct;
  526.     int            temp = 0;
  527.     int            isrecurse;    /* For #define foo foo    */
  528.  
  529.     nhash = 0;
  530.     if ((isrecurse = (c == DEF_MAGIC)))    /* If recursive macro    */
  531.         c = get();                /* hack, skip DEF_MAGIC    */
  532.     ct = 0;
  533.     do
  534.       {
  535.         if (ct == tokenbsize)
  536.           tokenbuf = incmem(tokenbuf, 1 + (tokenbsize *= 2));
  537.         tokenbuf[ct++] = c;        /* Store token byte    */
  538.         nhash += c;            /* Update hash value    */
  539.         c = get();
  540.       }
  541.     while (type[c] == LET || type[c] == DIG);
  542.     unget();                /* Rescan terminator    */
  543.     tokenbuf[ct] = EOS;            /* Terminate token    */
  544.     if (isrecurse)                /* Recursive definition    */
  545.         return (NULL);            /* undefined just now    */
  546.     nhash += ct;                /* Fix hash value    */
  547.     dp = symtab[nhash & SBMASK];        /* Starting bucket    */
  548.     while (dp != (DEFBUF *) NULL) {        /* Search symbol table    */
  549.         if (dp->hash == nhash        /* Fast precheck    */
  550.          && (temp = strcmp(dp->name, tokenbuf)) >= 0)
  551.         break;
  552.         dp = dp->link;            /* Nope, try next one    */
  553.     }
  554.     return ((temp == 0) ? dp : NULL);
  555. }
  556.  
  557. DEFBUF *
  558. defendel(name, delete)
  559. char        *name;
  560. int        delete;            /* TRUE to delete a symbol    */
  561. /*
  562.  * Enter this name in the lookup table (delete = FALSE)
  563.  * or delete this name (delete = TRUE).
  564.  * Returns a pointer to the define block (delete = FALSE)
  565.  * Returns NULL if the symbol wasn't defined (delete = TRUE).
  566.  */
  567. {
  568.     register DEFBUF        *dp;
  569.     register DEFBUF        **prevp;
  570.     register char        *np;
  571.     int            nhash;
  572.     int            temp;
  573.     int            size;
  574.  
  575.     for (nhash = 0, np = name; *np != EOS;)
  576.         nhash += *np++;
  577.     size = (np - name);
  578.     nhash += size;
  579.     prevp = &symtab[nhash & SBMASK];
  580.     while ((dp = *prevp) != (DEFBUF *) NULL) {
  581.         if (dp->hash == nhash
  582.          && (temp = strcmp(dp->name, name)) >= 0) {
  583.         if (temp > 0)
  584.             dp = NULL;            /* Not found        */
  585.         else {
  586.             *prevp = dp->link;        /* Found, unlink and    */
  587.             if (dp->repl != NULL)    /* Free the replacement    */
  588.             free(dp->repl);        /* if any, and then    */
  589.             free((char *) dp);        /* Free the symbol    */
  590.             dp = NULL;                /* Zap pointer */
  591.         }
  592.         break;
  593.         }
  594.         prevp = &dp->link;
  595.     }
  596.     if (!delete) {
  597.         dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
  598.         dp->link = *prevp;
  599.         *prevp = dp;
  600.         dp->hash = nhash;
  601.         dp->repl = NULL;
  602.         dp->nargs = 0;
  603.         strcpy(dp->name, name);
  604.     }
  605.     return (dp);
  606. }
  607.  
  608. #if DEBUG
  609.  
  610. dumpdef(why)
  611. char        *why;
  612. {
  613.     register DEFBUF        *dp;
  614.     register DEFBUF        **syp;
  615.  
  616.     printf("CPP symbol table dump %s\n", why);
  617.     for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
  618.         if ((dp = *syp) != (DEFBUF *) NULL) {
  619.         printf("symtab[%d]\n", (syp - symtab));
  620.         do {
  621.             dumpadef((char *) NULL, dp);
  622.         } while ((dp = dp->link) != (DEFBUF *) NULL);
  623.         }
  624.     }
  625. }
  626.  
  627. dumpadef(why, dp)
  628. char        *why;            /* Notation            */
  629. register DEFBUF    *dp;
  630. {
  631.     register char        *cp;
  632.     register int        c;
  633.  
  634.     printf(" \"%s\" [%d]", dp->name, dp->nargs);
  635.     if (why != NULL)
  636.         printf(" (%s)", why);
  637.     if (dp->repl != NULL) {
  638.         printf(" => ");
  639.         for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) {
  640.         if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
  641.             printf("<%d>", c - MAC_PARM);
  642.         else if (isprint(c) || c == '\n' || c == '\t')
  643.             putchar(c);
  644.         else if (c < ' ')
  645.             printf("<^%c>", c + '@');
  646.         else
  647.             printf("<\\0%o>", c);
  648.         }
  649.     }
  650.     else {
  651.         printf(", no replacement.");
  652.     }
  653.     putchar('\n');
  654. }
  655. #endif
  656.  
  657. /*
  658.  * PEEK
  659.  *     Return the next chartacter to be returned from get,
  660.  *     but don't actually remove it from the input buffer.
  661.  *
  662.  * This is used while doing comment lookahead in get.
  663.  * Try to avoid doing get/unget, because it gives us trouble
  664.  * when at the end of a buffer (the caller of get sometimes needs
  665.  * to do an unget, and two ungets in a row is unreliable)
  666.  */
  667. int peek() {
  668.   register int        c;
  669.  
  670.   if (infile == NULL)
  671.     return (EOF_CHAR);
  672.   if ((c = *infile->bptr) == EOS) {
  673.     if (infile->fp == NULL)       /* NULL if macro    */
  674.       c = *(infile->parent->bptr);
  675.     else {
  676.       instring = TRUE;
  677.       c = get();
  678.       instring = FALSE;
  679.       unget();
  680.     }
  681.   }
  682.   return c;
  683. }
  684.     
  685. /*
  686.  *            G E T
  687.  */
  688.  
  689. int
  690. get()
  691. /*
  692.  * Return the next character from a macro or the current file.
  693.  * Handle end of file from #include files.
  694.  */
  695. {
  696.     register int        c;
  697.  
  698. get_from_file:
  699.     if (infile == NULL)
  700.         return (EOF_CHAR);
  701. newline:
  702. #if DEBUG
  703.     printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",
  704.         infile->filename, recursion, line,
  705.         infile->bptr - infile->buffer, infile->buffer);
  706. #endif
  707.     /*
  708.      * Read a character from the current input line or macro.
  709.      * At EOS, either finish the current macro (freeing temp.
  710.      * storage) or read another line from the current input file.
  711.      * At EOF, exit the current file (#include) or, at EOF from
  712.      * the cpp input file, return EOF_CHAR to finish processing.
  713.      */
  714.     switch (c = *infile->bptr++) {
  715.       case EOS: {
  716.         register FILEINFO    *file = infile;
  717.         /*
  718.          * Nothing in current line or macro.  Get next line (if
  719.          * input from a file), or do end of file/macro processing.
  720.          * In the latter case, jump back to restart from the top.
  721.          */
  722.         if (file->fp == NULL) {      /* NULL if macro    */
  723.           recursion--;
  724.           if (recursion < 0)
  725.         recursion = 0;
  726.           infile = file->parent;      /* Unwind file chain    */
  727.         }
  728.         else {              /* Else get from a file    */
  729.           if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
  730.           != NULL) {
  731. #if DEBUG
  732.         if (debug > 1) {      /* Dump it to stdout    */
  733.           printf("\n#line %d (%s), %s",
  734.              line, file->filename, file->buffer);
  735.         }
  736. #endif
  737.         goto newline;          /* process the line    */
  738.           }
  739.           else {
  740.         fclose(file->fp);      /* Close finished file    */
  741.         if ((infile = file->parent) != NULL) {
  742.           /*
  743.            * There is an "ungotten" newline in the current
  744.            * infile buffer (set there by doinclude() in
  745.            * cpp1.c).  Thus, we know that the mainline code
  746.            * is skipping over blank lines and will do a
  747.            * #line at its convenience.
  748.            */
  749.           wrongline = TRUE;      /* Need a #line now    */
  750.         }
  751.           }
  752.         }
  753.  
  754.         /*
  755.          * Free up space used by the (finished) file or macro and
  756.          * restart input from the parent file/macro, if any.
  757.          */
  758.         free(file->filename);      /* Free name and    */
  759.         if (file->progname != NULL)      /* if a #line was seen,    */
  760.           free(file->progname);      /* free it, too.    */
  761.         free(file->buffer);          /* Free buffer */
  762.         free((char *) file);      /* Free file space    */
  763.         if (infile == NULL)          /* If at end of file    */
  764.           return (EOF_CHAR);      /* Return end of file    */
  765.         line = infile->line;      /* Reset line number    */
  766.         goto get_from_file;          /* Get from the top.    */
  767.       }
  768.       /* break; // this statement never reached */
  769.  
  770.         /*
  771.          * Common processing for the new character.
  772.          */
  773.       case DEF_MAGIC:
  774.         if (infile->fp != NULL)      /* Don't allow delete    */
  775.         goto newline;          /* from a file    */
  776.         break;
  777.       case '\n':              /* Maintain current    */
  778.         ++line;              /* line counter    */
  779.         break;
  780.       case '/':              /* Comment?        */
  781.         if (instring) return (c);      /* Strings just return the char */
  782.         if ((c = peek()) != '*' &&      /* Next byte '*'?    */
  783.         c != '/') {          /* or '/'?            */
  784.           instring = FALSE;          /* Nope, no comment    */
  785.           return ('/');          /* Return the slash    */
  786.         }
  787.         instring = TRUE;          /* So get() won't loop*/
  788.         if((c = get()) == '/') {      /* C++ comment        */
  789.           if (keepcomments) {      /* If writing comments*/
  790.         putchar('/');          /* Write out the    */
  791.         putchar(c);          /*   initializer    */
  792.         while ((c = get()) != '\n' && c != EOF_CHAR)
  793.           putchar(c);
  794.           } else {              /* Eat a comment    */
  795.         while ((c = get()) != '\n' && c != EOF_CHAR);
  796.           }
  797.           instring = FALSE;          /* End of c++ comment    */
  798.           return(c);
  799.         } else {              /* Normal comment     */
  800.           if (keepcomments) {      /* If writing comments*/
  801.         putchar('/');          /* Write out the    */
  802.         putchar(c);          /*   initializer    */
  803.           }
  804.           for (;;) {          /* Eat a comment    */
  805.         c = get();
  806.           test:
  807.         if (c == EOF_CHAR) {
  808.           cerror("EOF in comment", NULLST);
  809.           return (EOF_CHAR);
  810.         }
  811.         if (keepcomments)
  812.           cput(c);
  813.         switch (c) {
  814. #ifdef NOTDEF
  815.         case '/':
  816.           if ((c = get()) != '*') /* Don't let comments    */
  817.             goto test;          /* Nest.        */
  818.           cwarn("Nested comments", NULLST);
  819. #endif                      /* NOTDEF */
  820.           /* Fall into * stuff    */
  821.         case '*':
  822.           if ((c = get()) != '/') /* If comment doesn't    */
  823.             goto test;          /* end, look at next    */
  824.           instring = FALSE;      /* End of comment,    */
  825.           if (keepcomments) {      /* Put out the comment*/
  826.             cput(c);          /* terminator, too    */
  827.           }
  828.           /*
  829.            * A comment is syntactically "whitespace" --
  830.            * however, there are certain strange sequences
  831.            * such as
  832.            *        #define foo(x)    (something)
  833.            *            foo|* comment *|(123)
  834.            *       these are '/' ^           ^
  835.            * where just returning space (or COM_SEP) will cause
  836.            * problems.  This can be "fixed" by overwriting the
  837.            * '/' in the input line buffer with ' ' (or COM_SEP)
  838.            * but that may mess up an error message.
  839.            * So, we peek ahead -- if the next character is
  840.            * "whitespace" we just get another character, if not,
  841.            * we modify the buffer.  All in the name of purity.
  842.            */
  843.           if (*infile->bptr == '\n'
  844.               || type[*infile->bptr & 0xFF] == SPA)
  845.             goto newline;
  846. #if COMMENT_INVISIBLE
  847.           /*
  848.            * Return magic (old-fashioned) syntactic space.
  849.            */
  850.           return ((infile->bptr[-1] = COM_SEP));
  851. #else
  852.           return ((infile->bptr[-1] = ' '));
  853. #endif
  854.  
  855.         case '\n':            
  856.           if (!keepcomments)      /* we'll need a #line    */
  857.             wrongline = TRUE;      /* later...        */
  858.         default:          /* Anything else is    */
  859.           break;          /* Just a character    */
  860.         }              /* End switch        */
  861.           }                  /* End comment loop    */
  862.         }                  /* End if in comment    */
  863.         /* break; // this statement never reached */
  864.         case '\\':
  865.           if (instring) return (c);      /* Strings just return the char */
  866.           if (!inmacro) {          /* If backslash, peek     */
  867.         if ((c = get()) == '\n') { /* for a <nl>.  If so,    */
  868.           wrongline = TRUE;
  869. #ifdef readable_defines
  870.           if(infile->fp == NULL && /* If Expanding a macro,*/
  871.              keepcomments)      /* And human readable   */
  872.             return(c);          /* Convert \newline to just newline */
  873.           else
  874. #endif
  875.             goto newline;
  876.         }
  877.         else {              /* Backslash anything    */
  878.           unget();          /* Get it later        */
  879.           return ('\\');      /* Return the backslash    */
  880.         }
  881.           }
  882.           break;
  883.         case '\f':
  884.         case VT:              /* Form Feed, Vertical    */
  885.           if (instring) return (c);      /* Strings just return the char */
  886.           c = ' ';              /* Tab are whitespace    */
  887.           break;
  888.         }                  /* end switch */
  889.     return (c);             /* Just return the char    */
  890. }
  891.  
  892. unget()
  893. /*
  894.  * Backup the pointer to reread the last character.  Fatal error
  895.  * (code bug) if we backup too far.  unget() may be called,
  896.  * without problems, at end of file.  Only one character may
  897.  * be ungotten.  If you need to unget more, call ungetstring().
  898.  */
  899. {
  900.     register FILEINFO    *file;
  901.  
  902.     if ((file = infile) == NULL)
  903.         return;            /* Unget after EOF        */
  904.     if (--file->bptr < file->buffer)
  905.         cfatal("Too much pushback", NULLST);
  906.     if (*file->bptr == '\n')    /* Ungetting a newline?        */
  907.         --line;            /* Unget the line number, too    */
  908. }
  909.  
  910. ungetstring(text)
  911. char        *text;
  912. /*
  913.  * Push a string back on the input stream.  This is done by treating
  914.  * the text as if it were a macro.
  915.  */
  916. {
  917.     register FILEINFO    *file;
  918.     extern FILEINFO        *getfile();
  919.  
  920.     file = getfile(strlen(text) + 1, "");
  921.     strcpy(file->buffer, text);
  922. }
  923.  
  924. int
  925. cget()
  926. /*
  927.  * Get one character, absorb "funny space" after comments or
  928.  * token concatenation
  929.  */
  930. {
  931.     register int    c;
  932.  
  933.     do {
  934.         c = get();
  935. #if COMMENT_INVISIBLE
  936.     } while (c == TOK_SEP || c == COM_SEP);
  937. #else
  938.     } while (c == TOK_SEP);
  939. #endif
  940.     return (c);
  941. }
  942.  
  943. /*
  944.  * Error messages and other hacks.  The first byte of severity
  945.  * is 'S' for string arguments and 'I' for int arguments.  This
  946.  * is needed for portability with machines that have int's that
  947.  * are shorter than  char *'s.
  948.  */
  949.  
  950. static
  951. domsg(severity, format, arg)
  952. char        *severity;        /* "Error", "Warning", "Fatal"    */
  953. char        *format;        /* Format for the error message    */
  954. char        *arg;            /* Something for the message    */
  955. /*
  956.  * Print filenames, macro names, and line numbers for error messages.
  957.  */
  958. {
  959.     register char        *tp;
  960.     register FILEINFO    *file;
  961.     int line_number = line;
  962.                       /* Skip macros, get real line# */
  963.     for (file = infile; file && !file->fp;) {
  964.       file = file->parent;
  965.       line_number = file->line + line - 1;
  966.     }
  967.     tp = file ? file->filename : 0;
  968.     fprintf (stderr, "%s\"%s\", line %d: %s: ",
  969.          MSG_PREFIX, tp, line_number, &severity[1]);
  970.     if (*severity == 'S')
  971.       fprintf(stderr, format, arg);
  972.     else
  973.       fprintf(stderr, format, (int) arg);
  974.     putc('\n', stderr);
  975.  
  976.     while (file && (file = file->parent) != NULL) {
  977.         /* Print #includes, too */
  978.         tp = file->parent ? "," : ".";
  979.         if (file->fp == NULL)
  980.         fprintf(stderr, " from macro %s%s\n", file->filename, tp);
  981.         else {
  982.         fprintf(stderr, " from file %s, line %d%s\n",
  983.             (file->progname != NULL)
  984.             ? file->progname : file->filename,
  985.             file->line, tp);
  986.         }
  987.     }
  988. }
  989.  
  990. cerror(format, sarg)
  991. char        *format;
  992. char        *sarg;        /* Single string argument        */
  993. /*
  994.  * Print a normal error message, string argument.
  995.  */
  996. {
  997.     domsg("SError", format, sarg);
  998.     errors++;
  999. }
  1000.  
  1001. cierror(format, narg)
  1002. char        *format;
  1003. int        narg;        /* Single numeric argument        */
  1004. /*
  1005.  * Print a normal error message, numeric argument.
  1006.  */
  1007. {
  1008.         long     chrptr;
  1009.  
  1010.         chrptr = (long) narg;
  1011.     domsg("IError", format, (char *) chrptr);
  1012.     errors++;
  1013. }
  1014.  
  1015. cfatal(format, sarg)
  1016. char        *format;
  1017. char        *sarg;            /* Single string argument    */
  1018. /*
  1019.  * A real disaster
  1020.  */
  1021. {
  1022.     domsg("SFatal error", format, sarg);
  1023.     exit(IO_ERROR);
  1024. }
  1025.  
  1026. cwarn(format, sarg)
  1027. char        *format;
  1028. char        *sarg;            /* Single string argument    */
  1029. /*
  1030.  * A non-fatal error, string argument.
  1031.  */
  1032. {
  1033.     domsg("SWarning", format, sarg);
  1034. }
  1035.  
  1036. ciwarn(format, narg)
  1037. char        *format;
  1038. int        narg;            /* Single numeric argument    */
  1039. /*
  1040.  * A non-fatal error, numeric argument.
  1041.  */
  1042. {
  1043.         long     chrptr;
  1044.  
  1045.         chrptr = (long) narg;
  1046.     domsg("IWarning", format, (char *) chrptr);
  1047. }
  1048.  
  1049.  
  1050.