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