update dev300-m58
[ooovba.git] / rsc / source / rscpp / cpp6.c
blobbf12e08b805f2032f83e5c0b7a17862fea961a75
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: cpp6.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 <string.h>
34 #include "cppdef.h"
35 #include "cpp.h"
37 /*ER evaluate macros to pDefOut */
40 * skipnl() skips over input text to the end of the line.
41 * skipws() skips over "whitespace" (spaces or tabs), but
42 * not skip over the end of the line. It skips over
43 * TOK_SEP, however (though that shouldn't happen).
44 * scanid() reads the next token (C identifier) into token[].
45 * The caller has already read the first character of
46 * the identifier. Unlike macroid(), the token is
47 * never expanded.
48 * macroid() reads the next token (C identifier) into token[].
49 * If it is a #defined macro, it is expanded, and
50 * macroid() returns TRUE, otherwise, FALSE.
51 * catenate() Does the dirty work of token concatenation, TRUE if it did.
52 * scanstring() Reads a string from the input stream, calling
53 * a user-supplied function for each character.
54 * This function may be output() to write the
55 * string to the output file, or save() to save
56 * the string in the work buffer.
57 * scannumber() Reads a C numeric constant from the input stream,
58 * calling the user-supplied function for each
59 * character. (output() or save() as noted above.)
60 * save() Save one character in the work[] buffer.
61 * savestring() Saves a string in malloc() memory.
62 * getfile() Initialize a new FILEINFO structure, called when
63 * #include opens a new file, or a macro is to be
64 * expanded.
65 * getmem() Get a specified number of bytes from malloc memory.
66 * output() Write one character to stdout (calling PUTCHAR) --
67 * implemented as a function so its address may be
68 * passed to scanstring() and scannumber().
69 * lookid() Scans the next token (identifier) from the input
70 * stream. Looks for it in the #defined symbol table.
71 * Returns a pointer to the definition, if found, or NULL
72 * if not present. The identifier is stored in token[].
73 * defnedel() Define enter/delete subroutine. Updates the
74 * symbol table.
75 * get() Read the next byte from the current input stream,
76 * handling end of (macro/file) input and embedded
77 * comments appropriately. Note that the global
78 * instring is -- essentially -- a parameter to get().
79 * cget() Like get(), but skip over TOK_SEP.
80 * unget() Push last gotten character back on the input stream.
81 * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
82 * These routines format an print messages to the user.
83 * cerror & cwarn take a format and a single string argument.
84 * cierror & ciwarn take a format and a single int (char) argument.
85 * cfatal takes a format and a single string argument.
89 * This table must be rewritten for a non-Ascii machine.
91 * Note that several "non-visible" characters have special meaning:
92 * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
93 * Hex 1E TOK_SEP -- a delimiter for token concatenation
94 * Hex 1F COM_SEP -- a zero-width whitespace for comment concatenation
96 #if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D
97 << error type table is not correct >>
98 #endif
100 #if OK_DOLLAR
101 #define DOL LET
102 #else
103 #define DOL 000
104 #endif
106 #ifdef EBCDIC
108 char type[256] = { /* Character type codes Hex */
109 END, 000, 000, 000, 000, SPA, 000, 000, /* 00 */
110 000, 000, 000, 000, 000, 000, 000, 000, /* 08 */
111 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */
112 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */
113 000, 000, 000, 000, 000, 000, 000, 000, /* 20 */
114 000, 000, 000, 000, 000, 000, 000, 000, /* 28 */
115 000, 000, 000, 000, 000, 000, 000, 000, /* 30 */
116 000, 000, 000, 000, 000, 000, 000, 000, /* 38 */
117 SPA, 000, 000, 000, 000, 000, 000, 000, /* 40 */
118 000, 000, 000, DOT, OP_LT,OP_LPA,OP_ADD, OP_OR, /* 48 .<(+| */
119 OP_AND, 000, 000, 000, 000, 000, 000, 000, /* 50 & */
120 000, 000,OP_NOT, DOL,OP_MUL,OP_RPA, 000,OP_XOR, /* 58 !$*);^ */
121 OP_SUB,OP_DIV, 000, 000, 000, 000, 000, 000, /* 60 -/ */
122 000, 000, 000, 000,OP_MOD, LET, OP_GT,OP_QUE, /* 68 ,%_>? */
123 000, 000, 000, 000, 000, 000, 000, 000, /* 70 */
124 000, 000,OP_COL, 000, 000, QUO, OP_EQ, QUO, /* 78 `:#@'=" */
125 000, LET, LET, LET, LET, LET, LET, LET, /* 80 abcdefg */
126 LET, LET, 000, 000, 000, 000, 000, 000, /* 88 hi */
127 000, LET, LET, LET, LET, LET, LET, LET, /* 90 jklmnop */
128 LET, LET, 000, 000, 000, 000, 000, 000, /* 98 qr */
129 000,OP_NOT, LET, LET, LET, LET, LET, LET, /* A0 ~stuvwx */
130 LET, LET, 000, 000, 000, 000, 000, 000, /* A8 yz [ */
131 000, 000, 000, 000, 000, 000, 000, 000, /* B0 */
132 000, 000, 000, 000, 000, 000, 000, 000, /* B8 ] */
133 000, LET, LET, LET, LET, LET, LET, LET, /* C0 {ABCDEFG */
134 LET, LET, 000, 000, 000, 000, 000, 000, /* C8 HI */
135 000, LET, LET, LET, LET, LET, LET, LET, /* D0 }JKLMNOP */
136 LET, LET, 000, 000, 000, 000, 000, 000, /* D8 QR */
137 BSH, 000, LET, LET, LET, LET, LET, LET, /* E0 \ STUVWX */
138 LET, LET, 000, 000, 000, 000, 000, 000, /* E8 YZ */
139 DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* F0 01234567 */
140 DIG, DIG, 000, 000, 000, 000, 000, 000, /* F8 89 */
143 #else
145 char type[256] = { /* Character type codes Hex */
146 END, 000, 000, 000, 000, 000, 000, 000, /* 00 */
147 000, SPA, 000, 000, 000, 000, 000, 000, /* 08 */
148 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */
149 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */
150 SPA,OP_NOT, QUO, 000, DOL,OP_MOD,OP_AND, QUO, /* 20 !"#$%&' */
151 OP_LPA,OP_RPA,OP_MUL,OP_ADD, 000,OP_SUB, DOT,OP_DIV, /* 28 ()*+,-./ */
152 DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* 30 01234567 */
153 DIG, DIG,OP_COL, 000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */
154 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */
155 LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */
156 LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */
157 LET, LET, LET, 000, BSH, 000,OP_XOR, LET, /* 58 XYZ[\]^_ */
158 000, LET, LET, LET, LET, LET, LET, LET, /* 60 `abcdefg */
159 LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */
160 LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */
161 LET, LET, LET, 000, OP_OR, 000,OP_NOT, 000, /* 78 xyz{|}~ */
162 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
163 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
164 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
165 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
166 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
167 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
168 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
169 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
172 #endif
176 * C P P S y m b o l T a b l e s
180 * SBSIZE defines the number of hash-table slots for the symbol table.
181 * It must be a power of 2.
183 #ifndef SBSIZE
184 #define SBSIZE 64
185 #endif
186 #define SBMASK (SBSIZE - 1)
187 #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
188 << error, SBSIZE must be a power of 2 >>
189 #endif
192 static DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */
194 void InitCpp6()
196 int i;
197 for( i = 0; i < SBSIZE; i++ )
198 symtab[ i ] = NULL;
203 void skipnl()
205 * Skip to the end of the current input line.
208 register int c;
210 do { /* Skip to newline */
211 c = get();
212 } while (c != '\n' && c != EOF_CHAR);
216 skipws()
218 * Skip over whitespace
221 register int c;
223 do { /* Skip whitespace */
224 c = get();
225 #if COMMENT_INVISIBLE
226 } while (type[c] == SPA || c == COM_SEP);
227 #else
228 } while (type[c] == SPA);
229 #endif
230 return (c);
233 void scanid(int c)
235 * Get the next token (an id) into the token buffer.
236 * Note: this code is duplicated in lookid().
237 * Change one, change both.
240 register char *bp;
242 if (c == DEF_MAGIC) /* Eat the magic token */
243 c = get(); /* undefiner. */
244 bp = token;
245 do {
246 if (bp < &token[IDMAX]) /* token dim is IDMAX+1 */
247 *bp++ = (char)c;
248 c = get();
249 } while (type[c] == LET || type[c] == DIG);
250 unget();
251 *bp = EOS;
255 macroid(int c)
257 * If c is a letter, scan the id. if it's #defined, expand it and scan
258 * the next character and try again.
260 * Else, return the character. If type[c] is a LET, the token is in token.
263 register DEFBUF *dp;
265 if (infile != NULL && infile->fp != NULL)
266 recursion = 0;
267 while (type[c] == LET && (dp = lookid(c)) != NULL) {
268 expand(dp);
269 c = get();
271 return (c);
275 catenate()
277 * A token was just read (via macroid).
278 * If the next character is TOK_SEP, concatenate the next token
279 * return TRUE -- which should recall macroid after refreshing
280 * macroid's argument. If it is not TOK_SEP, unget() the character
281 * and return FALSE.
284 register int c;
285 register char *token1;
287 #if OK_CONCAT
288 if (get() != TOK_SEP) { /* Token concatenation */
289 unget();
290 return (FALSE);
292 else {
293 token1 = savestring(token); /* Save first token */
294 c = macroid(get()); /* Scan next token */
295 switch(type[c]) { /* What was it? */
296 case LET: /* An identifier, ... */
297 if (strlen(token1) + strlen(token) >= NWORK)
298 cfatal("work buffer overflow doing %s #", token1);
299 sprintf(work, "%s%s", token1, token);
300 break;
302 case DIG: /* A digit string */
303 strcpy(work, token1);
304 workp = work + strlen(work);
305 do {
306 save(c);
307 } while ((c = get()) != TOK_SEP);
309 * The trailing TOK_SEP is no longer needed.
311 save(EOS);
312 break;
314 default: /* An error, ... */
315 #if ! COMMENT_INVISIBLE
316 if (isprint(c))
317 cierror("Strange character '%c' after #", c);
318 else
319 cierror("Strange character (%d.) after #", c);
320 #endif
321 strcpy(work, token1);
322 unget();
323 break;
326 * work has the concatenated token and token1 has
327 * the first token (no longer needed). Unget the
328 * new (concatenated) token after freeing token1.
329 * Finally, setup to read the new token.
331 free(token1); /* Free up memory */
332 ungetstring(work); /* Unget the new thing, */
333 return (TRUE);
335 #else
336 return (FALSE); /* Not supported */
337 #endif
341 scanstring(int delim,
342 #ifndef _NO_PROTO
343 void (*outfun)( int ) /* BP */ /* Output function */
344 #else
345 void (*outfun)() /* BP */
346 #endif
349 * Scan off a string. Warning if terminated by newline or EOF.
350 * outfun() outputs the character -- to a buffer if in a macro.
351 * TRUE if ok, FALSE if error.
354 register int c;
356 instring = TRUE; /* Don't strip comments */
357 (*outfun)(delim);
358 while ((c = get()) != delim
359 && c != '\n'
360 && c != EOF_CHAR) {
362 if (c != DEF_MAGIC)
363 (*outfun)(c);
364 if (c == '\\')
365 (*outfun)(get());
367 instring = FALSE;
368 if (c == delim) {
369 (*outfun)(c);
370 return (TRUE);
372 else {
373 cerror("Unterminated string", NULLST);
374 unget();
375 return (FALSE);
379 void scannumber(int c,
380 #ifndef _NO_PROTO
381 register void (*outfun)( int ) /* BP */ /* Output/store func */
382 #else
383 register void (*outfun)() /* BP */
384 #endif
387 * Process a number. We know that c is from 0 to 9 or dot.
388 * Algorithm from Dave Conroy's Decus C.
391 register int radix; /* 8, 10, or 16 */
392 int expseen; /* 'e' seen in floater */
393 int signseen; /* '+' or '-' seen */
394 int octal89; /* For bad octal test */
395 int dotflag; /* TRUE if '.' was seen */
397 expseen = FALSE; /* No exponent seen yet */
398 signseen = TRUE; /* No +/- allowed yet */
399 octal89 = FALSE; /* No bad octal yet */
400 radix = 10; /* Assume decimal */
401 if ((dotflag = (c == '.')) != FALSE) { /* . something? */
402 (*outfun)('.'); /* Always out the dot */
403 if (type[(c = get())] != DIG) { /* If not a float numb, */
404 unget(); /* Rescan strange char */
405 return; /* All done for now */
407 } /* End of float test */
408 else if (c == '0') { /* Octal or hex? */
409 (*outfun)(c); /* Stuff initial zero */
410 radix = 8; /* Assume it's octal */
411 c = get(); /* Look for an 'x' */
412 if (c == 'x' || c == 'X') { /* Did we get one? */
413 radix = 16; /* Remember new radix */
414 (*outfun)(c); /* Stuff the 'x' */
415 c = get(); /* Get next character */
418 for (;;) { /* Process curr. char. */
420 * Note that this algorithm accepts "012e4" and "03.4"
421 * as legitimate floating-point numbers.
423 if (radix != 16 && (c == 'e' || c == 'E')) {
424 if (expseen) /* Already saw 'E'? */
425 break; /* Exit loop, bad nbr. */
426 expseen = TRUE; /* Set exponent seen */
427 signseen = FALSE; /* We can read '+' now */
428 radix = 10; /* Decimal exponent */
430 else if (radix != 16 && c == '.') {
431 if (dotflag) /* Saw dot already? */
432 break; /* Exit loop, two dots */
433 dotflag = TRUE; /* Remember the dot */
434 radix = 10; /* Decimal fraction */
436 else if (c == '+' || c == '-') { /* 1.0e+10 */
437 if (signseen) /* Sign in wrong place? */
438 break; /* Exit loop, not nbr. */
439 /* signseen = TRUE; */ /* Remember we saw it */
441 else { /* Check the digit */
442 switch (c) {
443 case '8': case '9': /* Sometimes wrong */
444 octal89 = TRUE; /* Do check later */
445 case '0': case '1': case '2': case '3':
446 case '4': case '5': case '6': case '7':
447 break; /* Always ok */
449 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
450 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
451 if (radix == 16) /* Alpha's are ok only */
452 break; /* if reading hex. */
453 default: /* At number end */
454 goto done; /* Break from for loop */
455 } /* End of switch */
456 } /* End general case */
457 (*outfun)(c); /* Accept the character */
458 signseen = TRUE; /* Don't read sign now */
459 c = get(); /* Read another char */
460 } /* End of scan loop */
462 * When we break out of the scan loop, c contains the first
463 * character (maybe) not in the number. If the number is an
464 * integer, allow a trailing 'L' for long and/or a trailing 'U'
465 * for unsigned. If not those, push the trailing character back
466 * on the input stream. Floating point numbers accept a trailing
467 * 'L' for "long double".
469 done: if (dotflag || expseen) { /* Floating point? */
470 if (c == 'l' || c == 'L') {
471 (*outfun)(c);
472 c = get(); /* Ungotten later */
475 else { /* Else it's an integer */
477 * We know that dotflag and expseen are both zero, now:
478 * dotflag signals "saw 'L'", and
479 * expseen signals "saw 'U'".
481 for (;;) {
482 switch (c) {
483 case 'l':
484 case 'L':
485 if (dotflag)
486 goto nomore;
487 dotflag = TRUE;
488 break;
490 case 'u':
491 case 'U':
492 if (expseen)
493 goto nomore;
494 expseen = TRUE;
495 break;
497 default:
498 goto nomore;
500 (*outfun)(c); /* Got 'L' or 'U'. */
501 c = get(); /* Look at next, too. */
504 nomore: unget(); /* Not part of a number */
505 if (octal89 && radix == 8)
506 cwarn("Illegal digit in octal number", NULLST);
509 void save(int c)
511 if (workp >= &work[NWORK]) {
512 work[NWORK-1] = '\0';
513 cfatal("Work buffer overflow: %s", work);
515 else *workp++ = (char)c;
518 char *
519 savestring(char* text)
521 * Store a string into free memory.
524 register char *result;
526 result = getmem(strlen(text) + 1);
527 strcpy(result, text);
528 return (result);
531 FILEINFO *
532 getfile(int bufsize, char* name)
534 * Common FILEINFO buffer initialization for a new file or macro.
537 register FILEINFO *file;
538 register int size;
540 size = strlen(name); /* File/macro name */
541 file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size);
542 file->parent = infile; /* Chain files together */
543 file->fp = NULL; /* No file yet */
544 file->filename = savestring(name); /* Save file/macro name */
545 file->progname = NULL; /* No #line seen yet */
546 file->unrecur = 0; /* No macro fixup */
547 file->bptr = file->buffer; /* Initialize line ptr */
548 file->buffer[0] = EOS; /* Force first read */
549 file->line = 0; /* (Not used just yet) */
550 if (infile != NULL) /* If #include file */
551 infile->line = line; /* Save current line */
552 infile = file; /* New current file */
553 line = 1; /* Note first line */
554 return (file); /* All done. */
557 char *
558 getmem(int size)
560 * Get a block of free memory.
563 register char *result;
565 if ((result = malloc((unsigned) size)) == NULL)
566 cfatal("Out of memory", NULLST);
567 return (result);
571 DEFBUF *
572 lookid(int c)
574 * Look for the next token in the symbol table. Returns token in "token".
575 * If found, returns the table pointer; Else returns NULL.
578 register int nhash;
579 register DEFBUF *dp;
580 register char *np;
581 int temp = 0;
582 int isrecurse; /* For #define foo foo */
584 np = token;
585 nhash = 0;
586 if (0 != (isrecurse = (c == DEF_MAGIC))) /* If recursive macro */
587 c = get(); /* hack, skip DEF_MAGIC */
588 do {
589 if (np < &token[IDMAX]) { /* token dim is IDMAX+1 */
590 *np++ = (char)c; /* Store token byte */
591 nhash += c; /* Update hash value */
593 c = get(); /* And get another byte */
594 } while (type[c] == LET || type[c] == DIG);
595 unget(); /* Rescan terminator */
596 *np = EOS; /* Terminate token */
597 if (isrecurse) /* Recursive definition */
598 return (NULL); /* undefined just now */
599 nhash += (np - token); /* Fix hash value */
600 dp = symtab[nhash & SBMASK]; /* Starting bucket */
601 while (dp != (DEFBUF *) NULL) { /* Search symbol table */
602 if (dp->hash == nhash /* Fast precheck */
603 && (temp = strcmp(dp->name, token)) >= 0)
604 break;
605 dp = dp->link; /* Nope, try next one */
607 return ((temp == 0) ? dp : NULL);
610 DEFBUF *
611 defendel(char* name, int delete)
613 * Enter this name in the lookup table (delete = FALSE)
614 * or delete this name (delete = TRUE).
615 * Returns a pointer to the define block (delete = FALSE)
616 * Returns NULL if the symbol wasn't defined (delete = TRUE).
619 register DEFBUF *dp;
620 register DEFBUF **prevp;
621 register char *np;
622 int nhash;
623 int temp;
624 int size;
626 for (nhash = 0, np = name; *np != EOS;)
627 nhash += *np++;
628 size = (np - name);
629 nhash += size;
630 prevp = &symtab[nhash & SBMASK];
631 while ((dp = *prevp) != (DEFBUF *) NULL) {
632 if (dp->hash == nhash
633 && (temp = strcmp(dp->name, name)) >= 0) {
634 if (temp > 0)
635 dp = NULL; /* Not found */
636 else {
637 *prevp = dp->link; /* Found, unlink and */
638 if (dp->repl != NULL) /* Free the replacement */
639 free(dp->repl); /* if any, and then */
640 free((char *) dp); /* Free the symbol */
642 break;
644 prevp = &dp->link;
646 if (!delete) {
647 dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
648 dp->link = *prevp;
649 *prevp = dp;
650 dp->hash = nhash;
651 dp->repl = NULL;
652 dp->nargs = 0;
653 strcpy(dp->name, name);
655 return (dp);
658 #if OSL_DEBUG_LEVEL > 1
660 void dumpdef(char *why)
662 register DEFBUF *dp;
663 register DEFBUF **syp;
664 FILE *pRememberOut = NULL;
666 if ( bDumpDefs ) /*ER */
668 pRememberOut = pCppOut;
669 pCppOut = pDefOut;
671 fprintf( pCppOut, "CPP symbol table dump %s\n", why);
672 for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
673 if ((dp = *syp) != (DEFBUF *) NULL) {
674 fprintf( pCppOut, "symtab[%d]\n", (syp - symtab));
675 do {
676 dumpadef((char *) NULL, dp);
677 } while ((dp = dp->link) != (DEFBUF *) NULL);
680 if ( bDumpDefs )
682 fprintf( pCppOut, "\n");
683 pCppOut = pRememberOut;
687 void dumpadef(char *why, register DEFBUF *dp)
689 register char *cp;
690 register int c;
691 FILE *pRememberOut = NULL;
693 /*ER dump #define's to pDefOut */
694 if ( bDumpDefs )
696 pRememberOut = pCppOut;
697 pCppOut = pDefOut;
699 fprintf( pCppOut, " \"%s\" [%d]", dp->name, dp->nargs);
700 if (why != NULL)
701 fprintf( pCppOut, " (%s)", why);
702 if (dp->repl != NULL) {
703 fprintf( pCppOut, " => ");
704 for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) {
705 #ifdef SOLAR
706 if (c == DEL) {
707 c = *cp++ & 0xFF;
708 if( c == EOS ) break;
709 fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
711 #else
712 if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
713 fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
714 #endif
715 else if (isprint(c) || c == '\n' || c == '\t')
716 PUTCHAR(c);
717 else if (c < ' ')
718 fprintf( pCppOut, "<^%c>", c + '@');
719 else
720 fprintf( pCppOut, "<\\0%o>", c);
722 /*ER evaluate macros to pDefOut */
723 #ifdef EVALDEFS
724 if ( bDumpDefs && !bIsInEval && dp->nargs <= 0 )
726 FILEINFO *infileSave = infile;
727 char *tokenSave = savestring( token );
728 char *workSave = savestring( work );
729 int lineSave = line;
730 int wronglineSave = wrongline;
731 int recursionSave = recursion;
732 FILEINFO *file;
733 EVALTYPE valEval;
735 bIsInEval = 1;
736 infile = NULL; /* start from scrap */
737 line = 0;
738 wrongline = 0;
739 *token = EOS;
740 *work = EOS;
741 recursion = 0;
742 file = getfile( strlen( dp->repl ), dp->name );
743 strcpy( file->buffer, dp->repl );
744 fprintf( pCppOut, " ===> ");
745 nEvalOff = 0;
746 cppmain(); /* get() frees also *file */
747 valEval = 0;
748 if ( 0 == evaluate( EvalBuf, &valEval ) )
750 #ifdef EVALFLOATS
751 if ( valEval != (EVALTYPE)((long)valEval ) )
752 fprintf( pCppOut, " ==eval=> %f", valEval );
753 else
754 #endif
755 fprintf( pCppOut, " ==eval=> %ld", (long)valEval );
757 recursion = recursionSave;
758 wrongline = wronglineSave;
759 line = lineSave;
760 strcpy( work, workSave );
761 free( workSave );
762 strcpy( token, tokenSave );
763 free( tokenSave );
764 infile = infileSave;
765 bIsInEval = 0;
767 #endif
769 else {
770 fprintf( pCppOut, ", no replacement.");
772 PUTCHAR('\n');
773 if ( bDumpDefs )
774 pCppOut = pRememberOut;
776 #endif
779 * G E T
783 get()
785 * Return the next character from a macro or the current file.
786 * Handle end of file from #include files.
789 register int c;
790 register FILEINFO *file;
791 register int popped; /* Recursion fixup */
793 popped = 0;
794 get_from_file:
795 if ((file = infile) == NULL)
796 return (EOF_CHAR);
797 newline:
798 #if 0
799 fprintf( pCppOut, "get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",
800 file->filename, recursion, line,
801 file->bptr - file->buffer, file->buffer);
802 #endif
804 * Read a character from the current input line or macro.
805 * At EOS, either finish the current macro (freeing temp.
806 * storage) or read another line from the current input file.
807 * At EOF, exit the current file (#include) or, at EOF from
808 * the cpp input file, return EOF_CHAR to finish processing.
810 if ((c = *file->bptr++ & 0xFF) == EOS) {
812 * Nothing in current line or macro. Get next line (if
813 * input from a file), or do end of file/macro processing.
814 * In the latter case, jump back to restart from the top.
816 if (file->fp == NULL) { /* NULL if macro */
817 popped++;
818 recursion -= file->unrecur;
819 if (recursion < 0)
820 recursion = 0;
821 infile = file->parent; /* Unwind file chain */
823 else { /* Else get from a file */
824 if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
825 != NULL) {
826 #if OSL_DEBUG_LEVEL > 1
827 if (debug > 1) { /* Dump it to stdout */
828 fprintf( pCppOut, "\n#line %d (%s), %s",
829 line, file->filename, file->buffer);
831 #endif
832 goto newline; /* process the line */
834 else {
835 if( file->fp != stdin )
836 fclose(file->fp); /* Close finished file */
837 if ((infile = file->parent) != NULL) {
839 * There is an "ungotten" newline in the current
840 * infile buffer (set there by doinclude() in
841 * cpp1.c). Thus, we know that the mainline code
842 * is skipping over blank lines and will do a
843 * #line at its convenience.
845 wrongline = TRUE; /* Need a #line now */
850 * Free up space used by the (finished) file or macro and
851 * restart input from the parent file/macro, if any.
853 free(file->filename); /* Free name and */
854 if (file->progname != NULL) /* if a #line was seen, */
855 free(file->progname); /* free it, too. */
856 free((char *) file); /* Free file space */
857 if (infile == NULL) /* If at end of file */
858 return (EOF_CHAR); /* Return end of file */
859 line = infile->line; /* Reset line number */
860 goto get_from_file; /* Get from the top. */
863 * Common processing for the new character.
865 if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete */
866 goto newline; /* from a file */
867 if (file->parent != NULL) { /* Macro or #include */
868 if (popped != 0)
869 file->parent->unrecur += popped;
870 else {
871 recursion -= file->parent->unrecur;
872 if (recursion < 0)
873 recursion = 0;
874 file->parent->unrecur = 0;
877 #if (HOST == SYS_UNIX)
878 /*ER*/ if (c == '\r')
879 /*ER*/ return get(); /* DOS fuck */
880 #endif
881 if (c == '\n') /* Maintain current */
882 ++line; /* line counter */
883 if (instring) /* Strings just return */
884 return (c); /* the character. */
885 else if (c == '/') { /* Comment? */
886 instring = TRUE; /* So get() won't loop */
887 /*MM c++ comments */
888 /*MM*/ c = get();
889 /*MM*/ if ((c != '*') && (c != '/')) { /* Next byte '*'? */
890 instring = FALSE; /* Nope, no comment */
891 unget(); /* Push the char. back */
892 return ('/'); /* Return the slash */
894 if (keepcomments) { /* If writing comments */
895 PUTCHAR('/'); /* Write out the */
896 /* initializer */
897 /*MM*/ if( '*' == c )
898 PUTCHAR('*');
899 /*MM*/ else
900 /*MM*/ PUTCHAR('/');
903 /*MM*/ if( '*' == c ){
904 for (;;) { /* Eat a comment */
905 c = get();
906 test: if (keepcomments && c != EOF_CHAR)
907 cput(c);
908 switch (c) {
909 case EOF_CHAR:
910 cerror("EOF in comment", NULLST);
911 return (EOF_CHAR);
913 case '/':
914 if ((c = get()) != '*') /* Don't let comments */
915 goto test; /* Nest. */
916 #ifdef STRICT_COMMENTS
917 cwarn("Nested comments", NULLST);
918 #endif
919 /* Fall into * stuff */
920 case '*':
921 if ((c = get()) != '/') /* If comment doesn't */
922 goto test; /* end, look at next */
923 instring = FALSE; /* End of comment, */
924 if (keepcomments) { /* Put out the comment */
925 cput(c); /* terminator, too */
928 * A comment is syntactically "whitespace" --
929 * however, there are certain strange sequences
930 * such as
931 * #define foo(x) (something)
932 * foo|* comment *|(123)
933 * these are '/' ^ ^
934 * where just returning space (or COM_SEP) will cause
935 * problems. This can be "fixed" by overwriting the
936 * '/' in the input line buffer with ' ' (or COM_SEP)
937 * but that may mess up an error message.
938 * So, we peek ahead -- if the next character is
939 * "whitespace" we just get another character, if not,
940 * we modify the buffer. All in the name of purity.
942 if (*file->bptr == '\n'
943 || type[*file->bptr & 0xFF] == SPA)
944 goto newline;
945 #if COMMENT_INVISIBLE
947 * Return magic (old-fashioned) syntactic space.
949 return ((file->bptr[-1] = COM_SEP));
950 #else
951 return ((file->bptr[-1] = ' '));
952 #endif
954 case '\n': /* we'll need a #line */
955 if (!keepcomments)
956 wrongline = TRUE; /* later... */
957 default: /* Anything else is */
958 break; /* Just a character */
959 } /* End switch */
960 } /* End comment loop */
962 else{ /* c++ comment */
963 /*MM c++ comment*/
964 for (;;) { /* Eat a comment */
965 c = get();
966 if (keepcomments && c != EOF_CHAR)
967 cput(c);
968 if( EOF_CHAR == c )
969 return (EOF_CHAR);
970 else if( '\n' == c ){
971 instring = FALSE; /* End of comment, */
972 return( c );
976 } /* End if in comment */
977 else if (!inmacro && c == '\\') { /* If backslash, peek */
978 if ((c = get()) == '\n') { /* for a <nl>. If so, */
979 wrongline = TRUE;
980 goto newline;
982 else { /* Backslash anything */
983 unget(); /* Get it later */
984 return ('\\'); /* Return the backslash */
987 else if (c == '\f' || c == VT) /* Form Feed, Vertical */
988 c = ' '; /* Tab are whitespace */
989 else if (c == 0xef) /* eat up UTF-8 BOM */
991 if((c = get()) == 0xbb)
993 if((c = get()) == 0xbf)
995 c = get();
996 return c;
998 else
1000 unget();
1001 unget();
1002 return 0xef;
1005 else
1007 unget();
1008 return 0xef;
1011 return (c); /* Just return the char */
1014 void unget()
1016 * Backup the pointer to reread the last character. Fatal error
1017 * (code bug) if we backup too far. unget() may be called,
1018 * without problems, at end of file. Only one character may
1019 * be ungotten. If you need to unget more, call ungetstring().
1022 register FILEINFO *file;
1024 if ((file = infile) == NULL)
1025 return; /* Unget after EOF */
1026 if (--file->bptr < file->buffer)
1027 cfatal("Too much pushback", NULLST);
1028 if (*file->bptr == '\n') /* Ungetting a newline? */
1029 --line; /* Unget the line number, too */
1032 void ungetstring(char* text)
1034 * Push a string back on the input stream. This is done by treating
1035 * the text as if it were a macro.
1038 register FILEINFO *file;
1039 #ifndef ZTC /* BP */
1040 extern FILEINFO *getfile();
1041 #endif
1042 file = getfile(strlen(text) + 1, "");
1043 strcpy(file->buffer, text);
1047 cget()
1049 * Get one character, absorb "funny space" after comments or
1050 * token concatenation
1053 register int c;
1055 do {
1056 c = get();
1057 #if COMMENT_INVISIBLE
1058 } while (c == TOK_SEP || c == COM_SEP);
1059 #else
1060 } while (c == TOK_SEP);
1061 #endif
1062 return (c);
1066 * Error messages and other hacks. The first byte of severity
1067 * is 'S' for string arguments and 'I' for int arguments. This
1068 * is needed for portability with machines that have int's that
1069 * are shorter than char *'s.
1072 static void domsg(char* severity, char* format, void* arg)
1074 * Print filenames, macro names, and line numbers for error messages.
1077 register char *tp;
1078 register FILEINFO *file;
1080 fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
1081 if (*severity == 'S')
1082 fprintf(stderr, format, (char *)arg);
1083 else
1084 fprintf(stderr, format, *((int *)arg) );
1085 putc('\n', stderr);
1086 if ((file = infile) == NULL)
1087 return; /* At end of file */
1088 if (file->fp != NULL) {
1089 tp = file->buffer; /* Print current file */
1090 fprintf(stderr, "%s", tp); /* name, making sure */
1091 if (tp[strlen(tp) - 1] != '\n') /* there's a newline */
1092 putc('\n', stderr);
1094 while ((file = file->parent) != NULL) { /* Print #includes, too */
1095 if (file->fp == NULL)
1096 fprintf(stderr, "from macro %s\n", file->filename);
1097 else {
1098 tp = file->buffer;
1099 fprintf(stderr, "from file %s, line %d:\n%s",
1100 (file->progname != NULL)
1101 ? file->progname : file->filename,
1102 file->line, tp);
1103 if (tp[strlen(tp) - 1] != '\n')
1104 putc('\n', stderr);
1109 void cerror(char* format, char* sarg)
1111 * Print a normal error message, string argument.
1114 domsg("SError", format, sarg);
1115 errors++;
1118 void cierror(char* format, int narg)
1120 * Print a normal error message, numeric argument.
1123 domsg("IError", format, &narg);
1124 errors++;
1127 void cfatal(char* format, char* sarg)
1129 * A real disaster
1132 domsg("SFatal error", format, sarg);
1133 exit(IO_ERROR);
1136 void cwarn(char* format, char* sarg)
1138 * A non-fatal error, string argument.
1141 domsg("SWarning", format, sarg);
1144 void ciwarn(char* format, int narg)
1146 * A non-fatal error, numeric argument.
1149 domsg("IWarning", format, &narg);