home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource4
/
243_01
/
cpp4.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-14
|
27KB
|
732 lines
/*
* C P P 4 . C
* M a c r o D e f i n i t i o n s
*
* Edit History
* 31-Aug-84 MM USENET net.sources release
* 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring()
* so they work correctly with token concatenation.
* Added string formal recognition.
* 25-Oct-84 MM "Short-circuit" evaluate #if's so that we
* don't print unnecessary error messages for
* #if !defined(FOO) && FOO != 0 && 10 / FOO ...
* 31-Oct-84 ado/MM Added token concatenation
* 6-Nov-84 MM Split off eval stuff
* 1-Apr-85 ado Fixed bug in STRING_FORMAL version
* 2-May-85 MM Changed the way macro parameters work -- only
* one byte is reserved, 255 param's possible.
*/
#include "cppdef.h"
#include "cpp.h"
FILE_LOCAL void mtokensave();
FILE_LOCAL void expstuff();
#if OK_CONCAT == CON_NOEXPAND
#define SEP COM_SEP /* concat token, don't reexpand */
#endif
#if OK_CONCAT == CON_EXPAND
#define SEP TOK_SEP /* concat token and reexpand */
#endif
/*
* parm[], parmp, and parlist[] are used to store #define() argument
* lists. nargs contains the actual number of parameters stored.
*/
static char parm[NPARMWORK + 1]; /* define param work buffer */
static char *parmp; /* Free space in parm */
static char *parlist[NMACPARS]; /* -> start of each parameter */
static int nargs; /* Parameters for this macro */
void
dodefine()
/*
* Called from control when a #define is scanned. This module
* parses formal parameters and the replacement string. When
* the formal parameter name is encountered in the replacement
* string, it is replaced by a character in the range 128 to
* 128+NPARAM (this allows up to 32 parameters within the
* Dec Multinational range). If cpp is ported to an EBCDIC
* machine, you will have to make other arrangements.
*
* There is some special case code to distinguish
* #define foo bar
* from #define foo() bar
*
* Also, we make sure that
* #define foo foo
* expands to "foo" but doesn't put cpp into an infinite loop.
*
* A warning message is printed if you redefine a symbol to a
* different text. I.e,
* #define foo 123
* #define foo 123
* is ok, but
* #define foo 123
* #define foo +123
* is not.
*
* The following subroutines are called from define():
* checkparm called when a token is scanned. It checks through the
* array of formal parameters. If a match is found, the
* token is replaced by a control byte which will be used
* to locate the parameter when the macro is expanded.
* textput puts a string in the macro work area (parm[]), updating
* parmp to point to the first free byte in parm[].
* textput() tests for work buffer overflow.
* charput puts a single character in the macro work area (parm[])
* in a manner analogous to textput().
*/
{
register int c;
register DEFBUF *dp; /* -> new definition */
int isredefine; /* TRUE if redefined */
char *old; /* Remember redefined */
if (type[(c = skipws())] != LET)
goto bad_define;
isredefine = FALSE; /* Set if redefining */
if ((dp = lookid(c)) == NULL) /* If not known now */
dp = defendel(token, FALSE); /* Save the name */
else { /* It's known: */
isredefine = TRUE; /* Remember this fact */
old = dp->repl; /* Remember replacement */
dp->repl = NULL; /* No replacement now */
}
parlist[0] = parmp = parm; /* Setup parm buffer */
if ((c = get()) == '(') { /* With arguments? */
nargs = 0; /* Init formals counter */
do { /* Collect formal parms */
if (nargs >= NMACPARS)
cfatal("Too many arguments for macro", NULLST);
else if ((c = skipws()) == ')')
break; /* Got them all */
else if (type[c] != LET) /* Bad formal syntax */
goto bad_define;
scanid(c); /* Get the formal param */
parlist[nargs++] = parmp; /* Save its start */
textput(token); /* Save text in parm[] */
} while ((c = skipws()) == ','); /* Get another argument */
if (c != ')') /* Must end at ) */
goto bad_define;
c = ' '; /* Will skip to body */
}
else {
/*
* DEF_NOARGS is needed to distinguish between
* "#define foo" and "#define foo()".
*/
nargs = DEF_NOARGS; /* No () parameters */
}
if (type[c] == SPA) /* At whitespace? */
c = skipws(); /* Not any more. */
workp = work; /* Replacement put here */
inmacro = TRUE; /* Keep \<newline> now */
for (; c != EOF_CHAR && c != '\n'; c = get()) {
#if OK_CONCAT != CON_FALSE
if (c == '#') { /* String/concat? */
if ((c = get()) == '#') { /* Concatenate tokens? */
while (workp > work && type[workp[-1]] == SPA)
--workp; /* Erase leading spaces */
save(SEP);
c = skipws(); /* Eat whitespace */
switch (type[c]) { /* What flavor of token */
case LET:
checkparm(c, dp); /* Save it normally */
break;
case DIG:
do { /* Stuff the digits */
save(c);
c = get();
} while (type[c] == DIG);
break;
default:
ciwarn("Strange character after # (%d.)", c);
save(c);
break;
}
save(SEP); /* Delimit 2nd token */
}
else { /* Stringize */
unget(); /* Gotta rescan it */
/*
* We store a magic cookie (which becomes " on output)
* so the macro expander doesn't block expansion
* of the actual parameter. For example,
* #define abc(a) #a
* abc(__LINE__)
* should yield "123", not "__LINE__".
* This is a hack, and probably going to cause trouble.
*/
save(ST_QUOTE);
if ((c = isformal(skipws())) == 0) {
cwarn("Expected formal parameter, got \"%s\"", token);
mtokensave(dp);
}
save(ST_QUOTE);
}
continue; /* Done with this token */
}
#endif
switch (ty