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