home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d0xx / d028 / cpp.lha / Cpp / cpp4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-07-17  |  16.7 KB  |  611 lines

  1. /*
  2.  *                C P P 4 . C
  3.  *        M a c r o  D e f i n i t i o n s
  4.  *
  5.  * Edit History
  6.  * 31-Aug-84    MM    USENET net.sources release
  7.  * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  8.  *            so they work correctly with token concatenation.
  9.  *            Added string formal recognition.
  10.  * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  11.  *            don't print unnecessary error messages for
  12.  *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  13.  * 31-Oct-84    ado/MM    Added token concatenation
  14.  *  6-Nov-84    MM    Split off eval stuff
  15.  * 21-Oct-85    RMS    Rename `token' to `tokenbuf'.
  16.  *            In doundef, don't complain if arg already not defined.
  17.  * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  18.  *            Port to Commodore AMIGA.
  19.  */
  20.  
  21. #include    <stdio.h>
  22. #include    <ctype.h>
  23. #include    "cppdef.h"
  24. #include    "cpp.h"
  25. /*
  26.  * parm[], parmp, and parlist[] are used to store #define() argument
  27.  * lists.  nargs contains the actual number of parameters stored.
  28.  */
  29. static char    parm[NPARMWORK + 1];    /* define param work buffer     */
  30. static char    *parmp;            /* Free space in parm        */
  31. static char    *parlist[LASTPARM];    /* -> start of each parameter    */
  32. static int    nargs;            /* Parameters for this macro    */
  33.  
  34. dodefine()
  35. /*
  36.  * Called from control when a #define is scanned.  This module
  37.  * parses formal parameters and the replacement string.  When
  38.  * the formal parameter name is encountered in the replacement
  39.  * string, it is replaced by a character in the range 128 to
  40.  * 128+NPARAM (this allows up to 32 parameters within the
  41.  * Dec Multinational range).  If cpp is ported to an EBCDIC
  42.  * machine, you will have to make other arrangements.
  43.  *
  44.  * There is some special case code to distinguish
  45.  *    #define foo    bar
  46.  * from    #define foo()    bar
  47.  *
  48.  * Also, we make sure that
  49.  *    #define    foo    foo
  50.  * expands to "foo" but doesn't put cpp into an infinite loop.
  51.  *
  52.  * A warning message is printed if you redefine a symbol to a
  53.  * different text.  I.e,
  54.  *    #define    foo    123
  55.  *    #define foo    123
  56.  * is ok, but
  57.  *    #define foo    123
  58.  *    #define    foo    +123
  59.  * is not.
  60.  *
  61.  * The following subroutines are called from define():
  62.  * checkparm    called when a token is scanned.  It checks through the
  63.  *        array of formal parameters.  If a match is found, the
  64.  *        token is replaced by a control byte which will be used
  65.  *        to locate the parameter when the macro is expanded.
  66.  * textput    puts a string in the macro work area (parm[]), updating
  67.  *        parmp to point to the first free byte in parm[].
  68.  *        textput() tests for work buffer overflow.
  69.  * charput    puts a single character in the macro work area (parm[])
  70.  *        in a manner analogous to textput().
  71.  */
  72. {
  73.     register int        c;
  74.     register DEFBUF        *dp;        /* -> new definition    */
  75.     int            isredefine;    /* TRUE if redefined    */
  76.     char            *old;        /* Remember redefined    */
  77.     extern int        save();        /* Save char in work[]    */
  78.  
  79.     DBUG_ENTER ("dodefine");
  80.     if (type[(c = skipws())] != LET)
  81.         goto bad_define;
  82.     isredefine = FALSE;            /* Set if redefining    */
  83.     if ((dp = lookid(c)) == NULL)        /* If not known now    */
  84.         dp = defendel(tokenbuf, FALSE);    /* Save the name    */
  85.     else {                    /* It's known:        */
  86.         isredefine = TRUE;            /* Remember this fact    */
  87.         old = dp->repl;            /* Remember replacement    */
  88.         dp->repl = NULL;            /* No replacement now    */
  89.     }
  90.     parlist[0] = parmp = parm;        /* Setup parm buffer    */
  91.     if ((c = get()) == '(') {        /* With arguments?    */
  92.         nargs = 0;                /* Init formals counter    */
  93.         do {                /* Collect formal parms    */
  94.         if (nargs >= LASTPARM)
  95.             cfatal("Too many arguments for macro", NULLST);
  96.         else if ((c = skipws()) == ')')
  97.             break;            /* Got them all        */
  98.         else if (type[c] != LET)    /* Bad formal syntax    */
  99.             goto bad_define;
  100.         scanid(c);            /* Get the formal param    */
  101.         parlist[nargs++] = parmp;    /* Save its start    */
  102.         textput(tokenbuf);        /* Save text in parm[]    */
  103.         } while ((c = skipws()) == ',');    /* Get another argument    */
  104.         if (c != ')')            /* Must end at )    */
  105.         goto bad_define;
  106.         c = ' ';                /* Will skip to body    */
  107.     }
  108.     else {
  109.         /*
  110.          * DEF_NOARGS is needed to distinguish between
  111.          * "#define foo" and "#define foo()".
  112.          */
  113.         nargs = DEF_NOARGS;            /* No () parameters    */
  114.     }
  115.     if (type[c] == SPA)            /* At whitespace?    */
  116.         c = skipws();            /* Not any more.    */
  117.     workp = work;                /* Replacement put here    */
  118.     inmacro = TRUE;                /* Keep \<newline> now    */
  119.     while (c != EOF_CHAR && c != '\n') {    /* Compile macro body    */
  120. #if OK_CONCAT
  121.         if (c == '#') {            /* Token concatenation?    */
  122.         while (workp > work && type[workp[-1]] == SPA)
  123.             --workp;            /* Erase leading spaces    */
  124.         save(TOK_SEP);            /* Stuff a delimiter    */
  125.         c = skipws();            /* Eat whitespace    */
  126.         if (type[c] == LET)        /* Another token here?    */
  127.             ;                /* Stuff it normally    */
  128.         else if (type[c] == DIG) {    /* Digit string after?    */
  129.             while (type[c] == DIG) {    /* Stuff the digits    */
  130.             save(c);
  131.             c = get();
  132.             }
  133.             save(TOK_SEP);        /* Delimit 2nd token    */
  134.         }
  135.         else {
  136.             ciwarn("Strange character after # (%d.)", c);
  137.         }
  138.         continue;
  139.         }
  140. #endif
  141.         switch (type[c]) {
  142.         case LET:
  143.         checkparm(c, dp);        /* Might be a formal    */
  144.         break;
  145.  
  146.         case DIG:                /* Number in mac. body    */
  147.         case DOT:                /* Maybe a float number    */
  148.         scannumber(c, save);        /* Scan it off        */
  149.         break;
  150.  
  151.         case QUO:                /* String in mac. body    */
  152. #if STRING_FORMAL
  153.         stparmscan(c, dp);        /* Do string magic    */
  154. #else
  155.         stparmscan(c);
  156. #endif
  157.         break;
  158.  
  159.         case BSH:                /* Backslash        */
  160.         save('\\');
  161.         if ((c = get()) == '\n')
  162.             wrongline = TRUE;
  163.         save(c);
  164.         break;
  165.  
  166.         case SPA:                /* Absorb whitespace    */
  167.         /*
  168.          * Note: the "end of comment" marker is passed on
  169.          * to allow comments to separate tokens.
  170.          */
  171.         if (workp[-1] == ' ')        /* Absorb multiple    */
  172.             break;            /* spaces        */
  173.         else if (c == '\t')
  174.             c = ' ';            /* Normalize tabs    */
  175.         /* Fall through to store character            */
  176.         default:                /* Other character    */
  177.         save(c);
  178.         break;
  179.         }
  180.         c = get();
  181.     }
  182.     inmacro = FALSE;            /* Stop newline hack    */
  183.     unget();                /* For control check    */
  184.     if (workp > work && workp[-1] == ' ')    /* Drop trailing blank    */
  185.         workp--;
  186.     *workp = EOS;                /* Terminate work    */
  187.     dp->repl = savestring(work);        /* Save the string    */
  188.     dp->nargs = nargs;            /* Save arg count    */
  189. #if DEBUG
  190.     if (debug)
  191.         dumpadef("macro definition", dp);
  192. #endif
  193.     if (isredefine) {            /* Error if redefined    */
  194.         if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
  195.          || (old == NULL && dp->repl != NULL)
  196.          || (old != NULL && dp->repl == NULL)) {
  197.         cerror("Redefining defined variable \"%s\"", dp->name);
  198.         }
  199.         if (old != NULL)            /* We don't need the    */
  200.         free(old);            /* old definition now.    */
  201.     }     
  202.     DBUG_VOID_RETURN;
  203.  
  204. bad_define:
  205.     cerror("#define syntax error", NULLST);
  206.     inmacro = FALSE;            /* Stop <newline> hack    */
  207.     DBUG_VOID_RETURN;
  208. }
  209.  
  210. checkparm(c, dp)
  211. register int    c;
  212. DEFBUF        *dp;
  213. /*
  214.  * Replace this param if it's defined.  Note that the macro name is a
  215.  * possible replacement token.  We stuff DEF_MAGIC in front of the token
  216.  * which is treated as a LETTER by the token scanner and eaten by
  217.  * the output routine.  This prevents the macro expander from
  218.  * looping if someone writes "#define foo foo".
  219.  */
  220. {
  221.     register int        i;
  222.     register char        *cp;
  223.  
  224.     DBUG_ENTER ("checkparm");
  225.     scanid(c);                /* Get parm to tokenbuf */
  226.     for (i = 0; i < nargs; i++) {        /* For each argument    */
  227.         if (streq(parlist[i], tokenbuf)) {    /* If it's known    */
  228.         save(i + MAC_PARM);        /* Save a magic cookie    */
  229.         DBUG_VOID_RETURN;        /* And exit the search    */
  230.         }
  231.     }
  232.     if (streq(dp->name, tokenbuf))        /* Macro name in body?    */
  233.         save(DEF_MAGIC);            /* Save magic marker    */
  234.     for (cp = tokenbuf; *cp != EOS;)    /* And save        */
  235.         save(*cp++);            /* The token itself    */
  236.     DBUG_VOID_RETURN;
  237. }
  238.  
  239. #if STRING_FORMAL
  240. stparmscan(delim, dp)
  241. int        delim;
  242. register DEFBUF    *dp;
  243. /*
  244.  * Scan the string (starting with the given delimiter).
  245.  * The token is replaced if it is the only text in this string or
  246.  * character constant.  The algorithm follows checkparm() above.
  247.  * Note that scanstring() has approved of the string.
  248.  */
  249. {
  250.     register int        c;
  251.  
  252.     DBUG_ENTER ("stparmscan");
  253.     /*
  254.      * Warning -- this code hasn't been tested for a while.
  255.      * It exists only to preserve compatibility with earlier
  256.      * implementations of cpp.  It is not part of the Draft
  257.      * ANSI Standard C language.
  258.      */
  259.     save(delim);
  260.     instring = TRUE;
  261.     while ((c = get()) != delim
  262.          && c != '\n'
  263.          && c != EOF_CHAR) {
  264.         if (type[c] == LET)            /* Maybe formal parm    */
  265.         checkparm(c, dp);
  266.         else {
  267.         save(c);
  268.         if (c == '\\')
  269.             save(get());
  270.         }
  271.     }
  272.     instring = FALSE;
  273.     if (c != delim)
  274.         cerror("Unterminated string in macro body", NULLST);
  275.     save(c);
  276.     DBUG_VOID_RETURN;
  277. }
  278. #else
  279. stparmscan(delim)
  280. int        delim;
  281. /*
  282.  * Normal string parameter scan.
  283.  */
  284. {
  285.     register char        *wp;
  286.     register int        i;
  287.     extern int        save();
  288.  
  289.     DBUG_ENTER ("stparmscan");
  290.     wp = workp;            /* Here's where it starts    */
  291.     if (!scanstring(delim, save))
  292.         DBUG_VOID_RETURN;        /* Exit on scanstring error    */
  293.     workp[-1] = EOS;        /* Erase trailing quote        */
  294.     wp++;                /* -> first string content byte    */ 
  295.     for (i = 0; i < nargs; i++) {
  296.         if (streq(parlist[i], wp)) {
  297.         *wp++ = MAC_PARM + PAR_MAC;    /* Stuff a magic marker    */
  298.         *wp++ = (i + MAC_PARM);        /* Make a formal marker    */
  299.         *wp = wp[-3];            /* Add on closing quote    */
  300.         workp = wp + 1;            /* Reset string end    */
  301.         DBUG_VOID_RETURN;
  302.         }
  303.     }
  304.     workp[-1] = wp[-1];        /* Nope, reset end quote.    */
  305.     DBUG_VOID_RETURN;
  306. }
  307. #endif
  308.  
  309. doundef()
  310. /*
  311.  * Remove the symbol from the defined list.
  312.  * Called from the #control processor.
  313.  */
  314. {
  315.   register int c;
  316.  
  317.   DBUG_ENTER ("doundef");
  318.   if (type[(c = skipws())] != LET)
  319.     cerror("Illegal #undef argument", NULLST);
  320.   else
  321.     {
  322.       scanid(c);                /* Get name to tokenbuf */
  323.       (void) defendel(tokenbuf, TRUE);
  324.     }
  325.   DBUG_VOID_RETURN;
  326. }
  327.  
  328. textput(text)
  329. char        *text;
  330. /*
  331.  * Put the string in the parm[] buffer.
  332.  */
  333. {
  334.     register int    size;
  335.  
  336.     DBUG_ENTER ("textput");
  337.     size = strlen(text) + 1;
  338.     if ((parmp + size) >= &parm[NPARMWORK])
  339.         cfatal("Macro work area overflow", NULLST);
  340.     else {
  341.         strcpy(parmp, text);
  342.         parmp += size;
  343.     }
  344.     DBUG_VOID_RETURN;
  345. }
  346.  
  347. charput(c)
  348. register int    c;
  349. /*
  350.  * Put the byte in the parm[] buffer.
  351.  */
  352. {
  353.     if (parmp >= &parm[NPARMWORK])
  354.         cfatal("Macro work area overflow", NULLST);
  355.     else {
  356.         *parmp++ = c;
  357.     }
  358. }
  359.  
  360. /*
  361.  *        M a c r o   E x p a n s i o n
  362.  */
  363.  
  364. static DEFBUF    *macro;        /* Catches start of infinite macro    */
  365.  
  366. expand(tokenp)
  367. register DEFBUF    *tokenp;
  368. /*
  369.  * Expand a macro.  Called from the cpp mainline routine (via subroutine
  370.  * macroid()) when a token is found in the symbol table.  It calls
  371.  * expcollect() to parse actual parameters, checking for the correct number.
  372.  * It then creates a "file" containing a single line containing the
  373.  * macro with actual parameters inserted appropriately.  This is
  374.  * "pushed back" onto the input stream.  (When the get() routine runs
  375.  * off the end of the macro line, it will dismiss the macro itself.)
  376.  */
  377. {
  378.     register int        c;
  379.     register FILEINFO    *file;
  380.     extern FILEINFO        *getfile();
  381.  
  382.     DBUG_ENTER ("expand");
  383. #if DEBUG
  384.     if (debug)
  385.         dumpadef("expand entry", tokenp);
  386. #endif
  387.     /*
  388.      * If no macro is pending, save the name of this macro
  389.      * for an eventual error message.
  390.      */
  391.     if (recursion++ == 0)
  392.         macro = tokenp;
  393.     else if (recursion == RECURSION_LIMIT) {
  394.         cerror("Recursive macro definition of \"%s\"", tokenp->name);
  395.         fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
  396.         if (rec_recover) {
  397.         do {
  398.             c = get();
  399.         } while (infile != NULL && infile->fp == NULL);
  400.         unget();
  401.         recursion = 0;
  402.         DBUG_VOID_RETURN;
  403.         }
  404.     }
  405.     /*
  406.      * Here's a macro to expand.
  407.      */
  408.     nargs = 0;                /* Formals counter    */
  409.     parmp = parm;                /* Setup parm buffer    */
  410.     switch (tokenp->nargs) {
  411.     case (-2):                /* __LINE__        */
  412.         sprintf(work, "%d", line);
  413.         ungetstring(work);
  414.         break;
  415.  
  416.     case (-3):                /* __FILE__        */
  417.         for (file = infile; file != NULL; file = file->parent) {
  418.         if (file->fp != NULL) {
  419.             sprintf(work, "\"%s\"", (file->progname != NULL)
  420.             ? file->progname : file->filename);
  421.             ungetstring(work);
  422.             break;
  423.         }
  424.         }
  425.         break;
  426.  
  427.     default:
  428.         /*
  429.          * Nothing funny about this macro.
  430.          */
  431.         if (tokenp->nargs < 0)
  432.         cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
  433.         while ((c = skipws()) == '\n')    /* Look for (, skipping    */
  434.         wrongline = TRUE;        /* spaces and newlines    */
  435.         if (c != '(') {
  436.         /*
  437.          * If the programmer writes
  438.          *    #define foo() ...
  439.          *    ...
  440.          *    foo [no ()]
  441.          * just write foo to the output stream.
  442.          */
  443.         unget();
  444.         cwarn("Macro \"%s\" needs arguments", tokenp->name);
  445.         fputs(tokenp->name, stdout);
  446.         DBUG_VOID_RETURN;
  447.         }
  448.         else if (expcollect()) {        /* Collect arguments    */
  449.         if (tokenp->nargs != nargs) {    /* Should be an error?    */
  450.             cwarn("Wrong number of macro arguments for \"%s\"",
  451.             tokenp->name);
  452.         }
  453. #if DEBUG
  454.         if (debug)
  455.             dumpparm("expand");
  456. #endif
  457.         }                /* Collect arguments        */
  458.     case DEF_NOARGS:        /* No parameters just stuffs    */
  459.         expstuff(tokenp);        /* Do actual parameters        */
  460.     }                /* nargs switch            */
  461.     DBUG_VOID_RETURN;
  462. }
  463.  
  464. FILE_LOCAL int
  465. expcollect()
  466. /*
  467.  * Collect the actual parameters for this macro.  TRUE if ok.
  468.  */
  469. {
  470.     register int    c;
  471.     register int    paren;            /* For embedded ()'s    */
  472.     extern int    charput();
  473.  
  474.     DBUG_ENTER ("expcollect");
  475.     for (;;) {
  476.         paren = 0;                /* Collect next arg.    */
  477.         while ((c = skipws()) == '\n')    /* Skip over whitespace    */
  478.         wrongline = TRUE;        /* and newlines.    */
  479.         if (c == ')') {            /* At end of all args?    */
  480.         /*
  481.          * Note that there is a guard byte in parm[]
  482.          * so we don't have to check for overflow here.
  483.          */
  484.         *parmp = EOS;            /* Make sure terminated    */
  485.         break;                /* Exit collection loop    */
  486.         }
  487.         else if (nargs >= LASTPARM)
  488.         cfatal("Too many arguments in macro expansion", NULLST);
  489.         parlist[nargs++] = parmp;        /* At start of new arg    */
  490.         for (;; c = cget()) {        /* Collect arg's bytes    */
  491.         if (c == EOF_CHAR) {
  492.             cerror("end of file within macro argument", NULLST);
  493.             DBUG_RETURN (FALSE);        /* Sorry.        */
  494.         }
  495.         else if (c == '\\') {        /* Quote next character    */
  496.             charput(c);            /* Save the \ for later    */
  497.             charput(cget());        /* Save the next char.    */
  498.             continue;            /* And go get another    */
  499.         }
  500.         else if (type[c] == QUO) {    /* Start of string?    */
  501.             scanstring(c, charput);    /* Scan it off        */
  502.             continue;            /* Go get next char    */
  503.         }
  504.         else if (c == '(')        /* Worry about balance    */
  505.             paren++;            /* To know about commas    */
  506.         else if (c == ')') {        /* Other side too    */
  507.             if (paren == 0) {        /* At the end?        */
  508.             unget();        /* Look at it later    */
  509.             break;            /* Exit arg getter.    */
  510.             }
  511.             paren--;            /* More to come.    */
  512.         }
  513.         else if (c == ',' && paren == 0) /* Comma delimits args    */
  514.             break;
  515.         else if (c == '\n')        /* Newline inside arg?    */
  516.             wrongline = TRUE;        /* We'll need a #line    */
  517.         charput(c);            /* Store this one    */
  518.         }                    /* Collect an argument    */
  519.         charput(EOS);            /* Terminate argument    */
  520. #if DEBUG
  521.         if (debug)
  522.             printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
  523. #endif
  524.     }                    /* Collect all args.    */
  525.     DBUG_RETURN (TRUE);            /* Normal return    */
  526. }
  527.  
  528. FILE_LOCAL
  529. expstuff(tokenp)
  530. DEFBUF        *tokenp;        /* Current macro being expanded    */
  531. /*
  532.  * Stuff the macro body, replacing formal parameters by actual parameters.
  533.  */
  534. {
  535.     register int    c;            /* Current character    */
  536.     register char    *inp;            /* -> repl string    */
  537.     register char    *defp;            /* -> macro output buff    */
  538.     int        size;            /* Actual parm. size    */
  539.     char        *defend;        /* -> output buff end    */
  540.     int        string_magic;        /* String formal hack    */
  541.     FILEINFO    *file;            /* Funny #include    */
  542.     extern FILEINFO    *getfile();
  543.  
  544.     DBUG_ENTER ("expstuff");
  545.     file = getfile(NBUFF, tokenp->name);
  546.     inp = tokenp->repl;            /* -> macro replacement    */
  547.     defp = file->buffer;            /* -> output buffer    */
  548.     defend = defp + (NBUFF - 1);        /* Note its end        */
  549.     if (inp != NULL) {
  550.         while ((c = (*inp++ & 0xFF)) != EOS) {
  551.         if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
  552.             string_magic = (c == (MAC_PARM + PAR_MAC));
  553.             if (string_magic)
  554.              c = (*inp++ & 0xFF);
  555.             /*
  556.              * Replace formal parameter by actual parameter string.
  557.              */
  558.             if ((c -= MAC_PARM) < nargs) {
  559.             size = strlen(parlist[c]);
  560.             if ((defp + size) >= defend)
  561.                 goto nospace;
  562.             /*
  563.              * Erase the extra set of quotes.
  564.              */
  565.             if (string_magic && defp[-1] == parlist[c][0]) {
  566.                 strcpy(defp-1, parlist[c]);
  567.                 defp += (size - 2);
  568.             }
  569.             else {
  570.                 strcpy(defp, parlist[c]);
  571.                 defp += size;
  572.             }
  573.             }
  574.         }
  575.         else if (defp >= defend) {
  576. nospace:        cfatal("Out of space in macro \"%s\" arg expansion",
  577.             tokenp->name);
  578.         }
  579.         else {
  580.             *defp++ = c;
  581.         }
  582.         }
  583.     }
  584.     *defp = EOS;
  585. #if DEBUG
  586.     if (debug > 1)
  587.         printf("macroline: \"%s\"\n", file->buffer);
  588. #endif
  589.     DBUG_VOID_RETURN;
  590. }
  591.  
  592. #if DEBUG
  593. dumpparm(why)
  594. char        *why;
  595. /*
  596.  * Dump parameter list.
  597.  */
  598. {
  599.     register int    i;
  600.  
  601.     DBUG_ENTER ("dumpparm");
  602.     printf("dump of %d parameters (%d bytes total) %s\n",
  603.         nargs, parmp - parm, why);
  604.     for (i = 0; i < nargs; i++) {
  605.         printf("parm[%d] (%d) = \"%s\"\n",
  606.         i + 1, strlen(parlist[i]), parlist[i]);
  607.     }
  608.     DBUG_VOID_RETURN;
  609. }
  610. #endif
  611.