mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2024-11-25 13:41:45 +00:00
252 lines
5.3 KiB
C
252 lines
5.3 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id$
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Log$
|
|
// Revision 1.5 2007/02/03 19:37:19 jbravo
|
|
// Adding CVS headers to new files in CVS.
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "../qcommon/q_shared.h"
|
|
#include "g_parser.h"
|
|
|
|
char *Script_GetToken(char **str)
|
|
{
|
|
const char *whiteSpace = " ,;\n\r\t";
|
|
char *ret = NULL;
|
|
int inQuotes = 0;
|
|
|
|
if (!str || !*str || !**str)
|
|
return NULL;
|
|
|
|
//skip whitespace
|
|
while (**str && strchr(whiteSpace, **str) != NULL)
|
|
(*str)++;
|
|
|
|
//end of string?
|
|
if (!**str)
|
|
return NULL;
|
|
|
|
if ( (inQuotes = (**str == '\"')) )
|
|
(*str)++;
|
|
ret = *str;
|
|
|
|
//get actual token
|
|
for ( ; **str; (*str)++)
|
|
{
|
|
if (inQuotes)
|
|
{
|
|
if (**str == '\"')
|
|
break;
|
|
continue;
|
|
}
|
|
if (strchr(whiteSpace, **str) != NULL)
|
|
break;
|
|
}
|
|
|
|
//end token
|
|
if (**str)
|
|
*(*str)++ = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int Script_HashKey(const char *keyword)
|
|
{
|
|
int register hash, i;
|
|
|
|
hash = 0;
|
|
for (i = 0; keyword[i] != '\0'; i++) {
|
|
if (keyword[i] >= 'A' && keyword[i] <= 'Z')
|
|
hash += (keyword[i] + ('a' - 'A')) * (119 + i);
|
|
else
|
|
hash += keyword[i] * (119 + i);
|
|
}
|
|
hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (SCRIPT_HASH_SIZE - 1);
|
|
return hash;
|
|
}
|
|
|
|
void Script_InitHashTable(TParseState *state)
|
|
{
|
|
if (state->initialized)
|
|
return;
|
|
|
|
memset((*state).hashTable, 0, sizeof((*state).hashTable));
|
|
FOR_EACH_RULE(*state, rule)
|
|
{
|
|
int index = Script_HashKey(rule->keyword) % SCRIPT_HASH_SIZE;
|
|
TParseRule *next = (*state).hashTable[index];
|
|
rule->next = next;
|
|
(*state).hashTable[index] = rule;
|
|
}
|
|
END_FOR_RULE();
|
|
|
|
state->initialized = 1;
|
|
}
|
|
|
|
PParseFunc Script_FindHandler(char *token, TParseState* state)
|
|
{
|
|
TParseRule *ptr;
|
|
int index = Script_HashKey(token) % SCRIPT_HASH_SIZE;
|
|
|
|
if (!state->initialized)
|
|
Script_InitHashTable(state);
|
|
|
|
for (ptr = state->hashTable[index]; ptr; ptr = ptr->next)
|
|
{
|
|
if (Q_stricmp(token, ptr->keyword) == 0)
|
|
return ptr->handler;
|
|
}
|
|
return (PParseFunc)0;
|
|
}
|
|
|
|
|
|
ID_INLINE void Script_InitStateStack(TStateStack *stack)
|
|
{
|
|
stack->top = 0;
|
|
}
|
|
|
|
|
|
int Script_PushState(TStateStack *stack, TParseState *state)
|
|
{
|
|
if (stack->top >= STATE_STACK_SIZE)
|
|
{
|
|
SCRIPT_INFO(SHOW_ERROR)
|
|
G_Printf("* ERROR: Stack overflow before %s.\n", (state) ? state->name : "[UNKNOWN]");
|
|
END_SCRIPT_INFO();
|
|
return 0;
|
|
}
|
|
stack->states[stack->top++] = state;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Script_GetTopState(const TStateStack *stack, TParseState **state)
|
|
{
|
|
if (!state)
|
|
return 1;
|
|
if (stack->top < 0 || stack->top >= STATE_STACK_SIZE)
|
|
{
|
|
*state = NULL;
|
|
SCRIPT_INFO(SHOW_ERROR)
|
|
G_Printf("* ERROR: Stack index out of bounds (%d).\n", stack->top);
|
|
END_SCRIPT_INFO();
|
|
return 0;
|
|
}
|
|
|
|
*state = stack->states[stack->top-1];
|
|
return 1;
|
|
}
|
|
|
|
int Script_PopState(TStateStack *stack, TParseState **state)
|
|
{
|
|
stack->top--;
|
|
if (stack->top < 0)
|
|
{
|
|
SCRIPT_INFO(SHOW_ERROR)
|
|
G_Printf("* ERROR: Stack underflow before %s.\n", (stack->states[0]) ? ((TParseState*)stack->states[0])->name : "[UNKNOWN]");
|
|
END_SCRIPT_INFO();
|
|
if (state)
|
|
*state = NULL;
|
|
return 0;
|
|
}
|
|
if (state)
|
|
*state = stack->states[stack->top];
|
|
return 1;
|
|
}
|
|
|
|
void Script_ParseString(char *str, TParseState *baseState)
|
|
{
|
|
char *token = NULL;
|
|
TStateStack stateStack;
|
|
|
|
Script_InitStateStack(&stateStack);
|
|
Script_PushState(&stateStack, baseState);
|
|
|
|
while ( (token = Script_GetToken(&str)) != NULL)
|
|
{
|
|
PParseFunc handler = (PParseFunc)0;
|
|
TParseState *state;
|
|
|
|
Script_GetTopState(&stateStack, &state);
|
|
|
|
if ( (handler = Script_FindHandler(token, state)) != NULL)
|
|
{
|
|
handler(&str, &stateStack);
|
|
} else {
|
|
SCRIPT_INFO(SHOW_WARNING)
|
|
G_Printf(S_COLOR_YELLOW "* Warning: unknown token, '%s'.\n", token);
|
|
END_SCRIPT_INFO();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int SCRIPT_SHOW_LEVEL = SHOW_NONE;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// SAMPLE FUNCTIONS ///////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
SCRIPT_FUNC(SFN_SkipComment)
|
|
///////////////////////////////////////////////////////////////
|
|
{
|
|
char *token;
|
|
while ( (token = Script_GetToken(SCRIPT_INPUT)) != NULL)
|
|
{
|
|
if (Q_stricmp(token, "*/") == 0)
|
|
return 1;
|
|
}
|
|
SCRIPT_INFO(SHOW_ERROR)
|
|
G_Printf(S_COLOR_RED "* ERROR: end of input found in comment.\n");
|
|
END_SCRIPT_INFO();
|
|
return 0;
|
|
}
|
|
END_SCRIPT_FUNC()
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
SCRIPT_FUNC(SFN_SkipLineComment)
|
|
///////////////////////////////////////////////////////////////
|
|
{
|
|
char *cursor;
|
|
for (cursor = *SCRIPT_INPUT; *cursor; cursor++)
|
|
{
|
|
if (*cursor == '\n' || *cursor == '\r')
|
|
{
|
|
*SCRIPT_INPUT = cursor + 1;
|
|
return 1;
|
|
}
|
|
}
|
|
SCRIPT_INFO(SHOW_ERROR)
|
|
G_Printf(S_COLOR_RED "* ERROR: end of input found in comment.\n");
|
|
END_SCRIPT_INFO();
|
|
return 0;
|
|
}
|
|
END_SCRIPT_FUNC()
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
SCRIPT_FUNC(SFN_SkipToken)
|
|
///////////////////////////////////////////////////////////////
|
|
{
|
|
return 1;
|
|
}
|
|
END_SCRIPT_FUNC()
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
SCRIPT_FUNC(SFN_PopState)
|
|
///////////////////////////////////////////////////////////////
|
|
{
|
|
SCRIPT_POP_STATE();
|
|
return 1;
|
|
}
|
|
END_SCRIPT_FUNC()
|
|
|