Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

textfileparser.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           textfileparser.cpp  -  description
00003                              -------------------
00004     begin                : Thu Jul 26 2001
00005     copyright            : (C) 2001 by Martin Bickel
00006     email                : bickel@asc-hq.org
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
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       for ( Entries::iterator i = entries.begin(); i != entries.end(); i++ ) {
00133          if ( i->op != Entry::eq && i->op != Entry::alias_all && i->op != Entry::alias) {
00134             Parents::iterator p = parents.begin();
00135             while ( p != parents.end() ) {
00136                i->parent = (*p)->find( i->propertyName );
00137                if ( i->parent )
00138                   break;
00139                p++;
00140             }
00141             if ( p == parents.end())
00142                error ( "could not find a parent entry for " + typeName + " :: " + i->propertyName  );
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          // if ( find ( i->propertyName ) == NULL )
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             // if ( existent == NULL || findGeneration(*i) <= findGeneration( existent ) ) {
00271             if ( existent == NULL || findGeneration( existent ) > 0 ) {
00272                /* if ( existent && findGeneration( existent ) == 0 ) {
00273                   displayLogMessage(10, "    overwriting entry " + existent->toString() + " because it belongs to an older generation\n" );
00274                   *existent = e;
00275                } else */
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          // empty line
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       if ( s3.empty() )
00438          error ( "missing data after operand");
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 

Generated on Tue Jun 24 01:27:53 2008 for Advanced Strategic Command by  doxygen 1.4.2