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