macro.c

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

C
681
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  maro processing routines
*
****************************************************************************/


#define     PLACEHOLDER_SIZE 3      /* for #dd - number sign, digit, digit */

#include "asmglob.h"
#include <ctype.h>

#include "asmalloc.h"
#include "asmins.h"
#include "asmdefs.h"
#include "asmeval.h"
#include "asmexpnd.h"
#include "directiv.h"
#include "asminput.h"

#include "myassert.h"

extern bool             GetQueueMacroHidden( void );

extern  int_8           DefineProc;     // TRUE if the definition of procedure
                                        // has not ended
extern int              MacroLocalVarCounter;

int                     MacroExitState = 0;

/* quick explanation:
 *
 * there are 2 entry points into this module:
 * MacroDef & ExpandMacro
 * MacroDef is called by asmins.c to define a macro
 * ExpandMacro is called by asmline to check if something is a macro, and
 * expand it if that is the case
 */

static asmlines *asmline_insert( asmlines **head, void *data )
/************************************************************/
{
    asmlines *entry;
    asmlines **ptr;

    /* get a pointer to the last next ptr ( or Head if empty ) */
    for( ptr = head; *ptr; ptr = &((*ptr)->next) );

    entry = AsmAlloc( sizeof( asmlines ) );
    entry->next = NULL;
    entry->line = AsmAlloc( strlen( data ) + 1 );
    entry->parmcount = 0;
    strcpy( entry->line, data );
    *ptr = entry;
    return( entry );
}

static char *replace_parm( parm_list *parms, char *start, char len, asmlines *lstruct )
/*************************************************************************************/
{
    /* search through parm list for word pointed at by start,
     * if you find it, set up the line string
     * this is similar to a printf format string
     * the placeholders are of the form #dd ( #, digit, digit )
     * this allows up to 100 parameters - lots :)
     * fixme - this max. should be docmented & checked for.
     */
    char            buffer[10];
    parm_list       *p;
    char            *new_line;
    char            *old_line;
    char            before;             // length of text before placeholder
    char            count = 0;

    old_line = lstruct->line;
    for( p = parms; p != NULL; p = p->next ) {
        if( ( p->label != NULL ) && ( strlen( p->label ) == len ) &&
            ( strncmp( start, p->label, len ) == 0 ) ) {
            /* hey! it matches! */

            new_line = AsmAlloc( strlen(old_line) - len + PLACEHOLDER_SIZE +1 );
            before = start - old_line;
            if( *(start-1) == '&' ) before--;
            strncpy( new_line, old_line, before );
            *(new_line+before) = '\0';
            strcat( new_line, "#" );
            if( sprintf(buffer,"%2d", count ) != 2 ) {
                myassert( 0 );
            }
            if( buffer[0] == ' ' ) buffer[0]='0'; /* no spaces */
            strcat( new_line, buffer );
            if( *(start+len) == '&' ) len++;
            strcat( new_line, start+len );
            lstruct->line = new_line;
            lstruct->parmcount++;

            AsmFree( old_line );

            return( new_line + before + PLACEHOLDER_SIZE );  /* ptr to char after #dd */
        }
        count++;
    }
    return( start+len );
}

#define is_valid_id_char( ch ) \
    ( isalpha(ch) || isdigit(ch) || ch=='_' || ch=='@' || ch=='$' || ch=='?' )

static void put_parm_placeholders_in_line( asmlines *linestruct, parm_list *parms )
/*********************************************************************************/
{
    char *line;
    char *tmp;
    char *start;
    char quote = FALSE;
    char len;

    /* handle the substitution operator ( & ) */
    line = linestruct->line;
    for( tmp = line; *tmp != '\0'; ) {
        /* scan across the string for space, &, " - to start a word */
        line = tmp;
        for( ; *tmp != '\0'; tmp++ ) {
            if( is_valid_id_char( *tmp ) ) {
                if( tmp == line ) break; /* ok to start at beginning of line */
                continue;
            } else if( isspace( *tmp ) ) {
                /* find 1st non blank char */
                while( isspace( *tmp ) ) tmp++;
                break;
            } else if( *tmp == '"' ) {
                /* toggle the quote flag */
                quote = ( quote + 1 ) %2;
                tmp++;
                break;
            } else {
                /* some other garbage */
                tmp++;
                break;
            }
        }
        start = tmp;
        /* scan across the string for space, &, " - to end the word */
        for( ; *tmp != '\0'; tmp++ ) {
            if( is_valid_id_char( *tmp ) ) {
                continue;
            } else if( isspace( *tmp ) ) {
                break;
            } else if( *tmp == '"' ) {
                /* toggle the quote flag */
                quote = ( quote + 1 ) %2;
                break;
            } else {
                break;
            }
        }
        len = tmp - start;
        /* look for this word in the macro parms, and replace it if it is */
        /* this would change line - it will have to be reallocated */
        if( !quote || *start =='&' || *(start-1)=='&' || *(start+len+1)=='&' ) {
            if( *start != '\0' && len > 0 ) {
                tmp = replace_parm( parms, start, len, linestruct );
            }
        }
    }
}

