mpreproc.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 2,112 行 · 第 1/4 页

C
2,112
字号
 * aborts:  if not nested
 * errors:  if elseFound
 */
{
    if( nestLevel == 0 ) {
        PrtMsg( FTL | LOC | UNMATCHED_WITH_IF, directives[D_ELSE] );
    }

    if( curNest.elseFound ) {
        PrtMsg( WRN | LOC | SKIPPING_AFTER_ELSE, directives[D_ELSE],
            directives[D_ELSE] );
        // must set these because we may not have been skipping previous block
        curNest.skip2endif = TRUE;
        curNest.skip = TRUE;
        return;
    }
    curNest.elseFound = TRUE;

    if( !curNest.skip2endif ) {
        // check we're not skipping. if !skip then we should skip the else part.
        if( !curNest.skip ) {
            // skip to the end - we've done a block in this nesting
            curNest.skip = TRUE;
            curNest.skip2endif = TRUE;
        } else {
            // we still haven't done block in this nesting, do the else portion
            curNest.skip = FALSE;
        }
    }

    if( curNest.skip ) {
        PrtMsg( DBG | INF | LOC | SKIPPING_BLOCK, directives[D_ELSE] );
    } else {
        PrtMsg( DBG | INF | LOC | ENTERING_BLOCK, directives[D_ELSE] );
    }
}


#ifdef __WATCOMC__
#pragma on (check_stack);
#endif
STATIC void doElIf( BOOLEAN (*logical)(void), enum directiveTok tok )
/********************************************************************
 * post:    skip if !logical || skip2endif
 * aborts:  if not nested
 * errors:  if elseFound
 */
{
    char    buf[MAX_DIR_LEN * 2];

    FmtStr( buf, "%s %s", directives[D_ELSE], directives[tok] );

    if( nestLevel == 0 ) {
        PrtMsg( FTL | LOC | UNMATCHED_WITH_IF, buf );
    }

    if( curNest.elseFound ) {
        PrtMsg( WRN | LOC | SKIPPING_AFTER_ELSE, buf, directives[D_ELSE] );
        // must set these because we may not have been skipping previous block
        curNest.skip2endif = TRUE;
        curNest.skip = TRUE;
        (void)eatToEOL();
        return;
    }

    if( !curNest.skip2endif ) {
        // check we're not skipping. if !skip, we should skip the else if part
        if( !curNest.skip ) {
            // skip to the end - we've done a block in this nesting
            curNest.skip = TRUE;
            curNest.skip2endif = TRUE;
            (void)eatToEOL();
        } else {
            // we still haven't done block in this nesting, try this logical.
            curNest.skip = !logical();
        }
    } else {
        (void)eatToEOL();
    }

    if( curNest.skip ) {
        PrtMsg( DBG | INF | LOC | SKIPPING_BLOCK, buf );
    } else {
        PrtMsg( DBG | INF | LOC | ENTERING_BLOCK, buf );
    }
}
#ifdef __WATCOMC__
#pragma off(check_stack);
#endif


STATIC void bangElse( void )
/***************************
 * pre:     next character of input is first after 'else' token
 * post:    atStartOfLine == EOL; skip may be modified
 * aborts:  if illegal directive
 */
{
    enum directiveTok   tok;

    tok = getPreTok();
    switch( tok ) {
    case D_BLANK:
        (void)eatToEOL();
        doElse();
        break;
    case D_IFDEF:   doElIf( ifDef,  D_IFDEF );  break;
    case D_IFEQ:    doElIf( ifEq,   D_IFEQ );   break;
    case D_IFEQI:   doElIf( ifEqi,  D_IFEQI );  break;
    case D_IFNDEF:  doElIf( ifNDef, D_IFNDEF ); break;
    case D_IF:      doElIf( ifOp,   D_IF );     break;
    case D_IFNEQ:   doElIf( ifNEq,  D_IFNEQ );  break;
    case D_IFNEQI:  doElIf( ifNEqi, D_IFNEQI ); break;
    default:
        (void)eatToEOL();
        PrtMsg( FTL | LOC | NOT_ALLOWED_AFTER_ELSE, directives[tok],
            directives[D_ELSE] );
    }
}


STATIC void bangDefine( void )
/*****************************
 * post:    atStartOfLine == EOL; macro may be defined
 * errors:  if !IsMacroName
 */
{
    char    *name;

    assert( !curNest.skip );

    name = DeMacro( MAC_PUNC );    /* decode name */

    if( !IsMacroName( name ) ) {
        (void)eatToEOL();
    } else {
        DefMacro( name );
    }
    FreeSafe( name );
}


static char *skipWhileWS( char *p )
/*********************************/
{
    while( isws( *p ) ) {
        ++p;
    }
    return( p );
}


static char *skipUntilWS( char *p )
/*********************************/
{
    while( *p != '\0' && !isws( *p ) ) {
        ++p;
    }
    return( p );
}


