macros.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,398 行 · 第 1/3 页
C
1,398 行
space = 0;
t = v;
for( p = v; *p != '\0'; ++p ) {
if( !isws( *p ) ) {
if( space ) {
*t = ' ';
++t;
}
*t = *p;
++t;
space = 0;
} else {
space = 1;
}
}
*t = '\0';
return( v );
}
#ifdef __WATCOMC__
#pragma on (check_stack);
#endif
STATIC void addMacro( const char *name, char *value )
/****************************************************
* post: new macro possibly allocated, copy of name made
*/
{
char macro[MAX_MAC_NAME];
MACRO *new;
assert( *name != ENVVAR );
value = trimMacroValue( value );
makeMacroName( macro, name ); // Does assert( IsMacroName( name ) );
new = getMacroNode( macro ); /* check if redefinition */
if( new != NULL && !new->readonly ) { /* reuse old node */
FreeSafe( (void *)new->value );
new->value = value;
new->readonly = Glob.macreadonly;
} else if( new == NULL ) {
new = MallocSafe( sizeof( *new ) ); /* get memory for new node */
new->node.name = StrDupSafe( macro );
AddHashNode( macTab, (HASHNODE *)new );
new->value = value;
new->readonly = Glob.macreadonly;
} else {
FreeSafe( value ); /* read only macro - don't change */
}
}
#ifdef __WATCOMC__
#pragma off(check_stack);
#endif
extern BOOLEAN IsMacroName( const char *inName )
/***********************************************
* returns: TRUE if name is a valid macro name, otherwise FALSE and print
* an error message
*/
{
char const *current = inName;
int pos = 0;
assert( inName != NULL );
while( pos < MAX_MAC_NAME && *current != NULLCHAR && *current != COLON ) {
if( !ismacc( *current ) ) {
PrtMsg( ERR | LOC | INVALID_MACRO_NAME, inName );
return( FALSE );
}
pos++, current++;
}
if( pos == 0 ) {
PrtMsg( ERR | LOC | INVALID_MACRO_NAME, inName );
return( FALSE );
}
if( pos >= MAX_MAC_NAME ) {
PrtMsg( ERR | LOC | MAXIMUM_TOKEN_IS, MAX_MAC_NAME - 1 );
return( FALSE );
}
return( TRUE );
}
#ifdef __WATCOMC__
#pragma on (check_stack);
#endif
extern void UnDefMacro( const char *name )
/*****************************************
* pre: IsMacroName( name ); getMacroNode( name ) != NULL
* post: MACRO node deallocated
*/
{
char macro[MAX_MAC_NAME];
MACRO *dead;
makeMacroName( macro, name ); // Does assert( IsMacroName( name ) );
if( *macro == ENVVAR ) {
ENV_TRACKER *env;
env = MallocSafe( sizeof( ENV_TRACKER ) + strlen( macro ) + 1 );
FmtStr( env->value, "%s=", macro + 1 );
PutEnvSafe( env );
return;
}
dead = (MACRO *)RemHashNode( macTab, macro, TRUE );
assert( dead != NULL );
FreeSafe( dead->node.name );
FreeSafe( (void *)dead->value );
FreeSafe( dead );
}
#ifdef __WATCOMC__
#pragma off(check_stack);
#endif
extern char *WrnGetMacroValue( const char *name )
/***********************************************/
{
const char *p;
p = GetMacroValue( name );
if( p == NULL ) {
PrtMsg( DBG | WRN | LOC | MACRO_UNDEFINED, name ); /* 13-Dec-90 DJG */
// we did this to minimize the number of debugging messages but
// it causes problems when it defines a macro for the user
//UnGetCH( EOL );
//DefMacro( name ); /* 12-jul-93 AFS */
}
return( (char *)p );
/* note we return NULL if it was undefined! */
}
extern char *DeMacroSpecial( char *InString)
/*******************************************
* This function is to specially handle the special macros
* in the dependencies
*/
{
char *old;
char *current;
VECSTR outString;
char *tempString;
char buffer[6];
int pos;
assert( InString != NULL );
current = InString;
old = InString;
outString = StartVec();
while( *current != NULLCHAR ) {
if( *current == SPECIAL_TMP_DOL_C ) {
CatNStrToVec( outString, old, current - old );
pos = 0;
UnGetCH( STRM_MAGIC );
buffer[pos++] = *(current++);
if( ismsspecial( *current ) && !ismsmodifier( *(current + 1) ) ) {
buffer[pos++] = *(current++);
} else {
assert( ismsspecial( *current ) );
buffer[pos++] = *(current++);
if( ismsmodifier( *current ) ) {
buffer[pos++] = *(current++);
}
}
old = current;
buffer[pos] = NULLCHAR;
InsString( buffer, FALSE );
tempString = DeMacro( STRM_MAGIC );
PreGetCH(); // eat STRM_MAGIC
CatStrToVec( outString, tempString );
FreeSafe( tempString);
}
++current;
}
CatNStrToVec( outString, old, current - old + 1 );
return( FinishVec( outString ) );
}
/*
* end1 is what the caller passed to DeMacro - it is pushed back into the
* input stream.
* end2 is for our own purposes
*
* deMacroText calls deMacroToEnd, and deMacroToEnd might call deMacroText.
*
* deMacroToEnd does a single pass of substitution. It calls deMacroText to
* handle constructs such as $(text); thus allowing $(text$(subtext)). All
* other constructs are written with their current value.
*
* deMacroText scans the string that deMacroToEnd returned for DOLLARs. If
* it doesn't find one it returns the string. If a DOLLAR is found, a
* STRM_MAGIC is pushed, the string is pushed, and deMacroToEnd is called
* again (ending at STRM_MAGIC). This process is repeated until no DOLLARs
* remain.
*
* This pair always stops at EOL, STRM_MAGIC, or STRM_END.
*
* Note that if a MAC_PUNC is passed for one of the end tokens, it is
* assumed to imply MAC_WS as well. This is used in mpreproc.c to find the
* end of a macro name for things such as !ifdef, !undef, etc.
*/
STATIC char *deMacroText( int depth, TOKEN_T end1, TOKEN_T end2 );
STATIC char *ProcessToken( int depth, TOKEN_T end1, TOKEN_T end2, TOKEN_T t )
/****************************************************************************
* Processes the tokens returned from lexToken in deMacroToEnd
*/
{
STRM_T temp;
char temp_str[2];
char macname[MAX_TOK_SIZE];
int pos;
char *p;
char *p2;
char const *cp2;
switch( t ) {
case MAC_START: /* recurse, get macro name */
/*
* in microsoft nmake and in POSIX mode,
* $HELLO is considered as $(H)ELLO
* if there are no parentheses then it takes only first char.
* after the $
*/
if( !Glob.microsoft && !Glob.posix ) {
p = deMacroText( depth + 1, end1, MAC_PUNC );
} else {
temp = PreGetCH ();
if( ismacc( temp ) ) {
temp_str[1] = NULLCHAR;
temp_str[0] = temp;
p = StrDupSafe( temp_str );
} else {
p = StrDupSafe( "" );
}
}
if( IsMacroName( p ) ) {
p2 = WrnGetMacroValue( p );
FreeSafe( p );
if( p2 != NULL ) {
return( p2 );
}
return( NULL );
}
FreeSafe( p );
break;
case MAC_DOLLAR:
return( StrDupSafe( TMP_DOL_S ) ); /* write a place holder */
case MAC_COMMENT:
return( StrDupSafe( TMP_COMMENT_S ) ); /* write a place holder */
case MAC_OPEN: /* recurse, get macro name */
if( !Glob.microsoft && !Glob.posix ) {
p = deMacroText( depth + 1, end1, MAC_CLOSE );
if( IsMacroName( p ) ) {
p2 = WrnGetMacroValue( p );
FreeSafe( p );
if( p2 != NULL ) {
return( p2 );
}
return( NULL );
}
FreeSafe( p );
} else {
pos = 0;
temp = PreGetCH();
if( ismsspecial( temp ) ) {
UnGetCH( temp );
// This is to invoke LexDollar
t = LexToken( LEX_MS_MAC );
// This is the only time to get the modifier
GetModifier();
p = ProcessToken( depth, end1, end2, t );
temp = PreGetCH();
if( temp != ')' ) {
PrtMsg( ERR | LOC | ILLEGAL_CHARACTER_IN_MAC, temp );
break;
}
return( p );
} else {
for( ;; ) {
if( temp == ')' ) {
break;
} else if( temp == STRM_MAGIC ||
temp == STRM_END ||
temp == EOL ) {
UnGetCH( temp );
break;
}
if( pos < MAX_TOK_SIZE -1 ) {
macname[pos++] = temp;
}
temp = PreGetCH();
}
macname[pos] = NULLCHAR;
if( IsMacroName( macname ) ) {
p2 = WrnGetMacroValue( macname );
if( p2 != NULL ) {
return( p2 );
}
return( NULL );
}
}
}
break;
case MAC_EXPAND_ON: /* fall through */
case MAC_EXPAND_OFF:
/* do nothing */
break;
case MAC_CUR: /* fall through */
case MAC_FIRST:
case MAC_LAST:
/* static pointer returned so we need to duplicate string */
cp2 = specialValue( t );
if( cp2 != NULL ) {
return( StrDupSafe( cp2 ) );
}
return( NULL );
case MAC_ALL_DEP:
p = GetCurDeps( FALSE, FALSE );
massageDollarOctothorpe( p );
return( p );
case MAC_INF_DEP:
p = GetCurDeps( FALSE, TRUE );
massageDollarOctothorpe( p );
return( p );
case MAC_YOUNG_DEP:
p = GetCurDeps( TRUE, FALSE );
massageDollarOctothorpe( p );
return( p );
case MAC_NAME: /* fall through */
case MAC_WS:
case MAC_PUNC:
p = CurAttr.ptr;
CurAttr.ptr = NULL;
return( p );
default:
#ifdef DEVELOPMENT
PrtMsg( FTL | LOC | INVALID_TOKEN_IN, t, "deMacroToEnd()" );
#else
PrtMsg( WRN | LOC | IGNORE_OUT_OF_PLACE_M, M_UNKNOWN_TOKEN );
break;
#endif
}
return( NULL );
}
STATIC char *deMacroToEnd( int depth, TOKEN_T end1, TOKEN_T end2 )
/*****************************************************************
* post: 0 or more characters removed from input; next character of
* input is STRM_END || STRM_MAGIC || EOL || end1 || end2
* returns: pointer to demacro'd string (caller must FreeSafe)
*/
{
TOKEN_T t;
VECSTR vec; /* we build expansion here */
char *p; /* temp str */
assert( end1 == EOL
|| end1 == MAC_PUNC
|| end1 == STRM_MAGIC
|| end1 == STRM_END
|| end1 == MAC_WS
);
assert( end2 == EOL
|| end2 == MAC_PUNC
|| end2 == STRM_MAGIC
|| end2 == STRM_END
|| end2 == MAC_EXPAND_OFF
|| end2 == MAC_CLOSE
);
vec = StartVec();
for( ;; ) {
t = LexToken( LEX_MAC_SUBST );
assert( t != MAC_TEXT ); /* should never recv this tok */
if( t == MAC_CLOSE && end2 != MAC_CLOSE ) {
t = MAC_PUNC;
CurAttr.ptr = StrDupSafe( ")" );
}
if( t == STRM_END /* always stops at these */
|| t == STRM_MAGIC
|| t == EOL
|| t == end2
|| t == end1
|| ( t == MAC_WS && ( end2 == MAC_PUNC || end1 == MAC_PUNC ) )
) {
break;
}
p = ProcessToken( depth, end1, end2, t );
if( p != NULL ) {
CatStrToVec( vec, p );
FreeSafe( p );
}
}
/* put back the token we demacro'd until */
switch( t ) {
case MAC_PUNC:
case MAC_WS:
InsString( CurAttr.ptr, TRUE );
break;
case EOL: /* fall through */
case STRM_END:
case STRM_MAGIC:
UnGetCH( t );
break;
}
return( FinishVec( vec ) );
}
STATIC char *deMacroText( int depth, TOKEN_T end1, TOKEN_T end2 )
/****************************************************************
* post: same as deMacroToEnd
* returns: same as deMacroToEnd
*/
{
char *result;
char *p;
if( depth > MAX_MAC_NEST ) {
PrtMsg( FTL | LOC | CANNOT_NEST_FURTHER );
}
result = deMacroToEnd( depth, end1, end2 );
while( strchr( result, DOLLAR ) != NULL ) {
UnGetCH( STRM_MAGIC );
InsString( result, TRUE );
++depth;
if( depth > MAX_MAC_NEST ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?