static int_8 lineis( char *str, char *substr )
/********************************************/
{
    int len;

    len = strlen( substr );
    wipe_space( str );
    if( strnicmp( str, substr, len ) ) {
        return( FALSE );
    }
    if( str[len] != '\0' && !isspace( str[len] ) ) {
        return( FALSE );
    }
    return( TRUE );
}

static int macro_local( void )
/****************************/
{
    /* take a line that looks like  LOCAL varname [, varname * ] */

    int i = 0;
    char buffer[MAX_LINE_LEN];

    if( AsmBuffer[i]->value != T_LOCAL ) {
        AsmError( SYNTAX_ERROR );
        return( ERROR );
    }

    PushLineQueue();
    for( i++; AsmBuffer[i]->token != T_FINAL; i++ ) {
        /* define an equ to expand the specified variable to a temp. name */
        if( AsmBuffer[i]->token != T_ID ) {
            AsmError( OPERAND_EXPECTED );
            return( ERROR );
        }
        strcpy( buffer, AsmBuffer[i]->string_ptr );
        strcat( buffer, " TEXTEQU " );
        sprintf( buffer + strlen( buffer ), "??%#04d", MacroLocalVarCounter );
        MacroLocalVarCounter++;
        InputQueueLine( buffer );
        i++;
        if( AsmBuffer[i]->token == T_FINAL ) break;
        /* now skip the comma */
        if( AsmBuffer[i]->token != T_COMMA ) {
            AsmError( EXPECTING_COMMA );
            return( ERROR );
        }
    }
    return( NOT_ERROR );
}


static int macro_exam( int i )
/****************************/
{
    macro_info          *info;
    char                *string;
    char                *token;
    char                *name;
    parm_list           *paranode;
    parm_list           *paracurr;
    asmlines            *linestruct;
    char                buffer[ MAX_LINE_LEN ];
    dir_node            *dir;
    uint                nesting_depth = 0;
    bool                store_data;

    name = AsmBuffer[i++]->string_ptr;
    dir = (dir_node *)AsmGetSymbol( name );
    info = dir->e.macroinfo;

    store_data = Parse_Pass == PASS_1 || info->data == NULL;

    /* go past "MACRO" */
    i++;

    if( store_data ) {
        for( ; i < Token_Count ; ) {
            token = AsmBuffer[i]->string_ptr;
            paranode = AsmAlloc( sizeof( parm_list ) );
            paranode->def = NULL;
            paranode->replace = NULL;
            paranode->required = FALSE;

            /* first get the parm. name */
            paranode->label = AsmAlloc( strlen( token ) + 1 );
            strcpy( paranode->label, token );
            i++;

            /* now see if it has a default value or is required */
            if( AsmBuffer[i]->token == T_COLON ) {
                i++;
                if( *AsmBuffer[i]->string_ptr == '=' ) {
                    i++;
                    if( AsmBuffer[i]->token != T_STRING ) {
                        AsmError( SYNTAX_ERROR );
                        return( ERROR );
                    }
                    token = AsmBuffer[i]->string_ptr;
                    paranode->def = AsmAlloc( strlen( token ) + 1 );
                    strcpy( paranode->def, token );
                    i++;
                } else if( strcmp( AsmBuffer[i]->string_ptr, "REQ" ) == 0 ) {
                    /* required parameter */
                    paranode->required = TRUE;
                    i++;
                }
            }
            if( i< Token_Count && AsmBuffer[i]->token != T_COMMA ) {
                AsmError( EXPECTING_COMMA );
                return( ERROR );
            }
            /* go past comma */
            i++;

            /* add this parm node to the list */
            // fixme
            paranode->next = NULL;
            if( info->parmlist == NULL ) {
                info->parmlist = paranode;
            } else {
                for( paracurr = info->parmlist;; paracurr = paracurr->next ) {
                    if( paracurr->next == NULL ) break;
                }
                paracurr->next = paranode;
            }

        } /* looping through parameters */
    }

    /* now read in all the contents of the macro, and store them */
    for( ; ; ) {
        char *ptr;

        string = ReadTextLine( buffer );
        if( string == NULL ) {
            AsmError( UNEXPECTED_END_OF_FILE );
            return( ERROR );
        } else if( lineis( string, "endm" ) ) {
            if( nesting_depth ) {
                nesting_depth--;
            } else {
                return( NOT_ERROR );
            }
        }
        ptr = string;
        while( isspace( *ptr ) ) ptr++;
        if( lineis( ptr, "for" )
         || lineis( ptr, "forc" )

⌨️ 快捷键说明

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