2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 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.
14 Doom 3 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.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
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.
26 ===========================================================================
29 #include "precompiled.h"
34 //longer punctuations first
35 punctuation_t default_punctuations[] = {
37 {">>=",P_RSHIFT_ASSIGN},
38 {"<<=",P_LSHIFT_ASSIGN},
41 //define merge operator
42 {"##",P_PRECOMPMERGE}, // pre-compiler
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
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
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
77 {"&",P_BIN_AND}, // pre-compiler
78 {"|",P_BIN_OR}, // pre-compiler
79 {"^",P_BIN_XOR}, // pre-compiler
80 {"~",P_BIN_NOT}, // pre-compiler
82 {"!",P_LOGIC_NOT}, // pre-compiler
83 {">",P_LOGIC_GREATER}, // pre-compiler
84 {"<",P_LOGIC_LESS}, // pre-compiler
88 {",",P_COMMA}, // pre-compiler
91 {":",P_COLON}, // pre-compiler
93 {"?",P_QUESTIONMARK}, // pre-compiler
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},
103 //precompiler operator
104 {"#",P_PRECOMP}, // pre-compiler
109 int default_punctuationtable[256];
110 int default_nextpunctuation[sizeof(default_punctuations) / sizeof(punctuation_t)];
113 char idLexer::baseFolder[ 256 ];
117 idLexer::CreatePunctuationTable
120 void idLexer::CreatePunctuationTable( const punctuation_t *punctuations ) {
122 const punctuation_t *p, *newp;
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 ) {
131 default_setup = true;
132 i = sizeof(default_punctuations) / sizeof(punctuation_t);
135 if ( !idLexer::punctuationtable || idLexer::punctuationtable == default_punctuationtable ) {
136 idLexer::punctuationtable = (int *) Mem_Alloc(256 * sizeof(int));
138 if ( idLexer::nextpunctuation && idLexer::nextpunctuation != default_nextpunctuation ) {
139 Mem_Free( idLexer::nextpunctuation );
141 for (i = 0; punctuations[i].p; i++) {
143 idLexer::nextpunctuation = (int *) Mem_Alloc(i * sizeof(int));
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];
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;
157 idLexer::nextpunctuation[lastp] = i;
160 idLexer::punctuationtable[(unsigned int) newp->p[0]] = i;
167 idLexer::nextpunctuation[i] = -1;
169 idLexer::nextpunctuation[lastp] = i;
172 idLexer::punctuationtable[(unsigned int) newp->p[0]] = i;
180 idLexer::GetPunctuationFromId
183 const char *idLexer::GetPunctuationFromId( int id ) {
186 for (i = 0; idLexer::punctuations[i].p; i++) {
187 if ( idLexer::punctuations[i].n == id ) {
188 return idLexer::punctuations[i].p;
191 return "unkown punctuation";
196 idLexer::GetPunctuationId
199 int idLexer::GetPunctuationId( const char *p ) {
202 for (i = 0; idLexer::punctuations[i].p; i++) {
203 if ( !strcmp(idLexer::punctuations[i].p, p) ) {
204 return idLexer::punctuations[i].n;
215 void idLexer::Error( const char *str, ... ) {
216 char text[MAX_STRING_CHARS];
221 if ( idLexer::flags & LEXFL_NOERRORS ) {
226 vsprintf(text, str, ap);
229 if ( idLexer::flags & LEXFL_NOFATALERRORS ) {
230 idLib::common->Warning( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
232 idLib::common->Error( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
241 void idLexer::Warning( const char *str, ... ) {
242 char text[MAX_STRING_CHARS];
245 if ( idLexer::flags & LEXFL_NOWARNINGS ) {
250 vsprintf( text, str, ap );
252 idLib::common->Warning( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
257 idLexer::SetPunctuations
260 void idLexer::SetPunctuations( const punctuation_t *p ) {
263 idLexer::CreatePunctuationTable( p );
266 idLexer::CreatePunctuationTable( default_punctuations );
270 idLexer::punctuations = p;
273 idLexer::punctuations = default_punctuations;
279 idLexer::ReadWhiteSpace
281 Reads spaces, tabs, C-like comments etc.
282 When a newline character is found the scripts line counter is increased.
285 int idLexer::ReadWhiteSpace( void ) {
288 while(*idLexer::script_p <= ' ') {
289 if (!*idLexer::script_p) {
292 if (*idLexer::script_p == '\n') {
298 if (*idLexer::script_p == '/') {
300 if (*(idLexer::script_p+1) == '/') {
304 if ( !*idLexer::script_p ) {
308 while( *idLexer::script_p != '\n' );
311 if ( !*idLexer::script_p ) {
317 else if (*(idLexer::script_p+1) == '*') {
321 if ( !*idLexer::script_p ) {
324 if ( *idLexer::script_p == '\n' ) {
327 else if ( *idLexer::script_p == '/' ) {
328 if ( *(idLexer::script_p-1) == '*' ) {
331 if ( *(idLexer::script_p+1) == '*' ) {
332 idLexer::Warning( "nested comment" );
337 if ( !*idLexer::script_p ) {
341 if ( !*idLexer::script_p ) {
354 idLexer::ReadEscapeCharacter
357 int idLexer::ReadEscapeCharacter( char *ch ) {
360 // step over the leading '\\'
362 // determine the escape character
363 switch(*idLexer::script_p) {
364 case '\\': c = '\\'; break;
365 case 'n': c = '\n'; break;
366 case 'r': c = '\r'; break;
367 case 't': c = '\t'; break;
368 case 'v': c = '\v'; break;
369 case 'b': c = '\b'; break;
370 case 'f': c = '\f'; break;
371 case 'a': c = '\a'; break;
372 case '\'': c = '\''; break;
373 case '\"': c = '\"'; break;
374 case '\?': c = '\?'; break;
378 for (i = 0, val = 0; ; i++, idLexer::script_p++) {
379 c = *idLexer::script_p;
380 if (c >= '0' && c <= '9')
382 else if (c >= 'A' && c <= 'Z')
384 else if (c >= 'a' && c <= 'z')
388 val = (val << 4) + c;
392 idLexer::Warning( "too large value in escape character" );
398 default: //NOTE: decimal ASCII code, NOT octal
400 if (*idLexer::script_p < '0' || *idLexer::script_p > '9') {
401 idLexer::Error("unknown escape char");
403 for (i = 0, val = 0; ; i++, idLexer::script_p++) {
404 c = *idLexer::script_p;
405 if (c >= '0' && c <= '9')
413 idLexer::Warning( "too large value in escape character" );
420 // step over the escape character or the last digit of the number
422 // store the escape character
424 // succesfully read escape character
432 Escape characters are interpretted.
433 Reads two strings with only a white space between them as one string.
436 int idLexer::ReadString( idToken *token, int quote ) {
438 const char *tmpscript_p;
441 if ( quote == '\"' ) {
442 token->type = TT_STRING;
444 token->type = TT_LITERAL;
451 // if there is an escape character and escape characters are allowed
452 if (*idLexer::script_p == '\\' && !(idLexer::flags & LEXFL_NOSTRINGESCAPECHARS)) {
453 if ( !idLexer::ReadEscapeCharacter( &ch ) ) {
456 token->AppendDirty( ch );
458 // if a trailing quote
459 else if (*idLexer::script_p == quote) {
460 // step over the quote
462 // if consecutive strings should not be concatenated
463 if ( (idLexer::flags & LEXFL_NOSTRINGCONCAT) &&
464 (!(idLexer::flags & LEXFL_ALLOWBACKSLASHSTRINGCONCAT) || (quote != '\"')) ) {
468 tmpscript_p = idLexer::script_p;
469 tmpline = idLexer::line;
470 // read white space between possible two consecutive strings
471 if ( !idLexer::ReadWhiteSpace() ) {
472 idLexer::script_p = tmpscript_p;
473 idLexer::line = tmpline;
477 if ( idLexer::flags & LEXFL_NOSTRINGCONCAT ) {
478 if ( *idLexer::script_p != '\\' ) {
479 idLexer::script_p = tmpscript_p;
480 idLexer::line = tmpline;
483 // step over the '\\'
485 if ( !idLexer::ReadWhiteSpace() || ( *idLexer::script_p != quote ) ) {
486 idLexer::Error( "expecting string after '\' terminated line" );
491 // if there's no leading qoute
492 if ( *idLexer::script_p != quote ) {
493 idLexer::script_p = tmpscript_p;
494 idLexer::line = tmpline;
497 // step over the new leading quote
501 if (*idLexer::script_p == '\0') {
502 idLexer::Error( "missing trailing quote" );
505 if (*idLexer::script_p == '\n') {
506 idLexer::Error( "newline inside string" );
509 token->AppendDirty( *idLexer::script_p++ );
512 token->data[token->len] = '\0';
514 if ( token->type == TT_LITERAL ) {
515 if ( !(idLexer::flags & LEXFL_ALLOWMULTICHARLITERALS) ) {
516 if ( token->Length() != 1 ) {
517 idLexer::Warning( "literal is not one character long" );
520 token->subtype = (*token)[0];
523 // the sub type is the length of the string
524 token->subtype = token->Length();
534 int idLexer::ReadName( idToken *token ) {
537 token->type = TT_NAME;
539 token->AppendDirty( *idLexer::script_p++ );
540 c = *idLexer::script_p;
541 } while ((c >= 'a' && c <= 'z') ||
542 (c >= 'A' && c <= 'Z') ||
543 (c >= '0' && c <= '9') ||
545 // if treating all tokens as strings, don't parse '-' as a seperate token
546 ((idLexer::flags & LEXFL_ONLYSTRINGS) && (c == '-')) ||
547 // if special path name characters are allowed
548 ((idLexer::flags & LEXFL_ALLOWPATHNAMES) && (c == '/' || c == '\\' || c == ':' || c == '.')) );
549 token->data[token->len] = '\0';
550 //the sub type is the length of the name
551 token->subtype = token->Length();
560 ID_INLINE int idLexer::CheckString( const char *str ) const {
563 for ( i = 0; str[i]; i++ ) {
564 if ( idLexer::script_p[i] != str[i] ) {
576 int idLexer::ReadNumber( idToken *token ) {
581 token->type = TT_NUMBER;
584 token->floatvalue = 0;
586 c = *idLexer::script_p;
587 c2 = *(idLexer::script_p + 1);
589 if ( c == '0' && c2 != '.' ) {
590 // check for a hexadecimal number
591 if ( c2 == 'x' || c2 == 'X' ) {
592 token->AppendDirty( *idLexer::script_p++ );
593 token->AppendDirty( *idLexer::script_p++ );
594 c = *idLexer::script_p;
595 while((c >= '0' && c <= '9') ||
596 (c >= 'a' && c <= 'f') ||
597 (c >= 'A' && c <= 'F')) {
598 token->AppendDirty( c );
599 c = *(++idLexer::script_p);
601 token->subtype = TT_HEX | TT_INTEGER;
603 // check for a binary number
604 else if ( c2 == 'b' || c2 == 'B' ) {
605 token->AppendDirty( *idLexer::script_p++ );
606 token->AppendDirty( *idLexer::script_p++ );
607 c = *idLexer::script_p;
608 while( c == '0' || c == '1' ) {
609 token->AppendDirty( c );
610 c = *(++idLexer::script_p);
612 token->subtype = TT_BINARY | TT_INTEGER;
614 // its an octal number
616 token->AppendDirty( *idLexer::script_p++ );
617 c = *idLexer::script_p;
618 while( c >= '0' && c <= '7' ) {
619 token->AppendDirty( c );
620 c = *(++idLexer::script_p);
622 token->subtype = TT_OCTAL | TT_INTEGER;
626 // decimal integer or floating point number or ip address
629 if ( c >= '0' && c <= '9' ) {
631 else if ( c == '.' ) {
637 token->AppendDirty( c );
638 c = *(++idLexer::script_p);
640 if( c == 'e' && dot == 0) {
641 //We have scientific notation without a decimal point
644 // if a floating point number
646 token->subtype = TT_DECIMAL | TT_FLOAT;
647 // check for floating point exponent
649 //Append the e so that GetFloatValue code works
650 token->AppendDirty( c );
651 c = *(++idLexer::script_p);
653 token->AppendDirty( c );
654 c = *(++idLexer::script_p);
656 else if ( c == '+' ) {
657 token->AppendDirty( c );
658 c = *(++idLexer::script_p);
660 while( c >= '0' && c <= '9' ) {
661 token->AppendDirty( c );
662 c = *(++idLexer::script_p);
665 // check for floating point exception infinite 1.#INF or indefinite 1.#IND or NaN
666 else if ( c == '#' ) {
668 if ( CheckString( "INF" ) ) {
669 token->subtype |= TT_INFINITE;
671 else if ( CheckString( "IND" ) ) {
672 token->subtype |= TT_INDEFINITE;
674 else if ( CheckString( "NAN" ) ) {
675 token->subtype |= TT_NAN;
677 else if ( CheckString( "QNAN" ) ) {
678 token->subtype |= TT_NAN;
681 else if ( CheckString( "SNAN" ) ) {
682 token->subtype |= TT_NAN;
685 for ( i = 0; i < c2; i++ ) {
686 token->AppendDirty( c );
687 c = *(++idLexer::script_p);
689 while( c >= '0' && c <= '9' ) {
690 token->AppendDirty( c );
691 c = *(++idLexer::script_p);
693 if ( !(idLexer::flags & LEXFL_ALLOWFLOATEXCEPTIONS) ) {
694 token->AppendDirty( 0 ); // zero terminate for c_str
695 idLexer::Error( "parsed %s", token->c_str() );
699 else if ( dot > 1 ) {
700 if ( !( idLexer::flags & LEXFL_ALLOWIPADDRESSES ) ) {
701 idLexer::Error( "more than one dot in number" );
705 idLexer::Error( "ip address should have three dots" );
708 token->subtype = TT_IPADDRESS;
711 token->subtype = TT_DECIMAL | TT_INTEGER;
715 if ( token->subtype & TT_FLOAT ) {
717 // single-precision: float
718 if ( c == 'f' || c == 'F' ) {
719 token->subtype |= TT_SINGLE_PRECISION;
722 // extended-precision: long double
723 else if ( c == 'l' || c == 'L' ) {
724 token->subtype |= TT_EXTENDED_PRECISION;
727 // default is double-precision: double
729 token->subtype |= TT_DOUBLE_PRECISION;
733 token->subtype |= TT_DOUBLE_PRECISION;
736 else if ( token->subtype & TT_INTEGER ) {
738 // default: signed long
739 for ( i = 0; i < 2; i++ ) {
741 if ( c == 'l' || c == 'L' ) {
742 token->subtype |= TT_LONG;
745 else if ( c == 'u' || c == 'U' ) {
746 token->subtype |= TT_UNSIGNED;
751 c = *(++idLexer::script_p);
755 else if ( token->subtype & TT_IPADDRESS ) {
757 token->AppendDirty( c );
758 c = *(++idLexer::script_p);
759 while( c >= '0' && c <= '9' ) {
760 token->AppendDirty( c );
761 c = *(++idLexer::script_p);
763 token->subtype |= TT_IPPORT;
766 token->data[token->len] = '\0';
772 idLexer::ReadPunctuation
775 int idLexer::ReadPunctuation( idToken *token ) {
778 const punctuation_t *punc;
781 for (n = idLexer::punctuationtable[(unsigned int)*(idLexer::script_p)]; n >= 0; n = idLexer::nextpunctuation[n])
783 punc = &(idLexer::punctuations[n]);
787 for (i = 0; idLexer::punctuations[i].p; i++) {
788 punc = &idLexer::punctuations[i];
791 // check for this punctuation in the script
792 for ( l = 0; p[l] && idLexer::script_p[l]; l++ ) {
793 if ( idLexer::script_p[l] != p[l] ) {
799 token->EnsureAlloced( l+1, false );
800 for ( i = 0; i <= l; i++ ) {
801 token->data[i] = p[i];
805 idLexer::script_p += l;
806 token->type = TT_PUNCTUATION;
807 // sub type is the punctuation id
808 token->subtype = punc->n;
820 int idLexer::ReadToken( idToken *token ) {
824 idLib::common->Error( "idLexer::ReadToken: no file loaded" );
828 // if there is a token available (from unreadToken)
829 if ( tokenavailable ) {
831 *token = idLexer::token;
834 // save script pointer
835 lastScript_p = script_p;
838 // clear the token stuff
839 token->data[0] = '\0';
841 // start of the white space
842 whiteSpaceStart_p = script_p;
843 token->whiteSpaceStart_p = script_p;
844 // read white space before token
845 if ( !ReadWhiteSpace() ) {
848 // end of the white space
849 idLexer::whiteSpaceEnd_p = script_p;
850 token->whiteSpaceEnd_p = script_p;
851 // line the token is on
853 // number of lines crossed before token
854 token->linesCrossed = line - lastline;
858 c = *idLexer::script_p;
860 // if we're keeping everything as whitespace deliminated strings
861 if ( idLexer::flags & LEXFL_ONLYSTRINGS ) {
862 // if there is a leading quote
863 if ( c == '\"' || c == '\'' ) {
864 if (!idLexer::ReadString( token, c )) {
867 } else if ( !idLexer::ReadName( token ) ) {
871 // if there is a number
872 else if ( (c >= '0' && c <= '9') ||
873 (c == '.' && (*(idLexer::script_p + 1) >= '0' && *(idLexer::script_p + 1) <= '9')) ) {
874 if ( !idLexer::ReadNumber( token ) ) {
877 // if names are allowed to start with a number
878 if ( idLexer::flags & LEXFL_ALLOWNUMBERNAMES ) {
879 c = *idLexer::script_p;
880 if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ) {
881 if ( !idLexer::ReadName( token ) ) {
887 // if there is a leading quote
888 else if ( c == '\"' || c == '\'' ) {
889 if (!idLexer::ReadString( token, c )) {
893 // if there is a name
894 else if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ) {
895 if ( !idLexer::ReadName( token ) ) {
899 // names may also start with a slash when pathnames are allowed
900 else if ( ( idLexer::flags & LEXFL_ALLOWPATHNAMES ) && ( (c == '/' || c == '\\') || c == '.' ) ) {
901 if ( !idLexer::ReadName( token ) ) {
905 // check for punctuations
906 else if ( !idLexer::ReadPunctuation( token ) ) {
907 idLexer::Error( "unknown punctuation %c", c );
910 // succesfully read a token
916 idLexer::ExpectTokenString
919 int idLexer::ExpectTokenString( const char *string ) {
922 if (!idLexer::ReadToken( &token )) {
923 idLexer::Error( "couldn't find expected '%s'", string );
926 if ( token != string ) {
927 idLexer::Error( "expected '%s' but found '%s'", string, token.c_str() );
935 idLexer::ExpectTokenType
938 int idLexer::ExpectTokenType( int type, int subtype, idToken *token ) {
941 if ( !idLexer::ReadToken( token ) ) {
942 idLexer::Error( "couldn't read expected token" );
946 if ( token->type != type ) {
948 case TT_STRING: str = "string"; break;
949 case TT_LITERAL: str = "literal"; break;
950 case TT_NUMBER: str = "number"; break;
951 case TT_NAME: str = "name"; break;
952 case TT_PUNCTUATION: str = "punctuation"; break;
953 default: str = "unknown type"; break;
955 idLexer::Error( "expected a %s but found '%s'", str.c_str(), token->c_str() );
958 if ( token->type == TT_NUMBER ) {
959 if ( (token->subtype & subtype) != subtype ) {
961 if ( subtype & TT_DECIMAL ) str = "decimal ";
962 if ( subtype & TT_HEX ) str = "hex ";
963 if ( subtype & TT_OCTAL ) str = "octal ";
964 if ( subtype & TT_BINARY ) str = "binary ";
965 if ( subtype & TT_UNSIGNED ) str += "unsigned ";
966 if ( subtype & TT_LONG ) str += "long ";
967 if ( subtype & TT_FLOAT ) str += "float ";
968 if ( subtype & TT_INTEGER ) str += "integer ";
969 str.StripTrailing( ' ' );
970 idLexer::Error( "expected %s but found '%s'", str.c_str(), token->c_str() );
974 else if ( token->type == TT_PUNCTUATION ) {
976 idLexer::Error( "BUG: wrong punctuation subtype" );
979 if ( token->subtype != subtype ) {
980 idLexer::Error( "expected '%s' but found '%s'", GetPunctuationFromId( subtype ), token->c_str() );
989 idLexer::ExpectAnyToken
992 int idLexer::ExpectAnyToken( idToken *token ) {
993 if (!idLexer::ReadToken( token )) {
994 idLexer::Error( "couldn't read expected token" );
1004 idLexer::CheckTokenString
1007 int idLexer::CheckTokenString( const char *string ) {
1010 if ( !ReadToken( &tok ) ) {
1013 // if the given string is available
1014 if ( tok == string ) {
1018 script_p = lastScript_p;
1025 idLexer::CheckTokenType
1028 int idLexer::CheckTokenType( int type, int subtype, idToken *token ) {
1031 if ( !ReadToken( &tok ) ) {
1034 // if the type matches
1035 if (tok.type == type && (tok.subtype & subtype) == subtype) {
1040 script_p = lastScript_p;
1047 idLexer::PeekTokenString
1050 int idLexer::PeekTokenString( const char *string ) {
1053 if ( !ReadToken( &tok ) ) {
1058 script_p = lastScript_p;
1061 // if the given string is available
1062 if ( tok == string ) {
1070 idLexer::PeekTokenType
1073 int idLexer::PeekTokenType( int type, int subtype, idToken *token ) {
1076 if ( !ReadToken( &tok ) ) {
1081 script_p = lastScript_p;
1084 // if the type matches
1085 if ( tok.type == type && ( tok.subtype & subtype ) == subtype ) {
1094 idLexer::SkipUntilString
1097 int idLexer::SkipUntilString( const char *string ) {
1100 while(idLexer::ReadToken( &token )) {
1101 if ( token == string ) {
1110 idLexer::SkipRestOfLine
1113 int idLexer::SkipRestOfLine( void ) {
1116 while(idLexer::ReadToken( &token )) {
1117 if ( token.linesCrossed ) {
1118 idLexer::script_p = lastScript_p;
1119 idLexer::line = lastline;
1128 idLexer::SkipBracedSection
1130 Skips until a matching close brace is found.
1131 Internal brace depths are properly skipped.
1134 int idLexer::SkipBracedSection( bool parseFirstBrace ) {
1138 depth = parseFirstBrace ? 0 : 1;
1140 if ( !ReadToken( &token ) ) {
1143 if ( token.type == TT_PUNCTUATION ) {
1144 if ( token == "{" ) {
1146 } else if ( token == "}" ) {
1156 idLexer::UnreadToken
1159 void idLexer::UnreadToken( const idToken *token ) {
1160 if ( idLexer::tokenavailable ) {
1161 idLib::common->FatalError( "idLexer::unreadToken, unread token twice\n" );
1163 idLexer::token = *token;
1164 idLexer::tokenavailable = 1;
1169 idLexer::ReadTokenOnLine
1172 int idLexer::ReadTokenOnLine( idToken *token ) {
1175 if (!idLexer::ReadToken( &tok )) {
1176 idLexer::script_p = lastScript_p;
1177 idLexer::line = lastline;
1180 // if no lines were crossed before this token
1181 if ( !tok.linesCrossed ) {
1185 // restore our position
1186 idLexer::script_p = lastScript_p;
1187 idLexer::line = lastline;
1194 idLexer::ReadRestOfLine
1197 const char* idLexer::ReadRestOfLine(idStr& out) {
1200 if(*idLexer::script_p == '\n') {
1205 if(!*idLexer::script_p) {
1209 if(*idLexer::script_p <= ' ') {
1212 out += *idLexer::script_p;
1214 idLexer::script_p++;
1227 int idLexer::ParseInt( void ) {
1230 if ( !idLexer::ReadToken( &token ) ) {
1231 idLexer::Error( "couldn't read expected integer" );
1234 if ( token.type == TT_PUNCTUATION && token == "-" ) {
1235 idLexer::ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
1236 return -((signed int) token.GetIntValue());
1238 else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
1239 idLexer::Error( "expected integer value, found '%s'", token.c_str() );
1241 return token.GetIntValue();
1249 bool idLexer::ParseBool( void ) {
1252 if ( !idLexer::ExpectTokenType( TT_NUMBER, 0, &token ) ) {
1253 idLexer::Error( "couldn't read expected boolean" );
1256 return ( token.GetIntValue() != 0 );
1264 float idLexer::ParseFloat( bool *errorFlag ) {
1271 if ( !idLexer::ReadToken( &token ) ) {
1273 idLexer::Warning( "couldn't read expected floating point number" );
1276 idLexer::Error( "couldn't read expected floating point number" );
1280 if ( token.type == TT_PUNCTUATION && token == "-" ) {
1281 idLexer::ExpectTokenType( TT_NUMBER, 0, &token );
1282 return -token.GetFloatValue();
1284 else if ( token.type != TT_NUMBER ) {
1286 idLexer::Warning( "expected float value, found '%s'", token.c_str() );
1289 idLexer::Error( "expected float value, found '%s'", token.c_str() );
1292 return token.GetFloatValue();
1297 idLexer::Parse1DMatrix
1300 int idLexer::Parse1DMatrix( int x, float *m ) {
1303 if ( !idLexer::ExpectTokenString( "(" ) ) {
1307 for ( i = 0; i < x; i++ ) {
1308 m[i] = idLexer::ParseFloat();
1311 if ( !idLexer::ExpectTokenString( ")" ) ) {
1319 idLexer::Parse2DMatrix
1322 int idLexer::Parse2DMatrix( int y, int x, float *m ) {
1325 if ( !idLexer::ExpectTokenString( "(" ) ) {
1329 for ( i = 0; i < y; i++ ) {
1330 if ( !idLexer::Parse1DMatrix( x, m + i * x ) ) {
1335 if ( !idLexer::ExpectTokenString( ")" ) ) {
1343 idLexer::Parse3DMatrix
1346 int idLexer::Parse3DMatrix( int z, int y, int x, float *m ) {
1349 if ( !idLexer::ExpectTokenString( "(" ) ) {
1353 for ( i = 0 ; i < z; i++ ) {
1354 if ( !idLexer::Parse2DMatrix( y, x, m + i * x*y ) ) {
1359 if ( !idLexer::ExpectTokenString( ")" ) ) {
1367 idParser::ParseBracedSection
1369 The next token should be an open brace.
1370 Parses until a matching close brace is found.
1371 Maintains exact characters between braces.
1373 FIXME: this should use ReadToken and replace the token white space with correct indents and newlines
1376 const char *idLexer::ParseBracedSectionExact( idStr &out, int tabs ) {
1383 if ( !idLexer::ExpectTokenString( "{" ) ) {
1384 return out.c_str( );
1392 while( depth && *idLexer::script_p ) {
1393 char c = *(idLexer::script_p++);
1429 for ( ; i > 0; i-- ) {
1440 idLexer::ParseBracedSection
1442 The next token should be an open brace.
1443 Parses until a matching close brace is found.
1444 Internal brace depths are properly skipped.
1447 const char *idLexer::ParseBracedSection( idStr &out ) {
1452 if ( !idLexer::ExpectTokenString( "{" ) ) {
1458 if ( !idLexer::ReadToken( &token ) ) {
1459 Error( "missing closing brace" );
1463 // if the token is on a new line
1464 for ( i = 0; i < token.linesCrossed; i++ ) {
1468 if ( token.type == TT_PUNCTUATION ) {
1469 if ( token[0] == '{' ) {
1472 else if ( token[0] == '}' ) {
1477 if ( token.type == TT_STRING ) {
1478 out += "\"" + token + "\"";
1491 idLexer::ParseRestOfLine
1493 parse the rest of the line
1496 const char *idLexer::ParseRestOfLine( idStr &out ) {
1500 while(idLexer::ReadToken( &token )) {
1501 if ( token.linesCrossed ) {
1502 idLexer::script_p = lastScript_p;
1503 idLexer::line = lastline;
1506 if ( out.Length() ) {
1516 idLexer::GetLastWhiteSpace
1519 int idLexer::GetLastWhiteSpace( idStr &whiteSpace ) const {
1521 for ( const char *p = whiteSpaceStart_p; p < whiteSpaceEnd_p; p++ ) {
1522 whiteSpace.Append( *p );
1524 return whiteSpace.Length();
1529 idLexer::GetLastWhiteSpaceStart
1532 int idLexer::GetLastWhiteSpaceStart( void ) const {
1533 return whiteSpaceStart_p - buffer;
1538 idLexer::GetLastWhiteSpaceEnd
1541 int idLexer::GetLastWhiteSpaceEnd( void ) const {
1542 return whiteSpaceEnd_p - buffer;
1550 void idLexer::Reset( void ) {
1551 // pointer in script buffer
1552 idLexer::script_p = idLexer::buffer;
1553 // pointer in script buffer before reading token
1554 idLexer::lastScript_p = idLexer::buffer;
1555 // begin of white space
1556 idLexer::whiteSpaceStart_p = NULL;
1557 // end of white space
1558 idLexer::whiteSpaceEnd_p = NULL;
1559 // set if there's a token available in idLexer::token
1560 idLexer::tokenavailable = 0;
1563 idLexer::lastline = 1;
1564 // clear the saved token
1565 idLexer::token = "";
1573 int idLexer::EndOfFile( void ) {
1574 return idLexer::script_p >= idLexer::end_p;
1579 idLexer::NumLinesCrossed
1582 int idLexer::NumLinesCrossed( void ) {
1583 return idLexer::line - idLexer::lastline;
1591 int idLexer::LoadFile( const char *filename, bool OSPath ) {
1597 if ( idLexer::loaded ) {
1598 idLib::common->Error("idLexer::LoadFile: another script already loaded");
1602 if ( !OSPath && ( baseFolder[0] != '\0' ) ) {
1603 pathname = va( "%s/%s", baseFolder, filename );
1605 pathname = filename;
1608 fp = idLib::fileSystem->OpenExplicitFileRead( pathname );
1610 fp = idLib::fileSystem->OpenFileRead( pathname );
1615 length = fp->Length();
1616 buf = (char *) Mem_Alloc( length + 1 );
1618 fp->Read( buf, length );
1619 idLexer::fileTime = fp->Timestamp();
1620 idLexer::filename = fp->GetFullPath();
1621 idLib::fileSystem->CloseFile( fp );
1623 idLexer::buffer = buf;
1624 idLexer::length = length;
1625 // pointer in script buffer
1626 idLexer::script_p = idLexer::buffer;
1627 // pointer in script buffer before reading token
1628 idLexer::lastScript_p = idLexer::buffer;
1629 // pointer to end of script buffer
1630 idLexer::end_p = &(idLexer::buffer[length]);
1632 idLexer::tokenavailable = 0;
1634 idLexer::lastline = 1;
1635 idLexer::allocated = true;
1636 idLexer::loaded = true;
1646 int idLexer::LoadMemory( const char *ptr, int length, const char *name, int startLine ) {
1647 if ( idLexer::loaded ) {
1648 idLib::common->Error("idLexer::LoadMemory: another script already loaded");
1651 idLexer::filename = name;
1652 idLexer::buffer = ptr;
1653 idLexer::fileTime = 0;
1654 idLexer::length = length;
1655 // pointer in script buffer
1656 idLexer::script_p = idLexer::buffer;
1657 // pointer in script buffer before reading token
1658 idLexer::lastScript_p = idLexer::buffer;
1659 // pointer to end of script buffer
1660 idLexer::end_p = &(idLexer::buffer[length]);
1662 idLexer::tokenavailable = 0;
1663 idLexer::line = startLine;
1664 idLexer::lastline = startLine;
1665 idLexer::allocated = false;
1666 idLexer::loaded = true;
1676 void idLexer::FreeSource( void ) {
1678 if ( idLexer::punctuationtable && idLexer::punctuationtable != default_punctuationtable ) {
1679 Mem_Free( (void *) idLexer::punctuationtable );
1680 idLexer::punctuationtable = NULL;
1682 if ( idLexer::nextpunctuation && idLexer::nextpunctuation != default_nextpunctuation ) {
1683 Mem_Free( (void *) idLexer::nextpunctuation );
1684 idLexer::nextpunctuation = NULL;
1687 if ( idLexer::allocated ) {
1688 Mem_Free( (void *) idLexer::buffer );
1689 idLexer::buffer = NULL;
1690 idLexer::allocated = false;
1692 idLexer::tokenavailable = 0;
1693 idLexer::token = "";
1694 idLexer::loaded = false;
1702 idLexer::idLexer( void ) {
1703 idLexer::loaded = false;
1704 idLexer::filename = "";
1706 idLexer::SetPunctuations( NULL );
1707 idLexer::allocated = false;
1708 idLexer::fileTime = 0;
1709 idLexer::length = 0;
1711 idLexer::lastline = 0;
1712 idLexer::tokenavailable = 0;
1713 idLexer::token = "";
1714 idLexer::next = NULL;
1715 idLexer::hadError = false;
1723 idLexer::idLexer( int flags ) {
1724 idLexer::loaded = false;
1725 idLexer::filename = "";
1726 idLexer::flags = flags;
1727 idLexer::SetPunctuations( NULL );
1728 idLexer::allocated = false;
1729 idLexer::fileTime = 0;
1730 idLexer::length = 0;
1732 idLexer::lastline = 0;
1733 idLexer::tokenavailable = 0;
1734 idLexer::token = "";
1735 idLexer::next = NULL;
1736 idLexer::hadError = false;
1744 idLexer::idLexer( const char *filename, int flags, bool OSPath ) {
1745 idLexer::loaded = false;
1746 idLexer::flags = flags;
1747 idLexer::SetPunctuations( NULL );
1748 idLexer::allocated = false;
1749 idLexer::token = "";
1750 idLexer::next = NULL;
1751 idLexer::hadError = false;
1752 idLexer::LoadFile( filename, OSPath );
1760 idLexer::idLexer( const char *ptr, int length, const char *name, int flags ) {
1761 idLexer::loaded = false;
1762 idLexer::flags = flags;
1763 idLexer::SetPunctuations( NULL );
1764 idLexer::allocated = false;
1765 idLexer::token = "";
1766 idLexer::next = NULL;
1767 idLexer::hadError = false;
1768 idLexer::LoadMemory( ptr, length, name );
1776 idLexer::~idLexer( void ) {
1777 idLexer::FreeSource();
1782 idLexer::SetBaseFolder
1785 void idLexer::SetBaseFolder( const char *path ) {
1786 idStr::Copynz( baseFolder, path, sizeof( baseFolder ) );
1794 bool idLexer::HadError( void ) const {