//----------------------------------------------------------------------------- // // $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()