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