engine/source/preprocessorlib/pp_parser.c
/**
 * Expands a macro.
 * Pre: the macro is defined in func_macros
 * Pre: the last token retrieved was a PP_TOKEN_LPAREN
 */
Expands a macro.
Pre: the macro is defined in func_macros
Pre: the last token retrieved was a PP_TOKEN_LPAREN
Expands a macro . Pre : the macro is defined in func_macros Pre : the last token retrieved was a PP_TOKEN_LPAREN
HRESULT pp_parser_insert_function_macro(pp_parser *self, char *name)
{
    int numParams, paramCount = 0, paramMacros = 0, parenLevel = 0, type;
    List* params, *paramDefs; 
    char paramBuffer[1024] = "", *tail;
    if(strcmp((char *)List_Retrieve(&self->ctx->func_macros), name))
    {
        List_FindByName(&self->ctx->func_macros, name);
    }
    params = List_Retrieve(&self->ctx->func_macros);
    numParams = List_GetSize(params) - 1;
    paramDefs = malloc(sizeof(List));
    List_Init(paramDefs);
    List_Reset(params);
    List_Reset(&self->ctx->macros);
    do
    {
        if(FAILED(pp_parser_lex_token_essential(self, false)))
        {
            return E_FAIL;
        }
        type = self->token.theType;
        bool write = false;
        switch(type)
        {
        case PP_TOKEN_NEWLINE:
            if(paramBuffer[0] != '\0')
            {
                return pp_error(self, "unexpected newline in parameter list for function '%s'", name);
            }
        case PP_TOKEN_EOF:
            return pp_error(self, "unexpected end of file in parameter list for function '%s'", name);
        case PP_TOKEN_LPAREN:
            parenLevel++;
            write = true;
            break;
        case PP_TOKEN_RPAREN:
            parenLevel--;
        case PP_TOKEN_COMMA:
            if(type == PP_TOKEN_RPAREN || parenLevel > 0)
            {
                write = true;
                if(parenLevel >= 0)
                {
                    break;
                }
            }
            tail = strchr(paramBuffer, '\0');
            while(--tail >= paramBuffer)
            {
                if(*tail == ' ' || *tail == '\t' || *tail == '\n' || *tail == '\r')
                {
                    *tail = '\0';
                }
                else
                {
                    break;
                }
            }
            if(type == PP_TOKEN_RPAREN && paramCount == 0 && paramBuffer[0] == '\0') break;
            paramCount++;
            if(paramCount > numParams)
            {
                return pp_error(self, "too many parameters to function '%s'", name);
            }
            if(strncmp(paramBuffer, List_GetName(params), sizeof(paramBuffer)) != 0)
            {
                paramMacros++;
                List_InsertAfter(paramDefs, strdup(paramBuffer), List_GetName(params));
            }
            List_GotoNext(params);
            paramBuffer[0] = '\0';
            break;
        case PP_TOKEN_IDENTIFIER:
            if(self->type == PP_FUNCTION_MACRO && List_FindByName(self->params, self->token.theSource))
            {
                if((strlen(paramBuffer) + strlen(List_Retrieve(self->params)) + 1) > sizeof(paramBuffer))
                {
                    return pp_error(self,
                                    "parameter %d of function '%s' exceeds max length of %d characters",
                                    name, sizeof(paramBuffer)-1);
                }
                strcat(paramBuffer, List_Retrieve(self->params));
                write = false;
            }
            else write = true;
            break;
        case PP_TOKEN_WHITESPACE:
            if(paramBuffer[0] == '\0')
                write = false;
            else
                write = true;
            break;
        default:
            write = true;
        }
        if(write)
        {
            if((strlen(paramBuffer) + strlen(self->token.theSource) + 1) > sizeof(paramBuffer))
                return pp_error(self, "parameter %d of function '%s' exceeds max length of %d characters",
                                name, sizeof(paramBuffer) - 1);
            strcat(paramBuffer, self->token.theSource);
        }
    }
    while(parenLevel >= 0 || type != PP_TOKEN_RPAREN);
    if(paramCount < numParams)
        return pp_error(self, "not enough parameters to function '%s' (%i given, %i expected)",
                        name, paramCount, numParams);
    List_GotoLast(params);
    pp_parser_alloc_macro(self, List_Retrieve(params), paramDefs, PP_FUNCTION_MACRO);
    self->child->macroName = strdup(name);
    return S_OK;
}
HRESULT pp_parser_insert_function_macro ( pp_parser * self , char * name ) { int numParams , paramCount = 0 , paramMacros = 0 , parenLevel = 0 , type ; List * params , * paramDefs ; char paramBuffer [ 1024 ] = " " , * tail ; if ( strcmp ( ( char * ) List_Retrieve ( & self -> ctx -> func_macros ) , name ) ) { List_FindByName ( & self -> ctx -> func_macros , name ) ; } params = List_Retrieve ( & self -> ctx -> func_macros ) ; numParams = List_GetSize ( params ) - 1 ; paramDefs = malloc ( sizeof ( List ) ) ; List_Init ( paramDefs ) ; List_Reset ( params ) ; List_Reset ( & self -> ctx -> macros ) ; do { if ( FAILED ( pp_parser_lex_token_essential ( self , false ) ) ) { return E_FAIL ; } type = self -> token . theType ; bool write = false ; switch ( type ) { case PP_TOKEN_NEWLINE : if ( paramBuffer [ 0 ] != ' \0 ' ) { return pp_error ( self , " " , name ) ; } case PP_TOKEN_EOF : return pp_error ( self , " " , name ) ; case PP_TOKEN_LPAREN : parenLevel ++ ; write = true ; break ; case PP_TOKEN_RPAREN : parenLevel -- ; case PP_TOKEN_COMMA : if ( type == PP_TOKEN_RPAREN || parenLevel > 0 ) { write = true ; if ( parenLevel >= 0 ) { break ; } } tail = strchr ( paramBuffer , ' \0 ' ) ; while ( -- tail >= paramBuffer ) { if ( * tail == ' ' || * tail == ' \t ' || * tail == ' \n ' || * tail == ' \r ' ) { * tail = ' \0 ' ; } else { break ; } } if ( type == PP_TOKEN_RPAREN && paramCount == 0 && paramBuffer [ 0 ] == ' \0 ' ) break ; paramCount ++ ; if ( paramCount > numParams ) { return pp_error ( self , " " , name ) ; } if ( strncmp ( paramBuffer , List_GetName ( params ) , sizeof ( paramBuffer ) ) != 0 ) { paramMacros ++ ; List_InsertAfter ( paramDefs , strdup ( paramBuffer ) , List_GetName ( params ) ) ; } List_GotoNext ( params ) ; paramBuffer [ 0 ] = ' \0 ' ; break ; case PP_TOKEN_IDENTIFIER : if ( self -> type == PP_FUNCTION_MACRO && List_FindByName ( self -> params , self -> token . theSource ) ) { if ( ( strlen ( paramBuffer ) + strlen ( List_Retrieve ( self -> params ) ) + 1 ) > sizeof ( paramBuffer ) ) { return pp_error ( self , " " , name , sizeof ( paramBuffer ) - 1 ) ; } strcat ( paramBuffer , List_Retrieve ( self -> params ) ) ; write = false ; } else write = true ; break ; case PP_TOKEN_WHITESPACE : if ( paramBuffer [ 0 ] == ' \0 ' ) write = false ; else write = true ; break ; default : write = true ; } if ( write ) { if ( ( strlen ( paramBuffer ) + strlen ( self -> token . theSource ) + 1 ) > sizeof ( paramBuffer ) ) return pp_error ( self , " " , name , sizeof ( paramBuffer ) - 1 ) ; strcat ( paramBuffer , self -> token . theSource ) ; } } while ( parenLevel >= 0 || type != PP_TOKEN_RPAREN ) ; if ( paramCount < numParams ) return pp_error ( self , " " , name , paramCount , numParams ) ; List_GotoLast ( params ) ; pp_parser_alloc_macro ( self , List_Retrieve ( params ) , paramDefs , PP_FUNCTION_MACRO ) ; self -> child -> macroName = strdup ( name ) ; return S_OK ; }
Expands a macro.
Expands a macro .
// note that params is different from self->params // find macro and get number of parameters // read the parameter list and temporarily define a "simple" macro for each parameter // fallthrough // remove trailing whitespace // handle the case of a function with no parameters // no need to create a macro if passed variable name is the same as the parameter name // add the new macro to the beginning of the macro list // do the actual parsing