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