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