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"
33 #define MAX_DEFINEPARMS 128
34 #define DEFINEHASHSIZE 2048
36 #define TOKEN_FL_RECURSIVE_DEFINE 1
38 define_t * idParser::globaldefines;
42 idParser::SetBaseFolder
45 void idParser::SetBaseFolder( const char *path) {
46 idLexer::SetBaseFolder(path);
51 idParser::AddGlobalDefine
54 int idParser::AddGlobalDefine( const char *string ) {
57 define = idParser::DefineFromString(string);
61 define->next = globaldefines;
62 globaldefines = define;
68 idParser::RemoveGlobalDefine
71 int idParser::RemoveGlobalDefine( const char *name ) {
74 for ( prev = NULL, d = idParser::globaldefines; d; prev = d, d = d->next ) {
75 if ( !strcmp( d->name, name ) ) {
84 idParser::globaldefines = d->next;
86 idParser::FreeDefine( d );
94 idParser::RemoveAllGlobalDefines
97 void idParser::RemoveAllGlobalDefines( void ) {
100 for ( define = globaldefines; define; define = globaldefines ) {
101 globaldefines = globaldefines->next;
102 idParser::FreeDefine(define);
108 ===============================================================================
112 ===============================================================================
117 idParser::PrintDefine
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);
129 PC_PrintDefineHashTable
132 static void PC_PrintDefineHashTable(define_t **definehash) {
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);
151 ID_INLINE int PC_NameHash( const char *name ) {
155 for ( i = 0; name[i] != '\0'; i++ ) {
156 hash += name[i] * (119 + i);
158 hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
164 idParser::AddDefineToHash
167 void idParser::AddDefineToHash( define_t *define, define_t **definehash ) {
170 hash = PC_NameHash(define->name);
171 define->hashnext = definehash[hash];
172 definehash[hash] = define;
180 define_t *idParser::FindHashedDefine( define_t **definehash, const char *name ) {
184 hash = PC_NameHash(name);
185 for ( d = definehash[hash]; d; d = d->hashnext ) {
186 if ( !strcmp(d->name, name) ) {
198 define_t *idParser::FindDefine( define_t *defines, const char *name ) {
201 for ( d = defines; d; d = d->next ) {
202 if ( !strcmp(d->name, name) ) {
211 idParser::FindDefineParm
214 int idParser::FindDefineParm( define_t *define, const char *name ) {
219 for ( p = define->parms; p; p = p->next ) {
220 if ( (*p) == name ) {
233 define_t *idParser::CopyDefine( define_t *define ) {
235 idToken *token, *newtoken, *lasttoken;
237 newdefine = (define_t *) Mem_Alloc(sizeof(define_t) + strlen(define->name) + 1);
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 idToken(token);
251 newtoken->next = NULL;
252 if (lasttoken) lasttoken->next = newtoken;
253 else newdefine->tokens = newtoken;
254 lasttoken = newtoken;
256 //copy the define parameters
257 newdefine->parms = NULL;
258 for (lasttoken = NULL, token = define->parms; token; token = token->next) {
259 newtoken = new idToken(token);
260 newtoken->next = NULL;
261 if (lasttoken) lasttoken->next = newtoken;
262 else newdefine->parms = newtoken;
263 lasttoken = newtoken;
273 void idParser::FreeDefine( define_t *define ) {
276 //free the define parameters
277 for (t = define->parms; t; t = next) {
281 //free the define tokens
282 for (t = define->tokens; t; t = next) {
292 idParser::DefineFromString
295 define_t *idParser::DefineFromString( const char *string ) {
299 if ( !src.LoadMemory(string, strlen(string), "*defineString") ) {
302 // create a define from the source
303 if ( !src.Directive_define() ) {
307 def = src.CopyFirstDefine();
309 //if the define was created succesfully
318 void idParser::Error( const char *str, ... ) const {
319 char text[MAX_STRING_CHARS];
323 vsprintf(text, str, ap);
325 if ( idParser::scriptstack ) {
326 idParser::scriptstack->Error( text );
335 void idParser::Warning( const char *str, ... ) const {
336 char text[MAX_STRING_CHARS];
340 vsprintf(text, str, ap);
342 if ( idParser::scriptstack ) {
343 idParser::scriptstack->Warning( text );
352 void idParser::PushIndent( int type, int skip ) {
355 indent = (indent_t *) Mem_Alloc(sizeof(indent_t));
357 indent->script = idParser::scriptstack;
358 indent->skip = (skip != 0);
359 idParser::skip += indent->skip;
360 indent->next = idParser::indentstack;
361 idParser::indentstack = indent;
369 void idParser::PopIndent( int *type, int *skip ) {
375 indent = idParser::indentstack;
378 // must be an indent from the current script
379 if (idParser::indentstack->script != idParser::scriptstack) {
383 *type = indent->type;
384 *skip = indent->skip;
385 idParser::indentstack = idParser::indentstack->next;
386 idParser::skip -= indent->skip;
395 void idParser::PushScript( idLexer *script ) {
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() );
404 //push the script on the script stack
405 script->next = idParser::scriptstack;
406 idParser::scriptstack = script;
411 idParser::ReadSourceToken
414 int idParser::ReadSourceToken( idToken *token ) {
417 int type, skip, changedScript;
419 if ( !idParser::scriptstack ) {
420 idLib::common->FatalError( "idParser::ReadSourceToken: not loaded" );
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;
430 // set the marker based on the start of the token read in
432 marker_p = token->whiteSpaceEnd_p;
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 );
445 // if this was the initial script
446 if ( !idParser::scriptstack->next ) {
449 // remove the script and return to the previous one
450 script = idParser::scriptstack;
451 idParser::scriptstack = idParser::scriptstack->next;
454 // copy the already available token
455 *token = idParser::tokens;
456 // remove the token from the source
457 t = idParser::tokens;
458 idParser::tokens = idParser::tokens->next;
465 idParser::UnreadSourceToken
468 int idParser::UnreadSourceToken( idToken *token ) {
471 t = new idToken(token);
472 t->next = idParser::tokens;
473 idParser::tokens = t;
479 idParser::ReadDefineParms
482 int idParser::ReadDefineParms( define_t *define, idToken **parms, int maxparms ) {
484 idToken token, *t, *last;
485 int i, done, lastcomma, numparms, indent;
487 if ( !idParser::ReadSourceToken( &token ) ) {
488 idParser::Error( "define '%s' missing parameters", define->name );
492 if ( define->numparms > maxparms ) {
493 idParser::Error( "define with more than %d parameters", maxparms );
497 for ( i = 0; i < define->numparms; i++ ) {
501 if ( token != "(" ) {
502 idParser::UnreadSourceToken( &token );
503 idParser::Error( "define '%s' missing parameters", define->name );
506 // read the define parameters
507 for ( done = 0, numparms = 0, indent = 1; !done; ) {
508 if ( numparms >= maxparms ) {
509 idParser::Error( "define '%s' with too many parameters", define->name );
512 parms[numparms] = NULL;
517 if ( !idParser::ReadSourceToken( &token ) ) {
518 idParser::Error( "define '%s' incomplete", define->name );
522 if ( token == "," ) {
525 idParser::Warning( "too many comma's" );
527 if ( numparms >= define->numparms ) {
528 idParser::Warning( "too many define parameters" );
534 else if ( token == "(" ) {
537 else if ( token == ")" ) {
540 if ( !parms[define->numparms-1] ) {
541 idParser::Warning( "too few define parameters" );
547 else if ( token.type == TT_NAME ) {
548 newdefine = FindHashedDefine( idParser::definehash, token.c_str() );
550 if ( !idParser::ExpandDefineIntoSource( &token, newdefine ) ) {
559 if ( numparms < define->numparms ) {
561 t = new idToken( token );
563 if (last) last->next = t;
564 else parms[numparms] = t;
575 idParser::StringizeTokens
578 int idParser::StringizeTokens( idToken *tokens, idToken *token ) {
581 token->type = TT_STRING;
582 token->whiteSpaceStart_p = NULL;
583 token->whiteSpaceEnd_p = NULL;
585 for ( t = tokens; t; t = t->next ) {
586 token->Append( t->c_str() );
593 idParser::MergeTokens
596 int idParser::MergeTokens( idToken *t1, idToken *t2 ) {
597 // merging of a name with a name or number
598 if ( t1->type == TT_NAME && (t2->type == TT_NAME || (t2->type == TT_NUMBER && !(t2->subtype & TT_FLOAT))) ) {
599 t1->Append( t2->c_str() );
602 // merging of two strings
603 if (t1->type == TT_STRING && t2->type == TT_STRING) {
604 t1->Append( t2->c_str() );
607 // merging of two numbers
608 if ( t1->type == TT_NUMBER && t2->type == TT_NUMBER &&
609 !(t1->subtype & (TT_HEX|TT_BINARY)) && !(t2->subtype & (TT_HEX|TT_BINARY)) &&
610 (!(t1->subtype & TT_FLOAT) || !(t2->subtype & TT_FLOAT)) ) {
611 t1->Append( t2->c_str() );
620 idParser::AddBuiltinDefines
623 void idParser::AddBuiltinDefines( void ) {
631 { "__LINE__", BUILTIN_LINE },
632 { "__FILE__", BUILTIN_FILE },
633 { "__DATE__", BUILTIN_DATE },
634 { "__TIME__", BUILTIN_TIME },
635 { "__STDC__", BUILTIN_STDC },
639 for (i = 0; builtin[i].string; i++) {
640 define = (define_t *) Mem_Alloc(sizeof(define_t) + strlen(builtin[i].string) + 1);
641 define->name = (char *) define + sizeof(define_t);
642 strcpy(define->name, builtin[i].string);
643 define->flags = DEFINE_FIXED;
644 define->builtin = builtin[i].id;
645 define->numparms = 0;
646 define->parms = NULL;
647 define->tokens = NULL;
648 // add the define to the source
649 AddDefineToHash(define, idParser::definehash);
655 idParser::CopyFirstDefine
658 define_t *idParser::CopyFirstDefine( void ) {
661 for ( i = 0; i < DEFINEHASHSIZE; i++ ) {
662 if ( idParser::definehash[i] ) {
663 return CopyDefine(idParser::definehash[i]);
671 idParser::ExpandBuiltinDefine
674 int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) {
678 char buf[MAX_STRING_CHARS];
680 token = new idToken(deftoken);
681 switch( define->builtin ) {
683 sprintf( buf, "%d", deftoken->line );
685 token->intvalue = deftoken->line;
686 token->floatvalue = deftoken->line;
687 token->type = TT_NUMBER;
688 token->subtype = TT_DECIMAL | TT_INTEGER | TT_VALUESVALID;
689 token->line = deftoken->line;
690 token->linesCrossed = deftoken->linesCrossed;
697 (*token) = idParser::scriptstack->GetFileName();
698 token->type = TT_NAME;
699 token->subtype = token->Length();
700 token->line = deftoken->line;
701 token->linesCrossed = deftoken->linesCrossed;
711 token->Append( curtime+4 );
713 token->Append( curtime+20 );
715 token->Append( "\"" );
717 token->type = TT_STRING;
718 token->subtype = token->Length();
719 token->line = deftoken->line;
720 token->linesCrossed = deftoken->linesCrossed;
730 token->Append( curtime+11 );
732 token->Append( "\"" );
734 token->type = TT_STRING;
735 token->subtype = token->Length();
736 token->line = deftoken->line;
737 token->linesCrossed = deftoken->linesCrossed;
744 idParser::Warning( "__STDC__ not supported\n" );
760 idParser::ExpandDefine
763 int idParser::ExpandDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) {
764 idToken *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
765 idToken *t1, *t2, *first, *last, *nextpt, token;
768 // if it is a builtin define
769 if ( define->builtin ) {
770 return idParser::ExpandBuiltinDefine( deftoken, define, firsttoken, lasttoken );
772 // if the define has parameters
773 if ( define->numparms ) {
774 if ( !idParser::ReadDefineParms( define, parms, MAX_DEFINEPARMS ) ) {
778 for ( i = 0; i < define->numparms; i++ ) {
779 Log_Write("define parms %d:", i);
780 for ( pt = parms[i]; pt; pt = pt->next ) {
781 Log_Write( "%s", pt->c_str() );
786 // empty list at first
789 // create a list with tokens of the expanded define
790 for ( dt = define->tokens; dt; dt = dt->next ) {
792 // if the token is a name, it could be a define parameter
793 if ( dt->type == TT_NAME ) {
794 parmnum = FindDefineParm( define, dt->c_str() );
796 // if it is a define parameter
797 if ( parmnum >= 0 ) {
798 for ( pt = parms[parmnum]; pt; pt = pt->next ) {
800 //add the token to the list
802 if (last) last->next = t;
808 // if stringizing operator
809 if ( (*dt) == "#" ) {
810 // the stringizing operator must be followed by a define parameter
812 parmnum = FindDefineParm( define, dt->next->c_str() );
818 if ( parmnum >= 0 ) {
819 // step over the stringizing operator
821 // stringize the define parameter tokens
822 if ( !idParser::StringizeTokens( parms[parmnum], &token ) ) {
823 idParser::Error( "can't stringize tokens" );
826 t = new idToken(token);
827 t->line = deftoken->line;
830 idParser::Warning( "stringizing operator without define parameter" );
836 t->line = deftoken->line;
838 // add the token to the list
840 // the token being read from the define list should use the line number of
841 // the original file, not the header file
842 t->line = deftoken->line;
844 if ( last ) last->next = t;
849 // check for the merging operator
850 for ( t = first; t; ) {
852 // if the merging operator
853 if ( (*t->next) == "##" ) {
857 if ( !idParser::MergeTokens( t1, t2 ) ) {
858 idParser::Error( "can't merge '%s' with '%s'", t1->c_str(), t2->c_str() );
863 if ( t2 == last ) last = t1;
871 // store the first and last token of the list
874 // free all the parameter tokens
875 for ( i = 0; i < define->numparms; i++ ) {
876 for ( pt = parms[i]; pt; pt = nextpt ) {
887 idParser::ExpandDefineIntoSource
890 int idParser::ExpandDefineIntoSource( idToken *deftoken, define_t *define ) {
891 idToken *firsttoken, *lasttoken;
893 if ( !idParser::ExpandDefine( deftoken, define, &firsttoken, &lasttoken ) ) {
896 // if the define is not empty
897 if ( firsttoken && lasttoken ) {
898 firsttoken->linesCrossed += deftoken->linesCrossed;
899 lasttoken->next = idParser::tokens;
900 idParser::tokens = firsttoken;
909 reads a token from the current line, continues reading on the next
910 line only if a backslash '\' is found
913 int idParser::ReadLine( idToken *token ) {
918 if (!idParser::ReadSourceToken( token )) {
922 if (token->linesCrossed > crossline) {
923 idParser::UnreadSourceToken( token );
927 } while( (*token) == "\\" );
933 idParser::Directive_include
936 int idParser::Directive_include( void ) {
941 if ( !idParser::ReadSourceToken( &token ) ) {
942 idParser::Error( "#include without file name" );
945 if ( token.linesCrossed > 0 ) {
946 idParser::Error( "#include without file name" );
949 if ( token.type == TT_STRING ) {
950 script = new idLexer;
951 // try relative to the current file
952 path = scriptstack->GetFileName();
953 path.StripFilename();
956 if ( !script->LoadFile( path, OSPath ) ) {
959 if ( !script->LoadFile( path, OSPath ) ) {
960 // try from the include path
961 path = includepath + token;
962 if ( !script->LoadFile( path, OSPath ) ) {
969 else if ( token.type == TT_PUNCTUATION && token == "<" ) {
970 path = idParser::includepath;
971 while( idParser::ReadSourceToken( &token ) ) {
972 if ( token.linesCrossed > 0 ) {
973 idParser::UnreadSourceToken( &token );
976 if ( token.type == TT_PUNCTUATION && token == ">" ) {
981 if ( token != ">" ) {
982 idParser::Warning( "#include missing trailing >" );
984 if ( !path.Length() ) {
985 idParser::Error( "#include without file name between < >" );
988 if ( idParser::flags & LEXFL_NOBASEINCLUDES ) {
991 script = new idLexer;
992 if ( !script->LoadFile( includepath + path, OSPath ) ) {
998 idParser::Error( "#include without file name" );
1002 idParser::Error( "file '%s' not found", path.c_str() );
1005 script->SetFlags( idParser::flags );
1006 script->SetPunctuations( idParser::punctuations );
1007 idParser::PushScript( script );
1013 idParser::Directive_undef
1016 int idParser::Directive_undef( void ) {
1018 define_t *define, *lastdefine;
1022 if (!idParser::ReadLine( &token )) {
1023 idParser::Error( "undef without name" );
1026 if (token.type != TT_NAME) {
1027 idParser::UnreadSourceToken( &token );
1028 idParser::Error( "expected name but found '%s'", token.c_str() );
1032 hash = PC_NameHash( token.c_str() );
1033 for (lastdefine = NULL, define = idParser::definehash[hash]; define; define = define->hashnext) {
1034 if (!strcmp(define->name, token.c_str()))
1036 if (define->flags & DEFINE_FIXED) {
1037 idParser::Warning( "can't undef '%s'", token.c_str() );
1041 lastdefine->hashnext = define->hashnext;
1044 idParser::definehash[hash] = define->hashnext;
1050 lastdefine = define;
1057 idParser::Directive_define
1060 int idParser::Directive_define( void ) {
1061 idToken token, *t, *last;
1064 if (!idParser::ReadLine( &token )) {
1065 idParser::Error( "#define without name" );
1068 if (token.type != TT_NAME) {
1069 idParser::UnreadSourceToken( &token );
1070 idParser::Error( "expected name after #define, found '%s'", token.c_str() );
1073 // check if the define already exists
1074 define = FindHashedDefine(idParser::definehash, token.c_str());
1076 if (define->flags & DEFINE_FIXED) {
1077 idParser::Error( "can't redefine '%s'", token.c_str() );
1080 idParser::Warning( "redefinition of '%s'", token.c_str() );
1081 // unread the define name before executing the #undef directive
1082 idParser::UnreadSourceToken( &token );
1083 if (!idParser::Directive_undef())
1085 // if the define was not removed (define->flags & DEFINE_FIXED)
1086 define = FindHashedDefine(idParser::definehash, token.c_str());
1089 define = (define_t *) Mem_ClearedAlloc(sizeof(define_t) + token.Length() + 1);
1090 define->name = (char *) define + sizeof(define_t);
1091 strcpy(define->name, token.c_str());
1092 // add the define to the source
1093 AddDefineToHash(define, idParser::definehash);
1094 // if nothing is defined, just return
1095 if ( !idParser::ReadLine( &token ) ) {
1098 // if it is a define with parameters
1099 if ( token.WhiteSpaceBeforeToken() == 0 && token == "(" ) {
1100 // read the define parameters
1102 if ( !idParser::CheckTokenString(")") ) {
1104 if ( !idParser::ReadLine( &token ) ) {
1105 idParser::Error( "expected define parameter" );
1108 // if it isn't a name
1109 if (token.type != TT_NAME) {
1110 idParser::Error( "invalid define parameter" );
1114 if (FindDefineParm(define, token.c_str()) >= 0) {
1115 idParser::Error( "two the same define parameters" );
1118 // add the define parm
1119 t = new idToken(token);
1120 t->ClearTokenWhiteSpace();
1122 if (last) last->next = t;
1123 else define->parms = t;
1127 if (!idParser::ReadLine( &token )) {
1128 idParser::Error( "define parameters not terminated" );
1132 if ( token == ")" ) {
1135 // then it must be a comma
1136 if ( token != "," ) {
1137 idParser::Error( "define not terminated" );
1142 if ( !idParser::ReadLine( &token ) ) {
1146 // read the defined stuff
1150 t = new idToken(token);
1151 if ( t->type == TT_NAME && !strcmp( t->c_str(), define->name ) ) {
1152 t->flags |= TOKEN_FL_RECURSIVE_DEFINE;
1153 idParser::Warning( "recursive define (removed recursion)" );
1155 t->ClearTokenWhiteSpace();
1157 if ( last ) last->next = t;
1158 else define->tokens = t;
1160 } while( idParser::ReadLine( &token ) );
1163 // check for merge operators at the beginning or end
1164 if ( (*define->tokens) == "##" || (*last) == "##" ) {
1165 idParser::Error( "define with misplaced ##" );
1177 int idParser::AddDefine( const char *string ) {
1180 define = DefineFromString( string );
1184 AddDefineToHash(define, idParser::definehash);
1190 idParser::AddGlobalDefinesToSource
1193 void idParser::AddGlobalDefinesToSource( void ) {
1194 define_t *define, *newdefine;
1196 for (define = globaldefines; define; define = define->next) {
1197 newdefine = CopyDefine( define );
1198 AddDefineToHash(newdefine, idParser::definehash);
1204 idParser::Directive_if_def
1207 int idParser::Directive_if_def( int type ) {
1212 if ( !idParser::ReadLine( &token ) ) {
1213 idParser::Error( "#ifdef without name" );
1216 if (token.type != TT_NAME) {
1217 idParser::UnreadSourceToken( &token );
1218 idParser::Error( "expected name after #ifdef, found '%s'", token.c_str() );
1221 d = FindHashedDefine(idParser::definehash, token.c_str());
1222 skip = (type == INDENT_IFDEF) == (d == NULL);
1223 idParser::PushIndent( type, skip );
1229 idParser::Directive_ifdef
1232 int idParser::Directive_ifdef( void ) {
1233 return idParser::Directive_if_def( INDENT_IFDEF );
1238 idParser::Directive_ifndef
1241 int idParser::Directive_ifndef( void ) {
1242 return idParser::Directive_if_def( INDENT_IFNDEF );
1247 idParser::Directive_else
1250 int idParser::Directive_else( void ) {
1253 idParser::PopIndent( &type, &skip );
1255 idParser::Error( "misplaced #else" );
1258 if (type == INDENT_ELSE) {
1259 idParser::Error( "#else after #else" );
1262 idParser::PushIndent( INDENT_ELSE, !skip );
1268 idParser::Directive_endif
1271 int idParser::Directive_endif( void ) {
1274 idParser::PopIndent( &type, &skip );
1276 idParser::Error( "misplaced #endif" );
1284 idParser::EvaluateTokens
1287 typedef struct operator_s
1292 struct operator_s *prev, *next;
1295 typedef struct value_s
1297 signed long int intvalue;
1300 struct value_s *prev, *next;
1303 int PC_OperatorPriority(int op) {
1305 case P_MUL: return 15;
1306 case P_DIV: return 15;
1307 case P_MOD: return 15;
1308 case P_ADD: return 14;
1309 case P_SUB: return 14;
1311 case P_LOGIC_AND: return 7;
1312 case P_LOGIC_OR: return 6;
1313 case P_LOGIC_GEQ: return 12;
1314 case P_LOGIC_LEQ: return 12;
1315 case P_LOGIC_EQ: return 11;
1316 case P_LOGIC_UNEQ: return 11;
1318 case P_LOGIC_NOT: return 16;
1319 case P_LOGIC_GREATER: return 12;
1320 case P_LOGIC_LESS: return 12;
1322 case P_RSHIFT: return 13;
1323 case P_LSHIFT: return 13;
1325 case P_BIN_AND: return 10;
1326 case P_BIN_OR: return 8;
1327 case P_BIN_XOR: return 9;
1328 case P_BIN_NOT: return 16;
1330 case P_COLON: return 5;
1331 case P_QUESTIONMARK: return 5;
1336 //#define AllocValue() GetClearedMemory(sizeof(value_t));
1337 //#define FreeValue(val) FreeMemory(val)
1338 //#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t));
1339 //#define FreeOperator(op) FreeMemory(op);
1341 #define MAX_VALUES 64
1342 #define MAX_OPERATORS 64
1344 #define AllocValue(val) \
1345 if ( numvalues >= MAX_VALUES ) { \
1346 idParser::Error( "out of value space\n" ); \
1351 val = &value_heap[numvalues++]; \
1354 #define FreeValue(val)
1356 #define AllocOperator(op) \
1357 if ( numoperators >= MAX_OPERATORS ) { \
1358 idParser::Error( "out of operator space\n" ); \
1363 op = &operator_heap[numoperators++]; \
1366 #define FreeOperator(op)
1368 int idParser::EvaluateTokens( idToken *tokens, signed long int *intvalue, double *floatvalue, int integer ) {
1369 operator_t *o, *firstoperator, *lastoperator;
1370 value_t *v, *firstvalue, *lastvalue, *v1, *v2;
1373 int parentheses = 0;
1375 int lastwasvalue = 0;
1376 int negativevalue = 0;
1377 int questmarkintvalue = 0;
1378 double questmarkfloatvalue = 0;
1379 int gotquestmarkvalue = false;
1380 int lastoperatortype = 0;
1382 operator_t operator_heap[MAX_OPERATORS];
1383 int numoperators = 0;
1384 value_t value_heap[MAX_VALUES];
1387 firstoperator = lastoperator = NULL;
1388 firstvalue = lastvalue = NULL;
1389 if (intvalue) *intvalue = 0;
1390 if (floatvalue) *floatvalue = 0;
1391 for ( t = tokens; t; t = t->next ) {
1395 if ( lastwasvalue || negativevalue ) {
1396 idParser::Error( "syntax error in #if/#elif" );
1400 if ( (*t) != "defined" ) {
1401 idParser::Error( "undefined name '%s' in #if/#elif", t->c_str() );
1406 if ( (*t) == "(" ) {
1410 if (!t || t->type != TT_NAME) {
1411 idParser::Error( "defined() without name in #if/#elif" );
1415 //v = (value_t *) GetClearedMemory(sizeof(value_t));
1417 if (FindHashedDefine(idParser::definehash, t->c_str())) {
1425 v->parentheses = parentheses;
1427 v->prev = lastvalue;
1428 if (lastvalue) lastvalue->next = v;
1429 else firstvalue = v;
1433 if (!t || (*t) != ")" ) {
1434 idParser::Error( "defined missing ) in #if/#elif" );
1440 // defined() creates a value
1447 idParser::Error( "syntax error in #if/#elif" );
1451 //v = (value_t *) GetClearedMemory(sizeof(value_t));
1453 if (negativevalue) {
1454 v->intvalue = - t->GetIntValue();
1455 v->floatvalue = - t->GetFloatValue();
1458 v->intvalue = t->GetIntValue();
1459 v->floatvalue = t->GetFloatValue();
1461 v->parentheses = parentheses;
1463 v->prev = lastvalue;
1464 if (lastvalue) lastvalue->next = v;
1465 else firstvalue = v;
1467 //last token was a value
1473 case TT_PUNCTUATION:
1475 if (negativevalue) {
1476 idParser::Error( "misplaced minus sign in #if/#elif" );
1480 if (t->subtype == P_PARENTHESESOPEN) {
1484 else if (t->subtype == P_PARENTHESESCLOSE) {
1486 if (parentheses < 0) {
1487 idParser::Error( "too many ) in #if/#elsif" );
1492 //check for invalid operators on floating point values
1494 if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
1495 t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
1496 t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
1497 t->subtype == P_BIN_XOR) {
1498 idParser::Error( "illigal operator '%s' on floating point operands\n", t->c_str() );
1503 switch( t->subtype ) {
1508 idParser::Error( "! or ~ after value in #if/#elif" );
1517 idParser::Error( "++ or -- used in #if/#elif" );
1522 if (!lastwasvalue) {
1540 case P_LOGIC_GREATER:
1551 case P_QUESTIONMARK:
1553 if (!lastwasvalue) {
1554 idParser::Error( "operator '%s' after operator in #if/#elif", t->c_str() );
1562 idParser::Error( "invalid operator '%s' in #if/#elif", t->c_str() );
1567 if (!error && !negativevalue) {
1568 //o = (operator_t *) GetClearedMemory(sizeof(operator_t));
1571 o->priority = PC_OperatorPriority(t->subtype);
1572 o->parentheses = parentheses;
1574 o->prev = lastoperator;
1575 if (lastoperator) lastoperator->next = o;
1576 else firstoperator = o;
1584 idParser::Error( "unknown '%s' in #if/#elif", t->c_str() );
1594 if (!lastwasvalue) {
1595 idParser::Error( "trailing operator in #if/#elif" );
1598 else if (parentheses) {
1599 idParser::Error( "too many ( in #if/#elif" );
1604 gotquestmarkvalue = false;
1605 questmarkintvalue = 0;
1606 questmarkfloatvalue = 0;
1607 //while there are operators
1608 while( !error && firstoperator ) {
1610 for (o = firstoperator; o->next; o = o->next) {
1611 //if the current operator is nested deeper in parentheses
1612 //than the next operator
1613 if (o->parentheses > o->next->parentheses) {
1616 //if the current and next operator are nested equally deep in parentheses
1617 if (o->parentheses == o->next->parentheses) {
1618 //if the priority of the current operator is equal or higher
1619 //than the priority of the next operator
1620 if (o->priority >= o->next->priority) {
1624 //if the arity of the operator isn't equal to 1
1625 if (o->op != P_LOGIC_NOT && o->op != P_BIN_NOT) {
1628 //if there's no value or no next value
1630 idParser::Error( "mising values in #if/#elif" );
1642 Log_Write("operator %s, value1 = %d", idParser::scriptstack->getPunctuationFromId(o->op), v1->intvalue);
1643 if (v2) Log_Write("value2 = %d", v2->intvalue);
1646 Log_Write("operator %s, value1 = %f", idParser::scriptstack->getPunctuationFromId(o->op), v1->floatvalue);
1647 if (v2) Log_Write("value2 = %f", v2->floatvalue);
1651 case P_LOGIC_NOT: v1->intvalue = !v1->intvalue;
1652 v1->floatvalue = !v1->floatvalue; break;
1653 case P_BIN_NOT: v1->intvalue = ~v1->intvalue;
1655 case P_MUL: v1->intvalue *= v2->intvalue;
1656 v1->floatvalue *= v2->floatvalue; break;
1657 case P_DIV: if (!v2->intvalue || !v2->floatvalue)
1659 idParser::Error( "divide by zero in #if/#elif\n" );
1663 v1->intvalue /= v2->intvalue;
1664 v1->floatvalue /= v2->floatvalue; break;
1665 case P_MOD: if (!v2->intvalue)
1667 idParser::Error( "divide by zero in #if/#elif\n" );
1671 v1->intvalue %= v2->intvalue; break;
1672 case P_ADD: v1->intvalue += v2->intvalue;
1673 v1->floatvalue += v2->floatvalue; break;
1674 case P_SUB: v1->intvalue -= v2->intvalue;
1675 v1->floatvalue -= v2->floatvalue; break;
1676 case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue;
1677 v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
1678 case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue;
1679 v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
1680 case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue;
1681 v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
1682 case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue;
1683 v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
1684 case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue;
1685 v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
1686 case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue;
1687 v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
1688 case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue;
1689 v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
1690 case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue;
1691 v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
1692 case P_RSHIFT: v1->intvalue >>= v2->intvalue;
1694 case P_LSHIFT: v1->intvalue <<= v2->intvalue;
1696 case P_BIN_AND: v1->intvalue &= v2->intvalue;
1698 case P_BIN_OR: v1->intvalue |= v2->intvalue;
1700 case P_BIN_XOR: v1->intvalue ^= v2->intvalue;
1704 if (!gotquestmarkvalue) {
1705 idParser::Error( ": without ? in #if/#elif" );
1710 if (!questmarkintvalue)
1711 v1->intvalue = v2->intvalue;
1714 if (!questmarkfloatvalue)
1715 v1->floatvalue = v2->floatvalue;
1717 gotquestmarkvalue = false;
1720 case P_QUESTIONMARK:
1722 if (gotquestmarkvalue) {
1723 idParser::Error( "? after ? in #if/#elif" );
1727 questmarkintvalue = v1->intvalue;
1728 questmarkfloatvalue = v1->floatvalue;
1729 gotquestmarkvalue = true;
1734 if (integer) Log_Write("result value = %d", v1->intvalue);
1735 else Log_Write("result value = %f", v1->floatvalue);
1739 lastoperatortype = o->op;
1740 //if not an operator with arity 1
1741 if (o->op != P_LOGIC_NOT && o->op != P_BIN_NOT) {
1742 //remove the second value if not question mark operator
1743 if (o->op != P_QUESTIONMARK) {
1747 if (v->prev) v->prev->next = v->next;
1748 else firstvalue = v->next;
1749 if (v->next) v->next->prev = v->prev;
1750 else lastvalue = v->prev;
1754 //remove the operator
1755 if (o->prev) o->prev->next = o->next;
1756 else firstoperator = o->next;
1757 if (o->next) o->next->prev = o->prev;
1758 else lastoperator = o->prev;
1763 if (intvalue) *intvalue = firstvalue->intvalue;
1764 if (floatvalue) *floatvalue = firstvalue->floatvalue;
1766 for (o = firstoperator; o; o = lastoperator) {
1767 lastoperator = o->next;
1771 for (v = firstvalue; v; v = lastvalue) {
1772 lastvalue = v->next;
1793 int idParser::Evaluate( signed long int *intvalue, double *floatvalue, int integer ) {
1794 idToken token, *firsttoken, *lasttoken;
1795 idToken *t, *nexttoken;
1797 int defined = false;
1806 if ( !idParser::ReadLine( &token ) ) {
1807 idParser::Error( "no value after #if/#elif" );
1813 //if the token is a name
1814 if (token.type == TT_NAME) {
1817 t = new idToken(token);
1819 if (lasttoken) lasttoken->next = t;
1820 else firsttoken = t;
1823 else if ( token == "defined" ) {
1825 t = new idToken(token);
1827 if (lasttoken) lasttoken->next = t;
1828 else firsttoken = t;
1832 //then it must be a define
1833 define = FindHashedDefine(idParser::definehash, token.c_str());
1835 idParser::Error( "can't Evaluate '%s', not defined", token.c_str() );
1838 if ( !idParser::ExpandDefineIntoSource( &token, define ) ) {
1843 //if the token is a number or a punctuation
1844 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) {
1845 t = new idToken(token);
1847 if (lasttoken) lasttoken->next = t;
1848 else firsttoken = t;
1852 idParser::Error( "can't Evaluate '%s'", token.c_str() );
1855 } while(idParser::ReadLine( &token ));
1857 if ( !idParser::EvaluateTokens( firsttoken, intvalue, floatvalue, integer ) ) {
1864 for (t = firsttoken; t; t = nexttoken) {
1866 Log_Write(" %s", t->c_str());
1868 nexttoken = t->next;
1872 if (integer) Log_Write("eval result: %d", *intvalue);
1873 else Log_Write("eval result: %f", *floatvalue);
1881 idParser::DollarEvaluate
1884 int idParser::DollarEvaluate( signed long int *intvalue, double *floatvalue, int integer) {
1885 int indent, defined = false;
1886 idToken token, *firsttoken, *lasttoken;
1887 idToken *t, *nexttoken;
1897 if ( !idParser::ReadSourceToken( &token ) ) {
1898 idParser::Error( "no leading ( after $evalint/$evalfloat" );
1901 if ( !idParser::ReadSourceToken( &token ) ) {
1902 idParser::Error( "nothing to Evaluate" );
1909 //if the token is a name
1910 if (token.type == TT_NAME) {
1913 t = new idToken(token);
1915 if (lasttoken) lasttoken->next = t;
1916 else firsttoken = t;
1919 else if ( token == "defined" ) {
1921 t = new idToken(token);
1923 if (lasttoken) lasttoken->next = t;
1924 else firsttoken = t;
1928 //then it must be a define
1929 define = FindHashedDefine(idParser::definehash, token.c_str());
1931 idParser::Warning( "can't Evaluate '%s', not defined", token.c_str() );
1934 if ( !idParser::ExpandDefineIntoSource( &token, define ) ) {
1939 //if the token is a number or a punctuation
1940 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) {
1941 if ( token[0] == '(' ) indent++;
1942 else if ( token[0] == ')' ) indent--;
1946 t = new idToken(token);
1948 if (lasttoken) lasttoken->next = t;
1949 else firsttoken = t;
1953 idParser::Error( "can't Evaluate '%s'", token.c_str() );
1956 } while(idParser::ReadSourceToken( &token ));
1958 if (!idParser::EvaluateTokens( firsttoken, intvalue, floatvalue, integer)) {
1963 Log_Write("$eval:");
1965 for (t = firsttoken; t; t = nexttoken) {
1967 Log_Write(" %s", t->c_str());
1969 nexttoken = t->next;
1973 if (integer) Log_Write("$eval result: %d", *intvalue);
1974 else Log_Write("$eval result: %f", *floatvalue);
1982 idParser::Directive_elif
1985 int idParser::Directive_elif( void ) {
1986 signed long int value;
1989 idParser::PopIndent( &type, &skip );
1990 if (!type || type == INDENT_ELSE) {
1991 idParser::Error( "misplaced #elif" );
1994 if ( !idParser::Evaluate( &value, NULL, true ) ) {
1997 skip = (value == 0);
1998 idParser::PushIndent( INDENT_ELIF, skip );
2004 idParser::Directive_if
2007 int idParser::Directive_if( void ) {
2008 signed long int value;
2011 if ( !idParser::Evaluate( &value, NULL, true ) ) {
2014 skip = (value == 0);
2015 idParser::PushIndent( INDENT_IF, skip );
2021 idParser::Directive_line
2024 int idParser::Directive_line( void ) {
2027 idParser::Error( "#line directive not supported" );
2028 while( idParser::ReadLine( &token ) ) {
2035 idParser::Directive_error
2038 int idParser::Directive_error( void ) {
2041 if ( !idParser::ReadLine( &token) || token.type != TT_STRING ) {
2042 idParser::Error( "#error without string" );
2045 idParser::Error( "#error: %s", token.c_str() );
2051 idParser::Directive_warning
2054 int idParser::Directive_warning( void ) {
2057 if ( !idParser::ReadLine( &token) || token.type != TT_STRING ) {
2058 idParser::Warning( "#warning without string" );
2061 idParser::Warning( "#warning: %s", token.c_str() );
2067 idParser::Directive_pragma
2070 int idParser::Directive_pragma( void ) {
2073 idParser::Warning( "#pragma directive not supported" );
2074 while( idParser::ReadLine( &token ) ) {
2081 idParser::UnreadSignToken
2084 void idParser::UnreadSignToken( void ) {
2087 token.line = idParser::scriptstack->GetLineNum();
2088 token.whiteSpaceStart_p = NULL;
2089 token.whiteSpaceEnd_p = NULL;
2090 token.linesCrossed = 0;
2093 token.type = TT_PUNCTUATION;
2094 token.subtype = P_SUB;
2095 idParser::UnreadSourceToken( &token );
2100 idParser::Directive_eval
2103 int idParser::Directive_eval( void ) {
2104 signed long int value;
2108 if ( !idParser::Evaluate( &value, NULL, true ) ) {
2112 token.line = idParser::scriptstack->GetLineNum();
2113 token.whiteSpaceStart_p = NULL;
2114 token.whiteSpaceEnd_p = NULL;
2115 token.linesCrossed = 0;
2117 sprintf(buf, "%d", abs(value));
2119 token.type = TT_NUMBER;
2120 token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
2121 idParser::UnreadSourceToken( &token );
2123 idParser::UnreadSignToken();
2130 idParser::Directive_evalfloat
2133 int idParser::Directive_evalfloat( void ) {
2138 if ( !idParser::Evaluate( NULL, &value, false ) ) {
2142 token.line = idParser::scriptstack->GetLineNum();
2143 token.whiteSpaceStart_p = NULL;
2144 token.whiteSpaceEnd_p = NULL;
2145 token.linesCrossed = 0;
2147 sprintf(buf, "%1.2f", idMath::Fabs(value));
2149 token.type = TT_NUMBER;
2150 token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
2151 idParser::UnreadSourceToken( &token );
2153 idParser::UnreadSignToken();
2160 idParser::ReadDirective
2163 int idParser::ReadDirective( void ) {
2166 //read the directive name
2167 if ( !idParser::ReadSourceToken( &token ) ) {
2168 idParser::Error( "found '#' without name" );
2171 //directive name must be on the same line
2172 if (token.linesCrossed > 0) {
2173 idParser::UnreadSourceToken( &token );
2174 idParser::Error( "found '#' at end of line" );
2178 if (token.type == TT_NAME) {
2179 if ( token == "if" ) {
2180 return idParser::Directive_if();
2182 else if ( token == "ifdef" ) {
2183 return idParser::Directive_ifdef();
2185 else if ( token == "ifndef" ) {
2186 return idParser::Directive_ifndef();
2188 else if ( token == "elif" ) {
2189 return idParser::Directive_elif();
2191 else if ( token == "else" ) {
2192 return idParser::Directive_else();
2194 else if ( token == "endif" ) {
2195 return idParser::Directive_endif();
2197 else if (idParser::skip > 0) {
2198 // skip the rest of the line
2199 while( idParser::ReadLine( &token ) ) {
2204 if ( token == "include" ) {
2205 return idParser::Directive_include();
2207 else if ( token == "define" ) {
2208 return idParser::Directive_define();
2210 else if ( token == "undef" ) {
2211 return idParser::Directive_undef();
2213 else if ( token == "line" ) {
2214 return idParser::Directive_line();
2216 else if ( token == "error" ) {
2217 return idParser::Directive_error();
2219 else if ( token == "warning" ) {
2220 return idParser::Directive_warning();
2222 else if ( token == "pragma" ) {
2223 return idParser::Directive_pragma();
2225 else if ( token == "eval" ) {
2226 return idParser::Directive_eval();
2228 else if ( token == "evalfloat" ) {
2229 return idParser::Directive_evalfloat();
2233 idParser::Error( "unknown precompiler directive '%s'", token.c_str() );
2239 idParser::DollarDirective_evalint
2242 int idParser::DollarDirective_evalint( void ) {
2243 signed long int value;
2247 if ( !idParser::DollarEvaluate( &value, NULL, true ) ) {
2251 token.line = idParser::scriptstack->GetLineNum();
2252 token.whiteSpaceStart_p = NULL;
2253 token.whiteSpaceEnd_p = NULL;
2254 token.linesCrossed = 0;
2256 sprintf( buf, "%d", abs( value ) );
2258 token.type = TT_NUMBER;
2259 token.subtype = TT_INTEGER | TT_LONG | TT_DECIMAL | TT_VALUESVALID;
2260 token.intvalue = abs( value );
2261 token.floatvalue = abs( value );
2262 idParser::UnreadSourceToken( &token );
2264 idParser::UnreadSignToken();
2271 idParser::DollarDirective_evalfloat
2274 int idParser::DollarDirective_evalfloat( void ) {
2279 if ( !idParser::DollarEvaluate( NULL, &value, false ) ) {
2283 token.line = idParser::scriptstack->GetLineNum();
2284 token.whiteSpaceStart_p = NULL;
2285 token.whiteSpaceEnd_p = NULL;
2286 token.linesCrossed = 0;
2288 sprintf( buf, "%1.2f", fabs( value ) );
2290 token.type = TT_NUMBER;
2291 token.subtype = TT_FLOAT | TT_LONG | TT_DECIMAL | TT_VALUESVALID;
2292 token.intvalue = (unsigned long) fabs( value );
2293 token.floatvalue = fabs( value );
2294 idParser::UnreadSourceToken( &token );
2296 idParser::UnreadSignToken();
2303 idParser::ReadDollarDirective
2306 int idParser::ReadDollarDirective( void ) {
2309 // read the directive name
2310 if ( !idParser::ReadSourceToken( &token ) ) {
2311 idParser::Error( "found '$' without name" );
2314 // directive name must be on the same line
2315 if ( token.linesCrossed > 0 ) {
2316 idParser::UnreadSourceToken( &token );
2317 idParser::Error( "found '$' at end of line" );
2321 if (token.type == TT_NAME) {
2322 if ( token == "evalint" ) {
2323 return idParser::DollarDirective_evalint();
2325 else if ( token == "evalfloat" ) {
2326 return idParser::DollarDirective_evalfloat();
2329 idParser::UnreadSourceToken( &token );
2338 int idParser::ReadToken( idToken *token ) {
2342 if ( !idParser::ReadSourceToken( token ) ) {
2345 // check for precompiler directives
2346 if ( token->type == TT_PUNCTUATION && (*token)[0] == '#' && (*token)[1] == '\0' ) {
2347 // read the precompiler directive
2348 if ( !idParser::ReadDirective() ) {
2353 // if skipping source because of conditional compilation
2354 if ( idParser::skip ) {
2357 // recursively concatenate strings that are behind each other still resolving defines
2358 if ( token->type == TT_STRING && !(idParser::scriptstack->GetFlags() & LEXFL_NOSTRINGCONCAT) ) {
2360 if ( idParser::ReadToken( &newtoken ) ) {
2361 if ( newtoken.type == TT_STRING ) {
2362 token->Append( newtoken.c_str() );
2365 idParser::UnreadSourceToken( &newtoken );
2370 if ( !(idParser::scriptstack->GetFlags() & LEXFL_NODOLLARPRECOMPILE) ) {
2371 // check for special precompiler directives
2372 if ( token->type == TT_PUNCTUATION && (*token)[0] == '$' && (*token)[1] == '\0' ) {
2373 // read the precompiler directive
2374 if ( idParser::ReadDollarDirective() ) {
2379 // if the token is a name
2380 if ( token->type == TT_NAME && !( token->flags & TOKEN_FL_RECURSIVE_DEFINE ) ) {
2381 // check if the name is a define macro
2382 define = FindHashedDefine( idParser::definehash, token->c_str() );
2383 // if it is a define macro
2385 // expand the defined macro
2386 if ( !idParser::ExpandDefineIntoSource( token, define ) ) {
2399 idParser::ExpectTokenString
2402 int idParser::ExpectTokenString( const char *string ) {
2405 if ( !idParser::ReadToken( &token ) ) {
2406 idParser::Error( "couldn't find expected '%s'", string );
2410 if ( token != string ) {
2411 idParser::Error( "expected '%s' but found '%s'", string, token.c_str() );
2419 idParser::ExpectTokenType
2422 int idParser::ExpectTokenType( int type, int subtype, idToken *token ) {
2425 if ( !idParser::ReadToken( token ) ) {
2426 idParser::Error( "couldn't read expected token" );
2430 if ( token->type != type ) {
2432 case TT_STRING: str = "string"; break;
2433 case TT_LITERAL: str = "literal"; break;
2434 case TT_NUMBER: str = "number"; break;
2435 case TT_NAME: str = "name"; break;
2436 case TT_PUNCTUATION: str = "punctuation"; break;
2437 default: str = "unknown type"; break;
2439 idParser::Error( "expected a %s but found '%s'", str.c_str(), token->c_str() );
2442 if ( token->type == TT_NUMBER ) {
2443 if ( (token->subtype & subtype) != subtype ) {
2445 if ( subtype & TT_DECIMAL ) str = "decimal ";
2446 if ( subtype & TT_HEX ) str = "hex ";
2447 if ( subtype & TT_OCTAL ) str = "octal ";
2448 if ( subtype & TT_BINARY ) str = "binary ";
2449 if ( subtype & TT_UNSIGNED ) str += "unsigned ";
2450 if ( subtype & TT_LONG ) str += "long ";
2451 if ( subtype & TT_FLOAT ) str += "float ";
2452 if ( subtype & TT_INTEGER ) str += "integer ";
2453 str.StripTrailing( ' ' );
2454 idParser::Error( "expected %s but found '%s'", str.c_str(), token->c_str() );
2458 else if ( token->type == TT_PUNCTUATION ) {
2459 if ( subtype < 0 ) {
2460 idParser::Error( "BUG: wrong punctuation subtype" );
2463 if ( token->subtype != subtype ) {
2464 idParser::Error( "expected '%s' but found '%s'", scriptstack->GetPunctuationFromId( subtype ), token->c_str() );
2473 idParser::ExpectAnyToken
2476 int idParser::ExpectAnyToken( idToken *token ) {
2477 if (!idParser::ReadToken( token )) {
2478 idParser::Error( "couldn't read expected token" );
2488 idParser::CheckTokenString
2491 int idParser::CheckTokenString( const char *string ) {
2494 if ( !ReadToken( &tok ) ) {
2497 //if the token is available
2498 if ( tok == string ) {
2502 UnreadSourceToken( &tok );
2508 idParser::CheckTokenType
2511 int idParser::CheckTokenType( int type, int subtype, idToken *token ) {
2514 if ( !ReadToken( &tok ) ) {
2517 //if the type matches
2518 if (tok.type == type && (tok.subtype & subtype) == subtype) {
2523 UnreadSourceToken( &tok );
2529 idParser::PeekTokenString
2532 int idParser::PeekTokenString( const char *string ) {
2535 if ( !ReadToken( &tok ) ) {
2539 UnreadSourceToken( &tok );
2541 // if the token is available
2542 if ( tok == string ) {
2550 idParser::PeekTokenType
2553 int idParser::PeekTokenType( int type, int subtype, idToken *token ) {
2556 if ( !ReadToken( &tok ) ) {
2560 UnreadSourceToken( &tok );
2562 // if the type matches
2563 if ( tok.type == type && ( tok.subtype & subtype ) == subtype ) {
2572 idParser::SkipUntilString
2575 int idParser::SkipUntilString( const char *string ) {
2578 while(idParser::ReadToken( &token )) {
2579 if ( token == string ) {
2588 idParser::SkipRestOfLine
2591 int idParser::SkipRestOfLine( void ) {
2594 while(idParser::ReadToken( &token )) {
2595 if ( token.linesCrossed ) {
2596 idParser::UnreadSourceToken( &token );
2605 idParser::SkipBracedSection
2607 Skips until a matching close brace is found.
2608 Internal brace depths are properly skipped.
2611 int idParser::SkipBracedSection( bool parseFirstBrace ) {
2615 depth = parseFirstBrace ? 0 : 1;
2617 if ( !ReadToken( &token ) ) {
2620 if( token.type == TT_PUNCTUATION ) {
2621 if( token == "{" ) {
2623 } else if ( token == "}" ) {
2633 idParser::ParseBracedSectionExact
2635 The next token should be an open brace.
2636 Parses until a matching close brace is found.
2637 Maintains the exact formating of the braced section
2639 FIXME: what about precompilation ?
2642 const char *idParser::ParseBracedSectionExact( idStr &out, int tabs ) {
2643 return scriptstack->ParseBracedSectionExact( out, tabs );
2648 idParser::ParseBracedSection
2650 The next token should be an open brace.
2651 Parses until a matching close brace is found.
2652 Internal brace depths are properly skipped.
2655 const char *idParser::ParseBracedSection( idStr &out, int tabs ) {
2658 bool doTabs = false;
2664 if ( !idParser::ExpectTokenString( "{" ) ) {
2670 if ( !idParser::ReadToken( &token ) ) {
2671 Error( "missing closing brace" );
2675 // if the token is on a new line
2676 for ( i = 0; i < token.linesCrossed; i++ ) {
2680 if (doTabs && token.linesCrossed) {
2682 if (token[0] == '}' && i > 0) {
2689 if ( token.type == TT_PUNCTUATION ) {
2690 if ( token[0] == '{' ) {
2696 else if ( token[0] == '}' ) {
2704 if ( token.type == TT_STRING ) {
2705 out += "\"" + token + "\"";
2718 idParser::ParseRestOfLine
2720 parse the rest of the line
2723 const char *idParser::ParseRestOfLine( idStr &out ) {
2727 while(idParser::ReadToken( &token )) {
2728 if ( token.linesCrossed ) {
2729 idParser::UnreadSourceToken( &token );
2732 if ( out.Length() ) {
2742 idParser::UnreadToken
2745 void idParser::UnreadToken( idToken *token ) {
2746 idParser::UnreadSourceToken( token );
2751 idParser::ReadTokenOnLine
2754 int idParser::ReadTokenOnLine( idToken *token ) {
2757 if (!idParser::ReadToken( &tok )) {
2760 // if no lines were crossed before this token
2761 if ( !tok.linesCrossed ) {
2766 idParser::UnreadSourceToken( &tok );
2775 int idParser::ParseInt( void ) {
2778 if ( !idParser::ReadToken( &token ) ) {
2779 idParser::Error( "couldn't read expected integer" );
2782 if ( token.type == TT_PUNCTUATION && token == "-" ) {
2783 idParser::ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
2784 return -((signed int) token.GetIntValue());
2786 else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
2787 idParser::Error( "expected integer value, found '%s'", token.c_str() );
2789 return token.GetIntValue();
2797 bool idParser::ParseBool( void ) {
2800 if ( !idParser::ExpectTokenType( TT_NUMBER, 0, &token ) ) {
2801 idParser::Error( "couldn't read expected boolean" );
2804 return ( token.GetIntValue() != 0 );
2809 idParser::ParseFloat
2812 float idParser::ParseFloat( void ) {
2815 if ( !idParser::ReadToken( &token ) ) {
2816 idParser::Error( "couldn't read expected floating point number" );
2819 if ( token.type == TT_PUNCTUATION && token == "-" ) {
2820 idParser::ExpectTokenType( TT_NUMBER, 0, &token );
2821 return -token.GetFloatValue();
2823 else if ( token.type != TT_NUMBER ) {
2824 idParser::Error( "expected float value, found '%s'", token.c_str() );
2826 return token.GetFloatValue();
2831 idParser::Parse1DMatrix
2834 int idParser::Parse1DMatrix( int x, float *m ) {
2837 if ( !idParser::ExpectTokenString( "(" ) ) {
2841 for ( i = 0; i < x; i++ ) {
2842 m[i] = idParser::ParseFloat();
2845 if ( !idParser::ExpectTokenString( ")" ) ) {
2853 idParser::Parse2DMatrix
2856 int idParser::Parse2DMatrix( int y, int x, float *m ) {
2859 if ( !idParser::ExpectTokenString( "(" ) ) {
2863 for ( i = 0; i < y; i++ ) {
2864 if ( !idParser::Parse1DMatrix( x, m + i * x ) ) {
2869 if ( !idParser::ExpectTokenString( ")" ) ) {
2877 idParser::Parse3DMatrix
2880 int idParser::Parse3DMatrix( int z, int y, int x, float *m ) {
2883 if ( !idParser::ExpectTokenString( "(" ) ) {
2887 for ( i = 0 ; i < z; i++ ) {
2888 if ( !idParser::Parse2DMatrix( y, x, m + i * x*y ) ) {
2893 if ( !idParser::ExpectTokenString( ")" ) ) {
2901 idParser::GetLastWhiteSpace
2904 int idParser::GetLastWhiteSpace( idStr &whiteSpace ) const {
2905 if ( scriptstack ) {
2906 scriptstack->GetLastWhiteSpace( whiteSpace );
2910 return whiteSpace.Length();
2918 void idParser::SetMarker( void ) {
2924 idParser::GetStringFromMarker
2926 FIXME: this is very bad code, the script isn't even garrenteed to still be around
2929 void idParser::GetStringFromMarker( idStr& out, bool clean ) {
2933 if ( marker_p == NULL ) {
2934 marker_p = scriptstack->buffer;
2938 p = (char*)tokens->whiteSpaceStart_p;
2940 p = (char*)scriptstack->script_p;
2943 // Set the end character to NULL to give us a complete string
2947 // If cleaning then reparse
2949 idParser temp( marker_p, strlen( marker_p ), "temp", flags );
2951 while ( temp.ReadToken ( &token ) ) {
2958 // restore the character we set to NULL
2964 idParser::SetIncludePath
2967 void idParser::SetIncludePath( const char *path ) {
2968 idParser::includepath = path;
2969 // add trailing path seperator
2970 if (idParser::includepath[idParser::includepath.Length()-1] != '\\' &&
2971 idParser::includepath[idParser::includepath.Length()-1] != '/') {
2972 idParser::includepath += PATHSEPERATOR_STR;
2978 idParser::SetPunctuations
2981 void idParser::SetPunctuations( const punctuation_t *p ) {
2982 idParser::punctuations = p;
2990 void idParser::SetFlags( int flags ) {
2993 idParser::flags = flags;
2994 for ( s = idParser::scriptstack; s; s = s->next ) {
2995 s->SetFlags( flags );
3004 int idParser::GetFlags( void ) const {
3005 return idParser::flags;
3013 int idParser::LoadFile( const char *filename, bool OSPath ) {
3016 if ( idParser::loaded ) {
3017 idLib::common->FatalError("idParser::loadFile: another source already loaded");
3020 script = new idLexer( filename, 0, OSPath );
3021 if ( !script->IsLoaded() ) {
3025 script->SetFlags( idParser::flags );
3026 script->SetPunctuations( idParser::punctuations );
3027 script->next = NULL;
3028 idParser::OSPath = OSPath;
3029 idParser::filename = filename;
3030 idParser::scriptstack = script;
3031 idParser::tokens = NULL;
3032 idParser::indentstack = NULL;
3034 idParser::loaded = true;
3036 if ( !idParser::definehash ) {
3037 idParser::defines = NULL;
3038 idParser::definehash = (define_t **) Mem_ClearedAlloc( DEFINEHASHSIZE * sizeof(define_t *) );
3039 idParser::AddGlobalDefinesToSource();
3046 idParser::LoadMemory
3049 int idParser::LoadMemory(const char *ptr, int length, const char *name ) {
3052 if ( idParser::loaded ) {
3053 idLib::common->FatalError("idParser::loadMemory: another source already loaded");
3056 script = new idLexer( ptr, length, name );
3057 if ( !script->IsLoaded() ) {
3061 script->SetFlags( idParser::flags );
3062 script->SetPunctuations( idParser::punctuations );
3063 script->next = NULL;
3064 idParser::filename = name;
3065 idParser::scriptstack = script;
3066 idParser::tokens = NULL;
3067 idParser::indentstack = NULL;
3069 idParser::loaded = true;
3071 if ( !idParser::definehash ) {
3072 idParser::defines = NULL;
3073 idParser::definehash = (define_t **) Mem_ClearedAlloc( DEFINEHASHSIZE * sizeof(define_t *) );
3074 idParser::AddGlobalDefinesToSource();
3081 idParser::FreeSource
3084 void idParser::FreeSource( bool keepDefines ) {
3091 // free all the scripts
3092 while( scriptstack ) {
3093 script = scriptstack;
3094 scriptstack = scriptstack->next;
3097 // free all the tokens
3100 tokens = tokens->next;
3104 while( indentstack ) {
3105 indent = indentstack;
3106 indentstack = indentstack->next;
3109 if ( !keepDefines ) {
3113 for ( i = 0; i < DEFINEHASHSIZE; i++ ) {
3114 while( definehash[i] ) {
3115 define = definehash[i];
3116 definehash[i] = definehash[i]->hashnext;
3121 Mem_Free( idParser::definehash );
3130 idParser::GetPunctuationFromId
3133 const char *idParser::GetPunctuationFromId( int id ) {
3136 if ( !idParser::punctuations ) {
3138 return lex.GetPunctuationFromId( id );
3141 for (i = 0; idParser::punctuations[i].p; i++) {
3142 if ( idParser::punctuations[i].n == id ) {
3143 return idParser::punctuations[i].p;
3146 return "unkown punctuation";
3151 idParser::GetPunctuationId
3154 int idParser::GetPunctuationId( const char *p ) {
3157 if ( !idParser::punctuations ) {
3159 return lex.GetPunctuationId( p );
3162 for (i = 0; idParser::punctuations[i].p; i++) {
3163 if ( !strcmp(idParser::punctuations[i].p, p) ) {
3164 return idParser::punctuations[i].n;
3175 idParser::idParser() {
3176 this->loaded = false;
3177 this->OSPath = false;
3178 this->punctuations = 0;
3180 this->scriptstack = NULL;
3181 this->indentstack = NULL;
3182 this->definehash = NULL;
3183 this->defines = NULL;
3184 this->tokens = NULL;
3185 this->marker_p = NULL;
3193 idParser::idParser( int flags ) {
3194 this->loaded = false;
3195 this->OSPath = false;
3196 this->punctuations = 0;
3197 this->flags = flags;
3198 this->scriptstack = NULL;
3199 this->indentstack = NULL;
3200 this->definehash = NULL;
3201 this->defines = NULL;
3202 this->tokens = NULL;
3203 this->marker_p = NULL;
3211 idParser::idParser( const char *filename, int flags, bool OSPath ) {
3212 this->loaded = false;
3213 this->OSPath = true;
3214 this->punctuations = 0;
3215 this->flags = flags;
3216 this->scriptstack = NULL;
3217 this->indentstack = NULL;
3218 this->definehash = NULL;
3219 this->defines = NULL;
3220 this->tokens = NULL;
3221 this->marker_p = NULL;
3222 LoadFile( filename, OSPath );
3230 idParser::idParser( const char *ptr, int length, const char *name, int flags ) {
3231 this->loaded = false;
3232 this->OSPath = false;
3233 this->punctuations = 0;
3234 this->flags = flags;
3235 this->scriptstack = NULL;
3236 this->indentstack = NULL;
3237 this->definehash = NULL;
3238 this->defines = NULL;
3239 this->tokens = NULL;
3240 this->marker_p = NULL;
3241 LoadMemory( ptr, length, name );
3249 idParser::~idParser( void ) {
3250 idParser::FreeSource( false );