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