DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Parser.cpp (74641B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "precompiled.h"
     30 #pragma hdrstop
     31 
     32 //#define DEBUG_EVAL
     33 #define MAX_DEFINEPARMS				128
     34 #define DEFINEHASHSIZE				2048
     35 
     36 #define TOKEN_FL_RECURSIVE_DEFINE	1
     37 
     38 define_t * idParser::globaldefines;
     39 
     40 /*
     41 ================
     42 idParser::SetBaseFolder
     43 ================
     44 */
     45 void idParser::SetBaseFolder( const char *path) {
     46 	idLexer::SetBaseFolder(path);
     47 }
     48 
     49 /*
     50 ================
     51 idParser::AddGlobalDefine
     52 ================
     53 */
     54 int idParser::AddGlobalDefine( const char *string ) {
     55 	define_t *define;
     56 
     57 	define = idParser::DefineFromString(string);
     58 	if (!define) {
     59 		return false;
     60 	}
     61 	define->next = globaldefines;
     62 	globaldefines = define;
     63 	return true;
     64 }
     65 
     66 /*
     67 ================
     68 idParser::RemoveGlobalDefine
     69 ================
     70 */
     71 int idParser::RemoveGlobalDefine( const char *name ) {
     72 	define_t *d, *prev;
     73 
     74 	for ( prev = NULL, d = idParser::globaldefines; d; prev = d, d = d->next ) {
     75 		if ( !strcmp( d->name, name ) ) {
     76 			break;
     77 		}
     78 	}
     79 	if ( d ) {
     80 		if ( prev ) {
     81 			prev->next = d->next;
     82 		}
     83 		else {
     84 			idParser::globaldefines = d->next;
     85 		}
     86 		idParser::FreeDefine( d );
     87 		return true;
     88 	}
     89 	return false;
     90 }
     91 
     92 /*
     93 ================
     94 idParser::RemoveAllGlobalDefines
     95 ================
     96 */
     97 void idParser::RemoveAllGlobalDefines() {
     98 	define_t *define;
     99 
    100 	for ( define = globaldefines; define; define = globaldefines ) {
    101 		globaldefines = globaldefines->next;
    102 		idParser::FreeDefine(define);
    103 	}
    104 }
    105 
    106 
    107 /*
    108 ===============================================================================
    109 
    110 idParser
    111 
    112 ===============================================================================
    113 */
    114 
    115 /*
    116 ================
    117 idParser::PrintDefine
    118 ================
    119 */
    120 void idParser::PrintDefine( define_t *define ) {
    121 	idLib::common->Printf("define->name = %s\n", define->name);
    122 	idLib::common->Printf("define->flags = %d\n", define->flags);
    123 	idLib::common->Printf("define->builtin = %d\n", define->builtin);
    124 	idLib::common->Printf("define->numparms = %d\n", define->numparms);
    125 }
    126 
    127 /*
    128 ================
    129 PC_PrintDefineHashTable
    130 ================
    131 * /
    132 static void PC_PrintDefineHashTable(define_t **definehash) {
    133 	int i;
    134 	define_t *d;
    135 
    136 	for (i = 0; i < DEFINEHASHSIZE; i++) {
    137 		Log_Write("%4d:", i);
    138 		for (d = definehash[i]; d; d = d->hashnext) {
    139 			Log_Write(" %s", d->name);
    140 		}
    141 		Log_Write("\n");
    142 	}
    143 }
    144 */
    145 
    146 /*
    147 ================
    148 PC_NameHash
    149 ================
    150 */
    151 ID_INLINE int PC_NameHash( const char *name ) {
    152 	int hash, i;
    153 
    154 	hash = 0;
    155 	for ( i = 0; name[i] != '\0'; i++ ) {
    156 		hash += name[i] * (119 + i);
    157 	}
    158 	hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
    159 	return hash;
    160 }
    161 
    162 /*
    163 ================
    164 idParser::AddDefineToHash
    165 ================
    166 */
    167 void idParser::AddDefineToHash( define_t *define, define_t **definehash ) {
    168 	int hash;
    169 
    170 	hash = PC_NameHash(define->name);
    171 	define->hashnext = definehash[hash];
    172 	definehash[hash] = define;
    173 }
    174 
    175 /*
    176 ================
    177 FindHashedDefine
    178 ================
    179 */
    180 define_t *idParser::FindHashedDefine( define_t **definehash, const char *name ) {
    181 	define_t *d;
    182 	int hash;
    183 
    184 	hash = PC_NameHash(name);
    185 	for ( d = definehash[hash]; d; d = d->hashnext ) {
    186 		if ( !strcmp(d->name, name) ) {
    187 			return d;
    188 		}
    189 	}
    190 	return NULL;
    191 }
    192 
    193 /*
    194 ================
    195 idParser::FindDefine
    196 ================
    197 */
    198 define_t *idParser::FindDefine( define_t *defines, const char *name ) {
    199 	define_t *d;
    200 
    201 	for ( d = defines; d; d = d->next ) {
    202 		if ( !strcmp(d->name, name) ) {
    203 			return d;
    204 		}
    205 	}
    206 	return NULL;
    207 }
    208 
    209 /*
    210 ================
    211 idParser::FindDefineParm
    212 ================
    213 */
    214 int idParser::FindDefineParm( define_t *define, const char *name ) {
    215 	idToken *p;
    216 	int i;
    217 
    218 	i = 0;
    219 	for ( p = define->parms; p; p = p->next ) {
    220 		if ( (*p) == name ) {
    221 			return i;
    222 		}
    223 		i++;
    224 	}
    225 	return -1;
    226 }
    227 
    228 /*
    229 ================
    230 idParser::CopyDefine
    231 ================
    232 */
    233 define_t *idParser::CopyDefine( define_t *define ) {
    234 	define_t *newdefine;
    235 	idToken *token, *newtoken, *lasttoken;
    236 
    237 	newdefine = (define_t *) Mem_Alloc(sizeof(define_t) + strlen(define->name) + 1, TAG_IDLIB_PARSER);
    238 	//copy the define name
    239 	newdefine->name = (char *) newdefine + sizeof(define_t);
    240 	strcpy(newdefine->name, define->name);
    241 	newdefine->flags = define->flags;
    242 	newdefine->builtin = define->builtin;
    243 	newdefine->numparms = define->numparms;
    244 	//the define is not linked
    245 	newdefine->next = NULL;
    246 	newdefine->hashnext = NULL;
    247 	//copy the define tokens
    248 	newdefine->tokens = NULL;
    249 	for (lasttoken = NULL, token = define->tokens; token; token = token->next) {
    250 		newtoken = new (TAG_IDLIB_PARSER) idToken(token);
    251 		newtoken->next = NULL;
    252 		if (lasttoken) lasttoken->next = newtoken;
    253 		else newdefine->tokens = newtoken;
    254 		lasttoken = newtoken;
    255 	}
    256 	//copy the define parameters
    257 	newdefine->parms = NULL;
    258 	for (lasttoken = NULL, token = define->parms; token; token = token->next) {
    259 		newtoken = new (TAG_IDLIB_PARSER) idToken(token);
    260 		newtoken->next = NULL;
    261 		if (lasttoken) lasttoken->next = newtoken;
    262 		else newdefine->parms = newtoken;
    263 		lasttoken = newtoken;
    264 	}
    265 	return newdefine;
    266 }
    267 
    268 /*
    269 ================
    270 idParser::FreeDefine
    271 ================
    272 */
    273 void idParser::FreeDefine( define_t *define ) {
    274 	idToken *t, *next;
    275 
    276 	//free the define parameters
    277 	for (t = define->parms; t; t = next) {
    278 		next = t->next;
    279 		delete t;
    280 	}
    281 	//free the define tokens
    282 	for (t = define->tokens; t; t = next) {
    283 		next = t->next;
    284 		delete t;
    285 	}
    286 	//free the define
    287 	Mem_Free( define );
    288 }
    289 
    290 /*
    291 ================
    292 idParser::DefineFromString
    293 ================
    294 */
    295 define_t *idParser::DefineFromString( const char *string ) {
    296 	idParser src;
    297 	define_t *def;
    298 
    299 	if ( !src.LoadMemory(string, strlen(string), "*defineString") ) {
    300 		return NULL;
    301 	}
    302 	// create a define from the source
    303 	if ( !src.Directive_define() ) {
    304 		src.FreeSource();
    305 		return NULL;
    306 	}
    307 	def = src.CopyFirstDefine();
    308 	src.FreeSource();
    309 	//if the define was created succesfully
    310 	return def;
    311 }
    312 
    313 /*
    314 ================
    315 idParser::Error
    316 ================
    317 */
    318 void idParser::Error( const char *str, ... ) const {
    319 	char text[MAX_STRING_CHARS];
    320 	va_list ap;
    321 
    322 	va_start(ap, str);
    323 	vsprintf(text, str, ap);
    324 	va_end(ap);
    325 	if ( idParser::scriptstack ) {
    326 		idParser::scriptstack->Error( text );
    327 	}
    328 }
    329 
    330 /*
    331 ================
    332 idParser::Warning
    333 ================
    334 */
    335 void idParser::Warning( const char *str, ... ) const {
    336 	char text[MAX_STRING_CHARS];
    337 	va_list ap;
    338 
    339 	va_start(ap, str);
    340 	vsprintf(text, str, ap);
    341 	va_end(ap);
    342 	if ( idParser::scriptstack ) {
    343 		idParser::scriptstack->Warning( text );
    344 	}
    345 }
    346 
    347 /*
    348 ================
    349 idParser::PushIndent
    350 ================
    351 */
    352 void idParser::PushIndent( int type, int skip ) {
    353 	indent_t *indent;
    354 
    355 	indent = (indent_t *) Mem_Alloc(sizeof(indent_t), TAG_IDLIB_PARSER);
    356 	indent->type = type;
    357 	indent->script = idParser::scriptstack;
    358 	indent->skip = (skip != 0);
    359 	idParser::skip += indent->skip;
    360 	indent->next = idParser::indentstack;
    361 	idParser::indentstack = indent;
    362 }
    363 
    364 /*
    365 ================
    366 idParser::PopIndent
    367 ================
    368 */
    369 void idParser::PopIndent( int *type, int *skip ) {
    370 	indent_t *indent;
    371 
    372 	*type = 0;
    373 	*skip = 0;
    374 
    375 	indent = idParser::indentstack;
    376 	if (!indent) return;
    377 
    378 	// must be an indent from the current script
    379 	if (idParser::indentstack->script != idParser::scriptstack) {
    380 		return;
    381 	}
    382 
    383 	*type = indent->type;
    384 	*skip = indent->skip;
    385 	idParser::indentstack = idParser::indentstack->next;
    386 	idParser::skip -= indent->skip;
    387 	Mem_Free( indent );
    388 }
    389 
    390 /*
    391 ================
    392 idParser::PushScript
    393 ================
    394 */
    395 void idParser::PushScript( idLexer *script ) {
    396 	idLexer *s;
    397 
    398 	for ( s = idParser::scriptstack; s; s = s->next ) {
    399 		if ( !idStr::Icmp(s->GetFileName(), script->GetFileName()) ) {
    400 			idParser::Warning( "'%s' recursively included", script->GetFileName() );
    401 			return;
    402 		}
    403 	}
    404 	//push the script on the script stack
    405 	script->next = idParser::scriptstack;
    406 	idParser::scriptstack = script;
    407 }
    408 
    409 /*
    410 ================
    411 idParser::ReadSourceToken
    412 ================
    413 */
    414 int idParser::ReadSourceToken( idToken *token ) {
    415 	idToken *t;
    416 	idLexer *script;
    417 	int type, skip, changedScript;
    418 
    419 	if ( !idParser::scriptstack ) {
    420 		idLib::common->FatalError( "idParser::ReadSourceToken: not loaded" );
    421 		return false;
    422 	}
    423 	changedScript = 0;
    424 	// if there's no token already available
    425 	while( !idParser::tokens ) {
    426 		// if there's a token to read from the script
    427 		if ( idParser::scriptstack->ReadToken( token ) ) {
    428 			token->linesCrossed += changedScript;
    429 
    430 			// set the marker based on the start of the token read in
    431 			if ( !marker_p ) {
    432 				marker_p = token->whiteSpaceEnd_p;
    433 			}
    434 			return true;
    435 		}
    436 		// if at the end of the script
    437 		if ( idParser::scriptstack->EndOfFile() ) {
    438 			// remove all indents of the script
    439 			while( idParser::indentstack && idParser::indentstack->script == idParser::scriptstack ) {
    440 				idParser::Warning( "missing #endif" );
    441 				idParser::PopIndent( &type, &skip );
    442 			}
    443 			changedScript = 1;
    444 		}
    445 		// if this was the initial script
    446 		if ( !idParser::scriptstack->next ) {
    447 			return false;
    448 		}
    449 		// remove the script and return to the previous one
    450 		script = idParser::scriptstack;
    451 		idParser::scriptstack = idParser::scriptstack->next;
    452 		delete script;
    453 	}
    454 	// copy the already available token
    455 	*token = idParser::tokens;
    456 	// remove the token from the source
    457 	t = idParser::tokens;
    458 	assert( idParser::tokens != NULL );
    459 	idParser::tokens = idParser::tokens->next;
    460 	delete t;
    461 	return true;
    462 }
    463 
    464 /*
    465 ================
    466 idParser::UnreadSourceToken
    467 ================
    468 */
    469 int idParser::UnreadSourceToken( idToken *token ) {
    470 	idToken *t;
    471 
    472 	t = new (TAG_IDLIB_PARSER) idToken(token);
    473 	t->next = idParser::tokens;
    474 	idParser::tokens = t;
    475 	return true;
    476 }
    477 
    478 /*
    479 ================
    480 idParser::ReadDefineParms
    481 ================
    482 */
    483 int idParser::ReadDefineParms( define_t *define, idToken **parms, int maxparms ) {
    484 	define_t *newdefine;
    485 	idToken token, *t, *last;
    486 	int i, done, lastcomma, numparms, indent;
    487 
    488 	if ( !idParser::ReadSourceToken( &token ) ) {
    489 		idParser::Error( "define '%s' missing parameters", define->name );
    490 		return false;
    491 	}
    492 
    493 	if ( define->numparms > maxparms ) {
    494 		idParser::Error( "define with more than %d parameters", maxparms );
    495 		return false;
    496 	}
    497 
    498 	for ( i = 0; i < define->numparms; i++ ) {
    499 		parms[i] = NULL;
    500 	}
    501 	// if no leading "("
    502 	if ( token != "(" ) {
    503 		idParser::UnreadSourceToken( &token );
    504 		idParser::Error( "define '%s' missing parameters", define->name );
    505 		return false;
    506 	}
    507 	// read the define parameters
    508 	for ( done = 0, numparms = 0, indent = 1; !done; ) {
    509 		if ( numparms >= maxparms ) {
    510 			idParser::Error( "define '%s' with too many parameters", define->name );
    511 			return false;
    512 		}
    513 		parms[numparms] = NULL;
    514 		lastcomma = 1;
    515 		last = NULL;
    516 		while( !done ) {
    517 
    518 			if ( !idParser::ReadSourceToken( &token ) ) {
    519 				idParser::Error( "define '%s' incomplete", define->name );
    520 				return false;
    521 			}
    522 
    523 			if ( token == "," ) {
    524 				if ( indent <= 1 ) {
    525 					if ( lastcomma ) {
    526 						idParser::Warning( "too many comma's" );
    527 					}
    528 					if ( numparms >= define->numparms ) {
    529 						idParser::Warning( "too many define parameters" );
    530 					}
    531 					lastcomma = 1;
    532 					break;
    533 				}
    534 			}
    535 			else if ( token == "(" ) {
    536 				indent++;
    537 			}
    538 			else if ( token == ")" ) {
    539 				indent--;
    540 				if ( indent <= 0 ) {
    541 					if ( !parms[define->numparms-1] ) {
    542 						idParser::Warning( "too few define parameters" );
    543 					}
    544 					done = 1;
    545 					break;
    546 				}
    547 			}
    548 			else if ( token.type == TT_NAME ) {
    549 				newdefine = FindHashedDefine( idParser::definehash, token.c_str() );
    550 				if ( newdefine ) {
    551 					if ( !idParser::ExpandDefineIntoSource( &token, newdefine ) ) {
    552 						return false;
    553 					}
    554 					continue;
    555 				}
    556 			}
    557 
    558 			lastcomma = 0;
    559 
    560 			if ( numparms < define->numparms ) {
    561 
    562 				t = new (TAG_IDLIB_PARSER) idToken( token );
    563 				t->next = NULL;
    564 				if (last) last->next = t;
    565 				else parms[numparms] = t;
    566 				last = t;
    567 			}
    568 		}
    569 		numparms++;
    570 	}
    571 	return true;
    572 }
    573 
    574 /*
    575 ================
    576 idParser::StringizeTokens
    577 ================
    578 */
    579 int idParser::StringizeTokens( idToken *tokens, idToken *token ) {
    580 	idToken *t;
    581 
    582 	token->type = TT_STRING;
    583 	token->whiteSpaceStart_p = NULL;
    584 	token->whiteSpaceEnd_p = NULL;
    585 	(*token) = "";
    586 	for ( t = tokens; t; t = t->next ) {
    587 		token->Append( t->c_str() );
    588 	}
    589 	return true;
    590 }
    591 
    592 /*
    593 ================
    594 idParser::MergeTokens
    595 ================
    596 */
    597 int idParser::MergeTokens( idToken *t1, idToken *t2 ) {
    598 	// merging of a name with a name or number
    599 	if ( t1->type == TT_NAME && (t2->type == TT_NAME || (t2->type == TT_NUMBER && !(t2->subtype & TT_FLOAT))) ) {
    600 		t1->Append( t2->c_str() );
    601 		return true;
    602 	}
    603 	// merging of two strings
    604 	if (t1->type == TT_STRING && t2->type == TT_STRING) {
    605 		t1->Append( t2->c_str() );
    606 		return true;
    607 	}
    608 	// merging of two numbers
    609 	if ( t1->type == TT_NUMBER && t2->type == TT_NUMBER &&
    610 			!(t1->subtype & (TT_HEX|TT_BINARY)) && !(t2->subtype & (TT_HEX|TT_BINARY)) &&
    611 			(!(t1->subtype & TT_FLOAT) || !(t2->subtype & TT_FLOAT)) ) {
    612 		t1->Append( t2->c_str() );
    613 		return true;
    614 	}
    615 
    616 	return false;
    617 }
    618 
    619 /*
    620 ================
    621 idParser::AddBuiltinDefines
    622 ================
    623 */
    624 void idParser::AddBuiltinDefines() {
    625 	int i;
    626 	define_t *define;
    627 	struct builtin
    628 	{
    629 		char *string;
    630 		int id;
    631 	} builtin[] = {
    632 		{ "__LINE__",	BUILTIN_LINE }, 
    633 		{ "__FILE__",	BUILTIN_FILE },
    634 		{ "__DATE__",	BUILTIN_DATE },
    635 		{ "__TIME__",	BUILTIN_TIME },
    636 		{ "__STDC__", BUILTIN_STDC },
    637 		{ NULL, 0 }
    638 	};
    639 
    640 	for (i = 0; builtin[i].string; i++) {
    641 		define = (define_t *) Mem_Alloc(sizeof(define_t) + strlen(builtin[i].string) + 1, TAG_IDLIB_PARSER);
    642 		define->name = (char *) define + sizeof(define_t);
    643 		strcpy(define->name, builtin[i].string);
    644 		define->flags = DEFINE_FIXED;
    645 		define->builtin = builtin[i].id;
    646 		define->numparms = 0;
    647 		define->parms = NULL;
    648 		define->tokens = NULL;
    649 		// add the define to the source
    650 		AddDefineToHash(define, idParser::definehash);
    651 	}
    652 }
    653 
    654 /*
    655 ================
    656 idParser::CopyFirstDefine
    657 ================
    658 */
    659 define_t *idParser::CopyFirstDefine() {
    660 	int i;
    661 
    662 	for ( i = 0; i < DEFINEHASHSIZE; i++ ) {
    663 		if ( idParser::definehash[i] ) {
    664 			return CopyDefine(idParser::definehash[i]);
    665 		}
    666 	}
    667 	return NULL;
    668 }
    669 
    670 static idStr PreProcessorDate() {
    671 	time_t t = time(NULL);
    672 	char *curtime = ctime(&t);
    673 	if ( idStr::Length( curtime ) < 24 ) {
    674 		return idStr( "*** BAD CURTIME ***" );
    675 	}
    676 	idStr	str = "\"";
    677 	// skip DAY, extract MMM DD
    678 	for ( int i = 4 ; i < 10 ; i++ ) { 
    679 		str.Append( curtime[i] );
    680 	}
    681 	// skip time, extract space+YYYY
    682 	for ( int i = 19 ; i < 24 ; i++ ) {
    683 		str.Append( curtime[i] );
    684 	}
    685 	str.Append( "\"" );
    686 	return str;
    687 }
    688 
    689 static idStr PreProcessorTime() {
    690 	time_t t = time(NULL);
    691 	char *curtime = ctime(&t);
    692 	if ( idStr::Length( curtime ) < 24 ) {
    693 		return idStr( "*** BAD CURTIME ***" );
    694 	}
    695 
    696 	idStr	str = "\"";
    697 	for ( int i = 11 ; i < 19 ; i++ ) {
    698 		str.Append( curtime[i] );
    699 	}
    700 	str.Append( "\"" );
    701 	return str;
    702 }
    703 
    704 CONSOLE_COMMAND( TestPreprocessorMacros, "check analyze warning", 0 ) {
    705 	idLib::Printf( "%s : %s\n", __DATE__, PreProcessorDate().c_str() );
    706 	idLib::Printf( "%s : %s\n", __TIME__, PreProcessorTime().c_str() );
    707 }
    708 
    709 /*
    710 ================
    711 idParser::ExpandBuiltinDefine
    712 ================
    713 */
    714 int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) {
    715 	idToken *token;
    716 	char buf[MAX_STRING_CHARS];
    717 
    718 	token = new (TAG_IDLIB_PARSER) idToken(deftoken);
    719 	switch( define->builtin ) {
    720 		case BUILTIN_LINE: {
    721 			sprintf( buf, "%d", deftoken->line );
    722 			(*token) = buf;
    723 			token->intvalue = deftoken->line;
    724 			token->floatvalue = deftoken->line;
    725 			token->type = TT_NUMBER;
    726 			token->subtype = TT_DECIMAL | TT_INTEGER | TT_VALUESVALID;
    727 			token->line = deftoken->line;
    728 			token->linesCrossed = deftoken->linesCrossed;
    729 			token->flags = 0;
    730 			*firsttoken = token;
    731 			*lasttoken = token;
    732 			break;
    733 		}
    734 		case BUILTIN_FILE: {
    735 			(*token) = idParser::scriptstack->GetFileName();
    736 			token->type = TT_NAME;
    737 			token->subtype = token->Length();
    738 			token->line = deftoken->line;
    739 			token->linesCrossed = deftoken->linesCrossed;
    740 			token->flags = 0;
    741 			*firsttoken = token;
    742 			*lasttoken = token;
    743 			break;
    744 		}
    745 		case BUILTIN_DATE: {
    746 			*token = PreProcessorDate();
    747 			token->type = TT_STRING;
    748 			token->subtype = token->Length();
    749 			token->line = deftoken->line;
    750 			token->linesCrossed = deftoken->linesCrossed;
    751 			token->flags = 0;
    752 			*firsttoken = token;
    753 			*lasttoken = token;
    754 			break;
    755 		}
    756 		case BUILTIN_TIME: {
    757 			*token = PreProcessorTime();
    758 			token->type = TT_STRING;
    759 			token->subtype = token->Length();
    760 			token->line = deftoken->line;
    761 			token->linesCrossed = deftoken->linesCrossed;
    762 			token->flags = 0;
    763 			*firsttoken = token;
    764 			*lasttoken = token;
    765 			break;
    766 		}
    767 		case BUILTIN_STDC: {
    768 			idParser::Warning( "__STDC__ not supported\n" );
    769 			*firsttoken = NULL;
    770 			*lasttoken = NULL;
    771 			break;
    772 		}
    773 		default: {
    774 			*firsttoken = NULL;
    775 			*lasttoken = NULL;
    776 			break;
    777 		}
    778 	}
    779 	return true;
    780 }
    781 
    782 /*
    783 ================
    784 idParser::ExpandDefine
    785 ================
    786 */
    787 int idParser::ExpandDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) {
    788 	idToken *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
    789 	idToken *t1, *t2, *first, *last, *nextpt, token;
    790 	int parmnum, i;
    791 
    792 	// if it is a builtin define
    793 	if ( define->builtin ) {
    794 		return idParser::ExpandBuiltinDefine( deftoken, define, firsttoken, lasttoken );
    795 	}
    796 	// if the define has parameters
    797 	if ( define->numparms ) {
    798 		if ( !idParser::ReadDefineParms( define, parms, MAX_DEFINEPARMS ) ) {
    799 			return false;
    800 		}
    801 #ifdef DEBUG_EVAL
    802 		for ( i = 0; i < define->numparms; i++ ) {
    803 			Log_Write("define parms %d:", i);
    804 			for ( pt = parms[i]; pt; pt = pt->next ) {
    805 				Log_Write( "%s", pt->c_str() );
    806 			}
    807 		}
    808 #endif //DEBUG_EVAL
    809 	}
    810 	// empty list at first
    811 	first = NULL;
    812 	last = NULL;
    813 	// create a list with tokens of the expanded define
    814 	for ( dt = define->tokens; dt; dt = dt->next ) {
    815 		parmnum = -1;
    816 		// if the token is a name, it could be a define parameter
    817 		if ( dt->type == TT_NAME ) {
    818 			parmnum = FindDefineParm( define, dt->c_str() );
    819 		}
    820 		// if it is a define parameter
    821 		if ( parmnum >= 0 ) {
    822 			for ( pt = parms[parmnum]; pt; pt = pt->next ) {
    823 				t = new (TAG_IDLIB_PARSER) idToken(pt);
    824 				//add the token to the list
    825 				t->next = NULL;
    826 				if (last) last->next = t;
    827 				else first = t;
    828 				last = t;
    829 			}
    830 		}
    831 		else {
    832 			// if stringizing operator
    833 			if ( (*dt) == "#" ) {
    834 				// the stringizing operator must be followed by a define parameter
    835 				if ( dt->next ) {
    836 					parmnum = FindDefineParm( define, dt->next->c_str() );
    837 				}
    838 				else {
    839 					parmnum = -1;
    840 				}
    841 
    842 				if ( parmnum >= 0 ) {
    843 					// step over the stringizing operator
    844 					dt = dt->next;
    845 					// stringize the define parameter tokens
    846 					if ( !idParser::StringizeTokens( parms[parmnum], &token ) ) {
    847 						idParser::Error( "can't stringize tokens" );
    848 						return false;
    849 					}
    850 					t = new (TAG_IDLIB_PARSER) idToken(token);
    851 					t->line = deftoken->line;
    852 				}
    853 				else {
    854 					idParser::Warning( "stringizing operator without define parameter" );
    855 					continue;
    856 				}
    857 			}
    858 			else {
    859 				t = new (TAG_IDLIB_PARSER) idToken(dt);
    860 				t->line = deftoken->line;
    861 			}
    862 			// add the token to the list
    863 			t->next = NULL;
    864 // the token being read from the define list should use the line number of
    865 // the original file, not the header file			
    866 			t->line = deftoken->line;
    867 
    868 			if ( last ) last->next = t;
    869 			else first = t;
    870 			last = t;
    871 		}
    872 	}
    873 	// check for the merging operator
    874 	for ( t = first; t; ) {
    875 		if ( t->next ) {
    876 			// if the merging operator
    877 			if ( (*t->next) == "##" ) {
    878 				t1 = t;
    879 				t2 = t->next->next;
    880 				if ( t2 ) {
    881 					if ( !idParser::MergeTokens( t1, t2 ) ) {
    882 						idParser::Error( "can't merge '%s' with '%s'", t1->c_str(), t2->c_str() );
    883 						return false;
    884 					}
    885 					delete t1->next;
    886 					t1->next = t2->next;
    887 					if ( t2 == last ) last = t1;
    888 					delete t2;
    889 					continue;
    890 				}
    891 			}
    892 		}
    893 		t = t->next;
    894 	}
    895 	// store the first and last token of the list
    896 	*firsttoken = first;
    897 	*lasttoken = last;
    898 	// free all the parameter tokens
    899 	for ( i = 0; i < define->numparms; i++ ) {
    900 		for ( pt = parms[i]; pt; pt = nextpt ) {
    901 			nextpt = pt->next;
    902 			delete pt;
    903 		}
    904 	}
    905 
    906 	return true;
    907 }
    908 
    909 /*
    910 ================
    911 idParser::ExpandDefineIntoSource
    912 ================
    913 */
    914 int idParser::ExpandDefineIntoSource( idToken *deftoken, define_t *define ) {
    915 	idToken *firsttoken, *lasttoken;
    916 
    917 	if ( !idParser::ExpandDefine( deftoken, define, &firsttoken, &lasttoken ) ) {
    918 		return false;
    919 	}
    920 	// if the define is not empty
    921 	if ( firsttoken && lasttoken ) {
    922 		firsttoken->linesCrossed += deftoken->linesCrossed;
    923 		lasttoken->next = idParser::tokens;
    924 		idParser::tokens = firsttoken;
    925 	}
    926 	return true;
    927 }
    928 
    929 /*
    930 ================
    931 idParser::ReadLine
    932 
    933 reads a token from the current line, continues reading on the next
    934 line only if a backslash '\' is found
    935 ================
    936 */
    937 int idParser::ReadLine( idToken *token ) {
    938 	int crossline;
    939 
    940 	crossline = 0;
    941 	do {
    942 		if (!idParser::ReadSourceToken( token )) {
    943 			return false;
    944 		}
    945 		
    946 		if (token->linesCrossed > crossline) {
    947 			idParser::UnreadSourceToken( token );
    948 			return false;
    949 		}
    950 		crossline = 1;
    951 	} while( (*token) == "\\" );
    952 	return true;
    953 }
    954 
    955 /*
    956 ================
    957 idParser::Directive_include
    958 ================
    959 */
    960 int idParser::Directive_include() {
    961 	idLexer *script;
    962 	idToken token;
    963 	idStr path;
    964 
    965 	if ( !idParser::ReadSourceToken( &token ) ) {
    966 		idParser::Error( "#include without file name" );
    967 		return false;
    968 	}
    969 	if ( token.linesCrossed > 0 ) {
    970 		idParser::Error( "#include without file name" );
    971 		return false;
    972 	}
    973 	if ( token.type == TT_STRING ) {
    974 		script = new (TAG_IDLIB_PARSER) idLexer;
    975 		// try relative to the current file
    976 		path = scriptstack->GetFileName();
    977 		path.StripFilename();
    978 		path += "/";
    979 		path += token;
    980 		if ( !script->LoadFile( path, OSPath ) ) {
    981 			// try absolute path
    982 			path = token;
    983 			if ( !script->LoadFile( path, OSPath ) ) {
    984 				// try from the include path
    985 				path = includepath + token;
    986 				if ( !script->LoadFile( path, OSPath ) ) {
    987 					delete script;
    988 					script = NULL;
    989 				}
    990 			}
    991 		}
    992 	}
    993 	else if ( token.type == TT_PUNCTUATION && token == "<" ) {
    994 		path = idParser::includepath;
    995 		while( idParser::ReadSourceToken( &token ) ) {
    996 			if ( token.linesCrossed > 0 ) {
    997 				idParser::UnreadSourceToken( &token );
    998 				break;
    999 			}
   1000 			if ( token.type == TT_PUNCTUATION && token == ">" ) {
   1001 				break;
   1002 			}
   1003 			path += token;
   1004 		}
   1005 		if ( token != ">" ) {
   1006 			idParser::Warning( "#include missing trailing >" );
   1007 		}
   1008 		if ( !path.Length() ) {
   1009 			idParser::Error( "#include without file name between < >" );
   1010 			return false;
   1011 		}
   1012 		if ( idParser::flags & LEXFL_NOBASEINCLUDES ) {
   1013 			return true;
   1014 		}
   1015 		script = new (TAG_IDLIB_PARSER) idLexer;
   1016 		if ( !script->LoadFile( includepath + path, OSPath ) ) {
   1017 			delete script;
   1018 			script = NULL;
   1019 		}
   1020 	}
   1021 	else {
   1022 		idParser::Error( "#include without file name" );
   1023 		return false;
   1024 	}
   1025 	if (!script) {
   1026 		idParser::Error( "file '%s' not found", path.c_str() );
   1027 		return false;
   1028 	}
   1029 	script->SetFlags( idParser::flags );
   1030 	script->SetPunctuations( idParser::punctuations );
   1031 	idParser::PushScript( script );
   1032 	return true;
   1033 }
   1034 
   1035 /*
   1036 ================
   1037 idParser::Directive_undef
   1038 ================
   1039 */
   1040 int idParser::Directive_undef() {
   1041 	idToken token;
   1042 	define_t *define, *lastdefine;
   1043 	int hash;
   1044 
   1045 	//
   1046 	if (!idParser::ReadLine( &token )) {
   1047 		idParser::Error( "undef without name" );
   1048 		return false;
   1049 	}
   1050 	if (token.type != TT_NAME) {
   1051 		idParser::UnreadSourceToken( &token );
   1052 		idParser::Error( "expected name but found '%s'", token.c_str() );
   1053 		return false;
   1054 	}
   1055 
   1056 	hash = PC_NameHash( token.c_str() );
   1057 	for (lastdefine = NULL, define = idParser::definehash[hash]; define; define = define->hashnext) {
   1058 		if (!strcmp(define->name, token.c_str()))
   1059 		{
   1060 			if (define->flags & DEFINE_FIXED) {
   1061 				idParser::Warning( "can't undef '%s'", token.c_str() );
   1062 			}
   1063 			else {
   1064 				if (lastdefine) {
   1065 					lastdefine->hashnext = define->hashnext;
   1066 				}
   1067 				else {
   1068 					idParser::definehash[hash] = define->hashnext;
   1069 				}
   1070 				FreeDefine(define);
   1071 			}
   1072 			break;
   1073 		}
   1074 		lastdefine = define;
   1075 	}
   1076 	return true;
   1077 }
   1078 
   1079 /*
   1080 ================
   1081 idParser::Directive_define
   1082 ================
   1083 */
   1084 int idParser::Directive_define() {
   1085 	idToken token, *t, *last;
   1086 	define_t *define;
   1087 
   1088 	if (!idParser::ReadLine( &token )) {
   1089 		idParser::Error( "#define without name" );
   1090 		return false;
   1091 	}
   1092 	if (token.type != TT_NAME) {
   1093 		idParser::UnreadSourceToken( &token );
   1094 		idParser::Error( "expected name after #define, found '%s'", token.c_str() );
   1095 		return false;
   1096 	}
   1097 	// check if the define already exists
   1098 	define = FindHashedDefine(idParser::definehash, token.c_str());
   1099 	if (define) {
   1100 		if (define->flags & DEFINE_FIXED) {
   1101 			idParser::Error( "can't redefine '%s'", token.c_str() );
   1102 			return false;
   1103 		}
   1104 		idParser::Warning( "redefinition of '%s'", token.c_str() );
   1105 		// unread the define name before executing the #undef directive
   1106 		idParser::UnreadSourceToken( &token );
   1107 		if (!idParser::Directive_undef())
   1108 			return false;
   1109 		// if the define was not removed (define->flags & DEFINE_FIXED)
   1110 		define = FindHashedDefine(idParser::definehash, token.c_str());
   1111 	}
   1112 	// allocate define
   1113 	define = (define_t *) Mem_ClearedAlloc(sizeof(define_t) + token.Length() + 1, TAG_IDLIB_PARSER);
   1114 	define->name = (char *) define + sizeof(define_t);
   1115 	strcpy(define->name, token.c_str());
   1116 	// add the define to the source
   1117 	AddDefineToHash(define, idParser::definehash);
   1118 	// if nothing is defined, just return
   1119 	if ( !idParser::ReadLine( &token ) ) {
   1120 		return true;
   1121 	}
   1122 	// if it is a define with parameters
   1123 	if ( token.WhiteSpaceBeforeToken() == 0 && token == "(" ) {
   1124 		// read the define parameters
   1125 		last = NULL;
   1126 		if ( !idParser::CheckTokenString(")") ) {
   1127 			while(1) {
   1128 				if ( !idParser::ReadLine( &token ) ) {
   1129 					idParser::Error( "expected define parameter" );
   1130 					return false;
   1131 				}
   1132 				// if it isn't a name
   1133 				if (token.type != TT_NAME) {
   1134 					idParser::Error( "invalid define parameter" );
   1135 					return false;
   1136 				}
   1137 
   1138 				if (FindDefineParm(define, token.c_str()) >= 0) {
   1139 					idParser::Error( "two the same define parameters" );
   1140 					return false;
   1141 				}
   1142 				// add the define parm
   1143 				t = new (TAG_IDLIB_PARSER) idToken(token);
   1144 				t->ClearTokenWhiteSpace();
   1145 				t->next = NULL;
   1146 				if (last) last->next = t;
   1147 				else define->parms = t;
   1148 				last = t;
   1149 				define->numparms++;
   1150 				// read next token
   1151 				if (!idParser::ReadLine( &token )) {
   1152 					idParser::Error( "define parameters not terminated" );
   1153 					return false;
   1154 				}
   1155 
   1156 				if ( token == ")" ) {
   1157 					break;
   1158 				}
   1159 				// then it must be a comma
   1160 				if ( token != "," ) {
   1161 					idParser::Error( "define not terminated" );
   1162 					return false;
   1163 				}
   1164 			}
   1165 		}
   1166 		if ( !idParser::ReadLine( &token ) ) {
   1167 			return true;
   1168 		}
   1169 	}
   1170 	// read the defined stuff
   1171 	last = NULL;
   1172 	do
   1173 	{
   1174 		t = new (TAG_IDLIB_PARSER) idToken(token);
   1175 		if ( t->type == TT_NAME && !strcmp( t->c_str(), define->name ) ) {
   1176 			t->flags |= TOKEN_FL_RECURSIVE_DEFINE;
   1177 			idParser::Warning( "recursive define (removed recursion)" );
   1178 		}
   1179 		t->ClearTokenWhiteSpace();
   1180 		t->next = NULL;
   1181 		if ( last ) last->next = t;
   1182 		else define->tokens = t;
   1183 		last = t;
   1184 	} while( idParser::ReadLine( &token ) );
   1185 
   1186 	if ( last ) {
   1187 		// check for merge operators at the beginning or end
   1188 		if ( (*define->tokens) == "##" || (*last) == "##" ) {
   1189 			idParser::Error( "define with misplaced ##" );
   1190 			return false;
   1191 		}
   1192 	}
   1193 	return true;
   1194 }
   1195 
   1196 /*
   1197 ================
   1198 idParser::AddDefine
   1199 ================
   1200 */
   1201 int idParser::AddDefine( const char *string ) {
   1202 	define_t *define;
   1203 
   1204 	define = DefineFromString( string );
   1205 	if (!define) {
   1206 		return false;
   1207 	}
   1208 	AddDefineToHash(define, idParser::definehash);
   1209 	return true;
   1210 }
   1211 
   1212 /*
   1213 ================
   1214 idParser::AddGlobalDefinesToSource
   1215 ================
   1216 */
   1217 void idParser::AddGlobalDefinesToSource() {
   1218 	define_t *define, *newdefine;
   1219 
   1220 	for (define = globaldefines; define; define = define->next) {
   1221 		newdefine = CopyDefine( define );
   1222 		AddDefineToHash(newdefine, idParser::definehash);
   1223 	}
   1224 }
   1225 
   1226 /*
   1227 ================
   1228 idParser::Directive_if_def
   1229 ================
   1230 */
   1231 int idParser::Directive_if_def( int type ) {
   1232 	idToken token;
   1233 	define_t *d;
   1234 	int skip;
   1235 
   1236 	if ( !idParser::ReadLine( &token ) ) {
   1237 		idParser::Error( "#ifdef without name" );
   1238 		return false;
   1239 	}
   1240 	if (token.type != TT_NAME) {
   1241 		idParser::UnreadSourceToken( &token );
   1242 		idParser::Error( "expected name after #ifdef, found '%s'", token.c_str() );
   1243 		return false;
   1244 	}
   1245 	d = FindHashedDefine(idParser::definehash, token.c_str());
   1246 	skip = (type == INDENT_IFDEF) == (d == NULL);
   1247 	idParser::PushIndent( type, skip );
   1248 	return true;
   1249 }
   1250 
   1251 /*
   1252 ================
   1253 idParser::Directive_ifdef
   1254 ================
   1255 */
   1256 int idParser::Directive_ifdef() {
   1257 	return idParser::Directive_if_def( INDENT_IFDEF );
   1258 }
   1259 
   1260 /*
   1261 ================
   1262 idParser::Directive_ifndef
   1263 ================
   1264 */
   1265 int idParser::Directive_ifndef() {
   1266 	return idParser::Directive_if_def( INDENT_IFNDEF );
   1267 }
   1268 
   1269 /*
   1270 ================
   1271 idParser::Directive_else
   1272 ================
   1273 */
   1274 int idParser::Directive_else() {
   1275 	int type, skip;
   1276 
   1277 	idParser::PopIndent( &type, &skip );
   1278 	if (!type) {
   1279 		idParser::Error( "misplaced #else" );
   1280 		return false;
   1281 	}
   1282 	if (type == INDENT_ELSE) {
   1283 		idParser::Error( "#else after #else" );
   1284 		return false;
   1285 	}
   1286 	idParser::PushIndent( INDENT_ELSE, !skip );
   1287 	return true;
   1288 }
   1289 
   1290 /*
   1291 ================
   1292 idParser::Directive_endif
   1293 ================
   1294 */
   1295 int idParser::Directive_endif() {
   1296 	int type, skip;
   1297 
   1298 	idParser::PopIndent( &type, &skip );
   1299 	if (!type) {
   1300 		idParser::Error( "misplaced #endif" );
   1301 		return false;
   1302 	}
   1303 	return true;
   1304 }
   1305 
   1306 /*
   1307 ================
   1308 idParser::EvaluateTokens
   1309 ================
   1310 */
   1311 typedef struct operator_s
   1312 {
   1313 	int op;
   1314 	int priority;
   1315 	int parentheses;
   1316 	struct operator_s *prev, *next;
   1317 } operator_t;
   1318 
   1319 typedef struct value_s
   1320 {
   1321 	signed long int intvalue;
   1322 	double floatvalue;
   1323 	int parentheses;
   1324 	struct value_s *prev, *next;
   1325 } value_t;
   1326 
   1327 int PC_OperatorPriority(int op) {
   1328 	switch(op) {
   1329 		case P_MUL: return 15;
   1330 		case P_DIV: return 15;
   1331 		case P_MOD: return 15;
   1332 		case P_ADD: return 14;
   1333 		case P_SUB: return 14;
   1334 
   1335 		case P_LOGIC_AND: return 7;
   1336 		case P_LOGIC_OR: return 6;
   1337 		case P_LOGIC_GEQ: return 12;
   1338 		case P_LOGIC_LEQ: return 12;
   1339 		case P_LOGIC_EQ: return 11;
   1340 		case P_LOGIC_UNEQ: return 11;
   1341 
   1342 		case P_LOGIC_NOT: return 16;
   1343 		case P_LOGIC_GREATER: return 12;
   1344 		case P_LOGIC_LESS: return 12;
   1345 
   1346 		case P_RSHIFT: return 13;
   1347 		case P_LSHIFT: return 13;
   1348 
   1349 		case P_BIN_AND: return 10;
   1350 		case P_BIN_OR: return 8;
   1351 		case P_BIN_XOR: return 9;
   1352 		case P_BIN_NOT: return 16;
   1353 
   1354 		case P_COLON: return 5;
   1355 		case P_QUESTIONMARK: return 5;
   1356 	}
   1357 	return false;
   1358 }
   1359 
   1360 //#define AllocValue()			GetClearedMemory(sizeof(value_t));
   1361 //#define FreeValue(val)		FreeMemory(val)
   1362 //#define AllocOperator(op)		op = (operator_t *) GetClearedMemory(sizeof(operator_t));
   1363 //#define FreeOperator(op)		FreeMemory(op);
   1364 
   1365 #define MAX_VALUES		64
   1366 #define MAX_OPERATORS	64
   1367 
   1368 #define AllocValue(val)									\
   1369 	if ( numvalues >= MAX_VALUES ) {					\
   1370 		idParser::Error( "out of value space\n" );		\
   1371 		error = 1;										\
   1372 		break;											\
   1373 	}													\
   1374 	else {												\
   1375 		val = &value_heap[numvalues++];					\
   1376 	}
   1377 
   1378 #define FreeValue(val)
   1379 
   1380 #define AllocOperator(op)								\
   1381 	if ( numoperators >= MAX_OPERATORS ) {				\
   1382 		idParser::Error( "out of operator space\n" );	\
   1383 		error = 1;										\
   1384 		break;											\
   1385 	}													\
   1386 	else {												\
   1387 		op = &operator_heap[numoperators++];			\
   1388 	}
   1389 
   1390 #define FreeOperator(op)
   1391 
   1392 int idParser::EvaluateTokens( idToken *tokens, signed long int *intvalue, double *floatvalue, int integer ) {
   1393 	operator_t *o, *firstoperator, *lastoperator;
   1394 	value_t *v, *firstvalue, *lastvalue, *v1, *v2;
   1395 	idToken *t;
   1396 	int brace = 0;
   1397 	int parentheses = 0;
   1398 	int error = 0;
   1399 	int lastwasvalue = 0;
   1400 	int negativevalue = 0;
   1401 	int questmarkintvalue = 0;
   1402 	double questmarkfloatvalue = 0;
   1403 	int gotquestmarkvalue = false;
   1404 	int lastoperatortype = 0;
   1405 	//
   1406 	operator_t operator_heap[MAX_OPERATORS];
   1407 	int numoperators = 0;
   1408 	value_t value_heap[MAX_VALUES];
   1409 	int numvalues = 0;
   1410 
   1411 	firstoperator = lastoperator = NULL;
   1412 	firstvalue = lastvalue = NULL;
   1413 	if (intvalue) *intvalue = 0;
   1414 	if (floatvalue) *floatvalue = 0;
   1415 	for ( t = tokens; t; t = t->next ) {
   1416 		switch( t->type ) {
   1417 			case TT_NAME:
   1418 			{
   1419 				if ( lastwasvalue || negativevalue ) {
   1420 					idParser::Error( "syntax error in #if/#elif" );
   1421 					error = 1;
   1422 					break;
   1423 				}
   1424 				if ( (*t) != "defined" ) {
   1425 					idParser::Error( "undefined name '%s' in #if/#elif", t->c_str() );
   1426 					error = 1;
   1427 					break;
   1428 				}
   1429 				t = t->next;
   1430 				if ( (*t) == "(" ) {
   1431 					brace = true;
   1432 					t = t->next;
   1433 				}
   1434 				if (!t || t->type != TT_NAME) {
   1435 					idParser::Error( "defined() without name in #if/#elif" );
   1436 					error = 1;
   1437 					break;
   1438 				}
   1439 				//v = (value_t *) GetClearedMemory(sizeof(value_t));
   1440 				AllocValue(v);
   1441 				if (FindHashedDefine(idParser::definehash, t->c_str())) {
   1442 					v->intvalue = 1;
   1443 					v->floatvalue = 1;
   1444 				}
   1445 				else {
   1446 					v->intvalue = 0;
   1447 					v->floatvalue = 0;
   1448 				}
   1449 				v->parentheses = parentheses;
   1450 				v->next = NULL;
   1451 				v->prev = lastvalue;
   1452 				if (lastvalue) lastvalue->next = v;
   1453 				else firstvalue = v;
   1454 				lastvalue = v;
   1455 				if (brace) {
   1456 					t = t->next;
   1457 					if (!t || (*t) != ")" ) {
   1458 						idParser::Error( "defined missing ) in #if/#elif" );
   1459 						error = 1;
   1460 						break;
   1461 					}
   1462 				}
   1463 				brace = false;
   1464 				// defined() creates a value
   1465 				lastwasvalue = 1;
   1466 				break;
   1467 			}
   1468 			case TT_NUMBER:
   1469 			{
   1470 				if (lastwasvalue) {
   1471 					idParser::Error( "syntax error in #if/#elif" );
   1472 					error = 1;
   1473 					break;
   1474 				}
   1475 				//v = (value_t *) GetClearedMemory(sizeof(value_t));
   1476 				AllocValue(v);
   1477 				if (negativevalue) {
   1478 					v->intvalue = - t->GetIntValue();
   1479 					v->floatvalue = - t->GetFloatValue();
   1480 				}
   1481 				else {
   1482 					v->intvalue = t->GetIntValue();
   1483 					v->floatvalue = t->GetFloatValue();
   1484 				}
   1485 				v->parentheses = parentheses;
   1486 				v->next = NULL;
   1487 				v->prev = lastvalue;
   1488 				if (lastvalue) lastvalue->next = v;
   1489 				else firstvalue = v;
   1490 				lastvalue = v;
   1491 				//last token was a value
   1492 				lastwasvalue = 1;
   1493 				//
   1494 				negativevalue = 0;
   1495 				break;
   1496 			}
   1497 			case TT_PUNCTUATION:
   1498 			{
   1499 				if (negativevalue) {
   1500 					idParser::Error( "misplaced minus sign in #if/#elif" );
   1501 					error = 1;
   1502 					break;
   1503 				}
   1504 				if (t->subtype == P_PARENTHESESOPEN) {
   1505 					parentheses++;
   1506 					break;
   1507 				}
   1508 				else if (t->subtype == P_PARENTHESESCLOSE) {
   1509 					parentheses--;
   1510 					if (parentheses < 0) {
   1511 						idParser::Error( "too many ) in #if/#elsif" );
   1512 						error = 1;
   1513 					}
   1514 					break;
   1515 				}
   1516 				//check for invalid operators on floating point values
   1517 				if ( !integer ) {
   1518 					if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
   1519 						t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
   1520 						t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
   1521 						t->subtype == P_BIN_XOR) {
   1522 						idParser::Error( "illigal operator '%s' on floating point operands\n", t->c_str() );
   1523 						error = 1;
   1524 						break;
   1525 					}
   1526 				}
   1527 				switch( t->subtype ) {
   1528 					case P_LOGIC_NOT:
   1529 					case P_BIN_NOT:
   1530 					{
   1531 						if (lastwasvalue) {
   1532 							idParser::Error( "! or ~ after value in #if/#elif" );
   1533 							error = 1;
   1534 							break;
   1535 						}
   1536 						break;
   1537 					}
   1538 					case P_INC:
   1539 					case P_DEC:
   1540 					{
   1541 						idParser::Error( "++ or -- used in #if/#elif" );
   1542 						break;
   1543 					}
   1544 					case P_SUB:
   1545 					{
   1546 						if (!lastwasvalue) {
   1547 							negativevalue = 1;
   1548 							break;
   1549 						}
   1550 					}
   1551 					
   1552 					case P_MUL:
   1553 					case P_DIV:
   1554 					case P_MOD:
   1555 					case P_ADD:
   1556 
   1557 					case P_LOGIC_AND:
   1558 					case P_LOGIC_OR:
   1559 					case P_LOGIC_GEQ:
   1560 					case P_LOGIC_LEQ:
   1561 					case P_LOGIC_EQ:
   1562 					case P_LOGIC_UNEQ:
   1563 
   1564 					case P_LOGIC_GREATER:
   1565 					case P_LOGIC_LESS:
   1566 
   1567 					case P_RSHIFT:
   1568 					case P_LSHIFT:
   1569 
   1570 					case P_BIN_AND:
   1571 					case P_BIN_OR:
   1572 					case P_BIN_XOR:
   1573 
   1574 					case P_COLON:
   1575 					case P_QUESTIONMARK:
   1576 					{
   1577 						if (!lastwasvalue) {
   1578 							idParser::Error( "operator '%s' after operator in #if/#elif", t->c_str() );
   1579 							error = 1;
   1580 							break;
   1581 						}
   1582 						break;
   1583 					}
   1584 					default:
   1585 					{
   1586 						idParser::Error( "invalid operator '%s' in #if/#elif", t->c_str() );
   1587 						error = 1;
   1588 						break;
   1589 					}
   1590 				}
   1591 				if (!error && !negativevalue) {
   1592 					//o = (operator_t *) GetClearedMemory(sizeof(operator_t));
   1593 					AllocOperator(o);
   1594 					o->op = t->subtype;
   1595 					o->priority = PC_OperatorPriority(t->subtype);
   1596 					o->parentheses = parentheses;
   1597 					o->next = NULL;
   1598 					o->prev = lastoperator;
   1599 					if (lastoperator) lastoperator->next = o;
   1600 					else firstoperator = o;
   1601 					lastoperator = o;
   1602 					lastwasvalue = 0;
   1603 				}
   1604 				break;
   1605 			}
   1606 			default:
   1607 			{
   1608 				idParser::Error( "unknown '%s' in #if/#elif", t->c_str() );
   1609 				error = 1;
   1610 				break;
   1611 			}
   1612 		}
   1613 		if (error) {
   1614 			break;
   1615 		}
   1616 	}
   1617 	if (!error) {
   1618 		if (!lastwasvalue) {
   1619 			idParser::Error( "trailing operator in #if/#elif" );
   1620 			error = 1;
   1621 		}
   1622 		else if (parentheses) {
   1623 			idParser::Error( "too many ( in #if/#elif" );
   1624 			error = 1;
   1625 		}
   1626 	}
   1627 	//
   1628 	gotquestmarkvalue = false;
   1629 	questmarkintvalue = 0;
   1630 	questmarkfloatvalue = 0;
   1631 	//while there are operators
   1632 	while( !error && firstoperator ) {
   1633 		v = firstvalue;
   1634 		for (o = firstoperator; o->next; o = o->next) {
   1635 			//if the current operator is nested deeper in parentheses
   1636 			//than the next operator
   1637 			if (o->parentheses > o->next->parentheses) {
   1638 				break;
   1639 			}
   1640 			//if the current and next operator are nested equally deep in parentheses
   1641 			if (o->parentheses == o->next->parentheses) {
   1642 				//if the priority of the current operator is equal or higher
   1643 				//than the priority of the next operator
   1644 				if (o->priority >= o->next->priority) {
   1645 					break;
   1646 				}
   1647 			}
   1648 			//if the arity of the operator isn't equal to 1
   1649 			if (o->op != P_LOGIC_NOT && o->op != P_BIN_NOT) {
   1650 				v = v->next;
   1651 			}
   1652 			//if there's no value or no next value
   1653 			if (!v) {
   1654 				idParser::Error( "mising values in #if/#elif" );
   1655 				error = 1;
   1656 				break;
   1657 			}
   1658 		}
   1659 		if (error) {
   1660 			break;
   1661 		}
   1662 		v1 = v;
   1663 		v2 = v->next;
   1664 #ifdef DEBUG_EVAL
   1665 		if (integer) {
   1666 			Log_Write("operator %s, value1 = %d", idParser::scriptstack->getPunctuationFromId(o->op), v1->intvalue);
   1667 			if (v2) Log_Write("value2 = %d", v2->intvalue);
   1668 		}
   1669 		else {
   1670 			Log_Write("operator %s, value1 = %f", idParser::scriptstack->getPunctuationFromId(o->op), v1->floatvalue);
   1671 			if (v2) Log_Write("value2 = %f", v2->floatvalue);
   1672 		}
   1673 #endif //DEBUG_EVAL
   1674 		switch(o->op) {
   1675 			case P_LOGIC_NOT:		v1->intvalue = !v1->intvalue;
   1676 									v1->floatvalue = !v1->floatvalue; break;
   1677 			case P_BIN_NOT:			v1->intvalue = ~v1->intvalue;
   1678 									break;
   1679 			case P_MUL:				v1->intvalue *= v2->intvalue;
   1680 									v1->floatvalue *= v2->floatvalue; break;
   1681 			case P_DIV:				if (!v2->intvalue || !v2->floatvalue)
   1682 									{
   1683 										idParser::Error( "divide by zero in #if/#elif\n" );
   1684 										error = 1;
   1685 										break;
   1686 									}
   1687 									v1->intvalue /= v2->intvalue;
   1688 									v1->floatvalue /= v2->floatvalue; break;
   1689 			case P_MOD:				if (!v2->intvalue)
   1690 									{
   1691 										idParser::Error( "divide by zero in #if/#elif\n" );
   1692 										error = 1;
   1693 										break;
   1694 									}
   1695 									v1->intvalue %= v2->intvalue; break;
   1696 			case P_ADD:				v1->intvalue += v2->intvalue;
   1697 									v1->floatvalue += v2->floatvalue; break;
   1698 			case P_SUB:				v1->intvalue -= v2->intvalue;
   1699 									v1->floatvalue -= v2->floatvalue; break;
   1700 			case P_LOGIC_AND:		v1->intvalue = v1->intvalue && v2->intvalue;
   1701 									v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
   1702 			case P_LOGIC_OR:		v1->intvalue = v1->intvalue || v2->intvalue;
   1703 									v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
   1704 			case P_LOGIC_GEQ:		v1->intvalue = v1->intvalue >= v2->intvalue;
   1705 									v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
   1706 			case P_LOGIC_LEQ:		v1->intvalue = v1->intvalue <= v2->intvalue;
   1707 									v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
   1708 			case P_LOGIC_EQ:		v1->intvalue = v1->intvalue == v2->intvalue;
   1709 									v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
   1710 			case P_LOGIC_UNEQ:		v1->intvalue = v1->intvalue != v2->intvalue;
   1711 									v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
   1712 			case P_LOGIC_GREATER:	v1->intvalue = v1->intvalue > v2->intvalue;
   1713 									v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
   1714 			case P_LOGIC_LESS:		v1->intvalue = v1->intvalue < v2->intvalue;
   1715 									v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
   1716 			case P_RSHIFT:			v1->intvalue >>= v2->intvalue;
   1717 									break;
   1718 			case P_LSHIFT:			v1->intvalue <<= v2->intvalue;
   1719 									break;
   1720 			case P_BIN_AND:			v1->intvalue &= v2->intvalue;
   1721 									break;
   1722 			case P_BIN_OR:			v1->intvalue |= v2->intvalue;
   1723 									break;
   1724 			case P_BIN_XOR:			v1->intvalue ^= v2->intvalue;
   1725 									break;
   1726 			case P_COLON:
   1727 			{
   1728 				if (!gotquestmarkvalue) {
   1729 					idParser::Error( ": without ? in #if/#elif" );
   1730 					error = 1;
   1731 					break;
   1732 				}
   1733 				if (integer) {
   1734 					if (!questmarkintvalue)
   1735 						v1->intvalue = v2->intvalue;
   1736 				}
   1737 				else {
   1738 					if (!questmarkfloatvalue)
   1739 						v1->floatvalue = v2->floatvalue;
   1740 				}
   1741 				gotquestmarkvalue = false;
   1742 				break;
   1743 			}
   1744 			case P_QUESTIONMARK:
   1745 			{
   1746 				if (gotquestmarkvalue) {
   1747 					idParser::Error( "? after ? in #if/#elif" );
   1748 					error = 1;
   1749 					break;
   1750 				}
   1751 				questmarkintvalue = v1->intvalue;
   1752 				questmarkfloatvalue = v1->floatvalue;
   1753 				gotquestmarkvalue = true;
   1754 				break;
   1755 			}
   1756 		}
   1757 #ifdef DEBUG_EVAL
   1758 		if (integer) Log_Write("result value = %d", v1->intvalue);
   1759 		else Log_Write("result value = %f", v1->floatvalue);
   1760 #endif //DEBUG_EVAL
   1761 		if (error)
   1762 			break;
   1763 		lastoperatortype = o->op;
   1764 		//if not an operator with arity 1
   1765 		if (o->op != P_LOGIC_NOT && o->op != P_BIN_NOT) {
   1766 			//remove the second value if not question mark operator
   1767 			if (o->op != P_QUESTIONMARK) {
   1768 				v = v->next;
   1769 			}
   1770 			//
   1771 			if (v->prev) v->prev->next = v->next;
   1772 			else firstvalue = v->next;
   1773 			if (v->next) v->next->prev = v->prev;
   1774 			else lastvalue = v->prev;
   1775 			//FreeMemory(v);
   1776 			FreeValue(v);
   1777 		}
   1778 		//remove the operator
   1779 		if (o->prev) o->prev->next = o->next;
   1780 		else firstoperator = o->next;
   1781 		if (o->next) o->next->prev = o->prev;
   1782 		else lastoperator = o->prev;
   1783 		//FreeMemory(o);
   1784 		FreeOperator(o);
   1785 	}
   1786 	if (firstvalue) {
   1787 		if (intvalue) *intvalue = firstvalue->intvalue;
   1788 		if (floatvalue) *floatvalue = firstvalue->floatvalue;
   1789 	}
   1790 	for (o = firstoperator; o; o = lastoperator) {
   1791 		lastoperator = o->next;
   1792 		//FreeMemory(o);
   1793 		FreeOperator(o);
   1794 	}
   1795 	for (v = firstvalue; v; v = lastvalue) {
   1796 		lastvalue = v->next;
   1797 		//FreeMemory(v);
   1798 		FreeValue(v);
   1799 	}
   1800 	if (!error) {
   1801 		return true;
   1802 	}
   1803 	if (intvalue) {
   1804 		*intvalue = 0;
   1805 	}
   1806 	if (floatvalue) {
   1807 		*floatvalue = 0;
   1808 	}
   1809 	return false;
   1810 }
   1811 
   1812 /*
   1813 ================
   1814 idParser::Evaluate
   1815 ================
   1816 */
   1817 int idParser::Evaluate( signed long int *intvalue, double *floatvalue, int integer ) {
   1818 	idToken token, *firsttoken, *lasttoken;
   1819 	idToken *t, *nexttoken;
   1820 	define_t *define;
   1821 	int defined = false;
   1822 
   1823 	if (intvalue) {
   1824 		*intvalue = 0;
   1825 	}
   1826 	if (floatvalue) {
   1827 		*floatvalue = 0;
   1828 	}
   1829 	//
   1830 	if ( !idParser::ReadLine( &token ) ) {
   1831 		idParser::Error( "no value after #if/#elif" );
   1832 		return false;
   1833 	}
   1834 	firsttoken = NULL;
   1835 	lasttoken = NULL;
   1836 	do {
   1837 		//if the token is a name
   1838 		if (token.type == TT_NAME) {
   1839 			if (defined) {
   1840 				defined = false;
   1841 				t = new (TAG_IDLIB_PARSER) idToken(token);
   1842 				t->next = NULL;
   1843 				if (lasttoken) lasttoken->next = t;
   1844 				else firsttoken = t;
   1845 				lasttoken = t;
   1846 			}
   1847 			else if ( token == "defined" ) {
   1848 				defined = true;
   1849 				t = new (TAG_IDLIB_PARSER) idToken(token);
   1850 				t->next = NULL;
   1851 				if (lasttoken) lasttoken->next = t;
   1852 				else firsttoken = t;
   1853 				lasttoken = t;
   1854 			}
   1855 			else {
   1856 				//then it must be a define
   1857 				define = FindHashedDefine(idParser::definehash, token.c_str());
   1858 				if (!define) {
   1859 					idParser::Error( "can't Evaluate '%s', not defined", token.c_str() );
   1860 					return false;
   1861 				}
   1862 				if ( !idParser::ExpandDefineIntoSource( &token, define ) ) {
   1863 					return false;
   1864 				}
   1865 			}
   1866 		}
   1867 		//if the token is a number or a punctuation
   1868 		else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) {
   1869 			t = new (TAG_IDLIB_PARSER) idToken(token);
   1870 			t->next = NULL;
   1871 			if (lasttoken) lasttoken->next = t;
   1872 			else firsttoken = t;
   1873 			lasttoken = t;
   1874 		}
   1875 		else {
   1876 			idParser::Error( "can't Evaluate '%s'", token.c_str() );
   1877 			return false;
   1878 		}
   1879 	} while(idParser::ReadLine( &token ));
   1880 	//
   1881 	if ( !idParser::EvaluateTokens( firsttoken, intvalue, floatvalue, integer ) ) {
   1882 		return false;
   1883 	}
   1884 	//
   1885 #ifdef DEBUG_EVAL
   1886 	Log_Write("eval:");
   1887 #endif //DEBUG_EVAL
   1888 	for (t = firsttoken; t; t = nexttoken) {
   1889 #ifdef DEBUG_EVAL
   1890 		Log_Write(" %s", t->c_str());
   1891 #endif //DEBUG_EVAL
   1892 		nexttoken = t->next;
   1893 		delete t;
   1894 	} //end for
   1895 #ifdef DEBUG_EVAL
   1896 	if (integer) Log_Write("eval result: %d", *intvalue);
   1897 	else Log_Write("eval result: %f", *floatvalue);
   1898 #endif //DEBUG_EVAL
   1899 	//
   1900 	return true;
   1901 }
   1902 
   1903 /*
   1904 ================
   1905 idParser::DollarEvaluate
   1906 ================
   1907 */
   1908 int idParser::DollarEvaluate( signed long int *intvalue, double *floatvalue, int integer) {
   1909 	int indent, defined = false;
   1910 	idToken token, *firsttoken, *lasttoken;
   1911 	idToken *t, *nexttoken;
   1912 	define_t *define;
   1913 
   1914 	if (intvalue) {
   1915 		*intvalue = 0;
   1916 	}
   1917 	if (floatvalue) {
   1918 		*floatvalue = 0;
   1919 	}
   1920 	//
   1921 	if ( !idParser::ReadSourceToken( &token ) ) {
   1922 		idParser::Error( "no leading ( after $evalint/$evalfloat" );
   1923 		return false;
   1924 	}
   1925 	if ( !idParser::ReadSourceToken( &token ) ) {
   1926 		idParser::Error( "nothing to Evaluate" );
   1927 		return false;
   1928 	}
   1929 	indent = 1;
   1930 	firsttoken = NULL;
   1931 	lasttoken = NULL;
   1932 	do {
   1933 		//if the token is a name
   1934 		if (token.type == TT_NAME) {
   1935 			if (defined) {
   1936 				defined = false;
   1937 				t = new (TAG_IDLIB_PARSER) idToken(token);
   1938 				t->next = NULL;
   1939 				if (lasttoken) lasttoken->next = t;
   1940 				else firsttoken = t;
   1941 				lasttoken = t;
   1942 			}
   1943 			else if ( token == "defined" ) {
   1944 				defined = true;
   1945 				t = new (TAG_IDLIB_PARSER) idToken(token);
   1946 				t->next = NULL;
   1947 				if (lasttoken) lasttoken->next = t;
   1948 				else firsttoken = t;
   1949 				lasttoken = t;
   1950 			}
   1951 			else {
   1952 				//then it must be a define
   1953 				define = FindHashedDefine(idParser::definehash, token.c_str());
   1954 				if (!define) {
   1955 					idParser::Warning( "can't Evaluate '%s', not defined", token.c_str() );
   1956 					return false;
   1957 				}
   1958 				if ( !idParser::ExpandDefineIntoSource( &token, define ) ) {
   1959 					return false;
   1960 				}
   1961 			}
   1962 		}
   1963 		//if the token is a number or a punctuation
   1964 		else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) {
   1965 			if ( token[0] == '(' ) indent++;
   1966 			else if ( token[0] == ')' ) indent--;
   1967 			if (indent <= 0) {
   1968 				break;
   1969 			}
   1970 			t = new (TAG_IDLIB_PARSER) idToken(token);
   1971 			t->next = NULL;
   1972 			if (lasttoken) lasttoken->next = t;
   1973 			else firsttoken = t;
   1974 			lasttoken = t;
   1975 		}
   1976 		else {
   1977 			idParser::Error( "can't Evaluate '%s'", token.c_str() );
   1978 			return false;
   1979 		}
   1980 	} while(idParser::ReadSourceToken( &token ));
   1981 	//
   1982 	if (!idParser::EvaluateTokens( firsttoken, intvalue, floatvalue, integer)) {
   1983 		return false;
   1984 	}
   1985 	//
   1986 #ifdef DEBUG_EVAL
   1987 	Log_Write("$eval:");
   1988 #endif //DEBUG_EVAL
   1989 	for (t = firsttoken; t; t = nexttoken) {
   1990 #ifdef DEBUG_EVAL
   1991 		Log_Write(" %s", t->c_str());
   1992 #endif //DEBUG_EVAL
   1993 		nexttoken = t->next;
   1994 		delete t;
   1995 	} //end for
   1996 #ifdef DEBUG_EVAL
   1997 	if (integer) Log_Write("$eval result: %d", *intvalue);
   1998 	else Log_Write("$eval result: %f", *floatvalue);
   1999 #endif //DEBUG_EVAL
   2000 	//
   2001 	return true;
   2002 }
   2003 
   2004 /*
   2005 ================
   2006 idParser::Directive_elif
   2007 ================
   2008 */
   2009 int idParser::Directive_elif() {
   2010 	signed long int value;
   2011 	int type, skip;
   2012 
   2013 	idParser::PopIndent( &type, &skip );
   2014 	if (!type || type == INDENT_ELSE) {
   2015 		idParser::Error( "misplaced #elif" );
   2016 		return false;
   2017 	}
   2018 	if ( !idParser::Evaluate( &value, NULL, true ) ) {
   2019 		return false;
   2020 	}
   2021 	skip = (value == 0);
   2022 	idParser::PushIndent( INDENT_ELIF, skip );
   2023 	return true;
   2024 }
   2025 
   2026 /*
   2027 ================
   2028 idParser::Directive_if
   2029 ================
   2030 */
   2031 int idParser::Directive_if() {
   2032 	signed long int value;
   2033 	int skip;
   2034 
   2035 	if ( !idParser::Evaluate( &value, NULL, true ) ) {
   2036 		return false;
   2037 	}
   2038 	skip = (value == 0);
   2039 	idParser::PushIndent( INDENT_IF, skip );
   2040 	return true;
   2041 }
   2042 
   2043 /*
   2044 ================
   2045 idParser::Directive_line
   2046 ================
   2047 */
   2048 int idParser::Directive_line() {
   2049 	idToken token;
   2050 
   2051 	idParser::Error( "#line directive not supported" );
   2052 	while( idParser::ReadLine( &token ) ) {
   2053 	}
   2054 	return true;
   2055 }
   2056 
   2057 /*
   2058 ================
   2059 idParser::Directive_error
   2060 ================
   2061 */
   2062 int idParser::Directive_error() {
   2063 	idToken token;
   2064 
   2065 	if ( !idParser::ReadLine( &token) || token.type != TT_STRING ) {
   2066 		idParser::Error( "#error without string" );
   2067 		return false;
   2068 	}
   2069 	idParser::Error( "#error: %s", token.c_str() );
   2070 	return true;
   2071 }
   2072 
   2073 /*
   2074 ================
   2075 idParser::Directive_warning
   2076 ================
   2077 */
   2078 int idParser::Directive_warning() {
   2079 	idToken token;
   2080 
   2081 	if ( !idParser::ReadLine( &token) || token.type != TT_STRING ) {
   2082 		idParser::Warning( "#warning without string" );
   2083 		return false;
   2084 	}
   2085 	idParser::Warning( "#warning: %s", token.c_str() );
   2086 	return true;
   2087 }
   2088 
   2089 /*
   2090 ================
   2091 idParser::Directive_pragma
   2092 ================
   2093 */
   2094 int idParser::Directive_pragma() {
   2095 	idToken token;
   2096 
   2097 	idParser::Warning( "#pragma directive not supported" );
   2098 	while( idParser::ReadLine( &token ) ) {
   2099 	}
   2100 	return true;
   2101 }
   2102 
   2103 /*
   2104 ================
   2105 idParser::UnreadSignToken
   2106 ================
   2107 */
   2108 void idParser::UnreadSignToken() {
   2109 	idToken token;
   2110 
   2111 	token.line = idParser::scriptstack->GetLineNum();
   2112 	token.whiteSpaceStart_p = NULL;
   2113 	token.whiteSpaceEnd_p = NULL;
   2114 	token.linesCrossed = 0;
   2115 	token.flags = 0;
   2116 	token = "-";
   2117 	token.type = TT_PUNCTUATION;
   2118 	token.subtype = P_SUB;
   2119 	idParser::UnreadSourceToken( &token );
   2120 }
   2121 
   2122 /*
   2123 ================
   2124 idParser::Directive_eval
   2125 ================
   2126 */
   2127 int idParser::Directive_eval() {
   2128 	signed long int value;
   2129 	idToken token;
   2130 	char buf[128];
   2131 
   2132 	if ( !idParser::Evaluate( &value, NULL, true ) ) {
   2133 		return false;
   2134 	}
   2135 
   2136 	token.line = idParser::scriptstack->GetLineNum();
   2137 	token.whiteSpaceStart_p = NULL;
   2138 	token.whiteSpaceEnd_p = NULL;
   2139 	token.linesCrossed = 0;
   2140 	token.flags = 0;
   2141 	sprintf(buf, "%d", abs(value));
   2142 	token = buf;
   2143 	token.type = TT_NUMBER;
   2144 	token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
   2145 	idParser::UnreadSourceToken( &token );
   2146 	if ( value < 0 ) {
   2147 		idParser::UnreadSignToken();
   2148 	}
   2149 	return true;
   2150 }
   2151 
   2152 /*
   2153 ================
   2154 idParser::Directive_evalfloat
   2155 ================
   2156 */
   2157 int idParser::Directive_evalfloat() {
   2158 	double value;
   2159 	idToken token;
   2160 	char buf[128];
   2161 
   2162 	if ( !idParser::Evaluate( NULL, &value, false ) ) {
   2163 		return false;
   2164 	}
   2165 
   2166 	token.line = idParser::scriptstack->GetLineNum();
   2167 	token.whiteSpaceStart_p = NULL;
   2168 	token.whiteSpaceEnd_p = NULL;
   2169 	token.linesCrossed = 0;
   2170 	token.flags = 0;
   2171 	sprintf(buf, "%1.2f", idMath::Fabs(value));
   2172 	token = buf;
   2173 	token.type = TT_NUMBER;
   2174 	token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
   2175 	idParser::UnreadSourceToken( &token );
   2176 	if (value < 0) {
   2177 		idParser::UnreadSignToken();
   2178 	}
   2179 	return true;
   2180 }
   2181 
   2182 /*
   2183 ================
   2184 idParser::ReadDirective
   2185 ================
   2186 */
   2187 int idParser::ReadDirective() {
   2188 	idToken token;
   2189 
   2190 	//read the directive name
   2191 	if ( !idParser::ReadSourceToken( &token ) ) {
   2192 		idParser::Error( "found '#' without name" );
   2193 		return false;
   2194 	}
   2195 	//directive name must be on the same line
   2196 	if (token.linesCrossed > 0) {
   2197 		idParser::UnreadSourceToken( &token );
   2198 		idParser::Error( "found '#' at end of line" );
   2199 		return false;
   2200 	}
   2201 	//if if is a name
   2202 	if (token.type == TT_NAME) {
   2203 		if ( token == "if" ) {
   2204 			return idParser::Directive_if();
   2205 		}
   2206 		else if ( token == "ifdef" ) {
   2207 			return idParser::Directive_ifdef();
   2208 		}
   2209 		else if ( token == "ifndef" ) {
   2210 			return idParser::Directive_ifndef();
   2211 		}
   2212 		else if ( token == "elif" ) {
   2213 			return idParser::Directive_elif();
   2214 		}
   2215 		else if ( token == "else" ) {
   2216 			return idParser::Directive_else();
   2217 		}
   2218 		else if ( token == "endif" ) {
   2219 			return idParser::Directive_endif();
   2220 		}
   2221 		else if (idParser::skip > 0) {
   2222 			// skip the rest of the line
   2223 			while( idParser::ReadLine( &token ) ) {
   2224 			}
   2225 			return true;
   2226 		}
   2227 		else {
   2228 			if ( token == "include" ) {
   2229 				return idParser::Directive_include();
   2230 			}
   2231 			else if ( token == "define" ) {
   2232 				return idParser::Directive_define();
   2233 			}
   2234 			else if ( token == "undef" ) {
   2235 				return idParser::Directive_undef();
   2236 			}
   2237 			else if ( token == "line" ) {
   2238 				return idParser::Directive_line();
   2239 			}
   2240 			else if ( token == "error" ) {
   2241 				return idParser::Directive_error();
   2242 			}
   2243 			else if ( token == "warning" ) {
   2244 				return idParser::Directive_warning();
   2245 			}
   2246 			else if ( token == "pragma" ) {
   2247 				return idParser::Directive_pragma();
   2248 			}
   2249 			else if ( token == "eval" ) {
   2250 				return idParser::Directive_eval();
   2251 			}
   2252 			else if ( token == "evalfloat" ) {
   2253 				return idParser::Directive_evalfloat();
   2254 			}
   2255 		}
   2256 	}
   2257 	idParser::Error( "unknown precompiler directive '%s'", token.c_str() );
   2258 	return false;
   2259 }
   2260 
   2261 /*
   2262 ================
   2263 idParser::DollarDirective_evalint
   2264 ================
   2265 */
   2266 int idParser::DollarDirective_evalint() {
   2267 	signed long int value;
   2268 	idToken token;
   2269 	char buf[128];
   2270 
   2271 	if ( !idParser::DollarEvaluate( &value, NULL, true ) ) {
   2272 		return false;
   2273 	}
   2274 
   2275 	token.line = idParser::scriptstack->GetLineNum();
   2276 	token.whiteSpaceStart_p = NULL;
   2277 	token.whiteSpaceEnd_p = NULL;
   2278 	token.linesCrossed = 0;
   2279 	token.flags = 0;
   2280 	sprintf( buf, "%d", abs( value ) );
   2281 	token = buf;
   2282 	token.type = TT_NUMBER;
   2283 	token.subtype = TT_INTEGER | TT_LONG | TT_DECIMAL | TT_VALUESVALID;
   2284 	token.intvalue = abs( value );
   2285 	token.floatvalue = abs( value );
   2286 	idParser::UnreadSourceToken( &token );
   2287 	if ( value < 0 ) {
   2288 		idParser::UnreadSignToken();
   2289 	}
   2290 	return true;
   2291 }
   2292 
   2293 /*
   2294 ================
   2295 idParser::DollarDirective_evalfloat
   2296 ================
   2297 */
   2298 int idParser::DollarDirective_evalfloat() {
   2299 	double value;
   2300 	idToken token;
   2301 	char buf[128];
   2302 
   2303 	if ( !idParser::DollarEvaluate( NULL, &value, false ) ) {
   2304 		return false;
   2305 	}
   2306 
   2307 	token.line = idParser::scriptstack->GetLineNum();
   2308 	token.whiteSpaceStart_p = NULL;
   2309 	token.whiteSpaceEnd_p = NULL;
   2310 	token.linesCrossed = 0;
   2311 	token.flags = 0;
   2312 	sprintf( buf, "%1.2f", fabs( value ) );
   2313 	token = buf;
   2314 	token.type = TT_NUMBER;
   2315 	token.subtype = TT_FLOAT | TT_LONG | TT_DECIMAL | TT_VALUESVALID;
   2316 	token.intvalue = (unsigned long) fabs( value );
   2317 	token.floatvalue = fabs( value );
   2318 	idParser::UnreadSourceToken( &token );
   2319 	if ( value < 0 ) {
   2320 		idParser::UnreadSignToken();
   2321 	}
   2322 	return true;
   2323 }
   2324 
   2325 /*
   2326 ================
   2327 idParser::ReadDollarDirective
   2328 ================
   2329 */
   2330 int idParser::ReadDollarDirective() {
   2331 	idToken token;
   2332 
   2333 	// read the directive name
   2334 	if ( !idParser::ReadSourceToken( &token ) ) {
   2335 		idParser::Error( "found '$' without name" );
   2336 		return false;
   2337 	}
   2338 	// directive name must be on the same line
   2339 	if ( token.linesCrossed > 0 ) {
   2340 		idParser::UnreadSourceToken( &token );
   2341 		idParser::Error( "found '$' at end of line" );
   2342 		return false;
   2343 	}
   2344 	// if if is a name
   2345 	if (token.type == TT_NAME) {
   2346 		if ( token == "evalint" ) {
   2347 			return idParser::DollarDirective_evalint();
   2348 		}
   2349 		else if ( token == "evalfloat" ) {
   2350 			return idParser::DollarDirective_evalfloat();
   2351 		}
   2352 	}
   2353 	idParser::UnreadSourceToken( &token );
   2354 	return false;
   2355 }
   2356 
   2357 /*
   2358 ================
   2359 idParser::ReadToken
   2360 ================
   2361 */
   2362 int idParser::ReadToken( idToken *token ) {
   2363 	define_t *define;
   2364 
   2365 	while(1) {
   2366 		if ( !idParser::ReadSourceToken( token ) ) {
   2367 			return false;
   2368 		}
   2369 		// check for precompiler directives
   2370 		if ( token->type == TT_PUNCTUATION && (*token)[0] == '#' && (*token)[1] == '\0' ) {
   2371 			// read the precompiler directive
   2372 			if ( !idParser::ReadDirective() ) {
   2373 				return false;
   2374 			}
   2375 			continue;
   2376 		}
   2377 		// if skipping source because of conditional compilation
   2378 		if ( idParser::skip ) {
   2379 			continue;
   2380 		}
   2381 		// recursively concatenate strings that are behind each other still resolving defines
   2382 		if ( token->type == TT_STRING && !(idParser::scriptstack->GetFlags() & LEXFL_NOSTRINGCONCAT) ) {
   2383 			idToken newtoken;
   2384 			if ( idParser::ReadToken( &newtoken ) ) {
   2385 				if ( newtoken.type == TT_STRING ) {
   2386 					token->Append( newtoken.c_str() );
   2387 				}
   2388 				else {
   2389 					idParser::UnreadSourceToken( &newtoken );
   2390 				}
   2391 			}
   2392 		}
   2393 		//
   2394 		if ( !(idParser::scriptstack->GetFlags() & LEXFL_NODOLLARPRECOMPILE) ) {
   2395 			// check for special precompiler directives
   2396 			if ( token->type == TT_PUNCTUATION && (*token)[0] == '$' && (*token)[1] == '\0' ) {
   2397 				// read the precompiler directive
   2398 				if ( idParser::ReadDollarDirective() ) {
   2399 					continue;
   2400 				}
   2401 			}
   2402 		}
   2403 		// if the token is a name
   2404 		if ( token->type == TT_NAME && !( token->flags & TOKEN_FL_RECURSIVE_DEFINE ) ) {
   2405 			// check if the name is a define macro
   2406 			define = FindHashedDefine( idParser::definehash, token->c_str() );
   2407 			// if it is a define macro
   2408 			if ( define ) {
   2409 				// expand the defined macro
   2410 				if ( !idParser::ExpandDefineIntoSource( token, define ) ) {
   2411 					return false;
   2412 				}
   2413 				continue;
   2414 			}
   2415 		}
   2416 		// found a token
   2417 		return true;
   2418 	}
   2419 }
   2420 
   2421 /*
   2422 ================
   2423 idParser::ExpectTokenString
   2424 ================
   2425 */
   2426 int idParser::ExpectTokenString( const char *string ) {
   2427 	idToken token;
   2428 
   2429 	if ( !idParser::ReadToken( &token ) ) {
   2430 		idParser::Error( "couldn't find expected '%s'", string );
   2431 		return false;
   2432 	}
   2433 
   2434 	if ( token != string ) {
   2435 		idParser::Error( "expected '%s' but found '%s'", string, token.c_str() );
   2436 		return false;
   2437 	}
   2438 	return true;
   2439 }
   2440 
   2441 /*
   2442 ================
   2443 idParser::ExpectTokenType
   2444 ================
   2445 */
   2446 int idParser::ExpectTokenType( int type, int subtype, idToken *token ) {
   2447 	idStr str;
   2448 
   2449 	if ( !idParser::ReadToken( token ) ) {
   2450 		idParser::Error( "couldn't read expected token" );
   2451 		return 0;
   2452 	}
   2453 
   2454 	if ( token->type != type ) {
   2455 		switch( type ) {
   2456 			case TT_STRING: str = "string"; break;
   2457 			case TT_LITERAL: str = "literal"; break;
   2458 			case TT_NUMBER: str = "number"; break;
   2459 			case TT_NAME: str = "name"; break;
   2460 			case TT_PUNCTUATION: str = "punctuation"; break;
   2461 			default: str = "unknown type"; break;
   2462 		}
   2463 		idParser::Error( "expected a %s but found '%s'", str.c_str(), token->c_str() );
   2464 		return 0;
   2465 	}
   2466 	if ( token->type == TT_NUMBER ) {
   2467 		if ( (token->subtype & subtype) != subtype ) {
   2468 			str.Clear();
   2469 			if ( subtype & TT_DECIMAL ) str = "decimal ";
   2470 			if ( subtype & TT_HEX ) str = "hex ";
   2471 			if ( subtype & TT_OCTAL ) str = "octal ";
   2472 			if ( subtype & TT_BINARY ) str = "binary ";
   2473 			if ( subtype & TT_UNSIGNED ) str += "unsigned ";
   2474 			if ( subtype & TT_LONG ) str += "long ";
   2475 			if ( subtype & TT_FLOAT ) str += "float ";
   2476 			if ( subtype & TT_INTEGER ) str += "integer ";
   2477 			str.StripTrailing( ' ' );
   2478 			idParser::Error( "expected %s but found '%s'", str.c_str(), token->c_str() );
   2479 			return 0;
   2480 		}
   2481 	}
   2482 	else if ( token->type == TT_PUNCTUATION ) {
   2483 		if ( subtype < 0 ) {
   2484 			idParser::Error( "BUG: wrong punctuation subtype" );
   2485 			return 0;
   2486 		}
   2487 		if ( token->subtype != subtype ) {
   2488 			idParser::Error( "expected '%s' but found '%s'", scriptstack->GetPunctuationFromId( subtype ), token->c_str() );
   2489 			return 0;
   2490 		}
   2491 	}
   2492 	return 1;
   2493 }
   2494 
   2495 /*
   2496 ================
   2497 idParser::ExpectAnyToken
   2498 ================
   2499 */
   2500 int idParser::ExpectAnyToken( idToken *token ) {
   2501 	if (!idParser::ReadToken( token )) {
   2502 		idParser::Error( "couldn't read expected token" );
   2503 		return false;
   2504 	}
   2505 	else {
   2506 		return true;
   2507 	}
   2508 }
   2509 
   2510 /*
   2511 ================
   2512 idParser::CheckTokenString
   2513 ================
   2514 */
   2515 int idParser::CheckTokenString( const char *string ) {
   2516 	idToken tok;
   2517 
   2518 	if ( !ReadToken( &tok ) ) {
   2519 		return false;
   2520 	}
   2521 	//if the token is available
   2522 	if ( tok == string ) {
   2523 		return true;
   2524 	}
   2525 
   2526 	UnreadSourceToken( &tok );
   2527 	return false;
   2528 }
   2529 
   2530 /*
   2531 ================
   2532 idParser::CheckTokenType
   2533 ================
   2534 */
   2535 int idParser::CheckTokenType( int type, int subtype, idToken *token ) {
   2536 	idToken tok;
   2537 
   2538 	if ( !ReadToken( &tok ) ) {
   2539 		return false;
   2540 	}
   2541 	//if the type matches
   2542 	if (tok.type == type && (tok.subtype & subtype) == subtype) {
   2543 		*token = tok;
   2544 		return true;
   2545 	}
   2546 
   2547 	UnreadSourceToken( &tok );
   2548 	return false;
   2549 }
   2550 
   2551 /*
   2552 ================
   2553 idParser::PeekTokenString
   2554 ================
   2555 */
   2556 int idParser::PeekTokenString( const char *string ) {
   2557 	idToken tok;
   2558 
   2559 	if ( !ReadToken( &tok ) ) {
   2560 		return false;
   2561 	}
   2562 
   2563 	UnreadSourceToken( &tok );
   2564 
   2565 	// if the token is available
   2566 	if ( tok == string ) {
   2567 		return true;
   2568 	}
   2569 	return false;
   2570 }
   2571 
   2572 /*
   2573 ================
   2574 idParser::PeekTokenType
   2575 ================
   2576 */
   2577 int idParser::PeekTokenType( int type, int subtype, idToken *token ) {
   2578 	idToken tok;
   2579 
   2580 	if ( !ReadToken( &tok ) ) {
   2581 		return false;
   2582 	}
   2583 
   2584 	UnreadSourceToken( &tok );
   2585 
   2586 	// if the type matches
   2587 	if ( tok.type == type && ( tok.subtype & subtype ) == subtype ) {
   2588 		*token = tok;
   2589 		return true;
   2590 	}
   2591 	return false;
   2592 }
   2593 
   2594 /*
   2595 ================
   2596 idParser::SkipUntilString
   2597 ================
   2598 */
   2599 int idParser::SkipUntilString( const char *string ) {
   2600 	idToken token;
   2601 
   2602 	while(idParser::ReadToken( &token )) {
   2603 		if ( token == string ) {
   2604 			return true;
   2605 		}
   2606 	}
   2607 	return false;
   2608 }
   2609 
   2610 /*
   2611 ================
   2612 idParser::SkipRestOfLine
   2613 ================
   2614 */
   2615 int idParser::SkipRestOfLine() {
   2616 	idToken token;
   2617 
   2618 	while(idParser::ReadToken( &token )) {
   2619 		if ( token.linesCrossed ) {
   2620 			idParser::UnreadSourceToken( &token );
   2621 			return true;
   2622 		}
   2623 	}
   2624 	return false;
   2625 }
   2626 
   2627 /*
   2628 =================
   2629 idParser::SkipBracedSection
   2630 
   2631 Skips until a matching close brace is found.
   2632 Internal brace depths are properly skipped.
   2633 =================
   2634 */
   2635 int idParser::SkipBracedSection( bool parseFirstBrace ) {
   2636 	idToken token;
   2637 	int depth;
   2638 
   2639 	depth = parseFirstBrace ? 0 : 1;
   2640 	do {
   2641 		if ( !ReadToken( &token ) ) {
   2642 			return false;
   2643 		}
   2644 		if( token.type == TT_PUNCTUATION ) {
   2645 			if( token == "{" ) {
   2646 				depth++;
   2647 			} else if ( token == "}" ) {
   2648 				depth--;
   2649 			}
   2650 		}
   2651 	} while( depth );
   2652 	return true;
   2653 }
   2654 
   2655 /*
   2656 =================
   2657 idParser::ParseBracedSectionExact
   2658 
   2659 The next token should be an open brace.
   2660 Parses until a matching close brace is found.
   2661 Maintains the exact formating of the braced section
   2662 
   2663   FIXME: what about precompilation ?
   2664 =================
   2665 */
   2666 const char *idParser::ParseBracedSectionExact( idStr &out, int tabs ) {
   2667 	return scriptstack->ParseBracedSectionExact( out, tabs );
   2668 }
   2669 
   2670 
   2671 /*
   2672 ========================
   2673 idParser::ParseBracedSection
   2674 
   2675 The next token should be an open brace. Parses until a matching close brace is found. Internal 
   2676 brace depths are properly skipped.
   2677 ========================
   2678 */
   2679 const char* idParser::ParseBracedSection( idStr& out, int tabs, bool parseFirstBrace, char intro, char outro ) {
   2680 	idToken token;
   2681 	int i, depth;
   2682 	bool doTabs;
   2683 
   2684 	char temp[ 2 ] = { 0, 0 };
   2685 	*temp = intro;
   2686 
   2687 	out.Empty();
   2688 	if ( parseFirstBrace ) {
   2689 		if ( !ExpectTokenString( temp ) ) {
   2690 			return out.c_str();
   2691 		}
   2692 		out = temp;
   2693 	}
   2694 	depth = 1;
   2695 	doTabs = ( tabs >= 0 );
   2696 	do {
   2697 		if ( !ReadToken( &token ) ) {
   2698 			Error( "missing closing brace" );
   2699 			return out.c_str();
   2700 		}
   2701 
   2702 		// if the token is on a new line
   2703 		for ( i = 0; i < token.linesCrossed; i++ ) {
   2704 			out += "\r\n";
   2705 		}
   2706 
   2707 		if ( doTabs && token.linesCrossed ) {
   2708 			i = tabs;
   2709 			if ( token[ 0 ] == outro && i > 0 ) {
   2710 				i--;
   2711 			}
   2712 			while( i-- > 0 ) {
   2713 				out += "\t";
   2714 			}
   2715 		}
   2716 		if ( token.type == TT_STRING ) {
   2717 			out += "\"" + token + "\"";
   2718 		} else if ( token.type == TT_LITERAL ) {
   2719 			out += "\'" + token + "\'";
   2720 		} else {
   2721 			if ( token[ 0 ] == intro ) {
   2722 				depth++;
   2723 				if ( doTabs ) {
   2724 					tabs++;
   2725 				}
   2726 			} else if ( token[ 0 ] == outro ) {
   2727 				depth--;
   2728 				if ( doTabs ) {
   2729 					tabs--;
   2730 				}
   2731 			}
   2732 			out += token;
   2733 		}
   2734 		out += " ";
   2735 	} while( depth );
   2736 
   2737 	return out.c_str();
   2738 }
   2739 
   2740 /*
   2741 =================
   2742 idParser::ParseRestOfLine
   2743 
   2744   parse the rest of the line
   2745 =================
   2746 */
   2747 const char *idParser::ParseRestOfLine( idStr &out ) {
   2748 	idToken token;
   2749 
   2750 	out.Empty();
   2751 	while(idParser::ReadToken( &token )) {
   2752 		if ( token.linesCrossed ) {
   2753 			idParser::UnreadSourceToken( &token );
   2754 			break;
   2755 		}
   2756 		if ( out.Length() ) {
   2757 			out += " ";
   2758 		}
   2759 		out += token;
   2760 	}
   2761 	return out.c_str();
   2762 }
   2763 
   2764 /*
   2765 ================
   2766 idParser::UnreadToken
   2767 ================
   2768 */
   2769 void idParser::UnreadToken( idToken *token ) {
   2770 	idParser::UnreadSourceToken( token );
   2771 }
   2772 
   2773 /*
   2774 ================
   2775 idParser::ReadTokenOnLine
   2776 ================
   2777 */
   2778 int idParser::ReadTokenOnLine( idToken *token ) {
   2779 	idToken tok;
   2780 
   2781 	if (!idParser::ReadToken( &tok )) {
   2782 		return false;
   2783 	}
   2784 	// if no lines were crossed before this token
   2785 	if ( !tok.linesCrossed ) {
   2786 		*token = tok;
   2787 		return true;
   2788 	}
   2789 	//
   2790 	idParser::UnreadSourceToken( &tok );
   2791 	return false;
   2792 }
   2793 
   2794 /*
   2795 ================
   2796 idParser::ParseInt
   2797 ================
   2798 */
   2799 int idParser::ParseInt() {
   2800 	idToken token;
   2801 
   2802 	if ( !idParser::ReadToken( &token ) ) {
   2803 		idParser::Error( "couldn't read expected integer" );
   2804 		return 0;
   2805 	}
   2806 	if ( token.type == TT_PUNCTUATION && token == "-" ) {
   2807 		idParser::ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
   2808 		return -((signed int) token.GetIntValue());
   2809 	}
   2810 	else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
   2811 		idParser::Error( "expected integer value, found '%s'", token.c_str() );
   2812 	}
   2813 	return token.GetIntValue();
   2814 }
   2815 
   2816 /*
   2817 ================
   2818 idParser::ParseBool
   2819 ================
   2820 */
   2821 bool idParser::ParseBool() {
   2822 	idToken token;
   2823 
   2824 	if ( !idParser::ExpectTokenType( TT_NUMBER, 0, &token ) ) {
   2825 		idParser::Error( "couldn't read expected boolean" );
   2826 		return false;
   2827 	}
   2828 	return ( token.GetIntValue() != 0 );
   2829 }
   2830 
   2831 /*
   2832 ================
   2833 idParser::ParseFloat
   2834 ================
   2835 */
   2836 float idParser::ParseFloat() {
   2837 	idToken token;
   2838 
   2839 	if ( !idParser::ReadToken( &token ) ) {
   2840 		idParser::Error( "couldn't read expected floating point number" );
   2841 		return 0.0f;
   2842 	}
   2843 	if ( token.type == TT_PUNCTUATION && token == "-" ) {
   2844 		idParser::ExpectTokenType( TT_NUMBER, 0, &token );
   2845 		return -token.GetFloatValue();
   2846 	}
   2847 	else if ( token.type != TT_NUMBER ) {
   2848 		idParser::Error( "expected float value, found '%s'", token.c_str() );
   2849 	}
   2850 	return token.GetFloatValue();
   2851 }
   2852 
   2853 /*
   2854 ================
   2855 idParser::Parse1DMatrix
   2856 ================
   2857 */
   2858 int idParser::Parse1DMatrix( int x, float *m ) {
   2859 	int i;
   2860 
   2861 	if ( !idParser::ExpectTokenString( "(" ) ) {
   2862 		return false;
   2863 	}
   2864 
   2865 	for ( i = 0; i < x; i++ ) {
   2866 		m[i] = idParser::ParseFloat();
   2867 	}
   2868 
   2869 	if ( !idParser::ExpectTokenString( ")" ) ) {
   2870 		return false;
   2871 	}
   2872 	return true;
   2873 }
   2874 
   2875 /*
   2876 ================
   2877 idParser::Parse2DMatrix
   2878 ================
   2879 */
   2880 int idParser::Parse2DMatrix( int y, int x, float *m ) {
   2881 	int i;
   2882 
   2883 	if ( !idParser::ExpectTokenString( "(" ) ) {
   2884 		return false;
   2885 	}
   2886 
   2887 	for ( i = 0; i < y; i++ ) {
   2888 		if ( !idParser::Parse1DMatrix( x, m + i * x ) ) {
   2889 			return false;
   2890 		}
   2891 	}
   2892 
   2893 	if ( !idParser::ExpectTokenString( ")" ) ) {
   2894 		return false;
   2895 	}
   2896 	return true;
   2897 }
   2898 
   2899 /*
   2900 ================
   2901 idParser::Parse3DMatrix
   2902 ================
   2903 */
   2904 int idParser::Parse3DMatrix( int z, int y, int x, float *m ) {
   2905 	int i;
   2906 
   2907 	if ( !idParser::ExpectTokenString( "(" ) ) {
   2908 		return false;
   2909 	}
   2910 
   2911 	for ( i = 0 ; i < z; i++ ) {
   2912 		if ( !idParser::Parse2DMatrix( y, x, m + i * x*y ) ) {
   2913 			return false;
   2914 		}
   2915 	}
   2916 
   2917 	if ( !idParser::ExpectTokenString( ")" ) ) {
   2918 		return false;
   2919 	}
   2920 	return true;
   2921 }
   2922 
   2923 /*
   2924 ================
   2925 idParser::GetLastWhiteSpace
   2926 ================
   2927 */
   2928 int idParser::GetLastWhiteSpace( idStr &whiteSpace ) const {
   2929 	if ( scriptstack ) {
   2930 		scriptstack->GetLastWhiteSpace( whiteSpace );
   2931 	} else {
   2932 		whiteSpace.Clear();
   2933 	}
   2934 	return whiteSpace.Length();
   2935 }
   2936 
   2937 /*
   2938 ================
   2939 idParser::SetMarker
   2940 ================
   2941 */
   2942 void idParser::SetMarker() {
   2943 	marker_p = NULL;
   2944 }
   2945 
   2946 /*
   2947 ================
   2948 idParser::GetStringFromMarker
   2949 
   2950   FIXME: this is very bad code, the script isn't even garrenteed to still be around
   2951 ================
   2952 */
   2953 void idParser::GetStringFromMarker( idStr& out, bool clean ) {
   2954 	char*	p;
   2955 	char	save;
   2956 
   2957 	if ( marker_p == NULL ) {
   2958 		marker_p = scriptstack->buffer;
   2959 	}
   2960 		
   2961 	if ( tokens ) {
   2962 		p = (char*)tokens->whiteSpaceStart_p;
   2963 	} else {
   2964 		p = (char*)scriptstack->script_p;
   2965 	}
   2966 	
   2967 	// Set the end character to NULL to give us a complete string
   2968 	save = *p;
   2969 	*p = 0;
   2970 	
   2971 	// If cleaning then reparse
   2972 	if ( clean ) {	
   2973 		idParser temp( marker_p, strlen( marker_p ), "temp", flags );
   2974 		idToken token;
   2975 		while ( temp.ReadToken ( &token ) ) {
   2976 			out += token;
   2977 		}
   2978 	} else {
   2979 		out = marker_p;
   2980 	}
   2981 	
   2982 	// restore the character we set to NULL
   2983 	*p = save;		
   2984 }
   2985 
   2986 /*
   2987 ================
   2988 idParser::SetIncludePath
   2989 ================
   2990 */
   2991 void idParser::SetIncludePath( const char *path ) {
   2992 	idParser::includepath = path;
   2993 	// add trailing path seperator
   2994 	if (idParser::includepath[idParser::includepath.Length()-1] != '\\' &&
   2995 		idParser::includepath[idParser::includepath.Length()-1] != '/') {
   2996 		idParser::includepath += PATHSEPARATOR_STR;
   2997 	}
   2998 }
   2999 
   3000 /*
   3001 ================
   3002 idParser::SetPunctuations
   3003 ================
   3004 */
   3005 void idParser::SetPunctuations( const punctuation_t *p ) {
   3006 	idParser::punctuations = p;
   3007 }
   3008 
   3009 /*
   3010 ================
   3011 idParser::SetFlags
   3012 ================
   3013 */
   3014 void idParser::SetFlags( int flags ) {
   3015 	idLexer *s;
   3016 
   3017 	idParser::flags = flags;
   3018 	for ( s = idParser::scriptstack; s; s = s->next ) {
   3019 		s->SetFlags( flags );
   3020 	}
   3021 }
   3022 
   3023 /*
   3024 ================
   3025 idParser::GetFlags
   3026 ================
   3027 */
   3028 int idParser::GetFlags() const {
   3029 	return idParser::flags;
   3030 }
   3031 
   3032 /*
   3033 ================
   3034 idParser::LoadFile
   3035 ================
   3036 */
   3037 int idParser::LoadFile( const char *filename, bool OSPath ) {
   3038 	idLexer *script;
   3039 
   3040 	if ( idParser::loaded ) {
   3041 		idLib::common->FatalError("idParser::loadFile: another source already loaded");
   3042 		return false;
   3043 	}
   3044 	script = new (TAG_IDLIB_PARSER) idLexer( filename, 0, OSPath );
   3045 	if ( !script->IsLoaded() ) {
   3046 		delete script;
   3047 		return false;
   3048 	}
   3049 	script->SetFlags( idParser::flags );
   3050 	script->SetPunctuations( idParser::punctuations );
   3051 	script->next = NULL;
   3052 	idParser::OSPath = OSPath;
   3053 	idParser::filename = filename;
   3054 	idParser::scriptstack = script;
   3055 	idParser::tokens = NULL;
   3056 	idParser::indentstack = NULL;
   3057 	idParser::skip = 0;
   3058 	idParser::loaded = true;
   3059 
   3060 	if ( !idParser::definehash ) {
   3061 		idParser::defines = NULL;
   3062 		idParser::definehash = (define_t **) Mem_ClearedAlloc( DEFINEHASHSIZE * sizeof(define_t *), TAG_IDLIB_PARSER );
   3063 		idParser::AddGlobalDefinesToSource();
   3064 	}
   3065 	return true;
   3066 }
   3067 
   3068 /*
   3069 ================
   3070 idParser::LoadMemory
   3071 ================
   3072 */
   3073 int idParser::LoadMemory(const char *ptr, int length, const char *name ) {
   3074 	idLexer *script;
   3075 
   3076 	if ( idParser::loaded ) {
   3077 		idLib::common->FatalError("idParser::loadMemory: another source already loaded");
   3078 		return false;
   3079 	}
   3080 	script = new (TAG_IDLIB_PARSER) idLexer( ptr, length, name );
   3081 	if ( !script->IsLoaded() ) {
   3082 		delete script;
   3083 		return false;
   3084 	}
   3085 	script->SetFlags( idParser::flags );
   3086 	script->SetPunctuations( idParser::punctuations );
   3087 	script->next = NULL;
   3088 	idParser::filename = name;
   3089 	idParser::scriptstack = script;
   3090 	idParser::tokens = NULL;
   3091 	idParser::indentstack = NULL;
   3092 	idParser::skip = 0;
   3093 	idParser::loaded = true;
   3094 
   3095 	if ( !idParser::definehash ) {
   3096 		idParser::defines = NULL;
   3097 		idParser::definehash = (define_t **) Mem_ClearedAlloc( DEFINEHASHSIZE * sizeof(define_t *), TAG_IDLIB_PARSER );
   3098 		idParser::AddGlobalDefinesToSource();
   3099 	}
   3100 	return true;
   3101 }
   3102 
   3103 /*
   3104 ================
   3105 idParser::FreeSource
   3106 ================
   3107 */
   3108 void idParser::FreeSource( bool keepDefines ) {
   3109 	idLexer *script;
   3110 	idToken *token;
   3111 	define_t *define;
   3112 	indent_t *indent;
   3113 	int i;
   3114 
   3115 	// free all the scripts
   3116 	while( scriptstack ) {
   3117 		script = scriptstack;
   3118 		scriptstack = scriptstack->next;
   3119 		delete script;
   3120 	}
   3121 	// free all the tokens
   3122 	while( tokens ) {
   3123 		token = tokens;
   3124 		tokens = tokens->next;
   3125 		delete token;
   3126 	}
   3127 	// free all indents
   3128 	while( indentstack ) {
   3129 		indent = indentstack;
   3130 		indentstack = indentstack->next;
   3131 		Mem_Free( indent );
   3132 	}
   3133 	if ( !keepDefines ) {
   3134 		// free hash table
   3135 		if ( definehash ) {
   3136 			// free defines
   3137 			for ( i = 0; i < DEFINEHASHSIZE; i++ ) {
   3138 				while( definehash[i] ) {
   3139 					define = definehash[i];
   3140 					definehash[i] = definehash[i]->hashnext;
   3141 					FreeDefine(define);
   3142 				}
   3143 			}
   3144 			defines = NULL;
   3145 			Mem_Free( idParser::definehash );
   3146 			definehash = NULL;
   3147 		}
   3148 	}
   3149 	loaded = false;
   3150 }
   3151 
   3152 /*
   3153 ================
   3154 idParser::GetPunctuationFromId
   3155 ================
   3156 */
   3157 const char *idParser::GetPunctuationFromId( int id ) {
   3158 	int i;
   3159 
   3160 	if ( !idParser::punctuations ) {
   3161 		idLexer lex;
   3162 		return lex.GetPunctuationFromId( id );
   3163 	}
   3164 
   3165 	for (i = 0; idParser::punctuations[i].p; i++) {
   3166 		if ( idParser::punctuations[i].n == id ) {
   3167 			return idParser::punctuations[i].p;
   3168 		}
   3169 	}
   3170 	return "unkown punctuation";
   3171 }
   3172 
   3173 /*
   3174 ================
   3175 idParser::GetPunctuationId
   3176 ================
   3177 */
   3178 int idParser::GetPunctuationId( const char *p ) {
   3179 	int i;
   3180 
   3181 	if ( !idParser::punctuations ) {
   3182 		idLexer lex;
   3183 		return lex.GetPunctuationId( p );
   3184 	}
   3185 
   3186 	for (i = 0; idParser::punctuations[i].p; i++) {
   3187 		if ( !strcmp(idParser::punctuations[i].p, p) ) {
   3188 			return idParser::punctuations[i].n;
   3189 		}
   3190 	}
   3191 	return 0;
   3192 }
   3193 
   3194 /*
   3195 ================
   3196 idParser::idParser
   3197 ================
   3198 */
   3199 idParser::idParser() {
   3200 	this->loaded = false;
   3201 	this->OSPath = false;
   3202 	this->punctuations = 0;
   3203 	this->flags = 0;
   3204 	this->scriptstack = NULL;
   3205 	this->indentstack = NULL;
   3206 	this->definehash = NULL;
   3207 	this->defines = NULL;
   3208 	this->tokens = NULL;
   3209 	this->marker_p = NULL;
   3210 }
   3211 
   3212 /*
   3213 ================
   3214 idParser::idParser
   3215 ================
   3216 */
   3217 idParser::idParser( int flags ) {
   3218 	this->loaded = false;
   3219 	this->OSPath = false;
   3220 	this->punctuations = 0;
   3221 	this->flags = flags;
   3222 	this->scriptstack = NULL;
   3223 	this->indentstack = NULL;
   3224 	this->definehash = NULL;
   3225 	this->defines = NULL;
   3226 	this->tokens = NULL;
   3227 	this->marker_p = NULL;
   3228 }
   3229 
   3230 /*
   3231 ================
   3232 idParser::idParser
   3233 ================
   3234 */
   3235 idParser::idParser( const char *filename, int flags, bool OSPath ) {
   3236 	this->loaded = false;
   3237 	this->OSPath = true;
   3238 	this->punctuations = 0;
   3239 	this->flags = flags;
   3240 	this->scriptstack = NULL;
   3241 	this->indentstack = NULL;
   3242 	this->definehash = NULL;
   3243 	this->defines = NULL;
   3244 	this->tokens = NULL;
   3245 	this->marker_p = NULL;
   3246 	LoadFile( filename, OSPath );
   3247 }
   3248 
   3249 /*
   3250 ================
   3251 idParser::idParser
   3252 ================
   3253 */
   3254 idParser::idParser( const char *ptr, int length, const char *name, int flags ) {
   3255 	this->loaded = false;
   3256 	this->OSPath = false;
   3257 	this->punctuations = 0;
   3258 	this->flags = flags;
   3259 	this->scriptstack = NULL;
   3260 	this->indentstack = NULL;
   3261 	this->definehash = NULL;
   3262 	this->defines = NULL;
   3263 	this->tokens = NULL;
   3264 	this->marker_p = NULL;
   3265 	LoadMemory( ptr, length, name );
   3266 }
   3267 
   3268 /*
   3269 ================
   3270 idParser::~idParser
   3271 ================
   3272 */
   3273 idParser::~idParser() {
   3274 	idParser::FreeSource( false );
   3275 }
   3276 
   3277 /*
   3278 ========================
   3279 idParser::EndOfFile
   3280 ========================
   3281 */
   3282 bool idParser::EndOfFile() {
   3283 	if ( scriptstack != NULL ) {
   3284 		return (bool) scriptstack->EndOfFile();
   3285 	}
   3286 	return true;
   3287 }
   3288