STATIC void bangInject( void )
/*****************************
 * !inject <text> <mac-name1> <mac-name2> ... <mac-nameN>
 * post:    atStartOfLine == EOL
 * errors:  none
 */
{
    char    *text;
    char    *contents;
    char    *end_contents;
    char    *curr;
    char    *mac_name;
    char    *value;

    assert( !curNest.skip );
    text = DeMacro( EOL );
    (void)eatToEOL();
    contents = skipWhileWS( text );
    if( *contents == '\0' ) {
        FreeSafe( text );
        return;
    }
    end_contents = skipUntilWS( contents );
    if( *end_contents == '\0' ) {
        FreeSafe( text );
        return;
    }
    *end_contents = '\0';
    curr = end_contents + 1;
    for( ;; ) {
        curr = skipWhileWS( curr );
        if( *curr == '\0' ) break;
        mac_name = curr;
        curr = skipUntilWS( curr );
        if( *curr != '\0' ) {
            *curr = '\0';
            ++curr;
        }
        if( !IsMacroName( mac_name ) ) {
            break;
        }
        UnGetCH( EOL );
        InsString( contents, FALSE );
        value = GetMacroValue( mac_name );
        if( value != NULL ) {
            InsString( " ", FALSE );
            InsString( value, TRUE );
        }
        DefMacro( mac_name );
    }
    FreeSafe( text );
}


STATIC void bangLoadDLL( void )
/******************************
 * !loaddll <cmd-name> <dll-name> [<entry-pt>]
 * post:    atStartOfLine == EOL
 * errors:  none
 */
{
    char    *text;
    char    *cmd_name;
    char    *end_cmd_name;
    char    *dll_name;
    char    *end_dll_name;
    char    *ent_name;
    char    *end_ent_name;

    assert( !curNest.skip );
    text = DeMacro( EOL );
    (void)eatToEOL();
    cmd_name = skipWhileWS( text );
    if( *cmd_name == '\0' ) {
        FreeSafe( text );
        return;
    }
    end_cmd_name = skipUntilWS( cmd_name );
    if( *end_cmd_name == '\0' ) {
        FreeSafe( text );
        return;
    }
    *end_cmd_name = '\0';
    dll_name = skipWhileWS( end_cmd_name + 1 );
    if( *dll_name == '\0' ) {
        FreeSafe( text );
        return;
    }
    end_dll_name = skipUntilWS( dll_name );
    if( *end_dll_name == '\0' ) {
        OSLoadDLL( cmd_name, dll_name, NULL );
        FreeSafe( text );
        return;
    }
    *end_dll_name = '\0';
    ent_name = skipWhileWS( end_dll_name + 1 );
    if( *ent_name == '\0' ) {
        OSLoadDLL( cmd_name, dll_name, NULL );
        FreeSafe( text );
        return;
    }
    end_ent_name = skipUntilWS( ent_name );
    if( *end_ent_name == '\0' ) {
        OSLoadDLL( cmd_name, dll_name, ent_name );
        FreeSafe( text );
        return;
    }
    *end_ent_name = '\0';
    OSLoadDLL( cmd_name, dll_name, ent_name );
    FreeSafe( text );
}


STATIC void bangUnDef( void )
/****************************
 * post:    atStartOfLine == EOL; macro may be undefined
 * errors:  if env_variable || !IsMacroName || not-defined
 */
{
    char    *name;
    char    *value;

    assert( !curNest.skip );

    name = DeMacro( MAC_PUNC );
    (void)eatToEOL();

    if( !IsMacroName( name ) ) {
        FreeSafe( name );
        return;
    }

    value = GetMacroValue( name );
    if( value == NULL ) {
        PrtMsg( WRN | LOC | TRYING_UNDEF_UNDEF, directives[D_UNDEF] );
        FreeSafe( name );
        return;
    }

    UnDefMacro( name );
    FreeSafe( name );
    FreeSafe( value );
}


STATIC char *formatLongFileName( char *text )
/*******************************************/
{
    char    *ret;
    char    *currentRet;
    char    *currentTxt;

    assert( text != NULL );
    ret = StrDupSafe( text );
    currentRet = ret;
    currentTxt = text;

    if( currentTxt[0] == DOUBLEQUOTE ) {
        ++currentTxt;
    }
    while( *currentTxt != NULLCHAR && *currentTxt != DOUBLEQUOTE ) {
        if( *currentTxt == '\\' ) {
            if( *(currentTxt + 1) == DOUBLEQUOTE ) {
                ++currentTxt;
            }
        }
        *(currentRet++) = *(currentTxt++);
    }
    *currentRet = NULLCHAR;
    if( *currentTxt == DOUBLEQUOTE ) {
        if( *(currentTxt + 1) != NULLCHAR ) {
            PrtMsg( ERR | LOC | UNABLE_TO_INCLUDE, text );
            FreeSafe( ret );
            return( NULL );
        }
    }
    return( ret );
}


