1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
26 * parm[], parmp, and parlist[] are used to store #define() argument
27 * lists. nargs contains the actual number of parameters stored.
29 static char parm
[NPARMWORK
+ 1]; /* define param work buffer */
30 static char *parmp
; /* Free space in parm */
31 static char *parlist
[LASTPARM
]; /* -> start of each parameter */
32 static int nargs
; /* Parameters for this macro */
37 for( i
= 0; i
< NPARMWORK
; i
++ )
39 for( i
= 0; i
< LASTPARM
; i
++ )
48 * Called from control when a #define is scanned. This module
49 * parses formal parameters and the replacement string. When
50 * the formal parameter name is encountered in the replacement
51 * string, it is replaced by a character in the range 128 to
52 * 128+NPARAM (this allows up to 32 parameters within the
53 * Dec Multinational range). If cpp is ported to an EBCDIC
54 * machine, you will have to make other arrangements.
56 * There is some special case code to distinguish
58 * from #define foo() bar
60 * Also, we make sure that
62 * expands to "foo" but doesn't put cpp into an infinite loop.
64 * A warning message is printed if you redefine a symbol to a
65 * different text. I.e,
73 * The following subroutines are called from define():
74 * checkparm called when a token is scanned. It checks through the
75 * array of formal parameters. If a match is found, the
76 * token is replaced by a control byte which will be used
77 * to locate the parameter when the macro is expanded.
78 * textput puts a string in the macro work area (parm[]), updating
79 * parmp to point to the first free byte in parm[].
80 * textput() tests for work buffer overflow.
81 * charput puts a single character in the macro work area (parm[])
82 * in a manner analogous to textput().
86 register DEFBUF
*dp
; /* -> new definition */
87 int isredefine
; /* TRUE if redefined */
88 char *old
= 0; /* Remember redefined */
90 if (type
[(c
= skipws())] != LET
)
92 isredefine
= FALSE
; /* Set if redefining */
93 if ((dp
= lookid(c
)) == NULL
) /* If not known now */
94 dp
= defendel(token
, FALSE
); /* Save the name */
95 else { /* It's known: */
96 isredefine
= TRUE
; /* Remember this fact */
97 old
= dp
->repl
; /* Remember replacement */
98 dp
->repl
= NULL
; /* No replacement now */
100 parlist
[0] = parmp
= parm
; /* Setup parm buffer */
101 if ((c
= get()) == '(') { /* With arguments? */
102 nargs
= 0; /* Init formals counter */
103 do { /* Collect formal parms */
104 if (nargs
>= LASTPARM
)
105 cfatal("Too many arguments for macro", NULLST
);
106 else if ((c
= skipws()) == ')')
107 break; /* Got them all */
108 else if (type
[c
] != LET
) /* Bad formal syntax */
110 scanid(c
); /* Get the formal param */
111 parlist
[nargs
++] = parmp
; /* Save its start */
112 textput(token
); /* Save text in parm[] */
113 } while ((c
= skipws()) == ','); /* Get another argument */
114 if (c
!= ')') /* Must end at ) */
116 c
= ' '; /* Will skip to body */
120 * DEF_NOARGS is needed to distinguish between
121 * "#define foo" and "#define foo()".
123 nargs
= DEF_NOARGS
; /* No () parameters */
125 if (type
[c
] == SPA
) /* At whitespace? */
126 c
= skipws(); /* Not any more. */
127 workp
= work
; /* Replacement put here */
128 inmacro
= TRUE
; /* Keep \<newline> now */
129 while (c
!= EOF_CHAR
&& c
!= '\n') { /* Compile macro body */
131 #if COMMENT_INVISIBLE
132 if (c
== COM_SEP
) { /* Token concatenation? */
133 save(TOK_SEP
); /* Stuff a delimiter */
136 if (c
== '#') { /* Token concatenation? */
137 while (workp
> work
&& type
[(int)workp
[-1]] == SPA
)
138 --workp
; /* Erase leading spaces */
139 save(TOK_SEP
); /* Stuff a delimiter */
140 c
= skipws(); /* Eat whitespace */
142 if (type
[c
] == LET
) /* Another token here? */
143 ; /* Stuff it normally */
144 else if (type
[c
] == DIG
) { /* Digit string after? */
145 while (type
[c
] == DIG
) { /* Stuff the digits */
149 save(TOK_SEP
); /* Delimit 2nd token */
152 #if ! COMMENT_INVISIBLE
153 ciwarn("Strange character after # (%d.)", c
);
161 checkparm(c
, dp
); /* Might be a formal */
164 case DIG
: /* Number in mac. body */
165 case DOT
: /* Maybe a float number */
166 scannumber(c
, save
); /* Scan it off */
169 case QUO
: /* String in mac. body */
171 stparmscan(c
, dp
); /* Do string magic */
177 case BSH
: /* Backslash */
179 if ((c
= get()) == '\n')
184 case SPA
: /* Absorb whitespace */
186 * Note: the "end of comment" marker is passed on
187 * to allow comments to separate tokens.
189 if (workp
[-1] == ' ') /* Absorb multiple */
192 c
= ' '; /* Normalize tabs */
193 /* Fall through to store character */
194 default: /* Other character */
200 inmacro
= FALSE
; /* Stop newline hack */
201 unget(); /* For control check */
202 if (workp
> work
&& workp
[-1] == ' ') /* Drop trailing blank */
204 *workp
= EOS
; /* Terminate work */
205 dp
->repl
= savestring(work
); /* Save the string */
206 dp
->nargs
= nargs
; /* Save arg count */
207 #if OSL_DEBUG_LEVEL > 1
209 dumpadef("macro definition", dp
);
213 if (isredefine
) { /* Error if redefined */
214 if ((old
!= NULL
&& dp
->repl
!= NULL
&& !streq(old
, dp
->repl
))
215 || (old
== NULL
&& dp
->repl
!= NULL
)
216 || (old
!= NULL
&& dp
->repl
== NULL
)) {
218 cerror("Redefining defined variable \"%s\"", dp
->name
);
220 cwarn("Redefining defined variable \"%s\"", dp
->name
);
223 if (old
!= NULL
) /* We don't need the */
224 free(old
); /* old definition now. */
229 cerror("#define syntax error", NULLST
);
230 inmacro
= FALSE
; /* Stop <newline> hack */
233 void checkparm(int c
, DEFBUF
* dp
)
235 * Replace this param if it's defined. Note that the macro name is a
236 * possible replacement token. We stuff DEF_MAGIC in front of the token
237 * which is treated as a LETTER by the token scanner and eaten by
238 * the output routine. This prevents the macro expander from
239 * looping if someone writes "#define foo foo".
245 scanid(c
); /* Get parm to token[] */
246 for (i
= 0; i
< nargs
; i
++) { /* For each argument */
247 if (streq(parlist
[i
], token
)) { /* If it's known */
251 save(i
+ MAC_PARM
); /* Save a magic cookie */
252 return; /* And exit the search */
255 if (streq(dp
->name
, token
)) /* Macro name in body? */
256 save(DEF_MAGIC
); /* Save magic marker */
257 for (cp
= token
; *cp
!= EOS
;) /* And save */
258 save(*cp
++); /* The token itself */
262 void stparmscan(delim
, dp
)
266 * Scan the string (starting with the given delimiter).
267 * The token is replaced if it is the only text in this string or
268 * character constant. The algorithm follows checkparm() above.
269 * Note that scanstring() has approved of the string.
275 * Warning -- this code hasn't been tested for a while.
276 * It exists only to preserve compatibility with earlier
277 * implementations of cpp. It is not part of the Draft
278 * ANSI Standard C language.
282 while ((c
= get()) != delim
285 if (type
[c
] == LET
) /* Maybe formal parm */
295 cerror("Unterminated string in macro body", NULLST
);
299 void stparmscan(int delim
)
301 * Normal string parameter scan.
307 wp
= workp
; /* Here's where it starts */
308 if (!scanstring(delim
, save
))
309 return; /* Exit on scanstring error */
310 workp
[-1] = EOS
; /* Erase trailing quote */
311 wp
++; /* -> first string content byte */
312 for (i
= 0; i
< nargs
; i
++) {
313 if (streq(parlist
[i
], wp
)) {
316 *wp
++ = MAC_PARM
+ PAR_MAC
; /* Stuff a magic marker */
317 *wp
++ = (char)(i
+ MAC_PARM
); /* Make a formal marker */
318 *wp
= wp
[-4]; /* Add on closing quote */
319 workp
= wp
+ 1; /* Reset string end */
321 *wp
++ = MAC_PARM
+ PAR_MAC
; /* Stuff a magic marker */
322 *wp
++ = (i
+ MAC_PARM
); /* Make a formal marker */
323 *wp
= wp
[-3]; /* Add on closing quote */
324 workp
= wp
+ 1; /* Reset string end */
329 workp
[-1] = wp
[-1]; /* Nope, reset end quote. */
335 * Remove the symbol from the defined list.
336 * Called from the #control processor.
341 if (type
[(c
= skipws())] != LET
)
342 cerror("Illegal #undef argument", NULLST
);
344 scanid(c
); /* Get name to token[] */
345 if (defendel(token
, TRUE
) == NULL
) {
347 cwarn("Symbol \"%s\" not defined in #undef", token
);
353 void textput(char* text
)
355 * Put the string in the parm[] buffer.
360 size
= strlen(text
) + 1;
361 if ((parmp
+ size
) >= &parm
[NPARMWORK
])
362 cfatal("Macro work area overflow", NULLST
);
371 * Put the byte in the parm[] buffer.
374 if (parmp
>= &parm
[NPARMWORK
])
375 cfatal("Macro work area overflow", NULLST
);
382 * M a c r o E x p a n s i o n
385 static DEFBUF
*macro
; /* Catches start of infinite macro */
387 void expand(DEFBUF
* tokenp
)
389 * Expand a macro. Called from the cpp mainline routine (via subroutine
390 * macroid()) when a token is found in the symbol table. It calls
391 * expcollect() to parse actual parameters, checking for the correct number.
392 * It then creates a "file" containing a single line containing the
393 * macro with actual parameters inserted appropriately. This is
394 * "pushed back" onto the input stream. (When the get() routine runs
395 * off the end of the macro line, it will dismiss the macro itself.)
399 register FILEINFO
*file
;
400 extern FILEINFO
*getfile();
402 #if OSL_DEBUG_LEVEL > 1
404 dumpadef("expand entry", tokenp
);
407 * If no macro is pending, save the name of this macro
408 * for an eventual error message.
410 if (recursion
++ == 0)
412 else if (recursion
== RECURSION_LIMIT
) {
413 cerror("Recursive macro definition of \"%s\"", tokenp
->name
);
414 fprintf(stderr
, "(Defined by \"%s\")\n", macro
->name
);
418 } while (infile
!= NULL
&& infile
->fp
== NULL
);
425 * Here's a macro to expand.
427 nargs
= 0; /* Formals counter */
428 parmp
= parm
; /* Setup parm buffer */
429 switch (tokenp
->nargs
) {
430 case (-2): /* __LINE__ */
431 sprintf(work
, "%d", line
);
435 case (-3): /* __FILE__ */
436 for (file
= infile
; file
!= NULL
; file
= file
->parent
) {
437 if (file
->fp
!= NULL
) {
438 sprintf(work
, "\"%s\"", (file
->progname
!= NULL
)
439 ? file
->progname
: file
->filename
);
448 * Nothing funny about this macro.
450 if (tokenp
->nargs
< 0)
451 cfatal("Bug: Illegal __ macro \"%s\"", tokenp
->name
);
452 while ((c
= skipws()) == '\n') /* Look for (, skipping */
453 wrongline
= TRUE
; /* spaces and newlines */
456 * If the programmer writes
460 * just write foo to the output stream.
463 cwarn("Macro \"%s\" needs arguments", tokenp
->name
);
464 fputs(tokenp
->name
, pCppOut
);
467 else if (expcollect()) { /* Collect arguments */
468 if (tokenp
->nargs
!= nargs
) { /* Should be an error? */
469 cwarn("Wrong number of macro arguments for \"%s\"",
472 #if OSL_DEBUG_LEVEL > 1
476 } /* Collect arguments */
477 case DEF_NOARGS
: /* No parameters just stuffs */
478 expstuff(tokenp
); /* Do actual parameters */
485 * Collect the actual parameters for this macro. TRUE if ok.
489 register int paren
; /* For embedded ()'s */
491 paren
= 0; /* Collect next arg. */
492 while ((c
= skipws()) == '\n') /* Skip over whitespace */
493 wrongline
= TRUE
; /* and newlines. */
494 if (c
== ')') { /* At end of all args? */
496 * Note that there is a guard byte in parm[]
497 * so we don't have to check for overflow here.
499 *parmp
= EOS
; /* Make sure terminated */
500 break; /* Exit collection loop */
502 else if (nargs
>= LASTPARM
)
503 cfatal("Too many arguments in macro expansion", NULLST
);
504 parlist
[nargs
++] = parmp
; /* At start of new arg */
505 for (;; c
= cget()) { /* Collect arg's bytes */
507 cerror("end of file within macro argument", NULLST
);
508 return (FALSE
); /* Sorry. */
510 else if (c
== '\\') { /* Quote next character */
511 charput(c
); /* Save the \ for later */
512 charput(cget()); /* Save the next char. */
513 continue; /* And go get another */
515 else if (type
[c
] == QUO
) { /* Start of string? */
516 scanstring(c
, charput
); /* Scan it off */
517 continue; /* Go get next char */
519 else if (c
== '(') /* Worry about balance */
520 paren
++; /* To know about commas */
521 else if (c
== ')') { /* Other side too */
522 if (paren
== 0) { /* At the end? */
523 unget(); /* Look at it later */
524 break; /* Exit arg getter. */
526 paren
--; /* More to come. */
528 else if (c
== ',' && paren
== 0) /* Comma delimits args */
530 else if (c
== '\n') /* Newline inside arg? */
531 wrongline
= TRUE
; /* We'll need a #line */
532 charput(c
); /* Store this one */
533 } /* Collect an argument */
534 charput(EOS
); /* Terminate argument */
535 #if OSL_DEBUG_LEVEL > 1
537 fprintf( pCppOut
, "parm[%d] = \"%s\"\n", nargs
, parlist
[nargs
- 1]);
539 } /* Collect all args. */
540 return (TRUE
); /* Normal return */
544 void expstuff(DEFBUF
* tokenp
)
546 * Stuff the macro body, replacing formal parameters by actual parameters.
549 register int c
; /* Current character */
550 register char *inp
; /* -> repl string */
551 register char *defp
; /* -> macro output buff */
552 int size
; /* Actual parm. size */
553 char *defend
; /* -> output buff end */
554 int string_magic
; /* String formal hack */
555 FILEINFO
*file
; /* Funny #include */
556 extern FILEINFO
*getfile();
558 file
= getfile(NBUFF
, tokenp
->name
);
559 inp
= tokenp
->repl
; /* -> macro replacement */
560 defp
= file
->buffer
; /* -> output buffer */
561 defend
= defp
+ (NBUFF
- 1); /* Note its end */
563 while ((c
= (*inp
++ & 0xFF)) != EOS
) {
568 if (c
>= MAC_PARM
&& c
<= (MAC_PARM
+ PAR_MAC
)) {
570 string_magic
= (c
== (MAC_PARM
+ PAR_MAC
));
574 * Replace formal parameter by actual parameter string.
576 if ((c
-= MAC_PARM
) < nargs
) {
577 size
= strlen(parlist
[c
]);
578 if ((defp
+ size
) >= defend
)
581 * Erase the extra set of quotes.
583 if (string_magic
&& defp
[-1] == parlist
[c
][0]) {
584 strcpy(defp
-1, parlist
[c
]);
588 strcpy(defp
, parlist
[c
]);
593 else if (defp
>= defend
) {
594 nospace
: cfatal("Out of space in macro \"%s\" arg expansion",
603 #if OSL_DEBUG_LEVEL > 1
605 fprintf( pCppOut
, "macroline: \"%s\"\n", file
->buffer
);
609 #if OSL_DEBUG_LEVEL > 1
610 void dumpparm(char* why
)
612 * Dump parameter list.
617 fprintf( pCppOut
, "dump of %d parameters (%" SAL_PRI_SIZET
"u bytes total) %s\n",
618 nargs
, parmp
- parm
, why
);
619 for (i
= 0; i
< nargs
; i
++) {
620 fprintf( pCppOut
, "parm[%d] (%d) = \"%s\"\n",
621 i
+ 1, (int)strlen(parlist
[i
]), parlist
[i
]);
626 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */