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