DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Lexer.cpp (41912B)


      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 PUNCTABLE
     33 
     34 //longer punctuations first
     35 punctuation_t default_punctuations[] = {
     36 	//binary operators
     37 	{">>=",P_RSHIFT_ASSIGN},
     38 	{"<<=",P_LSHIFT_ASSIGN},
     39 	//
     40 	{"...",P_PARMS},
     41 	//define merge operator
     42 	{"##",P_PRECOMPMERGE},				// pre-compiler
     43 	//logic operators
     44 	{"&&",P_LOGIC_AND},					// pre-compiler
     45 	{"||",P_LOGIC_OR},					// pre-compiler
     46 	{">=",P_LOGIC_GEQ},					// pre-compiler
     47 	{"<=",P_LOGIC_LEQ},					// pre-compiler
     48 	{"==",P_LOGIC_EQ},					// pre-compiler
     49 	{"!=",P_LOGIC_UNEQ},				// pre-compiler
     50 	//arithmatic operators
     51 	{"*=",P_MUL_ASSIGN},
     52 	{"/=",P_DIV_ASSIGN},
     53 	{"%=",P_MOD_ASSIGN},
     54 	{"+=",P_ADD_ASSIGN},
     55 	{"-=",P_SUB_ASSIGN},
     56 	{"++",P_INC},
     57 	{"--",P_DEC},
     58 	//binary operators
     59 	{"&=",P_BIN_AND_ASSIGN},
     60 	{"|=",P_BIN_OR_ASSIGN},
     61 	{"^=",P_BIN_XOR_ASSIGN},
     62 	{">>",P_RSHIFT},					// pre-compiler
     63 	{"<<",P_LSHIFT},					// pre-compiler
     64 	//reference operators
     65 	{"->",P_POINTERREF},
     66 	//C++
     67 	{"::",P_CPP1},
     68 	{".*",P_CPP2},
     69 	//arithmatic operators
     70 	{"*",P_MUL},						// pre-compiler
     71 	{"/",P_DIV},						// pre-compiler
     72 	{"%",P_MOD},						// pre-compiler
     73 	{"+",P_ADD},						// pre-compiler
     74 	{"-",P_SUB},						// pre-compiler
     75 	{"=",P_ASSIGN},
     76 	//binary operators
     77 	{"&",P_BIN_AND},					// pre-compiler
     78 	{"|",P_BIN_OR},						// pre-compiler
     79 	{"^",P_BIN_XOR},					// pre-compiler
     80 	{"~",P_BIN_NOT},					// pre-compiler
     81 	//logic operators
     82 	{"!",P_LOGIC_NOT},					// pre-compiler
     83 	{">",P_LOGIC_GREATER},				// pre-compiler
     84 	{"<",P_LOGIC_LESS},					// pre-compiler
     85 	//reference operator
     86 	{".",P_REF},
     87 	//seperators
     88 	{",",P_COMMA},						// pre-compiler
     89 	{";",P_SEMICOLON},
     90 	//label indication
     91 	{":",P_COLON},						// pre-compiler
     92 	//if statement
     93 	{"?",P_QUESTIONMARK},				// pre-compiler
     94 	//embracements
     95 	{"(",P_PARENTHESESOPEN},			// pre-compiler
     96 	{")",P_PARENTHESESCLOSE},			// pre-compiler
     97 	{"{",P_BRACEOPEN},					// pre-compiler
     98 	{"}",P_BRACECLOSE},					// pre-compiler
     99 	{"[",P_SQBRACKETOPEN},
    100 	{"]",P_SQBRACKETCLOSE},
    101 	//
    102 	{"\\",P_BACKSLASH},
    103 	//precompiler operator
    104 	{"#",P_PRECOMP},					// pre-compiler
    105 	{"$",P_DOLLAR},
    106 	{NULL, 0}
    107 };
    108 
    109 int default_punctuationtable[256];
    110 int default_nextpunctuation[sizeof(default_punctuations) / sizeof(punctuation_t)];
    111 int default_setup;
    112 
    113 char idLexer::baseFolder[ 256 ];
    114 
    115 /*
    116 ================
    117 idLexer::CreatePunctuationTable
    118 ================
    119 */
    120 void idLexer::CreatePunctuationTable( const punctuation_t *punctuations ) {
    121 	int i, n, lastp;
    122 	const punctuation_t *p, *newp;
    123 
    124 	//get memory for the table
    125 	if ( punctuations == default_punctuations ) {
    126 		idLexer::punctuationtable = default_punctuationtable;
    127 		idLexer::nextpunctuation = default_nextpunctuation;
    128 		if ( default_setup ) {
    129 			return;
    130 		}
    131 		default_setup = true;
    132 		i = sizeof(default_punctuations) / sizeof(punctuation_t);
    133 	}
    134 	else {
    135 		if ( !idLexer::punctuationtable || idLexer::punctuationtable == default_punctuationtable ) {
    136 			idLexer::punctuationtable = (int *) Mem_Alloc(256 * sizeof(int), TAG_IDLIB_LEXER);
    137 		}
    138 		if ( idLexer::nextpunctuation && idLexer::nextpunctuation != default_nextpunctuation ) {
    139 			Mem_Free( idLexer::nextpunctuation );
    140 		}
    141 		for (i = 0; punctuations[i].p; i++) {
    142 		}
    143 		idLexer::nextpunctuation = (int *) Mem_Alloc(i * sizeof(int), TAG_IDLIB_LEXER);
    144 	}
    145 	memset(idLexer::punctuationtable, 0xFF, 256 * sizeof(int));
    146 	memset(idLexer::nextpunctuation, 0xFF, i * sizeof(int));
    147 	//add the punctuations in the list to the punctuation table
    148 	for (i = 0; punctuations[i].p; i++) {
    149 		newp = &punctuations[i];
    150 		lastp = -1;
    151 		//sort the punctuations in this table entry on length (longer punctuations first)
    152 		for (n = idLexer::punctuationtable[(unsigned int) newp->p[0]]; n >= 0; n = idLexer::nextpunctuation[n] ) {
    153 			p = &punctuations[n];
    154 			if (strlen(p->p) < strlen(newp->p)) {
    155 				idLexer::nextpunctuation[i] = n;
    156 				if (lastp >= 0) {
    157 					idLexer::nextpunctuation[lastp] = i;
    158 				}
    159 				else {
    160 					idLexer::punctuationtable[(unsigned int) newp->p[0]] = i;
    161 				}
    162 				break;
    163 			}
    164 			lastp = n;
    165 		}
    166 		if (n < 0) {
    167 			idLexer::nextpunctuation[i] = -1;
    168 			if (lastp >= 0) {
    169 				idLexer::nextpunctuation[lastp] = i;
    170 			}
    171 			else {
    172 				idLexer::punctuationtable[(unsigned int) newp->p[0]] = i;
    173 			}
    174 		}
    175 	}
    176 }
    177 
    178 /*
    179 ================
    180 idLexer::GetPunctuationFromId
    181 ================
    182 */
    183 const char *idLexer::GetPunctuationFromId( int id ) {
    184 	int i;
    185 
    186 	for (i = 0; idLexer::punctuations[i].p; i++) {
    187 		if ( idLexer::punctuations[i].n == id ) {
    188 			return idLexer::punctuations[i].p;
    189 		}
    190 	}
    191 	return "unkown punctuation";
    192 }
    193 
    194 /*
    195 ================
    196 idLexer::GetPunctuationId
    197 ================
    198 */
    199 int idLexer::GetPunctuationId( const char *p ) {
    200 	int i;
    201 
    202 	for (i = 0; idLexer::punctuations[i].p; i++) {
    203 		if ( !strcmp(idLexer::punctuations[i].p, p) ) {
    204 			return idLexer::punctuations[i].n;
    205 		}
    206 	}
    207 	return 0;
    208 }
    209 
    210 /*
    211 ================
    212 idLexer::Error
    213 ================
    214 */
    215 void idLexer::Error( const char *str, ... ) {
    216 	char text[MAX_STRING_CHARS];
    217 	va_list ap;
    218 
    219 	hadError = true;
    220 
    221 	if ( idLexer::flags & LEXFL_NOERRORS ) {
    222 		return;
    223 	}
    224 
    225 	va_start(ap, str);
    226 	vsprintf(text, str, ap);
    227 	va_end(ap);
    228 
    229 	if ( idLexer::flags & LEXFL_NOFATALERRORS ) {
    230 		idLib::common->Warning( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
    231 	} else {
    232 		idLib::common->Error( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
    233 	}
    234 }
    235 
    236 /*
    237 ================
    238 idLexer::Warning
    239 ================
    240 */
    241 void idLexer::Warning( const char *str, ... ) {
    242 	char text[MAX_STRING_CHARS];
    243 	va_list ap;
    244 
    245 	if ( idLexer::flags & LEXFL_NOWARNINGS ) {
    246 		return;
    247 	}
    248 
    249 	va_start( ap, str );
    250 	vsprintf( text, str, ap );
    251 	va_end( ap );
    252 	idLib::common->Warning( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
    253 }
    254 
    255 /*
    256 ================
    257 idLexer::SetPunctuations
    258 ================
    259 */
    260 void idLexer::SetPunctuations( const punctuation_t *p ) {
    261 #ifdef PUNCTABLE
    262 	if (p) {
    263 		idLexer::CreatePunctuationTable( p );
    264 	}
    265 	else {
    266 		idLexer::CreatePunctuationTable( default_punctuations );
    267 	}
    268 #endif //PUNCTABLE
    269 	if (p) {
    270 		idLexer::punctuations = p;
    271 	}
    272 	else {
    273 		idLexer::punctuations = default_punctuations;
    274 	}
    275 }
    276 
    277 /*
    278 ================
    279 idLexer::ReadWhiteSpace
    280 
    281 Reads spaces, tabs, C-like comments etc.
    282 When a newline character is found the scripts line counter is increased.
    283 ================
    284 */
    285 int idLexer::ReadWhiteSpace() {
    286 	while(1) {
    287 		// skip white space
    288 		while(*idLexer::script_p <= ' ') {
    289 			if (!*idLexer::script_p) {
    290 				return 0;
    291 			}
    292 			if (*idLexer::script_p == '\n') {
    293 				idLexer::line++;
    294 			}
    295 			idLexer::script_p++;
    296 		}
    297 		// skip comments
    298 		if (*idLexer::script_p == '/') {
    299 			// comments //
    300 			if (*(idLexer::script_p+1) == '/') {
    301 				idLexer::script_p++;
    302 				do {
    303 					idLexer::script_p++;
    304 					if ( !*idLexer::script_p ) {
    305 						return 0;
    306 					}
    307 				}
    308 				while( *idLexer::script_p != '\n' );
    309 				idLexer::line++;
    310 				idLexer::script_p++;
    311 				if ( !*idLexer::script_p ) {
    312 					return 0;
    313 				}
    314 				continue;
    315 			}
    316 			// comments /* */
    317 			else if (*(idLexer::script_p+1) == '*') {
    318 				idLexer::script_p++;
    319 				while( 1 ) {
    320 					idLexer::script_p++;
    321 					if ( !*idLexer::script_p ) {
    322 						return 0;
    323 					}
    324 					if ( *idLexer::script_p == '\n' ) {
    325 						idLexer::line++;
    326 					}
    327 					else if ( *idLexer::script_p == '/' ) {
    328 						if ( *(idLexer::script_p-1) == '*' ) {
    329 							break;
    330 						}
    331 						if ( *(idLexer::script_p+1) == '*' ) {
    332 							idLexer::Warning( "nested comment" );
    333 						}
    334 					}
    335 				}
    336 				idLexer::script_p++;
    337 				if ( !*idLexer::script_p ) {
    338 					return 0;
    339 				}
    340 				idLexer::script_p++;
    341 				if ( !*idLexer::script_p ) {
    342 					return 0;
    343 				}
    344 				continue;
    345 			}
    346 		}
    347 		break;
    348 	}
    349 	return 1;
    350 }
    351 
    352 /*
    353 ========================
    354 idLexer::SkipWhiteSpace
    355 
    356 Reads spaces, tabs, C-like comments etc. When a newline character is found, the scripts line 
    357 counter is increased. Returns false if there is no token left to be read.
    358 ========================
    359 */
    360 bool idLexer::SkipWhiteSpace( bool currentLine ) {
    361 	while( 1 ) {
    362 		assert( script_p <= end_p );
    363 		if ( script_p == end_p ) {
    364 			return false;
    365 		}
    366 		// skip white space
    367 		while( *script_p <= ' ' ) {
    368 			if ( script_p == end_p ) {
    369 				return false;
    370 			}
    371 			if ( !*script_p ) {
    372 				return false;
    373 			}
    374 			if ( *script_p == '\n' ) {
    375 				line++;
    376 				if ( currentLine ) {
    377 					script_p++;
    378 					return true;
    379 				}
    380 			}
    381 			script_p++;
    382 		}
    383 		// skip comments
    384 		if ( *script_p == '/' ) {
    385 			// comments //
    386 			if ( *(script_p+1) == '/' ) {
    387 				script_p++;
    388 				do {
    389 					script_p++;
    390 					if ( !*script_p ) {
    391 						return false;
    392 					}
    393 				}
    394 				while( *script_p != '\n' );
    395 				line++;
    396 				script_p++;
    397 				if ( currentLine ) {
    398 					return true;
    399 				}
    400 				if ( !*script_p ) {
    401 					return false;
    402 				}
    403 				continue;
    404 			}
    405 			// comments /* */
    406 			else if ( *(script_p+1) == '*' ) {
    407 				script_p++;
    408 				while( 1 ) {
    409 					script_p++;
    410 					if ( !*script_p ) {
    411 						return false;
    412 					}
    413 					if ( *script_p == '\n' ) {
    414 						line++;
    415 					}
    416 					else if ( *script_p == '/' ) {
    417 						if ( *(script_p-1) == '*' ) {
    418 							break;
    419 						}
    420 						if ( *(script_p+1) == '*' ) {
    421 							Warning( "nested comment" );
    422 						}
    423 					}
    424 				}
    425 				script_p++;
    426 				if ( !*script_p ) {
    427 					return false;
    428 				}
    429 				continue;
    430 			}
    431 		}
    432 		break;
    433 	}
    434 	return true;
    435 }
    436 
    437 /*
    438 ================
    439 idLexer::ReadEscapeCharacter
    440 ================
    441 */
    442 int idLexer::ReadEscapeCharacter( char *ch ) {
    443 	int c, val, i;
    444 
    445 	// step over the leading '\\'
    446 	idLexer::script_p++;
    447 	// determine the escape character
    448 	switch(*idLexer::script_p) {
    449 		case '\\': c = '\\'; break;
    450 		case 'n': c = '\n'; break;
    451 		case 'r': c = '\r'; break;
    452 		case 't': c = '\t'; break;
    453 		case 'v': c = '\v'; break;
    454 		case 'b': c = '\b'; break;
    455 		case 'f': c = '\f'; break;
    456 		case 'a': c = '\a'; break;
    457 		case '\'': c = '\''; break;
    458 		case '\"': c = '\"'; break;
    459 		case '\?': c = '\?'; break;
    460 		case 'x':
    461 		{
    462 			idLexer::script_p++;
    463 			for (i = 0, val = 0; ; i++, idLexer::script_p++) {
    464 				c = *idLexer::script_p;
    465 				if (c >= '0' && c <= '9')
    466 					c = c - '0';
    467 				else if (c >= 'A' && c <= 'Z')
    468 					c = c - 'A' + 10;
    469 				else if (c >= 'a' && c <= 'z')
    470 					c = c - 'a' + 10;
    471 				else
    472 					break;
    473 				val = (val << 4) + c;
    474 			}
    475 			idLexer::script_p--;
    476 			if (val > 0xFF) {
    477 				idLexer::Warning( "too large value in escape character" );
    478 				val = 0xFF;
    479 			}
    480 			c = val;
    481 			break;
    482 		}
    483 		default: //NOTE: decimal ASCII code, NOT octal
    484 		{
    485 			if (*idLexer::script_p < '0' || *idLexer::script_p > '9') {
    486 				idLexer::Error("unknown escape char");
    487 			}
    488 			for (i = 0, val = 0; ; i++, idLexer::script_p++) {
    489 				c = *idLexer::script_p;
    490 				if (c >= '0' && c <= '9')
    491 					c = c - '0';
    492 				else
    493 					break;
    494 				val = val * 10 + c;
    495 			}
    496 			idLexer::script_p--;
    497 			if (val > 0xFF) {
    498 				idLexer::Warning( "too large value in escape character" );
    499 				val = 0xFF;
    500 			}
    501 			c = val;
    502 			break;
    503 		}
    504 	}
    505 	// step over the escape character or the last digit of the number
    506 	idLexer::script_p++;
    507 	// store the escape character
    508 	*ch = c;
    509 	// succesfully read escape character
    510 	return 1;
    511 }
    512 
    513 /*
    514 ================
    515 idLexer::ReadString
    516 
    517 Escape characters are interpretted.
    518 Reads two strings with only a white space between them as one string.
    519 ================
    520 */
    521 int idLexer::ReadString( idToken *token, int quote ) {
    522 	int tmpline;
    523 	const char *tmpscript_p;
    524 	char ch;
    525 
    526 	if ( quote == '\"' ) {
    527 		token->type = TT_STRING;
    528 	} else {
    529 		token->type = TT_LITERAL;
    530 	}
    531 
    532 	// leading quote
    533 	idLexer::script_p++;
    534 
    535 	while(1) {
    536 		// if there is an escape character and escape characters are allowed
    537 		if (*idLexer::script_p == '\\' && !(idLexer::flags & LEXFL_NOSTRINGESCAPECHARS)) {
    538 			if ( !idLexer::ReadEscapeCharacter( &ch ) ) {
    539 				return 0;
    540 			}
    541 			token->AppendDirty( ch );
    542 		}
    543 		// if a trailing quote
    544 		else if (*idLexer::script_p == quote) {
    545 			// step over the quote
    546 			idLexer::script_p++;
    547 			// if consecutive strings should not be concatenated
    548 			if ( (idLexer::flags & LEXFL_NOSTRINGCONCAT) &&
    549 					(!(idLexer::flags & LEXFL_ALLOWBACKSLASHSTRINGCONCAT) || (quote != '\"')) ) {
    550 				break;
    551 			}
    552 
    553 			tmpscript_p = idLexer::script_p;
    554 			tmpline = idLexer::line;
    555 			// read white space between possible two consecutive strings
    556 			if ( !idLexer::ReadWhiteSpace() ) {
    557 				idLexer::script_p = tmpscript_p;
    558 				idLexer::line = tmpline;
    559 				break;
    560 			}
    561 
    562 			if ( idLexer::flags & LEXFL_NOSTRINGCONCAT ) {
    563 				if ( *idLexer::script_p != '\\' ) {
    564 					idLexer::script_p = tmpscript_p;
    565 					idLexer::line = tmpline;
    566 					break;
    567 				}
    568 				// step over the '\\'
    569 				idLexer::script_p++;
    570 				if ( !idLexer::ReadWhiteSpace() || ( *idLexer::script_p != quote ) ) {
    571 					idLexer::Error( "expecting string after '\' terminated line" );
    572 					return 0;
    573 				}
    574 			}
    575 
    576 			// if there's no leading qoute
    577 			if ( *idLexer::script_p != quote ) {
    578 				idLexer::script_p = tmpscript_p;
    579 				idLexer::line = tmpline;
    580 				break;
    581 			}
    582 			// step over the new leading quote
    583 			idLexer::script_p++;
    584 		}
    585 		else {
    586 			if (*idLexer::script_p == '\0') {
    587 				idLexer::Error( "missing trailing quote" );
    588 				return 0;
    589 			}
    590 			if (*idLexer::script_p == '\n') {
    591 				idLexer::Error( "newline inside string" );
    592 				return 0;
    593 			}
    594 			token->AppendDirty( *idLexer::script_p++ );
    595 		}
    596 	}
    597 	token->data[token->len] = '\0';
    598 
    599 	if ( token->type == TT_LITERAL ) {
    600 		if ( !(idLexer::flags & LEXFL_ALLOWMULTICHARLITERALS) ) {
    601 			if ( token->Length() != 1 ) {
    602 				idLexer::Warning( "literal is not one character long" );
    603 			}
    604 		}
    605 		token->subtype = (*token)[0];
    606 	}
    607 	else {
    608 		// the sub type is the length of the string
    609 		token->subtype = token->Length();
    610 	}
    611 	return 1;
    612 }
    613 
    614 /*
    615 ================
    616 idLexer::ReadName
    617 ================
    618 */
    619 int idLexer::ReadName( idToken *token ) {
    620 	char c;
    621 
    622 	token->type = TT_NAME;
    623 	do {
    624 		token->AppendDirty( *idLexer::script_p++ );
    625 		c = *idLexer::script_p;
    626 	} while ((c >= 'a' && c <= 'z') ||
    627 				(c >= 'A' && c <= 'Z') ||
    628 				(c >= '0' && c <= '9') ||
    629 				c == '_' ||
    630 				// if treating all tokens as strings, don't parse '-' as a seperate token
    631 				((idLexer::flags & LEXFL_ONLYSTRINGS) && (c == '-')) ||
    632 				// if special path name characters are allowed
    633 				((idLexer::flags & LEXFL_ALLOWPATHNAMES) && (c == '/' || c == '\\' || c == ':' || c == '.')) );
    634 	token->data[token->len] = '\0';
    635 	//the sub type is the length of the name
    636 	token->subtype = token->Length();
    637 	return 1;
    638 }
    639 
    640 /*
    641 ================
    642 idLexer::CheckString
    643 ================
    644 */
    645 ID_INLINE int idLexer::CheckString( const char *str ) const {
    646 	int i;
    647 
    648 	for ( i = 0; str[i]; i++ ) {
    649 		if ( idLexer::script_p[i] != str[i] ) {
    650 			return false;
    651 		}
    652 	}
    653 	return true;
    654 }
    655 
    656 /*
    657 ================
    658 idLexer::ReadNumber
    659 ================
    660 */
    661 int idLexer::ReadNumber( idToken *token ) {
    662 	int i;
    663 	int dot;
    664 	char c, c2;
    665 
    666 	token->type = TT_NUMBER;
    667 	token->subtype = 0;
    668 	token->intvalue = 0;
    669 	token->floatvalue = 0;
    670 
    671 	c = *idLexer::script_p;
    672 	c2 = *(idLexer::script_p + 1);
    673 
    674 	if ( c == '0' && c2 != '.' ) {
    675 		// check for a hexadecimal number
    676 		if ( c2 == 'x' || c2 == 'X' ) {
    677 			token->AppendDirty( *idLexer::script_p++ );
    678 			token->AppendDirty( *idLexer::script_p++ );
    679 			c = *idLexer::script_p;
    680 			while((c >= '0' && c <= '9') ||
    681 						(c >= 'a' && c <= 'f') ||
    682 						(c >= 'A' && c <= 'F')) {
    683 				token->AppendDirty( c );
    684 				c = *(++idLexer::script_p);
    685 			}
    686 			token->subtype = TT_HEX | TT_INTEGER;
    687 		}
    688 		// check for a binary number
    689 		else if ( c2 == 'b' || c2 == 'B' ) {
    690 			token->AppendDirty( *idLexer::script_p++ );
    691 			token->AppendDirty( *idLexer::script_p++ );
    692 			c = *idLexer::script_p;
    693 			while( c == '0' || c == '1' ) {
    694 				token->AppendDirty( c );
    695 				c = *(++idLexer::script_p);
    696 			}
    697 			token->subtype = TT_BINARY | TT_INTEGER;
    698 		}
    699 		// its an octal number
    700 		else {
    701 			token->AppendDirty( *idLexer::script_p++ );
    702 			c = *idLexer::script_p;
    703 			while( c >= '0' && c <= '7' ) {
    704 				token->AppendDirty( c );
    705 				c = *(++idLexer::script_p);
    706 			}
    707 			token->subtype = TT_OCTAL | TT_INTEGER;
    708 		}
    709 	}
    710 	else {
    711 		// decimal integer or floating point number or ip address
    712 		dot = 0;
    713 		while( 1 ) {
    714 			if ( c >= '0' && c <= '9' ) {
    715 			}
    716 			else if ( c == '.' ) {
    717 				dot++;
    718 			}
    719 			else {
    720 				break;
    721 			}
    722 			token->AppendDirty( c );
    723 			c = *(++idLexer::script_p);
    724 		}
    725 		if( c == 'e' && dot == 0) {
    726 			//We have scientific notation without a decimal point
    727 			dot++;
    728 		}
    729 		// if a floating point number
    730 		if ( dot == 1 ) {
    731 			token->subtype = TT_DECIMAL | TT_FLOAT;
    732 			// check for floating point exponent
    733 			if ( c == 'e' ) {
    734 				//Append the e so that GetFloatValue code works
    735 				token->AppendDirty( c );
    736 				c = *(++idLexer::script_p);
    737 				if ( c == '-' ) {
    738 					token->AppendDirty( c );
    739 					c = *(++idLexer::script_p);
    740 				}
    741 				else if ( c == '+' ) {
    742 					token->AppendDirty( c );
    743 					c = *(++idLexer::script_p);
    744 				}
    745 				while( c >= '0' && c <= '9' ) {
    746 					token->AppendDirty( c );
    747 					c = *(++idLexer::script_p);
    748 				}
    749 			}
    750 			// check for floating point exception infinite 1.#INF or indefinite 1.#IND or NaN
    751 			else if ( c == '#' ) {
    752 				c2 = 4;
    753 				if ( CheckString( "INF" ) ) {
    754 					token->subtype |= TT_INFINITE;
    755 				}
    756 				else if ( CheckString( "IND" ) ) {
    757 					token->subtype |= TT_INDEFINITE;
    758 				}
    759 				else if ( CheckString( "NAN" ) ) {
    760 					token->subtype |= TT_NAN;
    761 				}
    762 				else if ( CheckString( "QNAN" ) ) {
    763 					token->subtype |= TT_NAN;
    764 					c2++;
    765 				}
    766 				else if ( CheckString( "SNAN" ) ) {
    767 					token->subtype |= TT_NAN;
    768 					c2++;
    769 				}
    770 				for ( i = 0; i < c2; i++ ) {
    771 					token->AppendDirty( c );
    772 					c = *(++idLexer::script_p);
    773 				}
    774 				while( c >= '0' && c <= '9' ) {
    775 					token->AppendDirty( c );
    776 					c = *(++idLexer::script_p);
    777 				}
    778 				if ( !(idLexer::flags & LEXFL_ALLOWFLOATEXCEPTIONS) ) {
    779 					token->AppendDirty( 0 );	// zero terminate for c_str
    780 					idLexer::Error( "parsed %s", token->c_str() );
    781 				}
    782 			}
    783 		}
    784 		else if ( dot > 1 ) {
    785 			if ( !( idLexer::flags & LEXFL_ALLOWIPADDRESSES ) ) {
    786 				idLexer::Error( "more than one dot in number" );
    787 				return 0;
    788 			}
    789 			if ( dot != 3 ) {
    790 				idLexer::Error( "ip address should have three dots" );
    791 				return 0;
    792 			}
    793 			token->subtype = TT_IPADDRESS;
    794 		}
    795 		else {
    796 			token->subtype = TT_DECIMAL | TT_INTEGER;
    797 		}
    798 	}
    799 
    800 	if ( token->subtype & TT_FLOAT ) {
    801 		if ( c > ' ' ) {
    802 			// single-precision: float
    803 			if ( c == 'f' || c == 'F' ) {
    804 				token->subtype |= TT_SINGLE_PRECISION;
    805 				idLexer::script_p++;
    806 			}
    807 			// extended-precision: long double
    808 			else if ( c == 'l' || c == 'L' ) {
    809 				token->subtype |= TT_EXTENDED_PRECISION;
    810 				idLexer::script_p++;
    811 			}
    812 			// default is double-precision: double
    813 			else {
    814 				token->subtype |= TT_DOUBLE_PRECISION;
    815 			}
    816 		}
    817 		else {
    818 			token->subtype |= TT_DOUBLE_PRECISION;
    819 		}
    820 	}
    821 	else if ( token->subtype & TT_INTEGER ) {
    822 		if ( c > ' ' ) {
    823 			// default: signed long
    824 			for ( i = 0; i < 2; i++ ) {
    825 				// long integer
    826 				if ( c == 'l' || c == 'L' ) {
    827 					token->subtype |= TT_LONG;
    828 				}
    829 				// unsigned integer
    830 				else if ( c == 'u' || c == 'U' ) {
    831 					token->subtype |= TT_UNSIGNED;
    832 				}
    833 				else {
    834 					break;
    835 				}
    836 				c = *(++idLexer::script_p);
    837 			}
    838 		}
    839 	}
    840 	else if ( token->subtype & TT_IPADDRESS ) {
    841 		if ( c == ':' ) {
    842 			token->AppendDirty( c );
    843 			c = *(++idLexer::script_p);
    844 			while( c >= '0' && c <= '9' ) {
    845 				token->AppendDirty( c );
    846 				c = *(++idLexer::script_p);
    847 			}
    848 			token->subtype |= TT_IPPORT;
    849 		}
    850 	}
    851 	token->data[token->len] = '\0';
    852 	return 1;
    853 }
    854 
    855 /*
    856 ================
    857 idLexer::ReadPunctuation
    858 ================
    859 */
    860 int idLexer::ReadPunctuation( idToken *token ) {
    861 	int l, n, i;
    862 	char *p;
    863 	const punctuation_t *punc;
    864 
    865 #ifdef PUNCTABLE
    866 	for (n = idLexer::punctuationtable[(unsigned int)*(idLexer::script_p)]; n >= 0; n = idLexer::nextpunctuation[n])
    867 	{
    868 		punc = &(idLexer::punctuations[n]);
    869 #else
    870 	int i;
    871 
    872 	for (i = 0; idLexer::punctuations[i].p; i++) {
    873 		punc = &idLexer::punctuations[i];
    874 #endif
    875 		p = punc->p;
    876 		// check for this punctuation in the script
    877 		for ( l = 0; p[l] && idLexer::script_p[l]; l++ ) {
    878 			if ( idLexer::script_p[l] != p[l] ) {
    879 				break;
    880 			}
    881 		}
    882 		if ( !p[l] ) {
    883 			//
    884 			token->EnsureAlloced( l+1, false );
    885 			for ( i = 0; i <= l; i++ ) {
    886 				token->data[i] = p[i];
    887 			}
    888 			token->len = l;
    889 			//
    890 			idLexer::script_p += l;
    891 			token->type = TT_PUNCTUATION;
    892 			// sub type is the punctuation id
    893 			token->subtype = punc->n;
    894 			return 1;
    895 		}
    896 	}
    897 	return 0;
    898 }
    899 
    900 /*
    901 ================
    902 idLexer::ReadToken
    903 ================
    904 */
    905 int idLexer::ReadToken( idToken *token ) {
    906 	int c;
    907 
    908 	if ( !loaded ) {
    909 		idLib::common->Error( "idLexer::ReadToken: no file loaded" );
    910 		return 0;
    911 	}
    912 
    913 	if ( script_p == NULL ) {
    914 		return 0;
    915 	}
    916 
    917 	// if there is a token available (from unreadToken)
    918 	if ( tokenavailable ) {
    919 		tokenavailable = 0;
    920 		*token = idLexer::token;
    921 		return 1;
    922 	}
    923 	// save script pointer
    924 	lastScript_p = script_p;
    925 	// save line counter
    926 	lastline = line;
    927 	// clear the token stuff
    928 	token->data[0] = '\0';
    929 	token->len = 0;
    930 	// start of the white space
    931 	whiteSpaceStart_p = script_p;
    932 	token->whiteSpaceStart_p = script_p;
    933 	// read white space before token
    934 	if ( !ReadWhiteSpace() ) {
    935 		return 0;
    936 	}
    937 	// end of the white space
    938 	idLexer::whiteSpaceEnd_p = script_p;
    939 	token->whiteSpaceEnd_p = script_p;
    940 	// line the token is on
    941 	token->line = line;
    942 	// number of lines crossed before token
    943 	token->linesCrossed = line - lastline;
    944 	// clear token flags
    945 	token->flags = 0;
    946 
    947 	c = *idLexer::script_p;
    948 
    949 	// if we're keeping everything as whitespace deliminated strings
    950 	if ( idLexer::flags & LEXFL_ONLYSTRINGS ) {
    951 		// if there is a leading quote
    952 		if ( c == '\"' || c == '\'' ) {
    953 			if (!idLexer::ReadString( token, c )) {
    954 				return 0;
    955 			}
    956 		} else if ( !idLexer::ReadName( token ) ) {
    957 			return 0;
    958 		}
    959 	}
    960 	// if there is a number
    961 	else if ( (c >= '0' && c <= '9') ||
    962 			(c == '.' && (*(idLexer::script_p + 1) >= '0' && *(idLexer::script_p + 1) <= '9')) ) {
    963 		if ( !idLexer::ReadNumber( token ) ) {
    964 			return 0;
    965 		}
    966 		// if names are allowed to start with a number
    967 		if ( idLexer::flags & LEXFL_ALLOWNUMBERNAMES ) {
    968 			c = *idLexer::script_p;
    969 			if ( (c >= 'a' && c <= 'z') ||	(c >= 'A' && c <= 'Z') || c == '_' ) {
    970 				if ( !idLexer::ReadName( token ) ) {
    971 					return 0;
    972 				}
    973 			}
    974 		}
    975 	}
    976 	// if there is a leading quote
    977 	else if ( c == '\"' || c == '\'' ) {
    978 		if (!idLexer::ReadString( token, c )) {
    979 			return 0;
    980 		}
    981 	}
    982 	// if there is a name
    983 	else if ( (c >= 'a' && c <= 'z') ||	(c >= 'A' && c <= 'Z') || c == '_' ) {
    984 		if ( !idLexer::ReadName( token ) ) {
    985 			return 0;
    986 		}
    987 	}
    988 	// names may also start with a slash when pathnames are allowed
    989 	else if ( ( idLexer::flags & LEXFL_ALLOWPATHNAMES ) && ( (c == '/' || c == '\\') || c == '.' ) ) {
    990 		if ( !idLexer::ReadName( token ) ) {
    991 			return 0;
    992 		}
    993 	}
    994 	// check for punctuations
    995 	else if ( !idLexer::ReadPunctuation( token ) ) {
    996 		idLexer::Error( "unknown punctuation %c", c );
    997 		return 0;
    998 	}
    999 	// succesfully read a token
   1000 	return 1;
   1001 }
   1002 
   1003 /*
   1004 ================
   1005 idLexer::ExpectTokenString
   1006 ================
   1007 */
   1008 int idLexer::ExpectTokenString( const char *string ) {
   1009 	idToken token;
   1010 
   1011 	if (!idLexer::ReadToken( &token )) {
   1012 		idLexer::Error( "couldn't find expected '%s'", string );
   1013 		return 0;
   1014 	}
   1015 	if ( token != string ) {
   1016 		idLexer::Error( "expected '%s' but found '%s'", string, token.c_str() );
   1017 		return 0;
   1018 	}
   1019 	return 1;
   1020 }
   1021 
   1022 /*
   1023 ================
   1024 idLexer::ExpectTokenType
   1025 ================
   1026 */
   1027 int idLexer::ExpectTokenType( int type, int subtype, idToken *token ) {
   1028 	idStr str;
   1029 
   1030 	if ( !idLexer::ReadToken( token ) ) {
   1031 		idLexer::Error( "couldn't read expected token" );
   1032 		return 0;
   1033 	}
   1034 
   1035 	if ( token->type != type ) {
   1036 		switch( type ) {
   1037 			case TT_STRING: str = "string"; break;
   1038 			case TT_LITERAL: str = "literal"; break;
   1039 			case TT_NUMBER: str = "number"; break;
   1040 			case TT_NAME: str = "name"; break;
   1041 			case TT_PUNCTUATION: str = "punctuation"; break;
   1042 			default: str = "unknown type"; break;
   1043 		}
   1044 		idLexer::Error( "expected a %s but found '%s'", str.c_str(), token->c_str() );
   1045 		return 0;
   1046 	}
   1047 	if ( token->type == TT_NUMBER ) {
   1048 		if ( (token->subtype & subtype) != subtype ) {
   1049 			str.Clear();
   1050 			if ( subtype & TT_DECIMAL ) str = "decimal ";
   1051 			if ( subtype & TT_HEX ) str = "hex ";
   1052 			if ( subtype & TT_OCTAL ) str = "octal ";
   1053 			if ( subtype & TT_BINARY ) str = "binary ";
   1054 			if ( subtype & TT_UNSIGNED ) str += "unsigned ";
   1055 			if ( subtype & TT_LONG ) str += "long ";
   1056 			if ( subtype & TT_FLOAT ) str += "float ";
   1057 			if ( subtype & TT_INTEGER ) str += "integer ";
   1058 			str.StripTrailing( ' ' );
   1059 			idLexer::Error( "expected %s but found '%s'", str.c_str(), token->c_str() );
   1060 			return 0;
   1061 		}
   1062 	}
   1063 	else if ( token->type == TT_PUNCTUATION ) {
   1064 		if ( subtype < 0 ) {
   1065 			idLexer::Error( "BUG: wrong punctuation subtype" );
   1066 			return 0;
   1067 		}
   1068 		if ( token->subtype != subtype ) {
   1069 			idLexer::Error( "expected '%s' but found '%s'", GetPunctuationFromId( subtype ), token->c_str() );
   1070 			return 0;
   1071 		}
   1072 	}
   1073 	return 1;
   1074 }
   1075 
   1076 /*
   1077 ================
   1078 idLexer::ExpectAnyToken
   1079 ================
   1080 */
   1081 int idLexer::ExpectAnyToken( idToken *token ) {
   1082 	if (!idLexer::ReadToken( token )) {
   1083 		idLexer::Error( "couldn't read expected token" );
   1084 		return 0;
   1085 	}
   1086 	else {
   1087 		return 1;
   1088 	}
   1089 }
   1090 
   1091 /*
   1092 ================
   1093 idLexer::CheckTokenString
   1094 ================
   1095 */
   1096 int idLexer::CheckTokenString( const char *string ) {
   1097 	idToken tok;
   1098 
   1099 	if ( !ReadToken( &tok ) ) {
   1100 		return 0;
   1101 	}
   1102 	// if the given string is available
   1103 	if ( tok == string ) {
   1104 		return 1;
   1105 	}
   1106 	// unread token
   1107 	script_p = lastScript_p;
   1108 	line = lastline;
   1109 	return 0;
   1110 }
   1111 
   1112 /*
   1113 ================
   1114 idLexer::CheckTokenType
   1115 ================
   1116 */
   1117 int idLexer::CheckTokenType( int type, int subtype, idToken *token ) {
   1118 	idToken tok;
   1119 
   1120 	if ( !ReadToken( &tok ) ) {
   1121 		return 0;
   1122 	}
   1123 	// if the type matches
   1124 	if (tok.type == type && (tok.subtype & subtype) == subtype) {
   1125 		*token = tok;
   1126 		return 1;
   1127 	}
   1128 	// unread token
   1129 	script_p = lastScript_p;
   1130 	line = lastline;
   1131 	return 0;
   1132 }
   1133 
   1134 /*
   1135 ================
   1136 idLexer::PeekTokenString
   1137 ================
   1138 */
   1139 int idLexer::PeekTokenString( const char *string ) {
   1140 	idToken tok;
   1141 
   1142 	if ( !ReadToken( &tok ) ) {
   1143 		return 0;
   1144 	}
   1145 
   1146 	// unread token
   1147 	script_p = lastScript_p;
   1148 	line = lastline;
   1149 
   1150 	// if the given string is available
   1151 	if ( tok == string ) {
   1152 		return 1;
   1153 	}
   1154 	return 0;
   1155 }
   1156 
   1157 /*
   1158 ================
   1159 idLexer::PeekTokenType
   1160 ================
   1161 */
   1162 int idLexer::PeekTokenType( int type, int subtype, idToken *token ) {
   1163 	idToken tok;
   1164 
   1165 	if ( !ReadToken( &tok ) ) {
   1166 		return 0;
   1167 	}
   1168 
   1169 	// unread token
   1170 	script_p = lastScript_p;
   1171 	line = lastline;
   1172 
   1173 	// if the type matches
   1174 	if ( tok.type == type && ( tok.subtype & subtype ) == subtype ) {
   1175 		*token = tok;
   1176 		return 1;
   1177 	}
   1178 	return 0;
   1179 }
   1180 
   1181 /*
   1182 ================
   1183 idLexer::SkipUntilString
   1184 ================
   1185 */
   1186 int idLexer::SkipUntilString( const char *string ) {
   1187 	idToken token;
   1188 
   1189 	while(idLexer::ReadToken( &token )) {
   1190 		if ( token == string ) {
   1191 			return 1;
   1192 		}
   1193 	}
   1194 	return 0;
   1195 }
   1196 
   1197 /*
   1198 ================
   1199 idLexer::SkipRestOfLine
   1200 ================
   1201 */
   1202 int idLexer::SkipRestOfLine() {
   1203 	idToken token;
   1204 
   1205 	while(idLexer::ReadToken( &token )) {
   1206 		if ( token.linesCrossed ) {
   1207 			idLexer::script_p = lastScript_p;
   1208 			idLexer::line = lastline;
   1209 			return 1;
   1210 		}
   1211 	}
   1212 	return 0;
   1213 }
   1214 
   1215 /*
   1216 =================
   1217 idLexer::SkipBracedSection
   1218 
   1219 Skips until a matching close brace is found.
   1220 Internal brace depths are properly skipped.
   1221 =================
   1222 */
   1223 int idLexer::SkipBracedSection( bool parseFirstBrace ) {
   1224 	idToken token;
   1225 	int depth;
   1226 
   1227 	depth = parseFirstBrace ? 0 : 1;
   1228 	do {
   1229 		if ( !ReadToken( &token ) ) {
   1230 			return false;
   1231 		}
   1232 		if ( token.type == TT_PUNCTUATION ) {
   1233 			if ( token == "{" ) {
   1234 				depth++;
   1235 			} else if ( token == "}" ) {
   1236 				depth--;
   1237 			}
   1238 		}
   1239 	} while( depth );
   1240 	return true;
   1241 }
   1242 
   1243 /*
   1244 ================
   1245 idLexer::UnreadToken
   1246 ================
   1247 */
   1248 void idLexer::UnreadToken( const idToken *token ) {
   1249 	if ( idLexer::tokenavailable ) {
   1250 		idLib::common->FatalError( "idLexer::unreadToken, unread token twice\n" );
   1251 	}
   1252 	idLexer::token = *token;
   1253 	idLexer::tokenavailable = 1;
   1254 }
   1255 
   1256 /*
   1257 ================
   1258 idLexer::ReadTokenOnLine
   1259 ================
   1260 */
   1261 int idLexer::ReadTokenOnLine( idToken *token ) {
   1262 	idToken tok;
   1263 
   1264 	if (!idLexer::ReadToken( &tok )) {
   1265 		idLexer::script_p = lastScript_p;
   1266 		idLexer::line = lastline;
   1267 		return false;
   1268 	}
   1269 	// if no lines were crossed before this token
   1270 	if ( !tok.linesCrossed ) {
   1271 		*token = tok;
   1272 		return true;
   1273 	}
   1274 	// restore our position
   1275 	idLexer::script_p = lastScript_p;
   1276 	idLexer::line = lastline;
   1277 	token->Clear();
   1278 	return false;
   1279 }
   1280 
   1281 /*
   1282 ================
   1283 idLexer::ReadRestOfLine
   1284 ================
   1285 */
   1286 const char*	idLexer::ReadRestOfLine(idStr& out) {
   1287 	while(1) {
   1288 
   1289 		if(*idLexer::script_p == '\n') {
   1290 			idLexer::line++;
   1291 			break;
   1292 		}
   1293 
   1294 		if(!*idLexer::script_p) {
   1295 			break;
   1296 		}
   1297 
   1298 		if(*idLexer::script_p <= ' ') {
   1299 			out += " ";
   1300 		} else {
   1301 			out += *idLexer::script_p;
   1302 		}
   1303 		idLexer::script_p++;
   1304 
   1305 	}
   1306 
   1307 	out.Strip(' ');
   1308 	return out.c_str();
   1309 }
   1310 
   1311 /*
   1312 ================
   1313 idLexer::ParseInt
   1314 ================
   1315 */
   1316 int idLexer::ParseInt() {
   1317 	idToken token;
   1318 
   1319 	if ( !idLexer::ReadToken( &token ) ) {
   1320 		idLexer::Error( "couldn't read expected integer" );
   1321 		return 0;
   1322 	}
   1323 	if ( token.type == TT_PUNCTUATION && token == "-" ) {
   1324 		idLexer::ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
   1325 		return -((signed int) token.GetIntValue());
   1326 	}
   1327 	else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
   1328 		idLexer::Error( "expected integer value, found '%s'", token.c_str() );
   1329 	}
   1330 	return token.GetIntValue();
   1331 }
   1332 
   1333 /*
   1334 ================
   1335 idLexer::ParseBool
   1336 ================
   1337 */
   1338 bool idLexer::ParseBool() {
   1339 	idToken token;
   1340 
   1341 	if ( !idLexer::ExpectTokenType( TT_NUMBER, 0, &token ) ) {
   1342 		idLexer::Error( "couldn't read expected boolean" );
   1343 		return false;
   1344 	}
   1345 	return ( token.GetIntValue() != 0 );
   1346 }
   1347 
   1348 /*
   1349 ================
   1350 idLexer::ParseFloat
   1351 ================
   1352 */
   1353 float idLexer::ParseFloat( bool *errorFlag ) {
   1354 	idToken token;
   1355 
   1356 	if ( errorFlag ) {
   1357 		*errorFlag = false;
   1358 	}
   1359 
   1360 	if ( !idLexer::ReadToken( &token ) ) {
   1361 		if ( errorFlag ) {
   1362 			idLexer::Warning( "couldn't read expected floating point number" );
   1363 			*errorFlag = true;
   1364 		} else {
   1365 			idLexer::Error( "couldn't read expected floating point number" );
   1366 		}
   1367 		return 0;
   1368 	}
   1369 	if ( token.type == TT_PUNCTUATION && token == "-" ) {
   1370 		idLexer::ExpectTokenType( TT_NUMBER, 0, &token );
   1371 		return -token.GetFloatValue();
   1372 	}
   1373 	else if ( token.type != TT_NUMBER ) {
   1374 		if ( errorFlag ) {
   1375 			idLexer::Warning( "expected float value, found '%s'", token.c_str() );
   1376 			*errorFlag = true;
   1377 		} else {
   1378 			idLexer::Error( "expected float value, found '%s'", token.c_str() );
   1379 		}
   1380 	}
   1381 	return token.GetFloatValue();
   1382 }
   1383 
   1384 /*
   1385 ================
   1386 idLexer::Parse1DMatrix
   1387 ================
   1388 */
   1389 int idLexer::Parse1DMatrix( int x, float *m ) {
   1390 	int i;
   1391 
   1392 	if ( !idLexer::ExpectTokenString( "(" ) ) {
   1393 		return false;
   1394 	}
   1395 
   1396 	for ( i = 0; i < x; i++ ) {
   1397 		m[i] = idLexer::ParseFloat();
   1398 	}
   1399 
   1400 	if ( !idLexer::ExpectTokenString( ")" ) ) {
   1401 		return false;
   1402 	}
   1403 	return true;
   1404 }
   1405 
   1406 /*
   1407 ================
   1408 idLexer::Parse2DMatrix
   1409 ================
   1410 */
   1411 int idLexer::Parse2DMatrix( int y, int x, float *m ) {
   1412 	int i;
   1413 
   1414 	if ( !idLexer::ExpectTokenString( "(" ) ) {
   1415 		return false;
   1416 	}
   1417 
   1418 	for ( i = 0; i < y; i++ ) {
   1419 		if ( !idLexer::Parse1DMatrix( x, m + i * x ) ) {
   1420 			return false;
   1421 		}
   1422 	}
   1423 
   1424 	if ( !idLexer::ExpectTokenString( ")" ) ) {
   1425 		return false;
   1426 	}
   1427 	return true;
   1428 }
   1429 
   1430 /*
   1431 ================
   1432 idLexer::Parse3DMatrix
   1433 ================
   1434 */
   1435 int idLexer::Parse3DMatrix( int z, int y, int x, float *m ) {
   1436 	int i;
   1437 
   1438 	if ( !idLexer::ExpectTokenString( "(" ) ) {
   1439 		return false;
   1440 	}
   1441 
   1442 	for ( i = 0 ; i < z; i++ ) {
   1443 		if ( !idLexer::Parse2DMatrix( y, x, m + i * x*y ) ) {
   1444 			return false;
   1445 		}
   1446 	}
   1447 
   1448 	if ( !idLexer::ExpectTokenString( ")" ) ) {
   1449 		return false;
   1450 	}
   1451 	return true;
   1452 }
   1453 
   1454 /*
   1455 =================
   1456 idParser::ParseBracedSection
   1457 
   1458 The next token should be an open brace.
   1459 Parses until a matching close brace is found.
   1460 Maintains exact characters between braces.
   1461 
   1462   FIXME: this should use ReadToken and replace the token white space with correct indents and newlines
   1463 =================
   1464 */
   1465 const char *idLexer::ParseBracedSectionExact( idStr &out, int tabs ) {
   1466 	int		depth;
   1467 	bool	doTabs;
   1468 	bool	skipWhite;
   1469 
   1470 	out.Empty();
   1471 
   1472 	if ( !idLexer::ExpectTokenString( "{" ) ) {
   1473 		return out.c_str( );
   1474 	}
   1475 
   1476 	out = "{";
   1477 	depth = 1;	
   1478 	skipWhite = false;
   1479 	doTabs = tabs >= 0;
   1480 
   1481 	while( depth && *idLexer::script_p ) {
   1482 		char c = *(idLexer::script_p++);
   1483 
   1484 		switch ( c ) {
   1485 			case '\t':
   1486 			case ' ': {
   1487 				if ( skipWhite ) {
   1488 					continue;
   1489 				}
   1490 				break;
   1491 			}
   1492 			case '\n': {
   1493 				if ( doTabs ) {
   1494 					skipWhite = true;
   1495 					out += c;
   1496 					continue;
   1497 				}
   1498 				break;
   1499 			}
   1500 			case '{': {
   1501 				depth++;
   1502 				tabs++;
   1503 				break;
   1504 			}
   1505 			case '}': {
   1506 				depth--;
   1507 				tabs--;
   1508 				break;				
   1509 			}
   1510 		}
   1511 
   1512 		if ( skipWhite ) {
   1513 			int i = tabs;
   1514 			if ( c == '{' ) {
   1515 				i--;
   1516 			}
   1517 			skipWhite = false;
   1518 			for ( ; i > 0; i-- ) {
   1519 				out += '\t';
   1520 			}
   1521 		}
   1522 		out += c;
   1523 	}
   1524 	return out.c_str();
   1525 }
   1526 
   1527 /*
   1528 =================
   1529 idLexer::ParseBracedSection
   1530 
   1531 The next token should be an open brace.
   1532 Parses until a matching close brace is found.
   1533 Internal brace depths are properly skipped.
   1534 =================
   1535 */
   1536 const char *idLexer::ParseBracedSection( idStr &out ) {
   1537 	idToken token;
   1538 	int i, depth;
   1539 
   1540 	out.Empty();
   1541 	if ( !idLexer::ExpectTokenString( "{" ) ) {
   1542 		return out.c_str();
   1543 	}
   1544 	out = "{";
   1545 	depth = 1;
   1546 	do {
   1547 		if ( !idLexer::ReadToken( &token ) ) {
   1548 			Error( "missing closing brace" );
   1549 			return out.c_str();
   1550 		}
   1551 
   1552 		// if the token is on a new line
   1553 		for ( i = 0; i < token.linesCrossed; i++ ) {
   1554 			out += "\r\n";
   1555 		}
   1556 
   1557 		if ( token.type == TT_PUNCTUATION ) {
   1558 			if ( token[0] == '{' ) {
   1559 				depth++;
   1560 			}
   1561 			else if ( token[0] == '}' ) {
   1562 				depth--;
   1563 			}
   1564 		}
   1565 
   1566 		if ( token.type == TT_STRING ) {
   1567 			out += "\"" + token + "\"";
   1568 		}
   1569 		else {
   1570 			out += token;
   1571 		}
   1572 		out += " ";
   1573 	} while( depth );
   1574 
   1575 	return out.c_str();
   1576 }
   1577 
   1578 /*
   1579 =================
   1580 idLexer::ParseRestOfLine
   1581 
   1582   parse the rest of the line
   1583 =================
   1584 */
   1585 const char *idLexer::ParseRestOfLine( idStr &out ) {
   1586 	idToken token;
   1587 
   1588 	out.Empty();
   1589 	while(idLexer::ReadToken( &token )) {
   1590 		if ( token.linesCrossed ) {
   1591 			idLexer::script_p = lastScript_p;
   1592 			idLexer::line = lastline;
   1593 			break;
   1594 		}
   1595 		if ( out.Length() ) {
   1596 			out += " ";
   1597 		}
   1598 		out += token;
   1599 	}
   1600 	return out.c_str();
   1601 }
   1602 
   1603 /*
   1604 ========================
   1605 idLexer::ParseCompleteLine
   1606 
   1607 Returns a string up to the \n, but doesn't eat any whitespace at the beginning of the next line.
   1608 ========================
   1609 */
   1610 const char *idLexer::ParseCompleteLine( idStr &out ) {
   1611 	idToken token;
   1612 	const char	*start;
   1613 
   1614 	start = script_p;
   1615 
   1616 	while ( 1 ) {
   1617 		// end of buffer
   1618 		if ( *script_p == 0 ) {
   1619 			break;
   1620 		}
   1621 		if ( *script_p == '\n' ) {
   1622 			line++;
   1623 			script_p++;
   1624 			break;
   1625 		}
   1626 		script_p++;
   1627 	}
   1628 
   1629 	out.Empty();
   1630 	out.Append( start, script_p - start );
   1631 
   1632 	return out.c_str();
   1633 }
   1634 
   1635 /*
   1636 ================
   1637 idLexer::GetLastWhiteSpace
   1638 ================
   1639 */
   1640 int idLexer::GetLastWhiteSpace( idStr &whiteSpace ) const {
   1641 	whiteSpace.Clear();
   1642 	for ( const char *p = whiteSpaceStart_p; p < whiteSpaceEnd_p; p++ ) {
   1643 		whiteSpace.Append( *p );
   1644 	}
   1645 	return whiteSpace.Length();
   1646 }
   1647 
   1648 /*
   1649 ================
   1650 idLexer::GetLastWhiteSpaceStart
   1651 ================
   1652 */
   1653 int idLexer::GetLastWhiteSpaceStart() const {
   1654 	return whiteSpaceStart_p - buffer;
   1655 }
   1656 
   1657 /*
   1658 ================
   1659 idLexer::GetLastWhiteSpaceEnd
   1660 ================
   1661 */
   1662 int idLexer::GetLastWhiteSpaceEnd() const {
   1663 	return whiteSpaceEnd_p - buffer;
   1664 }
   1665 
   1666 /*
   1667 ================
   1668 idLexer::Reset
   1669 ================
   1670 */
   1671 void idLexer::Reset() {
   1672 	// pointer in script buffer
   1673 	idLexer::script_p = idLexer::buffer;
   1674 	// pointer in script buffer before reading token
   1675 	idLexer::lastScript_p = idLexer::buffer;
   1676 	// begin of white space
   1677 	idLexer::whiteSpaceStart_p = NULL;
   1678 	// end of white space
   1679 	idLexer::whiteSpaceEnd_p = NULL;
   1680 	// set if there's a token available in idLexer::token
   1681 	idLexer::tokenavailable = 0;
   1682 
   1683 	idLexer::line = 1;
   1684 	idLexer::lastline = 1;
   1685 	// clear the saved token
   1686 	idLexer::token = "";
   1687 }
   1688 
   1689 /*
   1690 ================
   1691 idLexer::EndOfFile
   1692 ================
   1693 */
   1694 bool idLexer::EndOfFile() {
   1695 	return idLexer::script_p >= idLexer::end_p;
   1696 }
   1697 
   1698 /*
   1699 ================
   1700 idLexer::NumLinesCrossed
   1701 ================
   1702 */
   1703 int idLexer::NumLinesCrossed() {
   1704 	return idLexer::line - idLexer::lastline;
   1705 }
   1706 
   1707 /*
   1708 ================
   1709 idLexer::LoadFile
   1710 ================
   1711 */
   1712 int idLexer::LoadFile( const char *filename, bool OSPath ) {
   1713 	idFile *fp;
   1714 	idStr pathname;
   1715 	int length;
   1716 	char *buf;
   1717 
   1718 	if ( idLexer::loaded ) {
   1719 		idLib::common->Error("idLexer::LoadFile: another script already loaded");
   1720 		return false;
   1721 	}
   1722 	
   1723 	if ( !OSPath && ( baseFolder[0] != '\0' ) ) {
   1724 		pathname = va( "%s/%s", baseFolder, filename );
   1725 	} else {
   1726 		pathname = filename;
   1727 	}
   1728 	if ( OSPath ) {
   1729 		fp = idLib::fileSystem->OpenExplicitFileRead( pathname );
   1730 	} else {
   1731 		fp = idLib::fileSystem->OpenFileRead( pathname );
   1732 	}
   1733 	if ( !fp ) {
   1734 		return false;
   1735 	}
   1736 	length = fp->Length();
   1737 	buf = (char *) Mem_Alloc( length + 1, TAG_IDLIB_LEXER );
   1738 	buf[length] = '\0';
   1739 	fp->Read( buf, length );
   1740 	idLexer::fileTime = fp->Timestamp();
   1741 	idLexer::filename = fp->GetFullPath();
   1742 	idLib::fileSystem->CloseFile( fp );
   1743 
   1744 	idLexer::buffer = buf;
   1745 	idLexer::length = length;
   1746 	// pointer in script buffer
   1747 	idLexer::script_p = idLexer::buffer;
   1748 	// pointer in script buffer before reading token
   1749 	idLexer::lastScript_p = idLexer::buffer;
   1750 	// pointer to end of script buffer
   1751 	idLexer::end_p = &(idLexer::buffer[length]);
   1752 
   1753 	idLexer::tokenavailable = 0;
   1754 	idLexer::line = 1;
   1755 	idLexer::lastline = 1;
   1756 	idLexer::allocated = true;
   1757 	idLexer::loaded = true;
   1758 
   1759 	return true;
   1760 }
   1761 
   1762 /*
   1763 ================
   1764 idLexer::LoadMemory
   1765 ================
   1766 */
   1767 int idLexer::LoadMemory( const char *ptr, int length, const char *name, int startLine ) {
   1768 	if ( idLexer::loaded ) {
   1769 		idLib::common->Error("idLexer::LoadMemory: another script already loaded");
   1770 		return false;
   1771 	}
   1772 	idLexer::filename = name;
   1773 	idLexer::buffer = ptr;
   1774 	idLexer::fileTime = 0;
   1775 	idLexer::length = length;
   1776 	// pointer in script buffer
   1777 	idLexer::script_p = idLexer::buffer;
   1778 	// pointer in script buffer before reading token
   1779 	idLexer::lastScript_p = idLexer::buffer;
   1780 	// pointer to end of script buffer
   1781 	idLexer::end_p = &(idLexer::buffer[length]);
   1782 
   1783 	idLexer::tokenavailable = 0;
   1784 	idLexer::line = startLine;
   1785 	idLexer::lastline = startLine;
   1786 	idLexer::allocated = false;
   1787 	idLexer::loaded = true;
   1788 
   1789 	return true;
   1790 }
   1791 
   1792 /*
   1793 ================
   1794 idLexer::FreeSource
   1795 ================
   1796 */
   1797 void idLexer::FreeSource() {
   1798 #ifdef PUNCTABLE
   1799 	if ( idLexer::punctuationtable && idLexer::punctuationtable != default_punctuationtable ) {
   1800 		Mem_Free( (void *) idLexer::punctuationtable );
   1801 		idLexer::punctuationtable = NULL;
   1802 	}
   1803 	if ( idLexer::nextpunctuation && idLexer::nextpunctuation != default_nextpunctuation ) {
   1804 		Mem_Free( (void *) idLexer::nextpunctuation );
   1805 		idLexer::nextpunctuation = NULL;
   1806 	}
   1807 #endif //PUNCTABLE
   1808 	if ( idLexer::allocated ) {
   1809 		Mem_Free( (void *) idLexer::buffer );
   1810 		idLexer::buffer = NULL;
   1811 		idLexer::allocated = false;
   1812 	}
   1813 	idLexer::tokenavailable = 0;
   1814 	idLexer::token = "";
   1815 	idLexer::loaded = false;
   1816 }
   1817 
   1818 /*
   1819 ================
   1820 idLexer::idLexer
   1821 ================
   1822 */
   1823 idLexer::idLexer() {
   1824 	idLexer::loaded = false;
   1825 	idLexer::filename = "";
   1826 	idLexer::flags = 0;
   1827 	idLexer::SetPunctuations( NULL );
   1828 	idLexer::allocated = false;
   1829 	idLexer::fileTime = 0;
   1830 	idLexer::length = 0;
   1831 	idLexer::line = 0;
   1832 	idLexer::lastline = 0;
   1833 	idLexer::tokenavailable = 0;
   1834 	idLexer::token = "";
   1835 	idLexer::next = NULL;
   1836 	idLexer::hadError = false;
   1837 }
   1838 
   1839 /*
   1840 ================
   1841 idLexer::idLexer
   1842 ================
   1843 */
   1844 idLexer::idLexer( int flags ) {
   1845 	idLexer::loaded = false;
   1846 	idLexer::filename = "";
   1847 	idLexer::flags = flags;
   1848 	idLexer::SetPunctuations( NULL );
   1849 	idLexer::allocated = false;
   1850 	idLexer::fileTime = 0;
   1851 	idLexer::length = 0;
   1852 	idLexer::line = 0;
   1853 	idLexer::lastline = 0;
   1854 	idLexer::tokenavailable = 0;
   1855 	idLexer::token = "";
   1856 	idLexer::next = NULL;
   1857 	idLexer::hadError = false;
   1858 }
   1859 
   1860 /*
   1861 ================
   1862 idLexer::idLexer
   1863 ================
   1864 */
   1865 idLexer::idLexer( const char *filename, int flags, bool OSPath ) {
   1866 	idLexer::loaded = false;
   1867 	idLexer::flags = flags;
   1868 	idLexer::SetPunctuations( NULL );
   1869 	idLexer::allocated = false;
   1870 	idLexer::token = "";
   1871 	idLexer::next = NULL;
   1872 	idLexer::hadError = false;
   1873 	idLexer::LoadFile( filename, OSPath );
   1874 }
   1875 
   1876 /*
   1877 ================
   1878 idLexer::idLexer
   1879 ================
   1880 */
   1881 idLexer::idLexer( const char *ptr, int length, const char *name, int flags ) {
   1882 	idLexer::loaded = false;
   1883 	idLexer::flags = flags;
   1884 	idLexer::SetPunctuations( NULL );
   1885 	idLexer::allocated = false;
   1886 	idLexer::token = "";
   1887 	idLexer::next = NULL;
   1888 	idLexer::hadError = false;
   1889 	idLexer::LoadMemory( ptr, length, name );
   1890 }
   1891 
   1892 /*
   1893 ================
   1894 idLexer::~idLexer
   1895 ================
   1896 */
   1897 idLexer::~idLexer() {
   1898 	idLexer::FreeSource();
   1899 }
   1900 
   1901 /*
   1902 ================
   1903 idLexer::SetBaseFolder
   1904 ================
   1905 */
   1906 void idLexer::SetBaseFolder( const char *path ) {
   1907 	idStr::Copynz( baseFolder, path, sizeof( baseFolder ) );
   1908 }
   1909 
   1910 /*
   1911 ================
   1912 idLexer::HadError
   1913 ================
   1914 */
   1915 bool idLexer::HadError() const {
   1916 	return hadError;
   1917 }
   1918