00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <vector>
00019 #include <SDL_image.h>
00020 #include <algorithm>
00021 #include "ascstring.h"
00022 #include "textfileparser.h"
00023 #include "stringtokenizer.h"
00024 #include "textfile_evaluation.h"
00025
00026
00027 const int TextFormatParser::operationsNum = 6;
00028 const char* TextFormatParser::operations[6] = { "=", "*=", "+=", "->", "->*", "-=" };
00029 const char* TextFormatParser::whiteSpace = " \t";
00030
00031
00032
00033
00034 ASCString TextPropertyGroup::Entry::toString() const
00035 {
00036 Operator o = op;
00037 if ( o == alias_all_resolved )
00038 o = alias_all;
00039
00040 ASCString s = propertyName + TextFormatParser::operations[o] + value ;
00041 return s;
00042 }
00043
00044 void TextPropertyList::buildIDs()
00045 {
00046 for ( iterator i = begin(); i != end(); i++ ) {
00047 int id = (*i)->evalID();
00048 if ( id > 0 ) {
00049
00050 if ( identCache.find ( id ) != identCache.end() )
00051 fatalError("Duplicate ID in text file group " + (*i)->typeName + ": " + (*i)->location + " and " + identCache.find ( id )->second->location + " both have ID " + strrr(id ) + "\n\nThis is NOT a bug in ASC, this is a conflict between two data files.");
00052
00053 identCache[id] = *i;
00054 }
00055 }
00056 }
00057
00058 TextPropertyGroup* TextPropertyList::get ( int id )
00059 {
00060 IdentCache::iterator f = identCache.find ( id );
00061 if ( f != identCache.end() )
00062 return &(*(f->second));
00063 else
00064 return NULL;
00065 }
00066
00067
00069
00070
00071 void TextPropertyGroup :: error ( const ASCString& msg, bool printInheritance )
00072 {
00073 ASCString message = "Error evaluating file " + location + "\n" + msg;
00074 if ( printInheritance )
00075 message += "\nThe inheritance is\n" + listInheritanceFilenames() ;
00076
00077 fatalError ( message );
00078 }
00079
00080 void TextPropertyGroup :: print( int indent )
00081 {
00082 for ( Entries::iterator i = entries.begin(); i != entries.end(); i++ ) {
00083 for ( int m = 0; m<= indent; m++ )
00084 displayLogMessage(10, " " );
00085
00086 displayLogMessage(10, i->toString());
00087 displayLogMessage(10, "\n");
00088 }
00089
00090 for ( Parents::iterator i = parents.begin(); i != parents.end(); i++ ) {
00091 for ( int n = 0; n< indent; n++ )
00092 printf(" " );
00093 displayLogMessage(10, " is inheriting from " + (*i)->location + "\n" );
00094 (*i)->print(indent+1 );
00095 }
00096 }
00097
00098
00099 void TextPropertyGroup :: buildInheritance(TextPropertyList& tpl )
00100 {
00101 static list<TextPropertyGroup*> callStack;
00102
00103 if ( !inheritanceBuild ) {
00104 if ( std::find ( callStack.begin(), callStack.end(), this ) != callStack.end() )
00105 error ( "endless inheritance loop detected: type " + typeName + "; ID " + strrr ( id ), false);
00106
00107 callStack.push_back( this );
00108
00109 PropertyReadingContainer prc ( typeName, this );
00110 prc.addBool ( "abstract", abstract, false );
00111 int iid;
00112 prc.addInteger("ID", iid, 0 );
00113
00114 if ( find ( typeName+".parent") != NULL ) {
00115 typedef vector<int> ParentIDs;
00116 ParentIDs parentIDs;
00117 prc.addIntegerArray ( "parent", parentIDs );
00118 for ( ParentIDs::iterator i = parentIDs.begin(); i != parentIDs.end(); i++ ) {
00119 TextPropertyGroup* p = tpl.get ( *i );
00120 if ( p ) {
00121 parents.push_back ( p );
00122 displayLogMessage( 10, ASCString(" entering parent with ID ") + strrr(*i) + " ("+p->location+")\n" );
00123 p->buildInheritance( tpl );
00124 displayLogMessage( 10, ASCString(" leaving parent with ID ") + strrr(*i) + "\n" );
00125 } else
00126 error ( location + " : no parent with ID " + strrr(*i) + " of type " + typeName + " could be found !" );
00127 }
00128 }
00129
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 resolveAllAlias();
00148
00149 callStack.pop_back();
00150 inheritanceBuild = true;
00151 }
00152 }
00153
00154 ASCString TextPropertyGroup :: listInheritanceFilenames()
00155 {
00156 ASCString s;
00157 for ( Parents::iterator p = parents.begin(); p != parents.end(); p++ )
00158 s += (*p)->listInheritanceFilenames();
00159 s += location + "\n";
00160 return s;
00161 }
00162
00163 void TextPropertyGroup :: resolveAllAlias( )
00164 {
00165 int loop = 0;
00166 typedef list<Entry*> Unresolved;
00167 Unresolved unresolved;
00168 do {
00169 Entries additionalEntries;
00170 int resolvedCounter = 0;
00171 EntryPointerList toResolve;
00172
00173 if ( loop == 0 ) {
00174 for ( Entries::iterator i = entries.begin(); i != entries.end(); i++ ) {
00175 bool resolved = processAlias ( *i , additionalEntries, toResolve );
00176 if ( !resolved )
00177 unresolved.push_back ( &(*i) );
00178 else
00179 resolvedCounter++;
00180 }
00181 } else {
00182 Unresolved newunresolved;
00183 for ( Unresolved::iterator i = unresolved.begin(); i != unresolved.end(); i++ ) {
00184 bool resolved = processAlias ( **i , additionalEntries, toResolve );
00185 if ( !resolved )
00186 newunresolved.push_back ( *i );
00187 else
00188 resolvedCounter++;
00189 }
00190 unresolved = newunresolved;
00191 }
00192
00193 for ( Entries::iterator i = additionalEntries.begin(); i != additionalEntries.end(); i++ )
00194
00195 addEntry ( *i );
00196
00197 for ( EntryPointerList::iterator i = toResolve.begin(); i != toResolve.end(); i++ )
00198 (*i)->op = Entry::alias_all_resolved;
00199
00200 if ( !resolvedCounter && !unresolved.empty() )
00201 for ( Unresolved::iterator i = unresolved.begin(); i != unresolved.end(); i++ ) {
00202 error ( "could not resolve the reference for " + typeName + " :: " + (*i)->propertyName + " with operand " + (*i)->value + "\nSee STDOUT for a dump of current item" );
00203 print();
00204 }
00205
00206 loop++;
00207 } while ( !unresolved.empty() );
00208 }
00209
00210 bool reallyVerbose = false;
00211
00212 int TextPropertyGroup::findGeneration ( Entry* e )
00213 {
00214 for ( Entries::iterator i = entries.begin(); i != entries.end(); i++ )
00215 if ( &(*i) == e )
00216 return 0;
00217
00218 for ( Parents::iterator i = parents.begin(); i != parents.end(); i++ ) {
00219 int fg = (*i)->findGeneration( e );
00220 if ( fg >= 0 )
00221 return fg+1;
00222 }
00223 return -1;
00224 }
00225
00226
00227 bool TextPropertyGroup::processAlias( Entry& e, Entries& entriesToAdd, EntryPointerList& markAsResolved )
00228 {
00229 if ( e.op == Entry::alias_all ) {
00230 ASCString ss = e.value;
00231 ss.toLower();
00232 ASCString::size_type pos;
00233 do {
00234 pos = ss.find ( " " );
00235 if ( pos != ss.npos )
00236 ss.erase(pos,1);
00237 } while ( pos != ss.npos );
00238
00239 ASCString s_without_dot = ss;
00240 if ( ss.length() > 0 )
00241 if ( ss[ss.length()-1] != '.' )
00242 ss = ss + ".";
00243
00244 if ( s_without_dot.length() > 0 )
00245 if ( s_without_dot[s_without_dot.length()-1] == '.' )
00246 s_without_dot.erase ( s_without_dot.length()-1 );
00247
00248 ASCString newName = e.propertyName;
00249 if ( newName.length() > 0 )
00250 if ( newName[newName.length()-1] != '.' )
00251 newName = newName + ".";
00252
00253 int counter = 0;
00254 Matches matches;
00255
00256
00257 findMatches ( ss, s_without_dot, matches );
00258
00259 for ( Matches::iterator i = matches.begin(); i != matches.end(); i++ )
00260 if ( (*i)->op == Entry::alias_all ) {
00261 displayLogMessage ( 9, " alias is pending " + ss + "* <- " + e.propertyName + " because " + (*i)->propertyName + " is unresolved\n" );
00262 return false;
00263 }
00264
00265 for ( Matches::iterator i = matches.begin(); i != matches.end(); i++ )
00266 if ( (*i)->op != Entry::alias_all_resolved ) {
00267 Entry e = **i;
00268 e.propertyName.replace ( 0, ss.length(), newName );
00269 TextPropertyGroup::Entry* existent = find ( e.propertyName );
00270
00271 if ( existent == NULL || findGeneration( existent ) > 0 ) {
00272
00273
00274
00275
00276 entriesToAdd.push_back ( e );
00277 displayLogMessage(10, " aliasing entry " + (*i)->toString() + " to " + e.propertyName + " \n" );
00278 }
00279 counter++;
00280 } else
00281 displayLogMessage(10, " skipping aliasing entry " + (*i)->toString() + " to " + e.propertyName + " because it is already resolved\n" );
00282
00283 if ( !counter ) {
00284 displayLogMessage ( 9, " could not successfully resolve alias " + ss + "* <- " + e.propertyName + "\n" );
00285 return false;
00286 } else {
00287 markAsResolved.push_back ( &e );
00288 displayLogMessage ( 9, " successfully resolved alias " + e.propertyName + " ->* " + ss + "\n" );
00289 return true;
00290 }
00291 }
00292
00293 if ( e.op == Entry::alias ) {
00294 ASCString s = e.value;
00295 s.toLower();
00296 ASCString::size_type pos;
00297 do {
00298 pos = s.find ( " " );
00299 if ( pos != s.npos )
00300 s.erase(pos,1);
00301 } while ( pos != s.npos );
00302 Entry* alias = find ( s );
00303 if ( !alias )
00304 return false;
00305 else {
00306 e.value = alias->value;
00307 e.op = alias->op;
00308 e.parent = alias->parent;
00309 return true;
00310 }
00311 }
00312
00314 if ( e.op != Entry::eq && e.op != Entry::alias_all && e.op != Entry::alias && e.op != Entry::alias_all_resolved ) {
00315 Parents::iterator p = parents.begin();
00316 while ( p != parents.end() ) {
00317 e.parent = (*p)->find( e.propertyName );
00318 if ( e.parent )
00319 break;
00320 p++;
00321 }
00322 if ( p == parents.end())
00323 return false;
00324 else
00325 return true;
00326 }
00327
00328
00329 return true;
00330 }
00331
00332
00333 int TextPropertyGroup :: evalID()
00334 {
00335 PropertyReadingContainer prc ( typeName, this );
00336 prc.addInteger ( "ID", id, 0 );
00337 return id;
00338 }
00339
00340
00341
00342
00343 TextPropertyGroup::Entry* TextPropertyGroup :: find( const ASCString& n )
00344 {
00345 EntryCache::iterator i = entryCache.find ( n );
00346 if ( i != entryCache.end() )
00347 return i->second;
00348 else {
00349 for ( Parents::iterator p = parents.begin(); p != parents.end(); p++ ) {
00350 TextPropertyGroup::Entry* ent = (*p)->find ( n );
00351 if ( ent )
00352 return ent;
00353 }
00354 return NULL;
00355 }
00356 }
00357
00358 void TextPropertyGroup::findMatches( const ASCString& name, const ASCString& name_without_dot, Matches& matches )
00359 {
00360 for ( Entries::iterator i = entries.begin(); i != entries.end(); i++ )
00361 if ( i->propertyName.find ( name ) == 0 || i->propertyName == name_without_dot )
00362 matches.push_back ( &(*i) );
00363
00364 for ( Parents::iterator p = parents.begin(); p != parents.end(); p++ )
00365 (*p)->findMatches ( name, name_without_dot, matches );
00366 }
00367
00368
00369 void TextPropertyGroup::addEntry( const Entry& entry )
00370 {
00371 entries.push_back ( entry );
00372 entryCache[entry.propertyName] = &entries.back();
00373 }
00374
00375
00376
00378
00379 ASCString TextFormatParser::readLine ( )
00380 {
00381 ASCString s;
00382 int noCommentLines = 0;
00383 int bracketsOpen = 0;
00384 do {
00385 ASCString t = stream->readString();
00386 ASCString::size_type pos = t.find_first_not_of ( whiteSpace );
00387 if ( pos != ASCString::npos ) {
00388 if ( t[pos] != ';' ) {
00389 noCommentLines++;
00390 if ( !s.empty() )
00391 s += " ";
00392
00393 s += t.substr ( pos );
00394
00395 if ( t.find ( "[" ) != t.npos )
00396 bracketsOpen++;
00397
00398 if ( t.find ( "]" ) != t.npos )
00399 bracketsOpen--;
00400 }
00401 } else {
00402
00403 if ( bracketsOpen )
00404 s += "\n";
00405 }
00406
00407 } while ( noCommentLines == 0 || bracketsOpen > 0 );
00408
00409 ASCString::size_type pos = s.find ( "[" );
00410 if ( pos != s.npos )
00411 s.erase ( pos, 1 );
00412
00413 pos = s.rfind ( "]" );
00414 if ( pos != s.npos )
00415 s.erase ( pos, 1 );
00416
00417 return s;
00418 }
00419
00420
00421
00422 void TextFormatParser::parseLine ( const ASCString& line )
00423 {
00424
00425 StringTokenizer st ( line );
00426 s1 = st.getNextToken();
00427 s2 = st.getNextToken();
00428 s3 = st.getRemaining();
00429
00430 int op = -1;
00431 for ( int i = 0; i < operationsNum; i++ )
00432 if ( s2 == operations[i] )
00433 op = i;
00434
00435 if ( op != -1 ) {
00436
00437
00438
00439
00440
00441 ASCString s;
00442 for ( Level::iterator i = level.begin(); i != level.end(); i++ )
00443 s += *i + ".";
00444 s += s1;
00445 textPropertyGroup->addEntry ( TextPropertyGroup::Entry (s, TextPropertyGroup::Entry::Operator(op), s3 ) );
00446 return;
00447 }
00448
00449 if ( !s1.empty() && s2 == "{" ) {
00450 s1.toLower();
00451 startLevel ( s1 );
00452 return;
00453 }
00454
00455 if ( s1 == "}" ) {
00456 if ( level.empty() )
00457 error ("closing unopened bracket");
00458
00459 s2.toLower();
00460 if ( s2 != level.back() )
00461 error ( "unmatching close brackets: " + s2 );
00462
00463 level.pop_back();
00464 levelDepth--;
00465 return;
00466 }
00467 error ( "unknown operator in entry " + line + "\n token1: " + s1 + " ; token2: " + s2 + " ; token3: " + s3 );
00468 }
00469
00470
00471 void TextFormatParser::startLevel ( const ASCString& levelName )
00472 {
00473
00474 if ( levelDepth == 0 ) {
00475 if ( !primaryName.empty() )
00476 if ( levelName.compare_ci ( primaryName ) )
00477 error ( "expecting group " + primaryName + " , found " + levelName );
00478 textPropertyGroup->typeName = levelName;
00479 textPropertyGroup->typeName.toLower();
00480 }
00481
00482 int curlevel = ++levelDepth;
00483 level.push_back ( levelName );
00484
00485 do {
00486 parseLine ( readLine() );
00487 } while ( levelDepth >= curlevel );
00488 }
00489
00490
00491 TextPropertyGroup* TextFormatParser::run ( )
00492 {
00493 textPropertyGroup = new TextPropertyGroup ;
00494 textPropertyGroup->fileName = stream->getDeviceName();
00495 textPropertyGroup->location = stream->getLocation();
00496 parseLine ( readLine() );
00497 return textPropertyGroup;
00498 }
00499
00500 void TextFormatParser::error ( const ASCString& errmsg )
00501 {
00502 ASCString msg;
00503 if ( stream )
00504 msg = stream->getLocation() + " : " + errmsg;
00505 else
00506 msg = " : " + errmsg ;
00507
00508 displayLogMessage ( 0, msg + "\n" );
00509
00510 throw ParsingError ( msg );
00511 }
00512
00513
00514
00515
00516
00517