cmac1.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,383 行 · 第 1/3 页
C
1,383 行
MACRO_ARG *macro_parms,
TOKEN_LIST *token_list,
int total,
BUFFER_HDR **h )
{
TOKEN_LIST *last_token;
char *p;
*h = TokenBufAddChar( *h, T_NULL );
if( parm_cnt < fmentry->parm_count - 1 ) {
p = CMemAlloc( total + TokenBufTotalSize( *h ) + 1 );
macro_parms[ parm_cnt ].arg = p;
if( token_list != NULL ) {
last_token = token_list;
do {
token_list = token_list->next;
p = stvcpy( p, token_list->buf, token_list->length );
} while( token_list != last_token );
RingFree( &token_list );
}
*h = TokenBufMove( *h, p );
}
}
static MACRO_ARG *collectParms( MEPTR fmentry )
{
int bracket;
TOKEN tok;
TOKEN prev_tok;
unsigned parm_cnt_plus_one;
unsigned parm_cnt_reqd;
unsigned curr_cnt;
int total;
int ppscan_mode;
MACRO_ARG *macro_parms;
TOKEN_LIST *token_head;
BUFFER_HDR *htokenbuf;
macro_parms = NULL;
parm_cnt_plus_one = fmentry->parm_count;
if( parm_cnt_plus_one != 0 ) { /* if () expected */
// () = 1, (a) = 2, (a,b) = 3
parm_cnt_reqd = parm_cnt_plus_one - 1;
ppscan_mode = InitPPScan(); // enable T_PPNUMBER tokens
htokenbuf = TokenBufInit( NULL );
if( parm_cnt_reqd > 0 ) {
macro_parms = CMemAlloc( parm_cnt_reqd * sizeof( MACRO_ARG ) );
if( fmentry->macro_flags & MACRO_HAS_VAR_ARGS )
macro_parms[parm_cnt_reqd-1].arg = NULL;
}
curr_cnt = 0;
tok = T_NULL;
do {
tok = nextMToken( tok );
} while( tok == T_WHITE_SPACE );
/* tok will now be a '(' */
bracket = 0;
token_head = NULL;
total = 0;
for( ;; ) {
prev_tok = tok;
do {
tok = nextMToken( tok );
if( tok != T_WHITE_SPACE ) break;
} while( TokenBufSize( htokenbuf ) == 0 );
if( tok == T_EOF || tok == T_NULL ) {
CErr( ERR_INCOMPLETE_MACRO, fmentry->macro_name );
InfMacroDecl( fmentry );
macroDiagNesting();
break;
}
if( tok == T_BAD_TOKEN && BadTokenInfo == ERR_MISSING_QUOTE ) {
CErr1( ERR_MISSING_QUOTE );
InfMacroDecl( fmentry );
macroDiagNesting();
tok = T_RIGHT_PAREN;
}
if( tok == T_LEFT_PAREN ) {
++bracket;
} else if( tok == T_RIGHT_PAREN ) {
if( bracket == 0 ) break;
--bracket;
} else if( tok == T_COMMA && bracket == 0 &&
( !( ( fmentry->macro_flags & MACRO_HAS_VAR_ARGS ) &&
curr_cnt == fmentry->parm_count - 2 ) ) ) {
TokenBufRemoveWhiteSpace( htokenbuf );
if( macro_parms != NULL ) { // if expecting parms
saveParm( fmentry, curr_cnt, macro_parms, token_head,
total, &htokenbuf );
}
++curr_cnt;
token_head = NULL;
total = 0;
continue;
}
switch( tok ) {
case T_WHITE_SPACE:
if( prev_tok != T_WHITE_SPACE ) {
htokenbuf = TokenBufAddWhiteSpace( htokenbuf, tok );
}
break;
case T_BAD_CHAR:
htokenbuf = TokenBufAddChar( htokenbuf, tok );
htokenbuf = TokenBufAddChar( htokenbuf, Buffer[0] );
if( Buffer[1] != '\0' ) {
htokenbuf = TokenBufAddWhiteSpace( htokenbuf, T_WHITE_SPACE );
}
break;
case T_CONSTANT:
case T_PPNUMBER:
case T_STRING:
case T_LSTRING:
case T_ID:
case T_UNEXPANDABLE_ID:
case T_BAD_TOKEN:
htokenbuf = TokenBufAddChar( htokenbuf, tok );
htokenbuf = TokenBufAddStr( htokenbuf, Buffer );
break;
default :
htokenbuf = TokenBufAddChar( htokenbuf, tok );
break;
}
}
TokenBufRemoveWhiteSpace( htokenbuf );
if( macro_parms != NULL ) { // if expecting parms
saveParm( fmentry, curr_cnt, macro_parms,
token_head, total, &htokenbuf );
++curr_cnt;
} else if( TokenBufSize( htokenbuf ) + total != 0 ) {
++curr_cnt;
}
if( ( ( fmentry->macro_flags & MACRO_HAS_VAR_ARGS ) &&
( curr_cnt < parm_cnt_reqd - 1 ) )
||( !(fmentry->macro_flags & MACRO_HAS_VAR_ARGS ) &&
( curr_cnt < parm_cnt_reqd ) ) ) {
CErr( ERR_TOO_FEW_MACRO_PARMS, fmentry->macro_name );
InfMacroDecl( fmentry );
macroDiagNesting();
do {
htokenbuf = TokenBufAddWhiteSpace( htokenbuf, T_WHITE_SPACE );
saveParm( fmentry, curr_cnt, macro_parms, NULL, 1, &htokenbuf );
++curr_cnt;
} while( curr_cnt < parm_cnt_reqd );
} else if( !( fmentry->macro_flags & MACRO_HAS_VAR_ARGS ) &&
( curr_cnt > parm_cnt_reqd ) ) {
CErr( ANSI_TOO_MANY_MACRO_PARMS, fmentry->macro_name );
InfMacroDecl( fmentry );
macroDiagNesting();
} else if( strcmp( fmentry->macro_name, "va_start" ) == 0 ) {
if( ScopeFunctionInProgress() != NULL ) {
if( ! CurrFunctionHasEllipsis() ) {
CErr1( ERR_MUST_BE_VAR_PARM_FUNC );
macroDiagNesting();
}
}
}
FiniPPScan( ppscan_mode ); // disable T_PPNUMBER tokens
TokenBufFini( htokenbuf );
}
return( macro_parms );
}
#ifndef NDEBUG
void DumpMTokens( MACRO_TOKEN *mtok )
{
puts( "---" );
while( mtok ) {
if( mtok->token == T_MACRO_PARM ) {
printf( "%p: <macro-parm>\n", mtok );
} else {
printf( "%p: '%s'\n", mtok, mtok->data );
}
mtok = mtok->next;
}
puts( "---" );
}
void DumpNestedMacros( void )
{
NESTED_MACRO *nested;
nested = nestedMacros;
puts( "---" );
while( nested ) {
printf( "%p: %s\n", nested->fmentry, nested->fmentry->macro_name );
nested = nested->next;
}
puts( "---" );
}
#endif
static MACRO_TOKEN *buildAToken( unsigned token, char *p )
{
size_t nbytes;
MACRO_TOKEN *mtok;
nbytes = strlen( p ) + 1;
mtok = CMemAlloc( offsetof( MACRO_TOKEN, data ) + nbytes );
mtok->next = NULL;
mtok->token = token;
memcpy( mtok->data, p, nbytes );
return( mtok );
}
static MACRO_TOKEN **buildTokenOnEnd( MACRO_TOKEN **ptail, unsigned token, char *str )
{
MACRO_TOKEN *mtok;
mtok = buildAToken( token, str );
mtok->next = *ptail;
*ptail = mtok;
return( &(mtok->next) );
}
static void buildTokenAfter( MACRO_TOKEN *ptail, unsigned token, char *str )
{
MACRO_TOKEN *mtok;
mtok = buildAToken( token, str );
mtok->next = ptail->next;
ptail->next = mtok;
}
static MACRO_TOKEN *appendToken( MACRO_TOKEN *head, int token, char *data )
{
MACRO_TOKEN *tail;
MACRO_TOKEN *new_tok;
new_tok = buildAToken( token, data );
if( head == NULL ) {
head = new_tok;
} else {
tail = head;
while( tail->next != NULL ) tail = tail->next;
tail->next = new_tok;
}
return( head );
}
static int macroBeingExpanded( MEPTR fmentry )
{
NESTED_MACRO *nested;
nested = nestedMacros;
while( nested ) {
if( nested->fmentry == fmentry ) return( 1 );
if( ! nested->rescanning ) break;
nested = nested->next;
}
return( 0 );
}
static int isExpandable( MEPTR curr_mac, MACRO_TOKEN *mtok, int macro_parm )
{
int lparen;
if( curr_mac->macro_defn == 0 ) { /* if special macro */
if( ( curr_mac->parm_count == MACRO_FUNCTION )
|| ( curr_mac->parm_count == MACRO_FUNC ) ) {
if( ! _FUNCTION_expandable ) {
return( 0 );
}
}
return( 1 );
}
if( curr_mac->parm_count == 0 ) { /* if () not expected */
if( macro_parm ) {
if( macroBeingExpanded( curr_mac ) ) return( 0 );
}
return( 1 );
}
for(;;) {
if( mtok == NULL ) break;
if( mtok->token != T_WHITE_SPACE && mtok->token != T_NULL ) break;
mtok = mtok->next;
}
if( mtok != NULL ) {
if( mtok->token == T_LEFT_PAREN ) {
if( macroDepth == 1 && !macro_parm ) return( 1 );
lparen = 0;
for(;;) {
mtok = mtok->next;
if( mtok == NULL ) break;
if( mtok->token == T_LEFT_PAREN ) {
++lparen;
} else if( mtok->token == T_RIGHT_PAREN ) {
if( lparen == 0 ) return( 1 );
--lparen;
}
}
}
} else if( ! macro_parm ) {
SkipAhead();
if( CurrChar == '(' ) {
return( 1 );
} else if( CompFlags.cpp_output ) {
return( 2 );
}
}
return( 0 );
}
static MEPTR isAMacro( MACRO_TOKEN *mtok )
{
const char *s;
unsigned len;
MEPTR fmentry;
DbgStmt( ( Buffer[0] = '?' , Buffer[1] = '\0' ) );
s = mtok->data;
len = strlen( s );
fmentry = MacroLookup( s, len );
return( fmentry );
}
static MACRO_TOKEN *expandNestedMacros( MACRO_TOKEN *head, int rescanning )
{
MEPTR fmentry;
MACRO_TOKEN *mtok;
MACRO_TOKEN *toklist;
MACRO_TOKEN *old_tokenlist;
MACRO_TOKEN **ptail;
int i;
mtok = head;
ptail = &head;
++macroDepth;
#ifndef NDEBUG
if( macroDepth > 100 ) {
__trap();
}
#endif
for(;;) {
if( mtok == NULL ) break;
toklist = NULL;
if( mtok->token == T_ID ) {
// if macro and not being expanded, then expand it
// only tokens available for expansion are those in mtok list
fmentry = isAMacro( mtok );
if( fmentry != NULL ) {
if( rescanning ) {
if( macroBeingExpanded( fmentry ) ) {
mtok->token = T_UNEXPANDABLE_ID;
} else {
toklist = mtok;
while( toklist->next != NULL ) {
toklist = toklist->next;
}
toklist->next = internalTokenList;
i = isExpandable( fmentry, mtok->next, 0 );
switch( i ) {
case 0: // macro is currently not expandable
mtok->token = T_MACRO;
toklist->next = NULL;
toklist = NULL;
break;
case 1: // macro is expandable
internalTokenList = mtok->next;
if( head == mtok ) {
head = NULL;
ptail = &head;
}
CMemFree( mtok );
toklist = macroExpansion( fmentry, rescanning );
mtok = internalTokenList;
internalTokenList = NULL;
break;
case 2: // we skipped over some white space
mtok->token = T_UNEXPANDABLE_ID;
toklist->next = NULL;
buildTokenAfter( mtok, T_WHITE_SPACE, " " );
toklist = NULL;
break;
}
}
} else { // expanding a macro parm
if( isExpandable( fmentry, mtok->next, 1 ) ) {
old_tokenlist = internalTokenList;
internalTokenList = mtok->next;
if( head == mtok ) {
head = NULL;
ptail = &head;
}
CMemFree( mtok );
toklist = nestedMacroExpansion( fmentry, rescanning );
mtok = internalTokenList;
internalTokenList = old_tokenlist;
} else {
ptail = &(mtok->next);
mtok = mtok->next; // advance onto next token
}
}
} else {
mtok->token = T_SAVED_ID; // avoid rechecking this ID
ptail = &(mtok->next);
mtok = mtok->next; // advance onto next token
}
} else if( mtok->token == T_NULL ) {
toklist = mtok->next;
if( mtok->data[0] == 'Z' ) { // end of a macro
rescanning = nestedMacros->rescanning;
deleteNestedMacro();
CMemFree( mtok );
mtok = toklist;
} else { // end of a macro parm
if( toklist != NULL ) {
internalTokenList = toklist;
}
CMemFree( mtok );
mtok = NULL; // will cause us to exit
}
toklist = NULL;
} else { // advance onto next token
ptail = &(mtok->next);
mtok = mtok->next;
}
if( toklist != NULL ) { // new tokens to insert
*ptail = toklist;
if( mtok != NULL ) {
while( toklist->next != NULL ) toklist = toklist->next;
toklist->next = mtok;
}
mtok = *ptail;
} else {
// either no change, or tokens were deleted
*ptail = mtok;
}
}
for( mtok = head; mtok; mtok = mtok->next ) {
// change a temporarily unexpandable ID into an ID because it
// could become expandable in a later rescanning phase
if( mtok->token == T_MACRO ) mtok->token = T_ID;
}
--macroDepth;
return( head );
}
static MACRO_TOKEN *glue2Tokens( MACRO_TOKEN *first, MACRO_TOKEN *second )
{
MACRO_TOKEN *head;
MACRO_TOKEN **ptail;
unsigned i;
int ppscan_mode;
i = 10;
Buffer[i] = '\0';
if( first != NULL ) {
i = expandMacroToken( i, &first->token );
}
if( second != NULL ) {
i = expandMacroToken( i, &second->token );
}
ppscan_mode = InitPPScan();
ReScanInit( &Buffer[10] );
head = NULL;
ptail = &head;
for(;;) {
ReScanToken();
ptail = buildTokenOnEnd( ptail, CurToken, Buffer );
if( CompFlags.rescan_buffer_done ) break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?