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