From 6bf20c78f5b69d40bcc4931df93d29198435ab67 Mon Sep 17 00:00:00 2001 From: zakk Date: Fri, 26 Aug 2005 17:39:27 +0000 Subject: newlines fixed git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/botlib/l_precomp.c | 6456 +++++++++++++++++++++++------------------------ 1 file changed, 3228 insertions(+), 3228 deletions(-) (limited to 'code/botlib/l_precomp.c') diff --git a/code/botlib/l_precomp.c b/code/botlib/l_precomp.c index 4fa708b..ae82981 100755 --- a/code/botlib/l_precomp.c +++ b/code/botlib/l_precomp.c @@ -1,3228 +1,3228 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Foobar; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: l_precomp.c - * - * desc: pre compiler - * - * $Archive: /MissionPack/code/botlib/l_precomp.c $ - * - *****************************************************************************/ - -//Notes: fix: PC_StringizeTokens - -//#define SCREWUP -//#define BOTLIB -//#define QUAKE -//#define QUAKEC -//#define MEQCC - -#ifdef SCREWUP -#include -#include -#include -#include -#include -#include -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" - -typedef enum {qfalse, qtrue} qboolean; -#endif //SCREWUP - -#ifdef BOTLIB -#include "../game/q_shared.h" -#include "../game/botlib.h" -#include "be_interface.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_log.h" -#endif //BOTLIB - -#ifdef MEQCC -#include "qcc.h" -#include "time.h" //time & ctime -#include "math.h" //fabs -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_log.h" - -#define qtrue true -#define qfalse false -#endif //MEQCC - -#ifdef BSPC -//include files for usage in the BSP Converter -#include "../bspc/qbsp.h" -#include "../bspc/l_log.h" -#include "../bspc/l_mem.h" -#include "l_precomp.h" - -#define qtrue true -#define qfalse false -#define Q_stricmp stricmp - -#endif //BSPC - -#if defined(QUAKE) && !defined(BSPC) -#include "l_utils.h" -#endif //QUAKE - -//#define DEBUG_EVAL - -#define MAX_DEFINEPARMS 128 - -#define DEFINEHASHING 1 - -//directive name with parse function -typedef struct directive_s -{ - char *name; - int (*func)(source_t *source); -} directive_t; - -#define DEFINEHASHSIZE 1024 - -#define TOKEN_HEAP_SIZE 4096 - -int numtokens; -/* -int tokenheapinitialized; //true when the token heap is initialized -token_t token_heap[TOKEN_HEAP_SIZE]; //heap with tokens -token_t *freetokens; //free tokens from the heap -*/ - -//list with global defines added to every source loaded -define_t *globaldefines; - -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void QDECL SourceError(source_t *source, char *str, ...) -{ - char text[1024]; - va_list ap; - - va_start(ap, str); - vsprintf(text, str, ap); - va_end(ap); -#ifdef BOTLIB - botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BOTLIB -#ifdef MEQCC - printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //MEQCC -#ifdef BSPC - Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BSPC -} //end of the function SourceError -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL SourceWarning(source_t *source, char *str, ...) -{ - char text[1024]; - va_list ap; - - va_start(ap, str); - vsprintf(text, str, ap); - va_end(ap); -#ifdef BOTLIB - botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BOTLIB -#ifdef MEQCC - printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //MEQCC -#ifdef BSPC - Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BSPC -} //end of the function ScriptWarning -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PushIndent(source_t *source, int type, int skip) -{ - indent_t *indent; - - indent = (indent_t *) GetMemory(sizeof(indent_t)); - indent->type = type; - indent->script = source->scriptstack; - indent->skip = (skip != 0); - source->skip += indent->skip; - indent->next = source->indentstack; - source->indentstack = indent; -} //end of the function PC_PushIndent -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PopIndent(source_t *source, int *type, int *skip) -{ - indent_t *indent; - - *type = 0; - *skip = 0; - - indent = source->indentstack; - if (!indent) return; - - //must be an indent from the current script - if (source->indentstack->script != source->scriptstack) return; - - *type = indent->type; - *skip = indent->skip; - source->indentstack = source->indentstack->next; - source->skip -= indent->skip; - FreeMemory(indent); -} //end of the function PC_PopIndent -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PushScript(source_t *source, script_t *script) -{ - script_t *s; - - for (s = source->scriptstack; s; s = s->next) - { - if (!Q_stricmp(s->filename, script->filename)) - { - SourceError(source, "%s recursively included", script->filename); - return; - } //end if - } //end for - //push the script on the script stack - script->next = source->scriptstack; - source->scriptstack = script; -} //end of the function PC_PushScript -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_InitTokenHeap(void) -{ - /* - int i; - - if (tokenheapinitialized) return; - freetokens = NULL; - for (i = 0; i < TOKEN_HEAP_SIZE; i++) - { - token_heap[i].next = freetokens; - freetokens = &token_heap[i]; - } //end for - tokenheapinitialized = qtrue; - */ -} //end of the function PC_InitTokenHeap -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -token_t *PC_CopyToken(token_t *token) -{ - token_t *t; - -// t = (token_t *) malloc(sizeof(token_t)); - t = (token_t *) GetMemory(sizeof(token_t)); -// t = freetokens; - if (!t) - { -#ifdef BSPC - Error("out of token space\n"); -#else - Com_Error(ERR_FATAL, "out of token space\n"); -#endif - return NULL; - } //end if -// freetokens = freetokens->next; - Com_Memcpy(t, token, sizeof(token_t)); - t->next = NULL; - numtokens++; - return t; -} //end of the function PC_CopyToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_FreeToken(token_t *token) -{ - //free(token); - FreeMemory(token); -// token->next = freetokens; -// freetokens = token; - numtokens--; -} //end of the function PC_FreeToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadSourceToken(source_t *source, token_t *token) -{ - token_t *t; - script_t *script; - int type, skip; - - //if there's no token already available - while(!source->tokens) - { - //if there's a token to read from the script - if (PS_ReadToken(source->scriptstack, token)) return qtrue; - //if at the end of the script - if (EndOfScript(source->scriptstack)) - { - //remove all indents of the script - while(source->indentstack && - source->indentstack->script == source->scriptstack) - { - SourceWarning(source, "missing #endif"); - PC_PopIndent(source, &type, &skip); - } //end if - } //end if - //if this was the initial script - if (!source->scriptstack->next) return qfalse; - //remove the script and return to the last one - script = source->scriptstack; - source->scriptstack = source->scriptstack->next; - FreeScript(script); - } //end while - //copy the already available token - Com_Memcpy(token, source->tokens, sizeof(token_t)); - //free the read token - t = source->tokens; - source->tokens = source->tokens->next; - PC_FreeToken(t); - return qtrue; -} //end of the function PC_ReadSourceToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_UnreadSourceToken(source_t *source, token_t *token) -{ - token_t *t; - - t = PC_CopyToken(token); - t->next = source->tokens; - source->tokens = t; - return qtrue; -} //end of the function PC_UnreadSourceToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms) -{ - token_t token, *t, *last; - int i, done, lastcomma, numparms, indent; - - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "define %s missing parms", define->name); - return qfalse; - } //end if - // - if (define->numparms > maxparms) - { - SourceError(source, "define with more than %d parameters", maxparms); - return qfalse; - } //end if - // - for (i = 0; i < define->numparms; i++) parms[i] = NULL; - //if no leading "(" - if (strcmp(token.string, "(")) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "define %s missing parms", define->name); - return qfalse; - } //end if - //read the define parameters - for (done = 0, numparms = 0, indent = 0; !done;) - { - if (numparms >= maxparms) - { - SourceError(source, "define %s with too many parms", define->name); - return qfalse; - } //end if - if (numparms >= define->numparms) - { - SourceWarning(source, "define %s has too many parms", define->name); - return qfalse; - } //end if - parms[numparms] = NULL; - lastcomma = 1; - last = NULL; - while(!done) - { - // - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "define %s incomplete", define->name); - return qfalse; - } //end if - // - if (!strcmp(token.string, ",")) - { - if (indent <= 0) - { - if (lastcomma) SourceWarning(source, "too many comma's"); - lastcomma = 1; - break; - } //end if - } //end if - lastcomma = 0; - // - if (!strcmp(token.string, "(")) - { - indent++; - continue; - } //end if - else if (!strcmp(token.string, ")")) - { - if (--indent <= 0) - { - if (!parms[define->numparms-1]) - { - SourceWarning(source, "too few define parms"); - } //end if - done = 1; - break; - } //end if - } //end if - // - if (numparms < define->numparms) - { - // - t = PC_CopyToken(&token); - t->next = NULL; - if (last) last->next = t; - else parms[numparms] = t; - last = t; - } //end if - } //end while - numparms++; - } //end for - return qtrue; -} //end of the function PC_ReadDefineParms -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_StringizeTokens(token_t *tokens, token_t *token) -{ - token_t *t; - - token->type = TT_STRING; - token->whitespace_p = NULL; - token->endwhitespace_p = NULL; - token->string[0] = '\0'; - strcat(token->string, "\""); - for (t = tokens; t; t = t->next) - { - strncat(token->string, t->string, MAX_TOKEN - strlen(token->string)); - } //end for - strncat(token->string, "\"", MAX_TOKEN - strlen(token->string)); - return qtrue; -} //end of the function PC_StringizeTokens -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_MergeTokens(token_t *t1, token_t *t2) -{ - //merging of a name with a name or number - if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER)) - { - strcat(t1->string, t2->string); - return qtrue; - } //end if - //merging of two strings - if (t1->type == TT_STRING && t2->type == TT_STRING) - { - //remove trailing double quote - t1->string[strlen(t1->string)-1] = '\0'; - //concat without leading double quote - strcat(t1->string, &t2->string[1]); - return qtrue; - } //end if - //FIXME: merging of two number of the same sub type - return qfalse; -} //end of the function PC_MergeTokens -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -/* -void PC_PrintDefine(define_t *define) -{ - printf("define->name = %s\n", define->name); - printf("define->flags = %d\n", define->flags); - printf("define->builtin = %d\n", define->builtin); - printf("define->numparms = %d\n", define->numparms); -// token_t *parms; //define parameters -// token_t *tokens; //macro tokens (possibly containing parm tokens) -// struct define_s *next; //next defined macro in a list -} //end of the function PC_PrintDefine*/ -#if DEFINEHASHING -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PrintDefineHashTable(define_t **definehash) -{ - int i; - define_t *d; - - for (i = 0; i < DEFINEHASHSIZE; i++) - { - Log_Write("%4d:", i); - for (d = definehash[i]; d; d = d->hashnext) - { - Log_Write(" %s", d->name); - } //end for - Log_Write("\n"); - } //end for -} //end of the function PC_PrintDefineHashTable -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47}; - -int PC_NameHash(char *name) -{ - int register hash, i; - - hash = 0; - for (i = 0; name[i] != '\0'; i++) - { - hash += name[i] * (119 + i); - //hash += (name[i] << 7) + i; - //hash += (name[i] << (i&15)); - } //end while - hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1); - return hash; -} //end of the function PC_NameHash -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_AddDefineToHash(define_t *define, define_t **definehash) -{ - int hash; - - hash = PC_NameHash(define->name); - define->hashnext = definehash[hash]; - definehash[hash] = define; -} //end of the function PC_AddDefineToHash -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_FindHashedDefine(define_t **definehash, char *name) -{ - define_t *d; - int hash; - - hash = PC_NameHash(name); - for (d = definehash[hash]; d; d = d->hashnext) - { - if (!strcmp(d->name, name)) return d; - } //end for - return NULL; -} //end of the function PC_FindHashedDefine -#endif //DEFINEHASHING -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_FindDefine(define_t *defines, char *name) -{ - define_t *d; - - for (d = defines; d; d = d->next) - { - if (!strcmp(d->name, name)) return d; - } //end for - return NULL; -} //end of the function PC_FindDefine -//============================================================================ -// -// Parameter: - -// Returns: number of the parm -// if no parm found with the given name -1 is returned -// Changes Globals: - -//============================================================================ -int PC_FindDefineParm(define_t *define, char *name) -{ - token_t *p; - int i; - - i = 0; - for (p = define->parms; p; p = p->next) - { - if (!strcmp(p->string, name)) return i; - i++; - } //end for - return -1; -} //end of the function PC_FindDefineParm -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_FreeDefine(define_t *define) -{ - token_t *t, *next; - - //free the define parameters - for (t = define->parms; t; t = next) - { - next = t->next; - PC_FreeToken(t); - } //end for - //free the define tokens - for (t = define->tokens; t; t = next) - { - next = t->next; - PC_FreeToken(t); - } //end for - //free the define - FreeMemory(define); -} //end of the function PC_FreeDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_AddBuiltinDefines(source_t *source) -{ - int i; - define_t *define; - struct builtin - { - char *string; - int builtin; - } builtin[] = { // bk001204 - brackets - { "__LINE__", BUILTIN_LINE }, - { "__FILE__", BUILTIN_FILE }, - { "__DATE__", BUILTIN_DATE }, - { "__TIME__", BUILTIN_TIME }, -// { "__STDC__", BUILTIN_STDC }, - { NULL, 0 } - }; - - for (i = 0; builtin[i].string; i++) - { - define = (define_t *) GetMemory(sizeof(define_t) + strlen(builtin[i].string) + 1); - Com_Memset(define, 0, sizeof(define_t)); - define->name = (char *) define + sizeof(define_t); - strcpy(define->name, builtin[i].string); - define->flags |= DEFINE_FIXED; - define->builtin = builtin[i].builtin; - //add the define to the source -#if DEFINEHASHING - PC_AddDefineToHash(define, source->definehash); -#else - define->next = source->defines; - source->defines = define; -#endif //DEFINEHASHING - } //end for -} //end of the function PC_AddBuiltinDefines -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define, - token_t **firsttoken, token_t **lasttoken) -{ - token_t *token; - unsigned long t; // time_t t; //to prevent LCC warning - char *curtime; - - token = PC_CopyToken(deftoken); - switch(define->builtin) - { - case BUILTIN_LINE: - { - sprintf(token->string, "%d", deftoken->line); -#ifdef NUMBERVALUE - token->intvalue = deftoken->line; - token->floatvalue = deftoken->line; -#endif //NUMBERVALUE - token->type = TT_NUMBER; - token->subtype = TT_DECIMAL | TT_INTEGER; - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_FILE: - { - strcpy(token->string, source->scriptstack->filename); - token->type = TT_NAME; - token->subtype = strlen(token->string); - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_DATE: - { - t = time(NULL); - curtime = ctime(&t); - strcpy(token->string, "\""); - strncat(token->string, curtime+4, 7); - strncat(token->string+7, curtime+20, 4); - strcat(token->string, "\""); - free(curtime); - token->type = TT_NAME; - token->subtype = strlen(token->string); - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_TIME: - { - t = time(NULL); - curtime = ctime(&t); - strcpy(token->string, "\""); - strncat(token->string, curtime+11, 8); - strcat(token->string, "\""); - free(curtime); - token->type = TT_NAME; - token->subtype = strlen(token->string); - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_STDC: - default: - { - *firsttoken = NULL; - *lasttoken = NULL; - break; - } //end case - } //end switch - return qtrue; -} //end of the function PC_ExpandBuiltinDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, - token_t **firsttoken, token_t **lasttoken) -{ - token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; - token_t *t1, *t2, *first, *last, *nextpt, token; - int parmnum, i; - - //if it is a builtin define - if (define->builtin) - { - return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken); - } //end if - //if the define has parameters - if (define->numparms) - { - if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse; -#ifdef DEBUG_EVAL - for (i = 0; i < define->numparms; i++) - { - Log_Write("define parms %d:", i); - for (pt = parms[i]; pt; pt = pt->next) - { - Log_Write("%s", pt->string); - } //end for - } //end for -#endif //DEBUG_EVAL - } //end if - //empty list at first - first = NULL; - last = NULL; - //create a list with tokens of the expanded define - for (dt = define->tokens; dt; dt = dt->next) - { - parmnum = -1; - //if the token is a name, it could be a define parameter - if (dt->type == TT_NAME) - { - parmnum = PC_FindDefineParm(define, dt->string); - } //end if - //if it is a define parameter - if (parmnum >= 0) - { - for (pt = parms[parmnum]; pt; pt = pt->next) - { - t = PC_CopyToken(pt); - //add the token to the list - t->next = NULL; - if (last) last->next = t; - else first = t; - last = t; - } //end for - } //end if - else - { - //if stringizing operator - if (dt->string[0] == '#' && dt->string[1] == '\0') - { - //the stringizing operator must be followed by a define parameter - if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string); - else parmnum = -1; - // - if (parmnum >= 0) - { - //step over the stringizing operator - dt = dt->next; - //stringize the define parameter tokens - if (!PC_StringizeTokens(parms[parmnum], &token)) - { - SourceError(source, "can't stringize tokens"); - return qfalse; - } //end if - t = PC_CopyToken(&token); - } //end if - else - { - SourceWarning(source, "stringizing operator without define parameter"); - continue; - } //end if - } //end if - else - { - t = PC_CopyToken(dt); - } //end else - //add the token to the list - t->next = NULL; - if (last) last->next = t; - else first = t; - last = t; - } //end else - } //end for - //check for the merging operator - for (t = first; t; ) - { - if (t->next) - { - //if the merging operator - if (t->next->string[0] == '#' && t->next->string[1] == '#') - { - t1 = t; - t2 = t->next->next; - if (t2) - { - if (!PC_MergeTokens(t1, t2)) - { - SourceError(source, "can't merge %s with %s", t1->string, t2->string); - return qfalse; - } //end if - PC_FreeToken(t1->next); - t1->next = t2->next; - if (t2 == last) last = t1; - PC_FreeToken(t2); - continue; - } //end if - } //end if - } //end if - t = t->next; - } //end for - //store the first and last token of the list - *firsttoken = first; - *lasttoken = last; - //free all the parameter tokens - for (i = 0; i < define->numparms; i++) - { - for (pt = parms[i]; pt; pt = nextpt) - { - nextpt = pt->next; - PC_FreeToken(pt); - } //end for - } //end for - // - return qtrue; -} //end of the function PC_ExpandDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define) -{ - token_t *firsttoken, *lasttoken; - - if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse; - - if (firsttoken && lasttoken) - { - lasttoken->next = source->tokens; - source->tokens = firsttoken; - return qtrue; - } //end if - return qfalse; -} //end of the function PC_ExpandDefineIntoSource -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_ConvertPath(char *path) -{ - char *ptr; - - //remove double path seperators - for (ptr = path; *ptr;) - { - if ((*ptr == '\\' || *ptr == '/') && - (*(ptr+1) == '\\' || *(ptr+1) == '/')) - { - strcpy(ptr, ptr+1); - } //end if - else - { - ptr++; - } //end else - } //end while - //set OS dependent path seperators - for (ptr = path; *ptr;) - { - if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR; - ptr++; - } //end while -} //end of the function PC_ConvertPath -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_include(source_t *source) -{ - script_t *script; - token_t token; - char path[MAX_PATH]; -#ifdef QUAKE - foundfile_t file; -#endif //QUAKE - - if (source->skip > 0) return qtrue; - // - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "#include without file name"); - return qfalse; - } //end if - if (token.linescrossed > 0) - { - SourceError(source, "#include without file name"); - return qfalse; - } //end if - if (token.type == TT_STRING) - { - StripDoubleQuotes(token.string); - PC_ConvertPath(token.string); - script = LoadScriptFile(token.string); - if (!script) - { - strcpy(path, source->includepath); - strcat(path, token.string); - script = LoadScriptFile(path); - } //end if - } //end if - else if (token.type == TT_PUNCTUATION && *token.string == '<') - { - strcpy(path, source->includepath); - while(PC_ReadSourceToken(source, &token)) - { - if (token.linescrossed > 0) - { - PC_UnreadSourceToken(source, &token); - break; - } //end if - if (token.type == TT_PUNCTUATION && *token.string == '>') break; - strncat(path, token.string, MAX_PATH); - } //end while - if (*token.string != '>') - { - SourceWarning(source, "#include missing trailing >"); - } //end if - if (!strlen(path)) - { - SourceError(source, "#include without file name between < >"); - return qfalse; - } //end if - PC_ConvertPath(path); - script = LoadScriptFile(path); - } //end if - else - { - SourceError(source, "#include without file name"); - return qfalse; - } //end else -#ifdef QUAKE - if (!script) - { - Com_Memset(&file, 0, sizeof(foundfile_t)); - script = LoadScriptFile(path); - if (script) strncpy(script->filename, path, MAX_PATH); - } //end if -#endif //QUAKE - if (!script) - { -#ifdef SCREWUP - SourceWarning(source, "file %s not found", path); - return qtrue; -#else - SourceError(source, "file %s not found", path); - return qfalse; -#endif //SCREWUP - } //end if - PC_PushScript(source, script); - return qtrue; -} //end of the function PC_Directive_include -//============================================================================ -// reads a token from the current line, continues reading on the next -// line only if a backslash '\' is encountered. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadLine(source_t *source, token_t *token) -{ - int crossline; - - crossline = 0; - do - { - if (!PC_ReadSourceToken(source, token)) return qfalse; - - if (token->linescrossed > crossline) - { - PC_UnreadSourceToken(source, token); - return qfalse; - } //end if - crossline = 1; - } while(!strcmp(token->string, "\\")); - return qtrue; -} //end of the function PC_ReadLine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_WhiteSpaceBeforeToken(token_t *token) -{ - return token->endwhitespace_p - token->whitespace_p > 0; -} //end of the function PC_WhiteSpaceBeforeToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_ClearTokenWhiteSpace(token_t *token) -{ - token->whitespace_p = NULL; - token->endwhitespace_p = NULL; - token->linescrossed = 0; -} //end of the function PC_ClearTokenWhiteSpace -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_undef(source_t *source) -{ - token_t token; - define_t *define, *lastdefine; - int hash; - - if (source->skip > 0) return qtrue; - // - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "undef without name"); - return qfalse; - } //end if - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "expected name, found %s", token.string); - return qfalse; - } //end if -#if DEFINEHASHING - - hash = PC_NameHash(token.string); - for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext) - { - if (!strcmp(define->name, token.string)) - { - if (define->flags & DEFINE_FIXED) - { - SourceWarning(source, "can't undef %s", token.string); - } //end if - else - { - if (lastdefine) lastdefine->hashnext = define->hashnext; - else source->definehash[hash] = define->hashnext; - PC_FreeDefine(define); - } //end else - break; - } //end if - lastdefine = define; - } //end for -#else //DEFINEHASHING - for (lastdefine = NULL, define = source->defines; define; define = define->next) - { - if (!strcmp(define->name, token.string)) - { - if (define->flags & DEFINE_FIXED) - { - SourceWarning(source, "can't undef %s", token.string); - } //end if - else - { - if (lastdefine) lastdefine->next = define->next; - else source->defines = define->next; - PC_FreeDefine(define); - } //end else - break; - } //end if - lastdefine = define; - } //end for -#endif //DEFINEHASHING - return qtrue; -} //end of the function PC_Directive_undef -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_define(source_t *source) -{ - token_t token, *t, *last; - define_t *define; - - if (source->skip > 0) return qtrue; - // - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "#define without name"); - return qfalse; - } //end if - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "expected name after #define, found %s", token.string); - return qfalse; - } //end if - //check if the define already exists -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - if (define) - { - if (define->flags & DEFINE_FIXED) - { - SourceError(source, "can't redefine %s", token.string); - return qfalse; - } //end if - SourceWarning(source, "redefinition of %s", token.string); - //unread the define name before executing the #undef directive - PC_UnreadSourceToken(source, &token); - if (!PC_Directive_undef(source)) return qfalse; - //if the define was not removed (define->flags & DEFINE_FIXED) -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - } //end if - //allocate define - define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1); - Com_Memset(define, 0, sizeof(define_t)); - define->name = (char *) define + sizeof(define_t); - strcpy(define->name, token.string); - //add the define to the source -#if DEFINEHASHING - PC_AddDefineToHash(define, source->definehash); -#else //DEFINEHASHING - define->next = source->defines; - source->defines = define; -#endif //DEFINEHASHING - //if nothing is defined, just return - if (!PC_ReadLine(source, &token)) return qtrue; - //if it is a define with parameters - if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "(")) - { - //read the define parameters - last = NULL; - if (!PC_CheckTokenString(source, ")")) - { - while(1) - { - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "expected define parameter"); - return qfalse; - } //end if - //if it isn't a name - if (token.type != TT_NAME) - { - SourceError(source, "invalid define parameter"); - return qfalse; - } //end if - // - if (PC_FindDefineParm(define, token.string) >= 0) - { - SourceError(source, "two the same define parameters"); - return qfalse; - } //end if - //add the define parm - t = PC_CopyToken(&token); - PC_ClearTokenWhiteSpace(t); - t->next = NULL; - if (last) last->next = t; - else define->parms = t; - last = t; - define->numparms++; - //read next token - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "define parameters not terminated"); - return qfalse; - } //end if - // - if (!strcmp(token.string, ")")) break; - //then it must be a comma - if (strcmp(token.string, ",")) - { - SourceError(source, "define not terminated"); - return qfalse; - } //end if - } //end while - } //end if - if (!PC_ReadLine(source, &token)) return qtrue; - } //end if - //read the defined stuff - last = NULL; - do - { - t = PC_CopyToken(&token); - if (t->type == TT_NAME && !strcmp(t->string, define->name)) - { - SourceError(source, "recursive define (removed recursion)"); - continue; - } //end if - PC_ClearTokenWhiteSpace(t); - t->next = NULL; - if (last) last->next = t; - else define->tokens = t; - last = t; - } while(PC_ReadLine(source, &token)); - // - if (last) - { - //check for merge operators at the beginning or end - if (!strcmp(define->tokens->string, "##") || - !strcmp(last->string, "##")) - { - SourceError(source, "define with misplaced ##"); - return qfalse; - } //end if - } //end if - return qtrue; -} //end of the function PC_Directive_define -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_DefineFromString(char *string) -{ - script_t *script; - source_t src; - token_t *t; - int res, i; - define_t *def; - - PC_InitTokenHeap(); - - script = LoadScriptMemory(string, strlen(string), "*extern"); - //create a new source - Com_Memset(&src, 0, sizeof(source_t)); - strncpy(src.filename, "*extern", MAX_PATH); - src.scriptstack = script; -#if DEFINEHASHING - src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); -#endif //DEFINEHASHING - //create a define from the source - res = PC_Directive_define(&src); - //free any tokens if left - for (t = src.tokens; t; t = src.tokens) - { - src.tokens = src.tokens->next; - PC_FreeToken(t); - } //end for -#ifdef DEFINEHASHING - def = NULL; - for (i = 0; i < DEFINEHASHSIZE; i++) - { - if (src.definehash[i]) - { - def = src.definehash[i]; - break; - } //end if - } //end for -#else - def = src.defines; -#endif //DEFINEHASHING - // -#if DEFINEHASHING - FreeMemory(src.definehash); -#endif //DEFINEHASHING - // - FreeScript(script); - //if the define was created succesfully - if (res > 0) return def; - //free the define is created - if (src.defines) PC_FreeDefine(def); - // - return NULL; -} //end of the function PC_DefineFromString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_AddDefine(source_t *source, char *string) -{ - define_t *define; - - define = PC_DefineFromString(string); - if (!define) return qfalse; -#if DEFINEHASHING - PC_AddDefineToHash(define, source->definehash); -#else //DEFINEHASHING - define->next = source->defines; - source->defines = define; -#endif //DEFINEHASHING - return qtrue; -} //end of the function PC_AddDefine -//============================================================================ -// add a globals define that will be added to all opened sources -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_AddGlobalDefine(char *string) -{ - define_t *define; - - define = PC_DefineFromString(string); - if (!define) return qfalse; - define->next = globaldefines; - globaldefines = define; - return qtrue; -} //end of the function PC_AddGlobalDefine -//============================================================================ -// remove the given global define -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_RemoveGlobalDefine(char *name) -{ - define_t *define; - - define = PC_FindDefine(globaldefines, name); - if (define) - { - PC_FreeDefine(define); - return qtrue; - } //end if - return qfalse; -} //end of the function PC_RemoveGlobalDefine -//============================================================================ -// remove all globals defines -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_RemoveAllGlobalDefines(void) -{ - define_t *define; - - for (define = globaldefines; define; define = globaldefines) - { - globaldefines = globaldefines->next; - PC_FreeDefine(define); - } //end for -} //end of the function PC_RemoveAllGlobalDefines -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_CopyDefine(source_t *source, define_t *define) -{ - define_t *newdefine; - token_t *token, *newtoken, *lasttoken; - - newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1); - //copy the define name - newdefine->name = (char *) newdefine + sizeof(define_t); - strcpy(newdefine->name, define->name); - newdefine->flags = define->flags; - newdefine->builtin = define->builtin; - newdefine->numparms = define->numparms; - //the define is not linked - newdefine->next = NULL; - newdefine->hashnext = NULL; - //copy the define tokens - newdefine->tokens = NULL; - for (lasttoken = NULL, token = define->tokens; token; token = token->next) - { - newtoken = PC_CopyToken(token); - newtoken->next = NULL; - if (lasttoken) lasttoken->next = newtoken; - else newdefine->tokens = newtoken; - lasttoken = newtoken; - } //end for - //copy the define parameters - newdefine->parms = NULL; - for (lasttoken = NULL, token = define->parms; token; token = token->next) - { - newtoken = PC_CopyToken(token); - newtoken->next = NULL; - if (lasttoken) lasttoken->next = newtoken; - else newdefine->parms = newtoken; - lasttoken = newtoken; - } //end for - return newdefine; -} //end of the function PC_CopyDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_AddGlobalDefinesToSource(source_t *source) -{ - define_t *define, *newdefine; - - for (define = globaldefines; define; define = define->next) - { - newdefine = PC_CopyDefine(source, define); -#if DEFINEHASHING - PC_AddDefineToHash(newdefine, source->definehash); -#else //DEFINEHASHING - newdefine->next = source->defines; - source->defines = newdefine; -#endif //DEFINEHASHING - } //end for -} //end of the function PC_AddGlobalDefinesToSource -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_if_def(source_t *source, int type) -{ - token_t token; - define_t *d; - int skip; - - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "#ifdef without name"); - return qfalse; - } //end if - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "expected name after #ifdef, found %s", token.string); - return qfalse; - } //end if -#if DEFINEHASHING - d = PC_FindHashedDefine(source->definehash, token.string); -#else - d = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - skip = (type == INDENT_IFDEF) == (d == NULL); - PC_PushIndent(source, type, skip); - return qtrue; -} //end of the function PC_Directiveif_def -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_ifdef(source_t *source) -{ - return PC_Directive_if_def(source, INDENT_IFDEF); -} //end of the function PC_Directive_ifdef -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_ifndef(source_t *source) -{ - return PC_Directive_if_def(source, INDENT_IFNDEF); -} //end of the function PC_Directive_ifndef -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_else(source_t *source) -{ - int type, skip; - - PC_PopIndent(source, &type, &skip); - if (!type) - { - SourceError(source, "misplaced #else"); - return qfalse; - } //end if - if (type == INDENT_ELSE) - { - SourceError(source, "#else after #else"); - return qfalse; - } //end if - PC_PushIndent(source, INDENT_ELSE, !skip); - return qtrue; -} //end of the function PC_Directive_else -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_endif(source_t *source) -{ - int type, skip; - - PC_PopIndent(source, &type, &skip); - if (!type) - { - SourceError(source, "misplaced #endif"); - return qfalse; - } //end if - return qtrue; -} //end of the function PC_Directive_endif -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -typedef struct operator_s -{ - int operator; - int priority; - int parentheses; - struct operator_s *prev, *next; -} operator_t; - -typedef struct value_s -{ - signed long int intvalue; - double floatvalue; - int parentheses; - struct value_s *prev, *next; -} value_t; - -int PC_OperatorPriority(int op) -{ - switch(op) - { - case P_MUL: return 15; - case P_DIV: return 15; - case P_MOD: return 15; - case P_ADD: return 14; - case P_SUB: return 14; - - case P_LOGIC_AND: return 7; - case P_LOGIC_OR: return 6; - case P_LOGIC_GEQ: return 12; - case P_LOGIC_LEQ: return 12; - case P_LOGIC_EQ: return 11; - case P_LOGIC_UNEQ: return 11; - - case P_LOGIC_NOT: return 16; - case P_LOGIC_GREATER: return 12; - case P_LOGIC_LESS: return 12; - - case P_RSHIFT: return 13; - case P_LSHIFT: return 13; - - case P_BIN_AND: return 10; - case P_BIN_OR: return 8; - case P_BIN_XOR: return 9; - case P_BIN_NOT: return 16; - - case P_COLON: return 5; - case P_QUESTIONMARK: return 5; - } //end switch - return qfalse; -} //end of the function PC_OperatorPriority - -//#define AllocValue() GetClearedMemory(sizeof(value_t)); -//#define FreeValue(val) FreeMemory(val) -//#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t)); -//#define FreeOperator(op) FreeMemory(op); - -#define MAX_VALUES 64 -#define MAX_OPERATORS 64 -#define AllocValue(val) \ - if (numvalues >= MAX_VALUES) { \ - SourceError(source, "out of value space\n"); \ - error = 1; \ - break; \ - } \ - else \ - val = &value_heap[numvalues++]; -#define FreeValue(val) -// -#define AllocOperator(op) \ - if (numoperators >= MAX_OPERATORS) { \ - SourceError(source, "out of operator space\n"); \ - error = 1; \ - break; \ - } \ - else \ - op = &operator_heap[numoperators++]; -#define FreeOperator(op) - -int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue, - double *floatvalue, int integer) -{ - operator_t *o, *firstoperator, *lastoperator; - value_t *v, *firstvalue, *lastvalue, *v1, *v2; - token_t *t; - int brace = 0; - int parentheses = 0; - int error = 0; - int lastwasvalue = 0; - int negativevalue = 0; - int questmarkintvalue = 0; - double questmarkfloatvalue = 0; - int gotquestmarkvalue = qfalse; - int lastoperatortype = 0; - // - operator_t operator_heap[MAX_OPERATORS]; - int numoperators = 0; - value_t value_heap[MAX_VALUES]; - int numvalues = 0; - - firstoperator = lastoperator = NULL; - firstvalue = lastvalue = NULL; - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - for (t = tokens; t; t = t->next) - { - switch(t->type) - { - case TT_NAME: - { - if (lastwasvalue || negativevalue) - { - SourceError(source, "syntax error in #if/#elif"); - error = 1; - break; - } //end if - if (strcmp(t->string, "defined")) - { - SourceError(source, "undefined name %s in #if/#elif", t->string); - error = 1; - break; - } //end if - t = t->next; - if (!strcmp(t->string, "(")) - { - brace = qtrue; - t = t->next; - } //end if - if (!t || t->type != TT_NAME) - { - SourceError(source, "defined without name in #if/#elif"); - error = 1; - break; - } //end if - //v = (value_t *) GetClearedMemory(sizeof(value_t)); - AllocValue(v); -#if DEFINEHASHING - if (PC_FindHashedDefine(source->definehash, t->string)) -#else - if (PC_FindDefine(source->defines, t->string)) -#endif //DEFINEHASHING - { - v->intvalue = 1; - v->floatvalue = 1; - } //end if - else - { - v->intvalue = 0; - v->floatvalue = 0; - } //end else - v->parentheses = parentheses; - v->next = NULL; - v->prev = lastvalue; - if (lastvalue) lastvalue->next = v; - else firstvalue = v; - lastvalue = v; - if (brace) - { - t = t->next; - if (!t || strcmp(t->string, ")")) - { - SourceError(source, "defined without ) in #if/#elif"); - error = 1; - break; - } //end if - } //end if - brace = qfalse; - // defined() creates a value - lastwasvalue = 1; - break; - } //end case - case TT_NUMBER: - { - if (lastwasvalue) - { - SourceError(source, "syntax error in #if/#elif"); - error = 1; - break; - } //end if - //v = (value_t *) GetClearedMemory(sizeof(value_t)); - AllocValue(v); - if (negativevalue) - { - v->intvalue = - (signed int) t->intvalue; - v->floatvalue = - t->floatvalue; - } //end if - else - { - v->intvalue = t->intvalue; - v->floatvalue = t->floatvalue; - } //end else - v->parentheses = parentheses; - v->next = NULL; - v->prev = lastvalue; - if (lastvalue) lastvalue->next = v; - else firstvalue = v; - lastvalue = v; - //last token was a value - lastwasvalue = 1; - // - negativevalue = 0; - break; - } //end case - case TT_PUNCTUATION: - { - if (negativevalue) - { - SourceError(source, "misplaced minus sign in #if/#elif"); - error = 1; - break; - } //end if - if (t->subtype == P_PARENTHESESOPEN) - { - parentheses++; - break; - } //end if - else if (t->subtype == P_PARENTHESESCLOSE) - { - parentheses--; - if (parentheses < 0) - { - SourceError(source, "too many ) in #if/#elsif"); - error = 1; - } //end if - break; - } //end else if - //check for invalid operators on floating point values - if (!integer) - { - if (t->subtype == P_BIN_NOT || t->subtype == P_MOD || - t->subtype == P_RSHIFT || t->subtype == P_LSHIFT || - t->subtype == P_BIN_AND || t->subtype == P_BIN_OR || - t->subtype == P_BIN_XOR) - { - SourceError(source, "illigal operator %s on floating point operands\n", t->string); - error = 1; - break; - } //end if - } //end if - switch(t->subtype) - { - case P_LOGIC_NOT: - case P_BIN_NOT: - { - if (lastwasvalue) - { - SourceError(source, "! or ~ after value in #if/#elif"); - error = 1; - break; - } //end if - break; - } //end case - case P_INC: - case P_DEC: - { - SourceError(source, "++ or -- used in #if/#elif"); - break; - } //end case - case P_SUB: - { - if (!lastwasvalue) - { - negativevalue = 1; - break; - } //end if - } //end case - - case P_MUL: - case P_DIV: - case P_MOD: - case P_ADD: - - case P_LOGIC_AND: - case P_LOGIC_OR: - case P_LOGIC_GEQ: - case P_LOGIC_LEQ: - case P_LOGIC_EQ: - case P_LOGIC_UNEQ: - - case P_LOGIC_GREATER: - case P_LOGIC_LESS: - - case P_RSHIFT: - case P_LSHIFT: - - case P_BIN_AND: - case P_BIN_OR: - case P_BIN_XOR: - - case P_COLON: - case P_QUESTIONMARK: - { - if (!lastwasvalue) - { - SourceError(source, "operator %s after operator in #if/#elif", t->string); - error = 1; - break; - } //end if - break; - } //end case - default: - { - SourceError(source, "invalid operator %s in #if/#elif", t->string); - error = 1; - break; - } //end default - } //end switch - if (!error && !negativevalue) - { - //o = (operator_t *) GetClearedMemory(sizeof(operator_t)); - AllocOperator(o); - o->operator = t->subtype; - o->priority = PC_OperatorPriority(t->subtype); - o->parentheses = parentheses; - o->next = NULL; - o->prev = lastoperator; - if (lastoperator) lastoperator->next = o; - else firstoperator = o; - lastoperator = o; - lastwasvalue = 0; - } //end if - break; - } //end case - default: - { - SourceError(source, "unknown %s in #if/#elif", t->string); - error = 1; - break; - } //end default - } //end switch - if (error) break; - } //end for - if (!error) - { - if (!lastwasvalue) - { - SourceError(source, "trailing operator in #if/#elif"); - error = 1; - } //end if - else if (parentheses) - { - SourceError(source, "too many ( in #if/#elif"); - error = 1; - } //end else if - } //end if - // - gotquestmarkvalue = qfalse; - questmarkintvalue = 0; - questmarkfloatvalue = 0; - //while there are operators - while(!error && firstoperator) - { - v = firstvalue; - for (o = firstoperator; o->next; o = o->next) - { - //if the current operator is nested deeper in parentheses - //than the next operator - if (o->parentheses > o->next->parentheses) break; - //if the current and next operator are nested equally deep in parentheses - if (o->parentheses == o->next->parentheses) - { - //if the priority of the current operator is equal or higher - //than the priority of the next operator - if (o->priority >= o->next->priority) break; - } //end if - //if the arity of the operator isn't equal to 1 - if (o->operator != P_LOGIC_NOT - && o->operator != P_BIN_NOT) v = v->next; - //if there's no value or no next value - if (!v) - { - SourceError(source, "mising values in #if/#elif"); - error = 1; - break; - } //end if - } //end for - if (error) break; - v1 = v; - v2 = v->next; -#ifdef DEBUG_EVAL - if (integer) - { - Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue); - if (v2) Log_Write("value2 = %d", v2->intvalue); - } //end if - else - { - Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue); - if (v2) Log_Write("value2 = %f", v2->floatvalue); - } //end else -#endif //DEBUG_EVAL - switch(o->operator) - { - case P_LOGIC_NOT: v1->intvalue = !v1->intvalue; - v1->floatvalue = !v1->floatvalue; break; - case P_BIN_NOT: v1->intvalue = ~v1->intvalue; - break; - case P_MUL: v1->intvalue *= v2->intvalue; - v1->floatvalue *= v2->floatvalue; break; - case P_DIV: if (!v2->intvalue || !v2->floatvalue) - { - SourceError(source, "divide by zero in #if/#elif\n"); - error = 1; - break; - } - v1->intvalue /= v2->intvalue; - v1->floatvalue /= v2->floatvalue; break; - case P_MOD: if (!v2->intvalue) - { - SourceError(source, "divide by zero in #if/#elif\n"); - error = 1; - break; - } - v1->intvalue %= v2->intvalue; break; - case P_ADD: v1->intvalue += v2->intvalue; - v1->floatvalue += v2->floatvalue; break; - case P_SUB: v1->intvalue -= v2->intvalue; - v1->floatvalue -= v2->floatvalue; break; - case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue; - v1->floatvalue = v1->floatvalue && v2->floatvalue; break; - case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue; - v1->floatvalue = v1->floatvalue || v2->floatvalue; break; - case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue; - v1->floatvalue = v1->floatvalue >= v2->floatvalue; break; - case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue; - v1->floatvalue = v1->floatvalue <= v2->floatvalue; break; - case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue; - v1->floatvalue = v1->floatvalue == v2->floatvalue; break; - case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue; - v1->floatvalue = v1->floatvalue != v2->floatvalue; break; - case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue; - v1->floatvalue = v1->floatvalue > v2->floatvalue; break; - case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue; - v1->floatvalue = v1->floatvalue < v2->floatvalue; break; - case P_RSHIFT: v1->intvalue >>= v2->intvalue; - break; - case P_LSHIFT: v1->intvalue <<= v2->intvalue; - break; - case P_BIN_AND: v1->intvalue &= v2->intvalue; - break; - case P_BIN_OR: v1->intvalue |= v2->intvalue; - break; - case P_BIN_XOR: v1->intvalue ^= v2->intvalue; - break; - case P_COLON: - { - if (!gotquestmarkvalue) - { - SourceError(source, ": without ? in #if/#elif"); - error = 1; - break; - } //end if - if (integer) - { - if (!questmarkintvalue) v1->intvalue = v2->intvalue; - } //end if - else - { - if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue; - } //end else - gotquestmarkvalue = qfalse; - break; - } //end case - case P_QUESTIONMARK: - { - if (gotquestmarkvalue) - { - SourceError(source, "? after ? in #if/#elif"); - error = 1; - break; - } //end if - questmarkintvalue = v1->intvalue; - questmarkfloatvalue = v1->floatvalue; - gotquestmarkvalue = qtrue; - break; - } //end if - } //end switch -#ifdef DEBUG_EVAL - if (integer) Log_Write("result value = %d", v1->intvalue); - else Log_Write("result value = %f", v1->floatvalue); -#endif //DEBUG_EVAL - if (error) break; - lastoperatortype = o->operator; - //if not an operator with arity 1 - if (o->operator != P_LOGIC_NOT - && o->operator != P_BIN_NOT) - { - //remove the second value if not question mark operator - if (o->operator != P_QUESTIONMARK) v = v->next; - // - if (v->prev) v->prev->next = v->next; - else firstvalue = v->next; - if (v->next) v->next->prev = v->prev; - else lastvalue = v->prev; - //FreeMemory(v); - FreeValue(v); - } //end if - //remove the operator - if (o->prev) o->prev->next = o->next; - else firstoperator = o->next; - if (o->next) o->next->prev = o->prev; - else lastoperator = o->prev; - //FreeMemory(o); - FreeOperator(o); - } //end while - if (firstvalue) - { - if (intvalue) *intvalue = firstvalue->intvalue; - if (floatvalue) *floatvalue = firstvalue->floatvalue; - } //end if - for (o = firstoperator; o; o = lastoperator) - { - lastoperator = o->next; - //FreeMemory(o); - FreeOperator(o); - } //end for - for (v = firstvalue; v; v = lastvalue) - { - lastvalue = v->next; - //FreeMemory(v); - FreeValue(v); - } //end for - if (!error) return qtrue; - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - return qfalse; -} //end of the function PC_EvaluateTokens -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Evaluate(source_t *source, signed long int *intvalue, - double *floatvalue, int integer) -{ - token_t token, *firsttoken, *lasttoken; - token_t *t, *nexttoken; - define_t *define; - int defined = qfalse; - - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - // - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "no value after #if/#elif"); - return qfalse; - } //end if - firsttoken = NULL; - lasttoken = NULL; - do - { - //if the token is a name - if (token.type == TT_NAME) - { - if (defined) - { - defined = qfalse; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else if (!strcmp(token.string, "defined")) - { - defined = qtrue; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else - { - //then it must be a define -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - if (!define) - { - SourceError(source, "can't evaluate %s, not defined", token.string); - return qfalse; - } //end if - if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; - } //end else - } //end if - //if the token is a number or a punctuation - else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) - { - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end else - else //can't evaluate the token - { - SourceError(source, "can't evaluate %s", token.string); - return qfalse; - } //end else - } while(PC_ReadLine(source, &token)); - // - if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; - // -#ifdef DEBUG_EVAL - Log_Write("eval:"); -#endif //DEBUG_EVAL - for (t = firsttoken; t; t = nexttoken) - { -#ifdef DEBUG_EVAL - Log_Write(" %s", t->string); -#endif //DEBUG_EVAL - nexttoken = t->next; - PC_FreeToken(t); - } //end for -#ifdef DEBUG_EVAL - if (integer) Log_Write("eval result: %d", *intvalue); - else Log_Write("eval result: %f", *floatvalue); -#endif //DEBUG_EVAL - // - return qtrue; -} //end of the function PC_Evaluate -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_DollarEvaluate(source_t *source, signed long int *intvalue, - double *floatvalue, int integer) -{ - int indent, defined = qfalse; - token_t token, *firsttoken, *lasttoken; - token_t *t, *nexttoken; - define_t *define; - - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - // - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "no leading ( after $evalint/$evalfloat"); - return qfalse; - } //end if - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "nothing to evaluate"); - return qfalse; - } //end if - indent = 1; - firsttoken = NULL; - lasttoken = NULL; - do - { - //if the token is a name - if (token.type == TT_NAME) - { - if (defined) - { - defined = qfalse; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else if (!strcmp(token.string, "defined")) - { - defined = qtrue; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else - { - //then it must be a define -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - if (!define) - { - SourceError(source, "can't evaluate %s, not defined", token.string); - return qfalse; - } //end if - if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; - } //end else - } //end if - //if the token is a number or a punctuation - else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) - { - if (*token.string == '(') indent++; - else if (*token.string == ')') indent--; - if (indent <= 0) break; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end else - else //can't evaluate the token - { - SourceError(source, "can't evaluate %s", token.string); - return qfalse; - } //end else - } while(PC_ReadSourceToken(source, &token)); - // - if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; - // -#ifdef DEBUG_EVAL - Log_Write("$eval:"); -#endif //DEBUG_EVAL - for (t = firsttoken; t; t = nexttoken) - { -#ifdef DEBUG_EVAL - Log_Write(" %s", t->string); -#endif //DEBUG_EVAL - nexttoken = t->next; - PC_FreeToken(t); - } //end for -#ifdef DEBUG_EVAL - if (integer) Log_Write("$eval result: %d", *intvalue); - else Log_Write("$eval result: %f", *floatvalue); -#endif //DEBUG_EVAL - // - return qtrue; -} //end of the function PC_DollarEvaluate -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_elif(source_t *source) -{ - signed long int value; - int type, skip; - - PC_PopIndent(source, &type, &skip); - if (!type || type == INDENT_ELSE) - { - SourceError(source, "misplaced #elif"); - return qfalse; - } //end if - if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; - skip = (value == 0); - PC_PushIndent(source, INDENT_ELIF, skip); - return qtrue; -} //end of the function PC_Directive_elif -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_if(source_t *source) -{ - signed long int value; - int skip; - - if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; - skip = (value == 0); - PC_PushIndent(source, INDENT_IF, skip); - return qtrue; -} //end of the function PC_Directive -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_line(source_t *source) -{ - SourceError(source, "#line directive not supported"); - return qfalse; -} //end of the function PC_Directive_line -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_error(source_t *source) -{ - token_t token; - - strcpy(token.string, ""); - PC_ReadSourceToken(source, &token); - SourceError(source, "#error directive: %s", token.string); - return qfalse; -} //end of the function PC_Directive_error -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_pragma(source_t *source) -{ - token_t token; - - SourceWarning(source, "#pragma directive not supported"); - while(PC_ReadLine(source, &token)) ; - return qtrue; -} //end of the function PC_Directive_pragma -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void UnreadSignToken(source_t *source) -{ - token_t token; - - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - strcpy(token.string, "-"); - token.type = TT_PUNCTUATION; - token.subtype = P_SUB; - PC_UnreadSourceToken(source, &token); -} //end of the function UnreadSignToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_eval(source_t *source) -{ - signed long int value; - token_t token; - - if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; - // - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%d", abs(value)); - token.type = TT_NUMBER; - token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_Directive_eval -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_evalfloat(source_t *source) -{ - double value; - token_t token; - - if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse; - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%1.2f", fabs(value)); - token.type = TT_NUMBER; - token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_Directive_evalfloat -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -directive_t directives[20] = -{ - {"if", PC_Directive_if}, - {"ifdef", PC_Directive_ifdef}, - {"ifndef", PC_Directive_ifndef}, - {"elif", PC_Directive_elif}, - {"else", PC_Directive_else}, - {"endif", PC_Directive_endif}, - {"include", PC_Directive_include}, - {"define", PC_Directive_define}, - {"undef", PC_Directive_undef}, - {"line", PC_Directive_line}, - {"error", PC_Directive_error}, - {"pragma", PC_Directive_pragma}, - {"eval", PC_Directive_eval}, - {"evalfloat", PC_Directive_evalfloat}, - {NULL, NULL} -}; - -int PC_ReadDirective(source_t *source) -{ - token_t token; - int i; - - //read the directive name - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "found # without name"); - return qfalse; - } //end if - //directive name must be on the same line - if (token.linescrossed > 0) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "found # at end of line"); - return qfalse; - } //end if - //if if is a name - if (token.type == TT_NAME) - { - //find the precompiler directive - for (i = 0; directives[i].name; i++) - { - if (!strcmp(directives[i].name, token.string)) - { - return directives[i].func(source); - } //end if - } //end for - } //end if - SourceError(source, "unknown precompiler directive %s", token.string); - return qfalse; -} //end of the function PC_ReadDirective -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_DollarDirective_evalint(source_t *source) -{ - signed long int value; - token_t token; - - if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse; - // - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%d", abs(value)); - token.type = TT_NUMBER; - token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; -#ifdef NUMBERVALUE - token.intvalue = value; - token.floatvalue = value; -#endif //NUMBERVALUE - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_DollarDirective_evalint -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_DollarDirective_evalfloat(source_t *source) -{ - double value; - token_t token; - - if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse; - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%1.2f", fabs(value)); - token.type = TT_NUMBER; - token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; -#ifdef NUMBERVALUE - token.intvalue = (unsigned long) value; - token.floatvalue = value; -#endif //NUMBERVALUE - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_DollarDirective_evalfloat -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -directive_t dollardirectives[20] = -{ - {"evalint", PC_DollarDirective_evalint}, - {"evalfloat", PC_DollarDirective_evalfloat}, - {NULL, NULL} -}; - -int PC_ReadDollarDirective(source_t *source) -{ - token_t token; - int i; - - //read the directive name - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "found $ without name"); - return qfalse; - } //end if - //directive name must be on the same line - if (token.linescrossed > 0) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "found $ at end of line"); - return qfalse; - } //end if - //if if is a name - if (token.type == TT_NAME) - { - //find the precompiler directive - for (i = 0; dollardirectives[i].name; i++) - { - if (!strcmp(dollardirectives[i].name, token.string)) - { - return dollardirectives[i].func(source); - } //end if - } //end for - } //end if - PC_UnreadSourceToken(source, &token); - SourceError(source, "unknown precompiler directive %s", token.string); - return qfalse; -} //end of the function PC_ReadDirective - -#ifdef QUAKEC -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int BuiltinFunction(source_t *source) -{ - token_t token; - - if (!PC_ReadSourceToken(source, &token)) return qfalse; - if (token.type == TT_NUMBER) - { - PC_UnreadSourceToken(source, &token); - return qtrue; - } //end if - else - { - PC_UnreadSourceToken(source, &token); - return qfalse; - } //end else -} //end of the function BuiltinFunction -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int QuakeCMacro(source_t *source) -{ - int i; - token_t token; - - if (!PC_ReadSourceToken(source, &token)) return qtrue; - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - return qtrue; - } //end if - //find the precompiler directive - for (i = 0; dollardirectives[i].name; i++) - { - if (!strcmp(dollardirectives[i].name, token.string)) - { - PC_UnreadSourceToken(source, &token); - return qfalse; - } //end if - } //end for - PC_UnreadSourceToken(source, &token); - return qtrue; -} //end of the function QuakeCMacro -#endif //QUAKEC -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadToken(source_t *source, token_t *token) -{ - define_t *define; - - while(1) - { - if (!PC_ReadSourceToken(source, token)) return qfalse; - //check for precompiler directives - if (token->type == TT_PUNCTUATION && *token->string == '#') - { -#ifdef QUAKEC - if (!BuiltinFunction(source)) -#endif //QUAKC - { - //read the precompiler directive - if (!PC_ReadDirective(source)) return qfalse; - continue; - } //end if - } //end if - if (token->type == TT_PUNCTUATION && *token->string == '$') - { -#ifdef QUAKEC - if (!QuakeCMacro(source)) -#endif //QUAKEC - { - //read the precompiler directive - if (!PC_ReadDollarDirective(source)) return qfalse; - continue; - } //end if - } //end if - // recursively concatenate strings that are behind each other still resolving defines - if (token->type == TT_STRING) - { - token_t newtoken; - if (PC_ReadToken(source, &newtoken)) - { - if (newtoken.type == TT_STRING) - { - token->string[strlen(token->string)-1] = '\0'; - if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN) - { - SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN); - return qfalse; - } - strcat(token->string, newtoken.string+1); - } - else - { - PC_UnreadToken(source, &newtoken); - } - } - } //end if - //if skipping source because of conditional compilation - if (source->skip) continue; - //if the token is a name - if (token->type == TT_NAME) - { - //check if the name is a define macro -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token->string); -#else - define = PC_FindDefine(source->defines, token->string); -#endif //DEFINEHASHING - //if it is a define macro - if (define) - { - //expand the defined macro - if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse; - continue; - } //end if - } //end if - //copy token for unreading - Com_Memcpy(&source->token, token, sizeof(token_t)); - //found a token - return qtrue; - } //end while -} //end of the function PC_ReadToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpectTokenString(source_t *source, char *string) -{ - token_t token; - - if (!PC_ReadToken(source, &token)) - { - SourceError(source, "couldn't find expected %s", string); - return qfalse; - } //end if - - if (strcmp(token.string, string)) - { - SourceError(source, "expected %s, found %s", string, token.string); - return qfalse; - } //end if - return qtrue; -} //end of the function PC_ExpectTokenString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token) -{ - char str[MAX_TOKEN]; - - if (!PC_ReadToken(source, token)) - { - SourceError(source, "couldn't read expected token"); - return qfalse; - } //end if - - if (token->type != type) - { - strcpy(str, ""); - if (type == TT_STRING) strcpy(str, "string"); - if (type == TT_LITERAL) strcpy(str, "literal"); - if (type == TT_NUMBER) strcpy(str, "number"); - if (type == TT_NAME) strcpy(str, "name"); - if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); - SourceError(source, "expected a %s, found %s", str, token->string); - return qfalse; - } //end if - if (token->type == TT_NUMBER) - { - if ((token->subtype & subtype) != subtype) - { - if (subtype & TT_DECIMAL) strcpy(str, "decimal"); - if (subtype & TT_HEX) strcpy(str, "hex"); - if (subtype & TT_OCTAL) strcpy(str, "octal"); - if (subtype & TT_BINARY) strcpy(str, "binary"); - if (subtype & TT_LONG) strcat(str, " long"); - if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); - if (subtype & TT_FLOAT) strcat(str, " float"); - if (subtype & TT_INTEGER) strcat(str, " integer"); - SourceError(source, "expected %s, found %s", str, token->string); - return qfalse; - } //end if - } //end if - else if (token->type == TT_PUNCTUATION) - { - if (token->subtype != subtype) - { - SourceError(source, "found %s", token->string); - return qfalse; - } //end if - } //end else if - return qtrue; -} //end of the function PC_ExpectTokenType -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpectAnyToken(source_t *source, token_t *token) -{ - if (!PC_ReadToken(source, token)) - { - SourceError(source, "couldn't read expected token"); - return qfalse; - } //end if - else - { - return qtrue; - } //end else -} //end of the function PC_ExpectAnyToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_CheckTokenString(source_t *source, char *string) -{ - token_t tok; - - if (!PC_ReadToken(source, &tok)) return qfalse; - //if the token is available - if (!strcmp(tok.string, string)) return qtrue; - // - PC_UnreadSourceToken(source, &tok); - return qfalse; -} //end of the function PC_CheckTokenString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token) -{ - token_t tok; - - if (!PC_ReadToken(source, &tok)) return qfalse; - //if the type matches - if (tok.type == type && - (tok.subtype & subtype) == subtype) - { - Com_Memcpy(token, &tok, sizeof(token_t)); - return qtrue; - } //end if - // - PC_UnreadSourceToken(source, &tok); - return qfalse; -} //end of the function PC_CheckTokenType -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_SkipUntilString(source_t *source, char *string) -{ - token_t token; - - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, string)) return qtrue; - } //end while - return qfalse; -} //end of the function PC_SkipUntilString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_UnreadLastToken(source_t *source) -{ - PC_UnreadSourceToken(source, &source->token); -} //end of the function PC_UnreadLastToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_UnreadToken(source_t *source, token_t *token) -{ - PC_UnreadSourceToken(source, token); -} //end of the function PC_UnreadToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_SetIncludePath(source_t *source, char *path) -{ - strncpy(source->includepath, path, MAX_PATH); - //add trailing path seperator - if (source->includepath[strlen(source->includepath)-1] != '\\' && - source->includepath[strlen(source->includepath)-1] != '/') - { - strcat(source->includepath, PATHSEPERATOR_STR); - } //end if -} //end of the function PC_SetIncludePath -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_SetPunctuations(source_t *source, punctuation_t *p) -{ - source->punctuations = p; -} //end of the function PC_SetPunctuations -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -source_t *LoadSourceFile(const char *filename) -{ - source_t *source; - script_t *script; - - PC_InitTokenHeap(); - - script = LoadScriptFile(filename); - if (!script) return NULL; - - script->next = NULL; - - source = (source_t *) GetMemory(sizeof(source_t)); - Com_Memset(source, 0, sizeof(source_t)); - - strncpy(source->filename, filename, MAX_PATH); - source->scriptstack = script; - source->tokens = NULL; - source->defines = NULL; - source->indentstack = NULL; - source->skip = 0; - -#if DEFINEHASHING - source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); -#endif //DEFINEHASHING - PC_AddGlobalDefinesToSource(source); - return source; -} //end of the function LoadSourceFile -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -source_t *LoadSourceMemory(char *ptr, int length, char *name) -{ - source_t *source; - script_t *script; - - PC_InitTokenHeap(); - - script = LoadScriptMemory(ptr, length, name); - if (!script) return NULL; - script->next = NULL; - - source = (source_t *) GetMemory(sizeof(source_t)); - Com_Memset(source, 0, sizeof(source_t)); - - strncpy(source->filename, name, MAX_PATH); - source->scriptstack = script; - source->tokens = NULL; - source->defines = NULL; - source->indentstack = NULL; - source->skip = 0; - -#if DEFINEHASHING - source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); -#endif //DEFINEHASHING - PC_AddGlobalDefinesToSource(source); - return source; -} //end of the function LoadSourceMemory -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void FreeSource(source_t *source) -{ - script_t *script; - token_t *token; - define_t *define; - indent_t *indent; - int i; - - //PC_PrintDefineHashTable(source->definehash); - //free all the scripts - while(source->scriptstack) - { - script = source->scriptstack; - source->scriptstack = source->scriptstack->next; - FreeScript(script); - } //end for - //free all the tokens - while(source->tokens) - { - token = source->tokens; - source->tokens = source->tokens->next; - PC_FreeToken(token); - } //end for -#if DEFINEHASHING - for (i = 0; i < DEFINEHASHSIZE; i++) - { - while(source->definehash[i]) - { - define = source->definehash[i]; - source->definehash[i] = source->definehash[i]->hashnext; - PC_FreeDefine(define); - } //end while - } //end for -#else //DEFINEHASHING - //free all defines - while(source->defines) - { - define = source->defines; - source->defines = source->defines->next; - PC_FreeDefine(define); - } //end for -#endif //DEFINEHASHING - //free all indents - while(source->indentstack) - { - indent = source->indentstack; - source->indentstack = source->indentstack->next; - FreeMemory(indent); - } //end for -#if DEFINEHASHING - // - if (source->definehash) FreeMemory(source->definehash); -#endif //DEFINEHASHING - //free the source itself - FreeMemory(source); -} //end of the function FreeSource -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ - -#define MAX_SOURCEFILES 64 - -source_t *sourceFiles[MAX_SOURCEFILES]; - -int PC_LoadSourceHandle(const char *filename) -{ - source_t *source; - int i; - - for (i = 1; i < MAX_SOURCEFILES; i++) - { - if (!sourceFiles[i]) - break; - } //end for - if (i >= MAX_SOURCEFILES) - return 0; - PS_SetBaseFolder(""); - source = LoadSourceFile(filename); - if (!source) - return 0; - sourceFiles[i] = source; - return i; -} //end of the function PC_LoadSourceHandle -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_FreeSourceHandle(int handle) -{ - if (handle < 1 || handle >= MAX_SOURCEFILES) - return qfalse; - if (!sourceFiles[handle]) - return qfalse; - - FreeSource(sourceFiles[handle]); - sourceFiles[handle] = NULL; - return qtrue; -} //end of the function PC_FreeSourceHandle -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadTokenHandle(int handle, pc_token_t *pc_token) -{ - token_t token; - int ret; - - if (handle < 1 || handle >= MAX_SOURCEFILES) - return 0; - if (!sourceFiles[handle]) - return 0; - - ret = PC_ReadToken(sourceFiles[handle], &token); - strcpy(pc_token->string, token.string); - pc_token->type = token.type; - pc_token->subtype = token.subtype; - pc_token->intvalue = token.intvalue; - pc_token->floatvalue = token.floatvalue; - if (pc_token->type == TT_STRING) - StripDoubleQuotes(pc_token->string); - return ret; -} //end of the function PC_ReadTokenHandle -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_SourceFileAndLine(int handle, char *filename, int *line) -{ - if (handle < 1 || handle >= MAX_SOURCEFILES) - return qfalse; - if (!sourceFiles[handle]) - return qfalse; - - strcpy(filename, sourceFiles[handle]->filename); - if (sourceFiles[handle]->scriptstack) - *line = sourceFiles[handle]->scriptstack->line; - else - *line = 0; - return qtrue; -} //end of the function PC_SourceFileAndLine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_SetBaseFolder(char *path) -{ - PS_SetBaseFolder(path); -} //end of the function PC_SetBaseFolder -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_CheckOpenSourceHandles(void) -{ - int i; - - for (i = 1; i < MAX_SOURCEFILES; i++) - { - if (sourceFiles[i]) - { -#ifdef BOTLIB - botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename); -#endif //BOTLIB - } //end if - } //end for -} //end of the function PC_CheckOpenSourceHandles - +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// + +/***************************************************************************** + * name: l_precomp.c + * + * desc: pre compiler + * + * $Archive: /MissionPack/code/botlib/l_precomp.c $ + * + *****************************************************************************/ + +//Notes: fix: PC_StringizeTokens + +//#define SCREWUP +//#define BOTLIB +//#define QUAKE +//#define QUAKEC +//#define MEQCC + +#ifdef SCREWUP +#include +#include +#include +#include +#include +#include +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" + +typedef enum {qfalse, qtrue} qboolean; +#endif //SCREWUP + +#ifdef BOTLIB +#include "../game/q_shared.h" +#include "../game/botlib.h" +#include "be_interface.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_log.h" +#endif //BOTLIB + +#ifdef MEQCC +#include "qcc.h" +#include "time.h" //time & ctime +#include "math.h" //fabs +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_log.h" + +#define qtrue true +#define qfalse false +#endif //MEQCC + +#ifdef BSPC +//include files for usage in the BSP Converter +#include "../bspc/qbsp.h" +#include "../bspc/l_log.h" +#include "../bspc/l_mem.h" +#include "l_precomp.h" + +#define qtrue true +#define qfalse false +#define Q_stricmp stricmp + +#endif //BSPC + +#if defined(QUAKE) && !defined(BSPC) +#include "l_utils.h" +#endif //QUAKE + +//#define DEBUG_EVAL + +#define MAX_DEFINEPARMS 128 + +#define DEFINEHASHING 1 + +//directive name with parse function +typedef struct directive_s +{ + char *name; + int (*func)(source_t *source); +} directive_t; + +#define DEFINEHASHSIZE 1024 + +#define TOKEN_HEAP_SIZE 4096 + +int numtokens; +/* +int tokenheapinitialized; //true when the token heap is initialized +token_t token_heap[TOKEN_HEAP_SIZE]; //heap with tokens +token_t *freetokens; //free tokens from the heap +*/ + +//list with global defines added to every source loaded +define_t *globaldefines; + +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void QDECL SourceError(source_t *source, char *str, ...) +{ + char text[1024]; + va_list ap; + + va_start(ap, str); + vsprintf(text, str, ap); + va_end(ap); +#ifdef BOTLIB + botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BOTLIB +#ifdef MEQCC + printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //MEQCC +#ifdef BSPC + Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BSPC +} //end of the function SourceError +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL SourceWarning(source_t *source, char *str, ...) +{ + char text[1024]; + va_list ap; + + va_start(ap, str); + vsprintf(text, str, ap); + va_end(ap); +#ifdef BOTLIB + botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BOTLIB +#ifdef MEQCC + printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //MEQCC +#ifdef BSPC + Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BSPC +} //end of the function ScriptWarning +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PushIndent(source_t *source, int type, int skip) +{ + indent_t *indent; + + indent = (indent_t *) GetMemory(sizeof(indent_t)); + indent->type = type; + indent->script = source->scriptstack; + indent->skip = (skip != 0); + source->skip += indent->skip; + indent->next = source->indentstack; + source->indentstack = indent; +} //end of the function PC_PushIndent +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PopIndent(source_t *source, int *type, int *skip) +{ + indent_t *indent; + + *type = 0; + *skip = 0; + + indent = source->indentstack; + if (!indent) return; + + //must be an indent from the current script + if (source->indentstack->script != source->scriptstack) return; + + *type = indent->type; + *skip = indent->skip; + source->indentstack = source->indentstack->next; + source->skip -= indent->skip; + FreeMemory(indent); +} //end of the function PC_PopIndent +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PushScript(source_t *source, script_t *script) +{ + script_t *s; + + for (s = source->scriptstack; s; s = s->next) + { + if (!Q_stricmp(s->filename, script->filename)) + { + SourceError(source, "%s recursively included", script->filename); + return; + } //end if + } //end for + //push the script on the script stack + script->next = source->scriptstack; + source->scriptstack = script; +} //end of the function PC_PushScript +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_InitTokenHeap(void) +{ + /* + int i; + + if (tokenheapinitialized) return; + freetokens = NULL; + for (i = 0; i < TOKEN_HEAP_SIZE; i++) + { + token_heap[i].next = freetokens; + freetokens = &token_heap[i]; + } //end for + tokenheapinitialized = qtrue; + */ +} //end of the function PC_InitTokenHeap +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +token_t *PC_CopyToken(token_t *token) +{ + token_t *t; + +// t = (token_t *) malloc(sizeof(token_t)); + t = (token_t *) GetMemory(sizeof(token_t)); +// t = freetokens; + if (!t) + { +#ifdef BSPC + Error("out of token space\n"); +#else + Com_Error(ERR_FATAL, "out of token space\n"); +#endif + return NULL; + } //end if +// freetokens = freetokens->next; + Com_Memcpy(t, token, sizeof(token_t)); + t->next = NULL; + numtokens++; + return t; +} //end of the function PC_CopyToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_FreeToken(token_t *token) +{ + //free(token); + FreeMemory(token); +// token->next = freetokens; +// freetokens = token; + numtokens--; +} //end of the function PC_FreeToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadSourceToken(source_t *source, token_t *token) +{ + token_t *t; + script_t *script; + int type, skip; + + //if there's no token already available + while(!source->tokens) + { + //if there's a token to read from the script + if (PS_ReadToken(source->scriptstack, token)) return qtrue; + //if at the end of the script + if (EndOfScript(source->scriptstack)) + { + //remove all indents of the script + while(source->indentstack && + source->indentstack->script == source->scriptstack) + { + SourceWarning(source, "missing #endif"); + PC_PopIndent(source, &type, &skip); + } //end if + } //end if + //if this was the initial script + if (!source->scriptstack->next) return qfalse; + //remove the script and return to the last one + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + FreeScript(script); + } //end while + //copy the already available token + Com_Memcpy(token, source->tokens, sizeof(token_t)); + //free the read token + t = source->tokens; + source->tokens = source->tokens->next; + PC_FreeToken(t); + return qtrue; +} //end of the function PC_ReadSourceToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_UnreadSourceToken(source_t *source, token_t *token) +{ + token_t *t; + + t = PC_CopyToken(token); + t->next = source->tokens; + source->tokens = t; + return qtrue; +} //end of the function PC_UnreadSourceToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms) +{ + token_t token, *t, *last; + int i, done, lastcomma, numparms, indent; + + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "define %s missing parms", define->name); + return qfalse; + } //end if + // + if (define->numparms > maxparms) + { + SourceError(source, "define with more than %d parameters", maxparms); + return qfalse; + } //end if + // + for (i = 0; i < define->numparms; i++) parms[i] = NULL; + //if no leading "(" + if (strcmp(token.string, "(")) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "define %s missing parms", define->name); + return qfalse; + } //end if + //read the define parameters + for (done = 0, numparms = 0, indent = 0; !done;) + { + if (numparms >= maxparms) + { + SourceError(source, "define %s with too many parms", define->name); + return qfalse; + } //end if + if (numparms >= define->numparms) + { + SourceWarning(source, "define %s has too many parms", define->name); + return qfalse; + } //end if + parms[numparms] = NULL; + lastcomma = 1; + last = NULL; + while(!done) + { + // + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "define %s incomplete", define->name); + return qfalse; + } //end if + // + if (!strcmp(token.string, ",")) + { + if (indent <= 0) + { + if (lastcomma) SourceWarning(source, "too many comma's"); + lastcomma = 1; + break; + } //end if + } //end if + lastcomma = 0; + // + if (!strcmp(token.string, "(")) + { + indent++; + continue; + } //end if + else if (!strcmp(token.string, ")")) + { + if (--indent <= 0) + { + if (!parms[define->numparms-1]) + { + SourceWarning(source, "too few define parms"); + } //end if + done = 1; + break; + } //end if + } //end if + // + if (numparms < define->numparms) + { + // + t = PC_CopyToken(&token); + t->next = NULL; + if (last) last->next = t; + else parms[numparms] = t; + last = t; + } //end if + } //end while + numparms++; + } //end for + return qtrue; +} //end of the function PC_ReadDefineParms +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_StringizeTokens(token_t *tokens, token_t *token) +{ + token_t *t; + + token->type = TT_STRING; + token->whitespace_p = NULL; + token->endwhitespace_p = NULL; + token->string[0] = '\0'; + strcat(token->string, "\""); + for (t = tokens; t; t = t->next) + { + strncat(token->string, t->string, MAX_TOKEN - strlen(token->string)); + } //end for + strncat(token->string, "\"", MAX_TOKEN - strlen(token->string)); + return qtrue; +} //end of the function PC_StringizeTokens +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_MergeTokens(token_t *t1, token_t *t2) +{ + //merging of a name with a name or number + if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER)) + { + strcat(t1->string, t2->string); + return qtrue; + } //end if + //merging of two strings + if (t1->type == TT_STRING && t2->type == TT_STRING) + { + //remove trailing double quote + t1->string[strlen(t1->string)-1] = '\0'; + //concat without leading double quote + strcat(t1->string, &t2->string[1]); + return qtrue; + } //end if + //FIXME: merging of two number of the same sub type + return qfalse; +} //end of the function PC_MergeTokens +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +/* +void PC_PrintDefine(define_t *define) +{ + printf("define->name = %s\n", define->name); + printf("define->flags = %d\n", define->flags); + printf("define->builtin = %d\n", define->builtin); + printf("define->numparms = %d\n", define->numparms); +// token_t *parms; //define parameters +// token_t *tokens; //macro tokens (possibly containing parm tokens) +// struct define_s *next; //next defined macro in a list +} //end of the function PC_PrintDefine*/ +#if DEFINEHASHING +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PrintDefineHashTable(define_t **definehash) +{ + int i; + define_t *d; + + for (i = 0; i < DEFINEHASHSIZE; i++) + { + Log_Write("%4d:", i); + for (d = definehash[i]; d; d = d->hashnext) + { + Log_Write(" %s", d->name); + } //end for + Log_Write("\n"); + } //end for +} //end of the function PC_PrintDefineHashTable +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47}; + +int PC_NameHash(char *name) +{ + int register hash, i; + + hash = 0; + for (i = 0; name[i] != '\0'; i++) + { + hash += name[i] * (119 + i); + //hash += (name[i] << 7) + i; + //hash += (name[i] << (i&15)); + } //end while + hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1); + return hash; +} //end of the function PC_NameHash +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_AddDefineToHash(define_t *define, define_t **definehash) +{ + int hash; + + hash = PC_NameHash(define->name); + define->hashnext = definehash[hash]; + definehash[hash] = define; +} //end of the function PC_AddDefineToHash +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_FindHashedDefine(define_t **definehash, char *name) +{ + define_t *d; + int hash; + + hash = PC_NameHash(name); + for (d = definehash[hash]; d; d = d->hashnext) + { + if (!strcmp(d->name, name)) return d; + } //end for + return NULL; +} //end of the function PC_FindHashedDefine +#endif //DEFINEHASHING +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_FindDefine(define_t *defines, char *name) +{ + define_t *d; + + for (d = defines; d; d = d->next) + { + if (!strcmp(d->name, name)) return d; + } //end for + return NULL; +} //end of the function PC_FindDefine +//============================================================================ +// +// Parameter: - +// Returns: number of the parm +// if no parm found with the given name -1 is returned +// Changes Globals: - +//============================================================================ +int PC_FindDefineParm(define_t *define, char *name) +{ + token_t *p; + int i; + + i = 0; + for (p = define->parms; p; p = p->next) + { + if (!strcmp(p->string, name)) return i; + i++; + } //end for + return -1; +} //end of the function PC_FindDefineParm +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_FreeDefine(define_t *define) +{ + token_t *t, *next; + + //free the define parameters + for (t = define->parms; t; t = next) + { + next = t->next; + PC_FreeToken(t); + } //end for + //free the define tokens + for (t = define->tokens; t; t = next) + { + next = t->next; + PC_FreeToken(t); + } //end for + //free the define + FreeMemory(define); +} //end of the function PC_FreeDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_AddBuiltinDefines(source_t *source) +{ + int i; + define_t *define; + struct builtin + { + char *string; + int builtin; + } builtin[] = { // bk001204 - brackets + { "__LINE__", BUILTIN_LINE }, + { "__FILE__", BUILTIN_FILE }, + { "__DATE__", BUILTIN_DATE }, + { "__TIME__", BUILTIN_TIME }, +// { "__STDC__", BUILTIN_STDC }, + { NULL, 0 } + }; + + for (i = 0; builtin[i].string; i++) + { + define = (define_t *) GetMemory(sizeof(define_t) + strlen(builtin[i].string) + 1); + Com_Memset(define, 0, sizeof(define_t)); + define->name = (char *) define + sizeof(define_t); + strcpy(define->name, builtin[i].string); + define->flags |= DEFINE_FIXED; + define->builtin = builtin[i].builtin; + //add the define to the source +#if DEFINEHASHING + PC_AddDefineToHash(define, source->definehash); +#else + define->next = source->defines; + source->defines = define; +#endif //DEFINEHASHING + } //end for +} //end of the function PC_AddBuiltinDefines +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define, + token_t **firsttoken, token_t **lasttoken) +{ + token_t *token; + unsigned long t; // time_t t; //to prevent LCC warning + char *curtime; + + token = PC_CopyToken(deftoken); + switch(define->builtin) + { + case BUILTIN_LINE: + { + sprintf(token->string, "%d", deftoken->line); +#ifdef NUMBERVALUE + token->intvalue = deftoken->line; + token->floatvalue = deftoken->line; +#endif //NUMBERVALUE + token->type = TT_NUMBER; + token->subtype = TT_DECIMAL | TT_INTEGER; + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_FILE: + { + strcpy(token->string, source->scriptstack->filename); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_DATE: + { + t = time(NULL); + curtime = ctime(&t); + strcpy(token->string, "\""); + strncat(token->string, curtime+4, 7); + strncat(token->string+7, curtime+20, 4); + strcat(token->string, "\""); + free(curtime); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_TIME: + { + t = time(NULL); + curtime = ctime(&t); + strcpy(token->string, "\""); + strncat(token->string, curtime+11, 8); + strcat(token->string, "\""); + free(curtime); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_STDC: + default: + { + *firsttoken = NULL; + *lasttoken = NULL; + break; + } //end case + } //end switch + return qtrue; +} //end of the function PC_ExpandBuiltinDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, + token_t **firsttoken, token_t **lasttoken) +{ + token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; + token_t *t1, *t2, *first, *last, *nextpt, token; + int parmnum, i; + + //if it is a builtin define + if (define->builtin) + { + return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken); + } //end if + //if the define has parameters + if (define->numparms) + { + if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse; +#ifdef DEBUG_EVAL + for (i = 0; i < define->numparms; i++) + { + Log_Write("define parms %d:", i); + for (pt = parms[i]; pt; pt = pt->next) + { + Log_Write("%s", pt->string); + } //end for + } //end for +#endif //DEBUG_EVAL + } //end if + //empty list at first + first = NULL; + last = NULL; + //create a list with tokens of the expanded define + for (dt = define->tokens; dt; dt = dt->next) + { + parmnum = -1; + //if the token is a name, it could be a define parameter + if (dt->type == TT_NAME) + { + parmnum = PC_FindDefineParm(define, dt->string); + } //end if + //if it is a define parameter + if (parmnum >= 0) + { + for (pt = parms[parmnum]; pt; pt = pt->next) + { + t = PC_CopyToken(pt); + //add the token to the list + t->next = NULL; + if (last) last->next = t; + else first = t; + last = t; + } //end for + } //end if + else + { + //if stringizing operator + if (dt->string[0] == '#' && dt->string[1] == '\0') + { + //the stringizing operator must be followed by a define parameter + if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string); + else parmnum = -1; + // + if (parmnum >= 0) + { + //step over the stringizing operator + dt = dt->next; + //stringize the define parameter tokens + if (!PC_StringizeTokens(parms[parmnum], &token)) + { + SourceError(source, "can't stringize tokens"); + return qfalse; + } //end if + t = PC_CopyToken(&token); + } //end if + else + { + SourceWarning(source, "stringizing operator without define parameter"); + continue; + } //end if + } //end if + else + { + t = PC_CopyToken(dt); + } //end else + //add the token to the list + t->next = NULL; + if (last) last->next = t; + else first = t; + last = t; + } //end else + } //end for + //check for the merging operator + for (t = first; t; ) + { + if (t->next) + { + //if the merging operator + if (t->next->string[0] == '#' && t->next->string[1] == '#') + { + t1 = t; + t2 = t->next->next; + if (t2) + { + if (!PC_MergeTokens(t1, t2)) + { + SourceError(source, "can't merge %s with %s", t1->string, t2->string); + return qfalse; + } //end if + PC_FreeToken(t1->next); + t1->next = t2->next; + if (t2 == last) last = t1; + PC_FreeToken(t2); + continue; + } //end if + } //end if + } //end if + t = t->next; + } //end for + //store the first and last token of the list + *firsttoken = first; + *lasttoken = last; + //free all the parameter tokens + for (i = 0; i < define->numparms; i++) + { + for (pt = parms[i]; pt; pt = nextpt) + { + nextpt = pt->next; + PC_FreeToken(pt); + } //end for + } //end for + // + return qtrue; +} //end of the function PC_ExpandDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define) +{ + token_t *firsttoken, *lasttoken; + + if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse; + + if (firsttoken && lasttoken) + { + lasttoken->next = source->tokens; + source->tokens = firsttoken; + return qtrue; + } //end if + return qfalse; +} //end of the function PC_ExpandDefineIntoSource +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_ConvertPath(char *path) +{ + char *ptr; + + //remove double path seperators + for (ptr = path; *ptr;) + { + if ((*ptr == '\\' || *ptr == '/') && + (*(ptr+1) == '\\' || *(ptr+1) == '/')) + { + strcpy(ptr, ptr+1); + } //end if + else + { + ptr++; + } //end else + } //end while + //set OS dependent path seperators + for (ptr = path; *ptr;) + { + if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR; + ptr++; + } //end while +} //end of the function PC_ConvertPath +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_include(source_t *source) +{ + script_t *script; + token_t token; + char path[MAX_PATH]; +#ifdef QUAKE + foundfile_t file; +#endif //QUAKE + + if (source->skip > 0) return qtrue; + // + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "#include without file name"); + return qfalse; + } //end if + if (token.linescrossed > 0) + { + SourceError(source, "#include without file name"); + return qfalse; + } //end if + if (token.type == TT_STRING) + { + StripDoubleQuotes(token.string); + PC_ConvertPath(token.string); + script = LoadScriptFile(token.string); + if (!script) + { + strcpy(path, source->includepath); + strcat(path, token.string); + script = LoadScriptFile(path); + } //end if + } //end if + else if (token.type == TT_PUNCTUATION && *token.string == '<') + { + strcpy(path, source->includepath); + while(PC_ReadSourceToken(source, &token)) + { + if (token.linescrossed > 0) + { + PC_UnreadSourceToken(source, &token); + break; + } //end if + if (token.type == TT_PUNCTUATION && *token.string == '>') break; + strncat(path, token.string, MAX_PATH); + } //end while + if (*token.string != '>') + { + SourceWarning(source, "#include missing trailing >"); + } //end if + if (!strlen(path)) + { + SourceError(source, "#include without file name between < >"); + return qfalse; + } //end if + PC_ConvertPath(path); + script = LoadScriptFile(path); + } //end if + else + { + SourceError(source, "#include without file name"); + return qfalse; + } //end else +#ifdef QUAKE + if (!script) + { + Com_Memset(&file, 0, sizeof(foundfile_t)); + script = LoadScriptFile(path); + if (script) strncpy(script->filename, path, MAX_PATH); + } //end if +#endif //QUAKE + if (!script) + { +#ifdef SCREWUP + SourceWarning(source, "file %s not found", path); + return qtrue; +#else + SourceError(source, "file %s not found", path); + return qfalse; +#endif //SCREWUP + } //end if + PC_PushScript(source, script); + return qtrue; +} //end of the function PC_Directive_include +//============================================================================ +// reads a token from the current line, continues reading on the next +// line only if a backslash '\' is encountered. +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadLine(source_t *source, token_t *token) +{ + int crossline; + + crossline = 0; + do + { + if (!PC_ReadSourceToken(source, token)) return qfalse; + + if (token->linescrossed > crossline) + { + PC_UnreadSourceToken(source, token); + return qfalse; + } //end if + crossline = 1; + } while(!strcmp(token->string, "\\")); + return qtrue; +} //end of the function PC_ReadLine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_WhiteSpaceBeforeToken(token_t *token) +{ + return token->endwhitespace_p - token->whitespace_p > 0; +} //end of the function PC_WhiteSpaceBeforeToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_ClearTokenWhiteSpace(token_t *token) +{ + token->whitespace_p = NULL; + token->endwhitespace_p = NULL; + token->linescrossed = 0; +} //end of the function PC_ClearTokenWhiteSpace +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_undef(source_t *source) +{ + token_t token; + define_t *define, *lastdefine; + int hash; + + if (source->skip > 0) return qtrue; + // + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "undef without name"); + return qfalse; + } //end if + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "expected name, found %s", token.string); + return qfalse; + } //end if +#if DEFINEHASHING + + hash = PC_NameHash(token.string); + for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext) + { + if (!strcmp(define->name, token.string)) + { + if (define->flags & DEFINE_FIXED) + { + SourceWarning(source, "can't undef %s", token.string); + } //end if + else + { + if (lastdefine) lastdefine->hashnext = define->hashnext; + else source->definehash[hash] = define->hashnext; + PC_FreeDefine(define); + } //end else + break; + } //end if + lastdefine = define; + } //end for +#else //DEFINEHASHING + for (lastdefine = NULL, define = source->defines; define; define = define->next) + { + if (!strcmp(define->name, token.string)) + { + if (define->flags & DEFINE_FIXED) + { + SourceWarning(source, "can't undef %s", token.string); + } //end if + else + { + if (lastdefine) lastdefine->next = define->next; + else source->defines = define->next; + PC_FreeDefine(define); + } //end else + break; + } //end if + lastdefine = define; + } //end for +#endif //DEFINEHASHING + return qtrue; +} //end of the function PC_Directive_undef +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_define(source_t *source) +{ + token_t token, *t, *last; + define_t *define; + + if (source->skip > 0) return qtrue; + // + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "#define without name"); + return qfalse; + } //end if + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "expected name after #define, found %s", token.string); + return qfalse; + } //end if + //check if the define already exists +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + if (define) + { + if (define->flags & DEFINE_FIXED) + { + SourceError(source, "can't redefine %s", token.string); + return qfalse; + } //end if + SourceWarning(source, "redefinition of %s", token.string); + //unread the define name before executing the #undef directive + PC_UnreadSourceToken(source, &token); + if (!PC_Directive_undef(source)) return qfalse; + //if the define was not removed (define->flags & DEFINE_FIXED) +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + } //end if + //allocate define + define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1); + Com_Memset(define, 0, sizeof(define_t)); + define->name = (char *) define + sizeof(define_t); + strcpy(define->name, token.string); + //add the define to the source +#if DEFINEHASHING + PC_AddDefineToHash(define, source->definehash); +#else //DEFINEHASHING + define->next = source->defines; + source->defines = define; +#endif //DEFINEHASHING + //if nothing is defined, just return + if (!PC_ReadLine(source, &token)) return qtrue; + //if it is a define with parameters + if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "(")) + { + //read the define parameters + last = NULL; + if (!PC_CheckTokenString(source, ")")) + { + while(1) + { + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "expected define parameter"); + return qfalse; + } //end if + //if it isn't a name + if (token.type != TT_NAME) + { + SourceError(source, "invalid define parameter"); + return qfalse; + } //end if + // + if (PC_FindDefineParm(define, token.string) >= 0) + { + SourceError(source, "two the same define parameters"); + return qfalse; + } //end if + //add the define parm + t = PC_CopyToken(&token); + PC_ClearTokenWhiteSpace(t); + t->next = NULL; + if (last) last->next = t; + else define->parms = t; + last = t; + define->numparms++; + //read next token + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "define parameters not terminated"); + return qfalse; + } //end if + // + if (!strcmp(token.string, ")")) break; + //then it must be a comma + if (strcmp(token.string, ",")) + { + SourceError(source, "define not terminated"); + return qfalse; + } //end if + } //end while + } //end if + if (!PC_ReadLine(source, &token)) return qtrue; + } //end if + //read the defined stuff + last = NULL; + do + { + t = PC_CopyToken(&token); + if (t->type == TT_NAME && !strcmp(t->string, define->name)) + { + SourceError(source, "recursive define (removed recursion)"); + continue; + } //end if + PC_ClearTokenWhiteSpace(t); + t->next = NULL; + if (last) last->next = t; + else define->tokens = t; + last = t; + } while(PC_ReadLine(source, &token)); + // + if (last) + { + //check for merge operators at the beginning or end + if (!strcmp(define->tokens->string, "##") || + !strcmp(last->string, "##")) + { + SourceError(source, "define with misplaced ##"); + return qfalse; + } //end if + } //end if + return qtrue; +} //end of the function PC_Directive_define +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_DefineFromString(char *string) +{ + script_t *script; + source_t src; + token_t *t; + int res, i; + define_t *def; + + PC_InitTokenHeap(); + + script = LoadScriptMemory(string, strlen(string), "*extern"); + //create a new source + Com_Memset(&src, 0, sizeof(source_t)); + strncpy(src.filename, "*extern", MAX_PATH); + src.scriptstack = script; +#if DEFINEHASHING + src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); +#endif //DEFINEHASHING + //create a define from the source + res = PC_Directive_define(&src); + //free any tokens if left + for (t = src.tokens; t; t = src.tokens) + { + src.tokens = src.tokens->next; + PC_FreeToken(t); + } //end for +#ifdef DEFINEHASHING + def = NULL; + for (i = 0; i < DEFINEHASHSIZE; i++) + { + if (src.definehash[i]) + { + def = src.definehash[i]; + break; + } //end if + } //end for +#else + def = src.defines; +#endif //DEFINEHASHING + // +#if DEFINEHASHING + FreeMemory(src.definehash); +#endif //DEFINEHASHING + // + FreeScript(script); + //if the define was created succesfully + if (res > 0) return def; + //free the define is created + if (src.defines) PC_FreeDefine(def); + // + return NULL; +} //end of the function PC_DefineFromString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_AddDefine(source_t *source, char *string) +{ + define_t *define; + + define = PC_DefineFromString(string); + if (!define) return qfalse; +#if DEFINEHASHING + PC_AddDefineToHash(define, source->definehash); +#else //DEFINEHASHING + define->next = source->defines; + source->defines = define; +#endif //DEFINEHASHING + return qtrue; +} //end of the function PC_AddDefine +//============================================================================ +// add a globals define that will be added to all opened sources +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_AddGlobalDefine(char *string) +{ + define_t *define; + + define = PC_DefineFromString(string); + if (!define) return qfalse; + define->next = globaldefines; + globaldefines = define; + return qtrue; +} //end of the function PC_AddGlobalDefine +//============================================================================ +// remove the given global define +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_RemoveGlobalDefine(char *name) +{ + define_t *define; + + define = PC_FindDefine(globaldefines, name); + if (define) + { + PC_FreeDefine(define); + return qtrue; + } //end if + return qfalse; +} //end of the function PC_RemoveGlobalDefine +//============================================================================ +// remove all globals defines +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_RemoveAllGlobalDefines(void) +{ + define_t *define; + + for (define = globaldefines; define; define = globaldefines) + { + globaldefines = globaldefines->next; + PC_FreeDefine(define); + } //end for +} //end of the function PC_RemoveAllGlobalDefines +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_CopyDefine(source_t *source, define_t *define) +{ + define_t *newdefine; + token_t *token, *newtoken, *lasttoken; + + newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1); + //copy the define name + newdefine->name = (char *) newdefine + sizeof(define_t); + strcpy(newdefine->name, define->name); + newdefine->flags = define->flags; + newdefine->builtin = define->builtin; + newdefine->numparms = define->numparms; + //the define is not linked + newdefine->next = NULL; + newdefine->hashnext = NULL; + //copy the define tokens + newdefine->tokens = NULL; + for (lasttoken = NULL, token = define->tokens; token; token = token->next) + { + newtoken = PC_CopyToken(token); + newtoken->next = NULL; + if (lasttoken) lasttoken->next = newtoken; + else newdefine->tokens = newtoken; + lasttoken = newtoken; + } //end for + //copy the define parameters + newdefine->parms = NULL; + for (lasttoken = NULL, token = define->parms; token; token = token->next) + { + newtoken = PC_CopyToken(token); + newtoken->next = NULL; + if (lasttoken) lasttoken->next = newtoken; + else newdefine->parms = newtoken; + lasttoken = newtoken; + } //end for + return newdefine; +} //end of the function PC_CopyDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_AddGlobalDefinesToSource(source_t *source) +{ + define_t *define, *newdefine; + + for (define = globaldefines; define; define = define->next) + { + newdefine = PC_CopyDefine(source, define); +#if DEFINEHASHING + PC_AddDefineToHash(newdefine, source->definehash); +#else //DEFINEHASHING + newdefine->next = source->defines; + source->defines = newdefine; +#endif //DEFINEHASHING + } //end for +} //end of the function PC_AddGlobalDefinesToSource +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_if_def(source_t *source, int type) +{ + token_t token; + define_t *d; + int skip; + + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "#ifdef without name"); + return qfalse; + } //end if + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "expected name after #ifdef, found %s", token.string); + return qfalse; + } //end if +#if DEFINEHASHING + d = PC_FindHashedDefine(source->definehash, token.string); +#else + d = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + skip = (type == INDENT_IFDEF) == (d == NULL); + PC_PushIndent(source, type, skip); + return qtrue; +} //end of the function PC_Directiveif_def +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_ifdef(source_t *source) +{ + return PC_Directive_if_def(source, INDENT_IFDEF); +} //end of the function PC_Directive_ifdef +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_ifndef(source_t *source) +{ + return PC_Directive_if_def(source, INDENT_IFNDEF); +} //end of the function PC_Directive_ifndef +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_else(source_t *source) +{ + int type, skip; + + PC_PopIndent(source, &type, &skip); + if (!type) + { + SourceError(source, "misplaced #else"); + return qfalse; + } //end if + if (type == INDENT_ELSE) + { + SourceError(source, "#else after #else"); + return qfalse; + } //end if + PC_PushIndent(source, INDENT_ELSE, !skip); + return qtrue; +} //end of the function PC_Directive_else +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_endif(source_t *source) +{ + int type, skip; + + PC_PopIndent(source, &type, &skip); + if (!type) + { + SourceError(source, "misplaced #endif"); + return qfalse; + } //end if + return qtrue; +} //end of the function PC_Directive_endif +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +typedef struct operator_s +{ + int operator; + int priority; + int parentheses; + struct operator_s *prev, *next; +} operator_t; + +typedef struct value_s +{ + signed long int intvalue; + double floatvalue; + int parentheses; + struct value_s *prev, *next; +} value_t; + +int PC_OperatorPriority(int op) +{ + switch(op) + { + case P_MUL: return 15; + case P_DIV: return 15; + case P_MOD: return 15; + case P_ADD: return 14; + case P_SUB: return 14; + + case P_LOGIC_AND: return 7; + case P_LOGIC_OR: return 6; + case P_LOGIC_GEQ: return 12; + case P_LOGIC_LEQ: return 12; + case P_LOGIC_EQ: return 11; + case P_LOGIC_UNEQ: return 11; + + case P_LOGIC_NOT: return 16; + case P_LOGIC_GREATER: return 12; + case P_LOGIC_LESS: return 12; + + case P_RSHIFT: return 13; + case P_LSHIFT: return 13; + + case P_BIN_AND: return 10; + case P_BIN_OR: return 8; + case P_BIN_XOR: return 9; + case P_BIN_NOT: return 16; + + case P_COLON: return 5; + case P_QUESTIONMARK: return 5; + } //end switch + return qfalse; +} //end of the function PC_OperatorPriority + +//#define AllocValue() GetClearedMemory(sizeof(value_t)); +//#define FreeValue(val) FreeMemory(val) +//#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t)); +//#define FreeOperator(op) FreeMemory(op); + +#define MAX_VALUES 64 +#define MAX_OPERATORS 64 +#define AllocValue(val) \ + if (numvalues >= MAX_VALUES) { \ + SourceError(source, "out of value space\n"); \ + error = 1; \ + break; \ + } \ + else \ + val = &value_heap[numvalues++]; +#define FreeValue(val) +// +#define AllocOperator(op) \ + if (numoperators >= MAX_OPERATORS) { \ + SourceError(source, "out of operator space\n"); \ + error = 1; \ + break; \ + } \ + else \ + op = &operator_heap[numoperators++]; +#define FreeOperator(op) + +int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue, + double *floatvalue, int integer) +{ + operator_t *o, *firstoperator, *lastoperator; + value_t *v, *firstvalue, *lastvalue, *v1, *v2; + token_t *t; + int brace = 0; + int parentheses = 0; + int error = 0; + int lastwasvalue = 0; + int negativevalue = 0; + int questmarkintvalue = 0; + double questmarkfloatvalue = 0; + int gotquestmarkvalue = qfalse; + int lastoperatortype = 0; + // + operator_t operator_heap[MAX_OPERATORS]; + int numoperators = 0; + value_t value_heap[MAX_VALUES]; + int numvalues = 0; + + firstoperator = lastoperator = NULL; + firstvalue = lastvalue = NULL; + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + for (t = tokens; t; t = t->next) + { + switch(t->type) + { + case TT_NAME: + { + if (lastwasvalue || negativevalue) + { + SourceError(source, "syntax error in #if/#elif"); + error = 1; + break; + } //end if + if (strcmp(t->string, "defined")) + { + SourceError(source, "undefined name %s in #if/#elif", t->string); + error = 1; + break; + } //end if + t = t->next; + if (!strcmp(t->string, "(")) + { + brace = qtrue; + t = t->next; + } //end if + if (!t || t->type != TT_NAME) + { + SourceError(source, "defined without name in #if/#elif"); + error = 1; + break; + } //end if + //v = (value_t *) GetClearedMemory(sizeof(value_t)); + AllocValue(v); +#if DEFINEHASHING + if (PC_FindHashedDefine(source->definehash, t->string)) +#else + if (PC_FindDefine(source->defines, t->string)) +#endif //DEFINEHASHING + { + v->intvalue = 1; + v->floatvalue = 1; + } //end if + else + { + v->intvalue = 0; + v->floatvalue = 0; + } //end else + v->parentheses = parentheses; + v->next = NULL; + v->prev = lastvalue; + if (lastvalue) lastvalue->next = v; + else firstvalue = v; + lastvalue = v; + if (brace) + { + t = t->next; + if (!t || strcmp(t->string, ")")) + { + SourceError(source, "defined without ) in #if/#elif"); + error = 1; + break; + } //end if + } //end if + brace = qfalse; + // defined() creates a value + lastwasvalue = 1; + break; + } //end case + case TT_NUMBER: + { + if (lastwasvalue) + { + SourceError(source, "syntax error in #if/#elif"); + error = 1; + break; + } //end if + //v = (value_t *) GetClearedMemory(sizeof(value_t)); + AllocValue(v); + if (negativevalue) + { + v->intvalue = - (signed int) t->intvalue; + v->floatvalue = - t->floatvalue; + } //end if + else + { + v->intvalue = t->intvalue; + v->floatvalue = t->floatvalue; + } //end else + v->parentheses = parentheses; + v->next = NULL; + v->prev = lastvalue; + if (lastvalue) lastvalue->next = v; + else firstvalue = v; + lastvalue = v; + //last token was a value + lastwasvalue = 1; + // + negativevalue = 0; + break; + } //end case + case TT_PUNCTUATION: + { + if (negativevalue) + { + SourceError(source, "misplaced minus sign in #if/#elif"); + error = 1; + break; + } //end if + if (t->subtype == P_PARENTHESESOPEN) + { + parentheses++; + break; + } //end if + else if (t->subtype == P_PARENTHESESCLOSE) + { + parentheses--; + if (parentheses < 0) + { + SourceError(source, "too many ) in #if/#elsif"); + error = 1; + } //end if + break; + } //end else if + //check for invalid operators on floating point values + if (!integer) + { + if (t->subtype == P_BIN_NOT || t->subtype == P_MOD || + t->subtype == P_RSHIFT || t->subtype == P_LSHIFT || + t->subtype == P_BIN_AND || t->subtype == P_BIN_OR || + t->subtype == P_BIN_XOR) + { + SourceError(source, "illigal operator %s on floating point operands\n", t->string); + error = 1; + break; + } //end if + } //end if + switch(t->subtype) + { + case P_LOGIC_NOT: + case P_BIN_NOT: + { + if (lastwasvalue) + { + SourceError(source, "! or ~ after value in #if/#elif"); + error = 1; + break; + } //end if + break; + } //end case + case P_INC: + case P_DEC: + { + SourceError(source, "++ or -- used in #if/#elif"); + break; + } //end case + case P_SUB: + { + if (!lastwasvalue) + { + negativevalue = 1; + break; + } //end if + } //end case + + case P_MUL: + case P_DIV: + case P_MOD: + case P_ADD: + + case P_LOGIC_AND: + case P_LOGIC_OR: + case P_LOGIC_GEQ: + case P_LOGIC_LEQ: + case P_LOGIC_EQ: + case P_LOGIC_UNEQ: + + case P_LOGIC_GREATER: + case P_LOGIC_LESS: + + case P_RSHIFT: + case P_LSHIFT: + + case P_BIN_AND: + case P_BIN_OR: + case P_BIN_XOR: + + case P_COLON: + case P_QUESTIONMARK: + { + if (!lastwasvalue) + { + SourceError(source, "operator %s after operator in #if/#elif", t->string); + error = 1; + break; + } //end if + break; + } //end case + default: + { + SourceError(source, "invalid operator %s in #if/#elif", t->string); + error = 1; + break; + } //end default + } //end switch + if (!error && !negativevalue) + { + //o = (operator_t *) GetClearedMemory(sizeof(operator_t)); + AllocOperator(o); + o->operator = t->subtype; + o->priority = PC_OperatorPriority(t->subtype); + o->parentheses = parentheses; + o->next = NULL; + o->prev = lastoperator; + if (lastoperator) lastoperator->next = o; + else firstoperator = o; + lastoperator = o; + lastwasvalue = 0; + } //end if + break; + } //end case + default: + { + SourceError(source, "unknown %s in #if/#elif", t->string); + error = 1; + break; + } //end default + } //end switch + if (error) break; + } //end for + if (!error) + { + if (!lastwasvalue) + { + SourceError(source, "trailing operator in #if/#elif"); + error = 1; + } //end if + else if (parentheses) + { + SourceError(source, "too many ( in #if/#elif"); + error = 1; + } //end else if + } //end if + // + gotquestmarkvalue = qfalse; + questmarkintvalue = 0; + questmarkfloatvalue = 0; + //while there are operators + while(!error && firstoperator) + { + v = firstvalue; + for (o = firstoperator; o->next; o = o->next) + { + //if the current operator is nested deeper in parentheses + //than the next operator + if (o->parentheses > o->next->parentheses) break; + //if the current and next operator are nested equally deep in parentheses + if (o->parentheses == o->next->parentheses) + { + //if the priority of the current operator is equal or higher + //than the priority of the next operator + if (o->priority >= o->next->priority) break; + } //end if + //if the arity of the operator isn't equal to 1 + if (o->operator != P_LOGIC_NOT + && o->operator != P_BIN_NOT) v = v->next; + //if there's no value or no next value + if (!v) + { + SourceError(source, "mising values in #if/#elif"); + error = 1; + break; + } //end if + } //end for + if (error) break; + v1 = v; + v2 = v->next; +#ifdef DEBUG_EVAL + if (integer) + { + Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue); + if (v2) Log_Write("value2 = %d", v2->intvalue); + } //end if + else + { + Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue); + if (v2) Log_Write("value2 = %f", v2->floatvalue); + } //end else +#endif //DEBUG_EVAL + switch(o->operator) + { + case P_LOGIC_NOT: v1->intvalue = !v1->intvalue; + v1->floatvalue = !v1->floatvalue; break; + case P_BIN_NOT: v1->intvalue = ~v1->intvalue; + break; + case P_MUL: v1->intvalue *= v2->intvalue; + v1->floatvalue *= v2->floatvalue; break; + case P_DIV: if (!v2->intvalue || !v2->floatvalue) + { + SourceError(source, "divide by zero in #if/#elif\n"); + error = 1; + break; + } + v1->intvalue /= v2->intvalue; + v1->floatvalue /= v2->floatvalue; break; + case P_MOD: if (!v2->intvalue) + { + SourceError(source, "divide by zero in #if/#elif\n"); + error = 1; + break; + } + v1->intvalue %= v2->intvalue; break; + case P_ADD: v1->intvalue += v2->intvalue; + v1->floatvalue += v2->floatvalue; break; + case P_SUB: v1->intvalue -= v2->intvalue; + v1->floatvalue -= v2->floatvalue; break; + case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue; + v1->floatvalue = v1->floatvalue && v2->floatvalue; break; + case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue; + v1->floatvalue = v1->floatvalue || v2->floatvalue; break; + case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue; + v1->floatvalue = v1->floatvalue >= v2->floatvalue; break; + case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue; + v1->floatvalue = v1->floatvalue <= v2->floatvalue; break; + case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue; + v1->floatvalue = v1->floatvalue == v2->floatvalue; break; + case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue; + v1->floatvalue = v1->floatvalue != v2->floatvalue; break; + case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue; + v1->floatvalue = v1->floatvalue > v2->floatvalue; break; + case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue; + v1->floatvalue = v1->floatvalue < v2->floatvalue; break; + case P_RSHIFT: v1->intvalue >>= v2->intvalue; + break; + case P_LSHIFT: v1->intvalue <<= v2->intvalue; + break; + case P_BIN_AND: v1->intvalue &= v2->intvalue; + break; + case P_BIN_OR: v1->intvalue |= v2->intvalue; + break; + case P_BIN_XOR: v1->intvalue ^= v2->intvalue; + break; + case P_COLON: + { + if (!gotquestmarkvalue) + { + SourceError(source, ": without ? in #if/#elif"); + error = 1; + break; + } //end if + if (integer) + { + if (!questmarkintvalue) v1->intvalue = v2->intvalue; + } //end if + else + { + if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue; + } //end else + gotquestmarkvalue = qfalse; + break; + } //end case + case P_QUESTIONMARK: + { + if (gotquestmarkvalue) + { + SourceError(source, "? after ? in #if/#elif"); + error = 1; + break; + } //end if + questmarkintvalue = v1->intvalue; + questmarkfloatvalue = v1->floatvalue; + gotquestmarkvalue = qtrue; + break; + } //end if + } //end switch +#ifdef DEBUG_EVAL + if (integer) Log_Write("result value = %d", v1->intvalue); + else Log_Write("result value = %f", v1->floatvalue); +#endif //DEBUG_EVAL + if (error) break; + lastoperatortype = o->operator; + //if not an operator with arity 1 + if (o->operator != P_LOGIC_NOT + && o->operator != P_BIN_NOT) + { + //remove the second value if not question mark operator + if (o->operator != P_QUESTIONMARK) v = v->next; + // + if (v->prev) v->prev->next = v->next; + else firstvalue = v->next; + if (v->next) v->next->prev = v->prev; + else lastvalue = v->prev; + //FreeMemory(v); + FreeValue(v); + } //end if + //remove the operator + if (o->prev) o->prev->next = o->next; + else firstoperator = o->next; + if (o->next) o->next->prev = o->prev; + else lastoperator = o->prev; + //FreeMemory(o); + FreeOperator(o); + } //end while + if (firstvalue) + { + if (intvalue) *intvalue = firstvalue->intvalue; + if (floatvalue) *floatvalue = firstvalue->floatvalue; + } //end if + for (o = firstoperator; o; o = lastoperator) + { + lastoperator = o->next; + //FreeMemory(o); + FreeOperator(o); + } //end for + for (v = firstvalue; v; v = lastvalue) + { + lastvalue = v->next; + //FreeMemory(v); + FreeValue(v); + } //end for + if (!error) return qtrue; + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + return qfalse; +} //end of the function PC_EvaluateTokens +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Evaluate(source_t *source, signed long int *intvalue, + double *floatvalue, int integer) +{ + token_t token, *firsttoken, *lasttoken; + token_t *t, *nexttoken; + define_t *define; + int defined = qfalse; + + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + // + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "no value after #if/#elif"); + return qfalse; + } //end if + firsttoken = NULL; + lasttoken = NULL; + do + { + //if the token is a name + if (token.type == TT_NAME) + { + if (defined) + { + defined = qfalse; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else if (!strcmp(token.string, "defined")) + { + defined = qtrue; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else + { + //then it must be a define +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + if (!define) + { + SourceError(source, "can't evaluate %s, not defined", token.string); + return qfalse; + } //end if + if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; + } //end else + } //end if + //if the token is a number or a punctuation + else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) + { + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end else + else //can't evaluate the token + { + SourceError(source, "can't evaluate %s", token.string); + return qfalse; + } //end else + } while(PC_ReadLine(source, &token)); + // + if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; + // +#ifdef DEBUG_EVAL + Log_Write("eval:"); +#endif //DEBUG_EVAL + for (t = firsttoken; t; t = nexttoken) + { +#ifdef DEBUG_EVAL + Log_Write(" %s", t->string); +#endif //DEBUG_EVAL + nexttoken = t->next; + PC_FreeToken(t); + } //end for +#ifdef DEBUG_EVAL + if (integer) Log_Write("eval result: %d", *intvalue); + else Log_Write("eval result: %f", *floatvalue); +#endif //DEBUG_EVAL + // + return qtrue; +} //end of the function PC_Evaluate +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_DollarEvaluate(source_t *source, signed long int *intvalue, + double *floatvalue, int integer) +{ + int indent, defined = qfalse; + token_t token, *firsttoken, *lasttoken; + token_t *t, *nexttoken; + define_t *define; + + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + // + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "no leading ( after $evalint/$evalfloat"); + return qfalse; + } //end if + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "nothing to evaluate"); + return qfalse; + } //end if + indent = 1; + firsttoken = NULL; + lasttoken = NULL; + do + { + //if the token is a name + if (token.type == TT_NAME) + { + if (defined) + { + defined = qfalse; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else if (!strcmp(token.string, "defined")) + { + defined = qtrue; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else + { + //then it must be a define +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + if (!define) + { + SourceError(source, "can't evaluate %s, not defined", token.string); + return qfalse; + } //end if + if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; + } //end else + } //end if + //if the token is a number or a punctuation + else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) + { + if (*token.string == '(') indent++; + else if (*token.string == ')') indent--; + if (indent <= 0) break; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end else + else //can't evaluate the token + { + SourceError(source, "can't evaluate %s", token.string); + return qfalse; + } //end else + } while(PC_ReadSourceToken(source, &token)); + // + if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; + // +#ifdef DEBUG_EVAL + Log_Write("$eval:"); +#endif //DEBUG_EVAL + for (t = firsttoken; t; t = nexttoken) + { +#ifdef DEBUG_EVAL + Log_Write(" %s", t->string); +#endif //DEBUG_EVAL + nexttoken = t->next; + PC_FreeToken(t); + } //end for +#ifdef DEBUG_EVAL + if (integer) Log_Write("$eval result: %d", *intvalue); + else Log_Write("$eval result: %f", *floatvalue); +#endif //DEBUG_EVAL + // + return qtrue; +} //end of the function PC_DollarEvaluate +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_elif(source_t *source) +{ + signed long int value; + int type, skip; + + PC_PopIndent(source, &type, &skip); + if (!type || type == INDENT_ELSE) + { + SourceError(source, "misplaced #elif"); + return qfalse; + } //end if + if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; + skip = (value == 0); + PC_PushIndent(source, INDENT_ELIF, skip); + return qtrue; +} //end of the function PC_Directive_elif +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_if(source_t *source) +{ + signed long int value; + int skip; + + if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; + skip = (value == 0); + PC_PushIndent(source, INDENT_IF, skip); + return qtrue; +} //end of the function PC_Directive +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_line(source_t *source) +{ + SourceError(source, "#line directive not supported"); + return qfalse; +} //end of the function PC_Directive_line +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_error(source_t *source) +{ + token_t token; + + strcpy(token.string, ""); + PC_ReadSourceToken(source, &token); + SourceError(source, "#error directive: %s", token.string); + return qfalse; +} //end of the function PC_Directive_error +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_pragma(source_t *source) +{ + token_t token; + + SourceWarning(source, "#pragma directive not supported"); + while(PC_ReadLine(source, &token)) ; + return qtrue; +} //end of the function PC_Directive_pragma +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void UnreadSignToken(source_t *source) +{ + token_t token; + + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + strcpy(token.string, "-"); + token.type = TT_PUNCTUATION; + token.subtype = P_SUB; + PC_UnreadSourceToken(source, &token); +} //end of the function UnreadSignToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_eval(source_t *source) +{ + signed long int value; + token_t token; + + if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; + // + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%d", abs(value)); + token.type = TT_NUMBER; + token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; + PC_UnreadSourceToken(source, &token); + if (value < 0) UnreadSignToken(source); + return qtrue; +} //end of the function PC_Directive_eval +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_evalfloat(source_t *source) +{ + double value; + token_t token; + + if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse; + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%1.2f", fabs(value)); + token.type = TT_NUMBER; + token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; + PC_UnreadSourceToken(source, &token); + if (value < 0) UnreadSignToken(source); + return qtrue; +} //end of the function PC_Directive_evalfloat +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +directive_t directives[20] = +{ + {"if", PC_Directive_if}, + {"ifdef", PC_Directive_ifdef}, + {"ifndef", PC_Directive_ifndef}, + {"elif", PC_Directive_elif}, + {"else", PC_Directive_else}, + {"endif", PC_Directive_endif}, + {"include", PC_Directive_include}, + {"define", PC_Directive_define}, + {"undef", PC_Directive_undef}, + {"line", PC_Directive_line}, + {"error", PC_Directive_error}, + {"pragma", PC_Directive_pragma}, + {"eval", PC_Directive_eval}, + {"evalfloat", PC_Directive_evalfloat}, + {NULL, NULL} +}; + +int PC_ReadDirective(source_t *source) +{ + token_t token; + int i; + + //read the directive name + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "found # without name"); + return qfalse; + } //end if + //directive name must be on the same line + if (token.linescrossed > 0) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "found # at end of line"); + return qfalse; + } //end if + //if if is a name + if (token.type == TT_NAME) + { + //find the precompiler directive + for (i = 0; directives[i].name; i++) + { + if (!strcmp(directives[i].name, token.string)) + { + return directives[i].func(source); + } //end if + } //end for + } //end if + SourceError(source, "unknown precompiler directive %s", token.string); + return qfalse; +} //end of the function PC_ReadDirective +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_DollarDirective_evalint(source_t *source) +{ + signed long int value; + token_t token; + + if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse; + // + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%d", abs(value)); + token.type = TT_NUMBER; + token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; +#ifdef NUMBERVALUE + token.intvalue = value; + token.floatvalue = value; +#endif //NUMBERVALUE + PC_UnreadSourceToken(source, &token); + if (value < 0) UnreadSignToken(source); + return qtrue; +} //end of the function PC_DollarDirective_evalint +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_DollarDirective_evalfloat(source_t *source) +{ + double value; + token_t token; + + if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse; + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%1.2f", fabs(value)); + token.type = TT_NUMBER; + token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; +#ifdef NUMBERVALUE + token.intvalue = (unsigned long) value; + token.floatvalue = value; +#endif //NUMBERVALUE + PC_UnreadSourceToken(source, &token); + if (value < 0) UnreadSignToken(source); + return qtrue; +} //end of the function PC_DollarDirective_evalfloat +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +directive_t dollardirectives[20] = +{ + {"evalint", PC_DollarDirective_evalint}, + {"evalfloat", PC_DollarDirective_evalfloat}, + {NULL, NULL} +}; + +int PC_ReadDollarDirective(source_t *source) +{ + token_t token; + int i; + + //read the directive name + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "found $ without name"); + return qfalse; + } //end if + //directive name must be on the same line + if (token.linescrossed > 0) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "found $ at end of line"); + return qfalse; + } //end if + //if if is a name + if (token.type == TT_NAME) + { + //find the precompiler directive + for (i = 0; dollardirectives[i].name; i++) + { + if (!strcmp(dollardirectives[i].name, token.string)) + { + return dollardirectives[i].func(source); + } //end if + } //end for + } //end if + PC_UnreadSourceToken(source, &token); + SourceError(source, "unknown precompiler directive %s", token.string); + return qfalse; +} //end of the function PC_ReadDirective + +#ifdef QUAKEC +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int BuiltinFunction(source_t *source) +{ + token_t token; + + if (!PC_ReadSourceToken(source, &token)) return qfalse; + if (token.type == TT_NUMBER) + { + PC_UnreadSourceToken(source, &token); + return qtrue; + } //end if + else + { + PC_UnreadSourceToken(source, &token); + return qfalse; + } //end else +} //end of the function BuiltinFunction +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int QuakeCMacro(source_t *source) +{ + int i; + token_t token; + + if (!PC_ReadSourceToken(source, &token)) return qtrue; + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + return qtrue; + } //end if + //find the precompiler directive + for (i = 0; dollardirectives[i].name; i++) + { + if (!strcmp(dollardirectives[i].name, token.string)) + { + PC_UnreadSourceToken(source, &token); + return qfalse; + } //end if + } //end for + PC_UnreadSourceToken(source, &token); + return qtrue; +} //end of the function QuakeCMacro +#endif //QUAKEC +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadToken(source_t *source, token_t *token) +{ + define_t *define; + + while(1) + { + if (!PC_ReadSourceToken(source, token)) return qfalse; + //check for precompiler directives + if (token->type == TT_PUNCTUATION && *token->string == '#') + { +#ifdef QUAKEC + if (!BuiltinFunction(source)) +#endif //QUAKC + { + //read the precompiler directive + if (!PC_ReadDirective(source)) return qfalse; + continue; + } //end if + } //end if + if (token->type == TT_PUNCTUATION && *token->string == '$') + { +#ifdef QUAKEC + if (!QuakeCMacro(source)) +#endif //QUAKEC + { + //read the precompiler directive + if (!PC_ReadDollarDirective(source)) return qfalse; + continue; + } //end if + } //end if + // recursively concatenate strings that are behind each other still resolving defines + if (token->type == TT_STRING) + { + token_t newtoken; + if (PC_ReadToken(source, &newtoken)) + { + if (newtoken.type == TT_STRING) + { + token->string[strlen(token->string)-1] = '\0'; + if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN) + { + SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN); + return qfalse; + } + strcat(token->string, newtoken.string+1); + } + else + { + PC_UnreadToken(source, &newtoken); + } + } + } //end if + //if skipping source because of conditional compilation + if (source->skip) continue; + //if the token is a name + if (token->type == TT_NAME) + { + //check if the name is a define macro +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token->string); +#else + define = PC_FindDefine(source->defines, token->string); +#endif //DEFINEHASHING + //if it is a define macro + if (define) + { + //expand the defined macro + if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse; + continue; + } //end if + } //end if + //copy token for unreading + Com_Memcpy(&source->token, token, sizeof(token_t)); + //found a token + return qtrue; + } //end while +} //end of the function PC_ReadToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpectTokenString(source_t *source, char *string) +{ + token_t token; + + if (!PC_ReadToken(source, &token)) + { + SourceError(source, "couldn't find expected %s", string); + return qfalse; + } //end if + + if (strcmp(token.string, string)) + { + SourceError(source, "expected %s, found %s", string, token.string); + return qfalse; + } //end if + return qtrue; +} //end of the function PC_ExpectTokenString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token) +{ + char str[MAX_TOKEN]; + + if (!PC_ReadToken(source, token)) + { + SourceError(source, "couldn't read expected token"); + return qfalse; + } //end if + + if (token->type != type) + { + strcpy(str, ""); + if (type == TT_STRING) strcpy(str, "string"); + if (type == TT_LITERAL) strcpy(str, "literal"); + if (type == TT_NUMBER) strcpy(str, "number"); + if (type == TT_NAME) strcpy(str, "name"); + if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); + SourceError(source, "expected a %s, found %s", str, token->string); + return qfalse; + } //end if + if (token->type == TT_NUMBER) + { + if ((token->subtype & subtype) != subtype) + { + if (subtype & TT_DECIMAL) strcpy(str, "decimal"); + if (subtype & TT_HEX) strcpy(str, "hex"); + if (subtype & TT_OCTAL) strcpy(str, "octal"); + if (subtype & TT_BINARY) strcpy(str, "binary"); + if (subtype & TT_LONG) strcat(str, " long"); + if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); + if (subtype & TT_FLOAT) strcat(str, " float"); + if (subtype & TT_INTEGER) strcat(str, " integer"); + SourceError(source, "expected %s, found %s", str, token->string); + return qfalse; + } //end if + } //end if + else if (token->type == TT_PUNCTUATION) + { + if (token->subtype != subtype) + { + SourceError(source, "found %s", token->string); + return qfalse; + } //end if + } //end else if + return qtrue; +} //end of the function PC_ExpectTokenType +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpectAnyToken(source_t *source, token_t *token) +{ + if (!PC_ReadToken(source, token)) + { + SourceError(source, "couldn't read expected token"); + return qfalse; + } //end if + else + { + return qtrue; + } //end else +} //end of the function PC_ExpectAnyToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_CheckTokenString(source_t *source, char *string) +{ + token_t tok; + + if (!PC_ReadToken(source, &tok)) return qfalse; + //if the token is available + if (!strcmp(tok.string, string)) return qtrue; + // + PC_UnreadSourceToken(source, &tok); + return qfalse; +} //end of the function PC_CheckTokenString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token) +{ + token_t tok; + + if (!PC_ReadToken(source, &tok)) return qfalse; + //if the type matches + if (tok.type == type && + (tok.subtype & subtype) == subtype) + { + Com_Memcpy(token, &tok, sizeof(token_t)); + return qtrue; + } //end if + // + PC_UnreadSourceToken(source, &tok); + return qfalse; +} //end of the function PC_CheckTokenType +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_SkipUntilString(source_t *source, char *string) +{ + token_t token; + + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, string)) return qtrue; + } //end while + return qfalse; +} //end of the function PC_SkipUntilString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_UnreadLastToken(source_t *source) +{ + PC_UnreadSourceToken(source, &source->token); +} //end of the function PC_UnreadLastToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_UnreadToken(source_t *source, token_t *token) +{ + PC_UnreadSourceToken(source, token); +} //end of the function PC_UnreadToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_SetIncludePath(source_t *source, char *path) +{ + strncpy(source->includepath, path, MAX_PATH); + //add trailing path seperator + if (source->includepath[strlen(source->includepath)-1] != '\\' && + source->includepath[strlen(source->includepath)-1] != '/') + { + strcat(source->includepath, PATHSEPERATOR_STR); + } //end if +} //end of the function PC_SetIncludePath +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_SetPunctuations(source_t *source, punctuation_t *p) +{ + source->punctuations = p; +} //end of the function PC_SetPunctuations +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +source_t *LoadSourceFile(const char *filename) +{ + source_t *source; + script_t *script; + + PC_InitTokenHeap(); + + script = LoadScriptFile(filename); + if (!script) return NULL; + + script->next = NULL; + + source = (source_t *) GetMemory(sizeof(source_t)); + Com_Memset(source, 0, sizeof(source_t)); + + strncpy(source->filename, filename, MAX_PATH); + source->scriptstack = script; + source->tokens = NULL; + source->defines = NULL; + source->indentstack = NULL; + source->skip = 0; + +#if DEFINEHASHING + source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); +#endif //DEFINEHASHING + PC_AddGlobalDefinesToSource(source); + return source; +} //end of the function LoadSourceFile +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +source_t *LoadSourceMemory(char *ptr, int length, char *name) +{ + source_t *source; + script_t *script; + + PC_InitTokenHeap(); + + script = LoadScriptMemory(ptr, length, name); + if (!script) return NULL; + script->next = NULL; + + source = (source_t *) GetMemory(sizeof(source_t)); + Com_Memset(source, 0, sizeof(source_t)); + + strncpy(source->filename, name, MAX_PATH); + source->scriptstack = script; + source->tokens = NULL; + source->defines = NULL; + source->indentstack = NULL; + source->skip = 0; + +#if DEFINEHASHING + source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); +#endif //DEFINEHASHING + PC_AddGlobalDefinesToSource(source); + return source; +} //end of the function LoadSourceMemory +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void FreeSource(source_t *source) +{ + script_t *script; + token_t *token; + define_t *define; + indent_t *indent; + int i; + + //PC_PrintDefineHashTable(source->definehash); + //free all the scripts + while(source->scriptstack) + { + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + FreeScript(script); + } //end for + //free all the tokens + while(source->tokens) + { + token = source->tokens; + source->tokens = source->tokens->next; + PC_FreeToken(token); + } //end for +#if DEFINEHASHING + for (i = 0; i < DEFINEHASHSIZE; i++) + { + while(source->definehash[i]) + { + define = source->definehash[i]; + source->definehash[i] = source->definehash[i]->hashnext; + PC_FreeDefine(define); + } //end while + } //end for +#else //DEFINEHASHING + //free all defines + while(source->defines) + { + define = source->defines; + source->defines = source->defines->next; + PC_FreeDefine(define); + } //end for +#endif //DEFINEHASHING + //free all indents + while(source->indentstack) + { + indent = source->indentstack; + source->indentstack = source->indentstack->next; + FreeMemory(indent); + } //end for +#if DEFINEHASHING + // + if (source->definehash) FreeMemory(source->definehash); +#endif //DEFINEHASHING + //free the source itself + FreeMemory(source); +} //end of the function FreeSource +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ + +#define MAX_SOURCEFILES 64 + +source_t *sourceFiles[MAX_SOURCEFILES]; + +int PC_LoadSourceHandle(const char *filename) +{ + source_t *source; + int i; + + for (i = 1; i < MAX_SOURCEFILES; i++) + { + if (!sourceFiles[i]) + break; + } //end for + if (i >= MAX_SOURCEFILES) + return 0; + PS_SetBaseFolder(""); + source = LoadSourceFile(filename); + if (!source) + return 0; + sourceFiles[i] = source; + return i; +} //end of the function PC_LoadSourceHandle +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_FreeSourceHandle(int handle) +{ + if (handle < 1 || handle >= MAX_SOURCEFILES) + return qfalse; + if (!sourceFiles[handle]) + return qfalse; + + FreeSource(sourceFiles[handle]); + sourceFiles[handle] = NULL; + return qtrue; +} //end of the function PC_FreeSourceHandle +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadTokenHandle(int handle, pc_token_t *pc_token) +{ + token_t token; + int ret; + + if (handle < 1 || handle >= MAX_SOURCEFILES) + return 0; + if (!sourceFiles[handle]) + return 0; + + ret = PC_ReadToken(sourceFiles[handle], &token); + strcpy(pc_token->string, token.string); + pc_token->type = token.type; + pc_token->subtype = token.subtype; + pc_token->intvalue = token.intvalue; + pc_token->floatvalue = token.floatvalue; + if (pc_token->type == TT_STRING) + StripDoubleQuotes(pc_token->string); + return ret; +} //end of the function PC_ReadTokenHandle +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_SourceFileAndLine(int handle, char *filename, int *line) +{ + if (handle < 1 || handle >= MAX_SOURCEFILES) + return qfalse; + if (!sourceFiles[handle]) + return qfalse; + + strcpy(filename, sourceFiles[handle]->filename); + if (sourceFiles[handle]->scriptstack) + *line = sourceFiles[handle]->scriptstack->line; + else + *line = 0; + return qtrue; +} //end of the function PC_SourceFileAndLine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_SetBaseFolder(char *path) +{ + PS_SetBaseFolder(path); +} //end of the function PC_SetBaseFolder +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_CheckOpenSourceHandles(void) +{ + int i; + + for (i = 1; i < MAX_SOURCEFILES; i++) + { + if (sourceFiles[i]) + { +#ifdef BOTLIB + botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename); +#endif //BOTLIB + } //end if + } //end for +} //end of the function PC_CheckOpenSourceHandles + -- cgit v1.2.3