engine/source/preprocessorlib/pp_parser.c
/**
 * Defines a macro specified with the #define directive.
 * The length of the contents is limited to MACRO_CONTENTS_SIZE (512) characters.
 * @param name the macro name
 */
Defines a macro specified with the #define directive.
The length of the contents is limited to MACRO_CONTENTS_SIZE (512) characters.
@param name the macro name
Defines a macro specified with the #define directive . The length of the contents is limited to MACRO_CONTENTS_SIZE ( 512 ) characters . @param name the macro name
HRESULT pp_parser_define(pp_parser *self, char *name)
{
    char *contents = NULL;
    bool is_function = false; 
    List *params = malloc(sizeof(List));
    List_Init(params);
    if(!strcmp(name, "defined"))
    {
        pp_error(self, "'defined' can't be defined as a macro");
        goto error;
    }
    if(pp_is_builtin_macro(name))
    {
        pp_error(self, "'%s' is a builtin macro and cannot be redefined", name);
        goto error;
    }
    if(List_FindByName(&self->ctx->macros, name))
    {
        pp_warning(self, "'%s' redefined (previously \"%s\")", name, List_Retrieve(&self->ctx->macros));
        free(List_Retrieve(&self->ctx->macros));
        List_Remove(&self->ctx->macros);
    }
    if(List_FindByName(&self->ctx->func_macros, name))
    {
        List *params2 = List_Retrieve(&self->ctx->func_macros);
        List_GotoLast(params2);
        pp_warning(self, "'%s' redefined (previously \"%s\")", name, List_Retrieve(params2));
        List_Reset(params2);
        while(params2->size > 0)
        {
            free(List_Retrieve(params2));
            List_Remove(params2);
        }
        List_Clear(params2);
        free(params2);
        List_Remove(&self->ctx->func_macros);
    }
    if(FAILED(pp_parser_lex_token(self, false)))
    {
        goto error;
    }
    if(self->token.theType == PP_TOKEN_LPAREN) 
    {
        is_function = true;
        if(FAILED(pp_parser_lex_token(self, true)))
        {
            goto error;
        }
        while(self->token.theType != PP_TOKEN_RPAREN)
        {
            switch(self->token.theType)
            {
            case PP_TOKEN_IDENTIFIER:
            case PP_TOKEN_INCLUDE:
            case PP_TOKEN_DEFINE:
            case PP_TOKEN_UNDEF:
            case PP_TOKEN_IFDEF:
            case PP_TOKEN_IFNDEF:
            case PP_TOKEN_ELIF:
            case PP_TOKEN_ENDIF:
            case PP_TOKEN_PRAGMA:
            case PP_TOKEN_DEFINED:
            case PP_TOKEN_WARNING:
            case PP_TOKEN_ERROR_TEXT:
                List_InsertAfter(params, NULL, self->token.theSource);
                if(FAILED(pp_parser_lex_token(self, true)))
                {
                    goto error;
                }
                if(self->token.theType == PP_TOKEN_COMMA || self->token.theType == PP_TOKEN_RPAREN)
                {
                    break;
                }
            default:
                return pp_error(self, "unexpected token '%s' in #define parameter list", self->token.theSource);
            }
            if(self->token.theType != PP_TOKEN_RPAREN)
            {
                pp_parser_lex_token(self, true);
            }
        }
        self->overread = false;
    }
    else
    {
        self->overread = true;
    }
    contents = malloc(MACRO_CONTENTS_SIZE);
    contents[0] = '\0';
    if(FAILED(pp_parser_readline(self, contents, MACRO_CONTENTS_SIZE)))
    {
        goto error;
    }
    if(is_function)
    {
        List_InsertAfter(params, contents, NULL);
        List_InsertAfter(&self->ctx->func_macros, params, name);
    }
    else
    {
        free(params);
        List_InsertAfter(&self->ctx->macros, contents, name);
    }
    return S_OK;
error:
    List_Reset(params);
    while(List_GetSize(params))
    {
        List_Remove(params);
    }
    free(params);
    if(contents)
    {
        free(contents);
    }
    return E_FAIL;
}
HRESULT pp_parser_define ( pp_parser * self , char * name ) { char * contents = NULL ; bool is_function = false ; List * params = malloc ( sizeof ( List ) ) ; List_Init ( params ) ; if ( ! strcmp ( name , " " ) ) { pp_error ( self , " " ) ; goto error ; } if ( pp_is_builtin_macro ( name ) ) { pp_error ( self , " " , name ) ; goto error ; } if ( List_FindByName ( & self -> ctx -> macros , name ) ) { pp_warning ( self , " \" \" " , name , List_Retrieve ( & self -> ctx -> macros ) ) ; free ( List_Retrieve ( & self -> ctx -> macros ) ) ; List_Remove ( & self -> ctx -> macros ) ; } if ( List_FindByName ( & self -> ctx -> func_macros , name ) ) { List * params2 = List_Retrieve ( & self -> ctx -> func_macros ) ; List_GotoLast ( params2 ) ; pp_warning ( self , " \" \" " , name , List_Retrieve ( params2 ) ) ; List_Reset ( params2 ) ; while ( params2 -> size > 0 ) { free ( List_Retrieve ( params2 ) ) ; List_Remove ( params2 ) ; } List_Clear ( params2 ) ; free ( params2 ) ; List_Remove ( & self -> ctx -> func_macros ) ; } if ( FAILED ( pp_parser_lex_token ( self , false ) ) ) { goto error ; } if ( self -> token . theType == PP_TOKEN_LPAREN ) { is_function = true ; if ( FAILED ( pp_parser_lex_token ( self , true ) ) ) { goto error ; } while ( self -> token . theType != PP_TOKEN_RPAREN ) { switch ( self -> token . theType ) { case PP_TOKEN_IDENTIFIER : case PP_TOKEN_INCLUDE : case PP_TOKEN_DEFINE : case PP_TOKEN_UNDEF : case PP_TOKEN_IFDEF : case PP_TOKEN_IFNDEF : case PP_TOKEN_ELIF : case PP_TOKEN_ENDIF : case PP_TOKEN_PRAGMA : case PP_TOKEN_DEFINED : case PP_TOKEN_WARNING : case PP_TOKEN_ERROR_TEXT : List_InsertAfter ( params , NULL , self -> token . theSource ) ; if ( FAILED ( pp_parser_lex_token ( self , true ) ) ) { goto error ; } if ( self -> token . theType == PP_TOKEN_COMMA || self -> token . theType == PP_TOKEN_RPAREN ) { break ; } default : return pp_error ( self , " " , self -> token . theSource ) ; } if ( self -> token . theType != PP_TOKEN_RPAREN ) { pp_parser_lex_token ( self , true ) ; } } self -> overread = false ; } else { self -> overread = true ; } contents = malloc ( MACRO_CONTENTS_SIZE ) ; contents [ 0 ] = ' \0 ' ; if ( FAILED ( pp_parser_readline ( self , contents , MACRO_CONTENTS_SIZE ) ) ) { goto error ; } if ( is_function ) { List_InsertAfter ( params , contents , NULL ) ; List_InsertAfter ( & self -> ctx -> func_macros , params , name ) ; } else { free ( params ) ; List_InsertAfter ( & self -> ctx -> macros , contents , name ) ; } return S_OK ; error : List_Reset ( params ) ; while ( List_GetSize ( params ) ) { List_Remove ( params ) ; } free ( params ) ; if ( contents ) { free ( contents ) ; } return E_FAIL ; }
Defines a macro specified with the #define directive.
Defines a macro specified with the #define directive .
// true if this is a function-style #define; false otherwise // emit an error if the macro is already defined // emit a warning if the macro is already defined // note: this won't mess with function macro parameters since #define can't be used from inside a macro // do NOT skip whitespace here - the '(' must come immediately after the name! // function-style #define // All of the below types are technically valid macro names // Read macro contents // Add macro to the correct list, either macros or func_macros