home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 243_01 / cpp4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-12  |  26.6 KB  |  732 lines

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