STATIC void bangInclude( void )
/******************************
 * post:    atStartOfLine == EOL; maybe( new file in stream )
 * errors:  if unable to InsertFile()
 * for MS-Compatability we add <> angular bracket support to look
 *    for the file in the INCLUDE directory
 */
{
    char    *text;
    char    *temp = NULL;
#ifdef __WATCOMC__
    char    *current;
    char    full_path[_MAX_PATH];
    RET_T   ret;
#endif

    assert( !curNest.skip );

    text = DeMacro( EOL );
    (void)eatToEOL();

    chopTrailWS( text );    /* get rid of trailing ws */

#ifdef __WATCOMC__
    if( *text == LESSTHAN ) {
        current = text;
        while( *current != GREATERTHAN && *current != NULLCHAR ) {
            ++current;
        }
        if( *current == GREATERTHAN ) {
            *current = NULLCHAR;
            temp = text;
            text = formatLongFileName( temp + 1 );
            if( text == NULL ) {
                FreeSafe( temp );
                return;
            }
            for( ;; ) {
                if( *current == NULLCHAR ) {
                    _searchenv( text, INCLUDE, full_path );
                    ret = RET_ERROR;
                    if( *full_path != NULLCHAR ) {
                        ret = InsFile( full_path, FALSE );
                    }
                    if( ret == RET_ERROR ) {
                        PrtMsg( ERR | LOC | UNABLE_TO_INCLUDE, text );
                    }
                    break;
                }
                // check if there are any trailing characters if there are
                // then error
                if( !isws( *current ) ) {
                    PrtMsg( ERR | LOC | UNABLE_TO_INCLUDE, text );
                    break;
                }
                ++current;
            }
        } else {
              PrtMsg( ERR | LOC | UNABLE_TO_INCLUDE, text );
        }
    } else
#endif
    {
        temp = text;
        text = formatLongFileName( text );
        if( text == NULL ) {
            FreeSafe( temp );
            return;
        }
        if( InsFile( text, FALSE ) != RET_SUCCESS ) {
            PrtMsg( ERR | LOC | UNABLE_TO_INCLUDE, text );
        }
    }
    FreeSafe( temp );
    FreeSafe( text );
}


STATIC void bangMessage( void )
/******************************
 * post:    atStartOfLine == EOL
 */
{
    char    *text;

    assert( !curNest.skip );

    text = DeMacro( EOL );
    (void)eatToEOL();

    chopTrailWS( text );

    PrtMsg( PRNTSTR, text );
    FreeSafe( text );
}


STATIC void bangError( void )
/****************************
 * post:    atStartOfLine == EOL
 */
{
    char    *text;

    assert( !curNest.skip );

    text = DeMacro( EOL );
    (void)eatToEOL();

    chopTrailWS( text );

    PrtMsg( ERR | LOC | NEOL | USER_ERROR );
    PrtMsg( ERR | PRNTSTR, text );
    FreeSafe( text );
}


STATIC void handleBang( void )
/*****************************
 * post:    atStartOfLine == EOL
 */
{
    enum directiveTok   tok;

    tok = getPreTok();
    /* these are executed regardless of skip */
    switch( tok ) {
    case D_BLANK:   (void)eatToEOL();           break;
    case D_ELSE:    bangElse();                 break;
    case D_ENDIF:   bangEndIf();                break;
    case D_IF:      bangIf( ifOp,   D_IF );     break;
    case D_IFDEF:   bangIf( ifDef,  D_IFDEF );  break;
    case D_IFEQ:    bangIf( ifEq,   D_IFEQ );   break;
    case D_IFEQI:   bangIf( ifEqi,  D_IFEQI );  break;
    case D_IFNDEF:  bangIf( ifNDef, D_IFNDEF ); break;
    case D_IFNEQ:   bangIf( ifNEq,  D_IFNEQ );  break;
    case D_IFNEQI:  bangIf( ifNEqi, D_IFNEQI ); break;
    default:
        if( !curNest.skip ) {
            /* these are only executed if !skip */
            switch( tok ) {
            case D_DEFINE:  bangDefine();       break;
            case D_ERROR:   bangError();        break;
            case D_MESSAGE: bangMessage();      break;
            case D_INCLUDE: bangInclude();      break;
            case D_INJECT:  bangInject();       break;
            case D_LOADDLL: bangLoadDLL();      break;
            case D_UNDEF:   bangUnDef();        break;
            default:
                break;
            }
        } else {
            (void)eatToEOL(); /* otherwise, we just eat it up */
        }
    }
}


static int PreTestString( const char *str )
/******************************************
 * Test if 'str' is the next sequence of characters in stream.
 * If not, push back any characters read.
 */
{
    const char  *s = str;
    STRM_T      t;
    int         rc = FALSE;

    for( ;; ) {
        t = GetCHR();
        if( t != *s ) {
            UnGetCH( t );
            while( s-- > str ) {
                UnGetCH( *s );
            }
            break;
        }
        ++s;
        if( *s == '\0' ) {
            rc = TRUE;
            break;
        }
    }
    return( rc );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?