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 + -
显示快捷键?