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