Gaudi Framework, version v20r3

Generated: 24 Nov 2008

Parser.cpp

Go to the documentation of this file.
00001 // $Id: Parser.cpp,v 1.11 2007/12/06 15:14:21 marcocle Exp $
00002 // ============================================================================
00003 // Include files
00004 // ============================================================================
00005 // STD & STL 
00006 // ============================================================================
00007 #include <iostream>
00008 // ============================================================================
00009 // Boost
00010 // ============================================================================
00011 #include <boost/filesystem/operations.hpp>
00012 #include <boost/format.hpp>
00013 #include <boost/algorithm/string.hpp>
00014 // ============================================================================
00015 // GaudiKernel
00016 // ============================================================================
00017 #include <GaudiKernel/SystemOfUnits.h>
00018 // ============================================================================
00019 // local 
00020 // ============================================================================
00021 #include "ParserUtils.h"
00022 #include "ParserGrammar.h"
00023 // ============================================================================
00024 // local namespaces:
00025 // ============================================================================
00026 namespace fs = boost::filesystem;
00027 namespace ba = boost::algorithm;
00028 // ============================================================================
00029 namespace 
00030 {
00031   const std::string GPP_COMMENT = "//GP:" ;
00032 }
00033 // ============================================================================
00034 Gaudi::Parsers::Parser::Parser
00035 ( Catalogue&                catalogue , 
00036   std::vector<std::string>& included  , 
00037   std::ostream&             m         )
00038   : m_isPrint(true)
00039   , m_isPrintOptions(false)
00040   , m_catalogue(catalogue)
00041   , m_included(included)
00042   , m_stream ( m )
00043 {
00044   m_searchPath = Gaudi::Parsers::Utils::extractPath("$JOBOPTSEARCHPATH");
00045   initUnits();
00046 }
00047 // ============================================================================
00048 Gaudi::Parsers::Parser::Parser
00049 ( Catalogue&                      catalogue  , 
00050   std::vector<std::string>&       included   ,  
00051   const std::vector<std::string>& searchPath , 
00052   std::ostream&                   m          )
00053   : m_isPrint(true)
00054   , m_isPrintOptions(false)
00055   , m_catalogue(catalogue)
00056   , m_included(included)
00057   , m_stream ( m )
00058 {
00059   m_searchPath = searchPath;
00060   initUnits();
00061 }
00062 // ============================================================================
00063 Gaudi::Parsers::Parser::Parser 
00064 ( Catalogue&                catalogue  ,  
00065   std::vector<std::string>& included   ,  
00066   const std::string&        searchPath , 
00067   std::ostream&             m          )
00068   : m_isPrint(true)
00069   , m_isPrintOptions(false)
00070   , m_catalogue(catalogue)
00071   , m_included(included)
00072   , m_stream ( m )
00073 {
00074   m_searchPath = Gaudi::Parsers::Utils::extractPath(searchPath);
00075   initUnits();
00076 }
00077 // ============================================================================
00078 StatusCode Gaudi::Parsers::Parser::parse ( const std::string& fileName )
00079 {
00080   m_stream << GPP_COMMENT + std::string(80,'=') << std::endl;
00081   parseFile(fileName,Position()).ignore();
00082   resolveReferences();
00083   if ( m_isPrintOptions ){ printOptions(); }
00084   m_stream << GPP_COMMENT + std::string(80,'=') << std::endl;
00085   return errorsCount()==0?StatusCode::SUCCESS:StatusCode::FAILURE;
00086 }
00087 // ============================================================================
00088 int Gaudi::Parsers::Parser::errorsCount()
00089 {
00090         int result=0;
00091         for ( MessagesStoreT::const_iterator cur=m_messages.begin();
00092         cur!=m_messages.end() ; ++cur)
00093   { if ( cur->severity() == Message::E_ERROR){ ++result; } }
00094         return result;
00095 }
00096 // ============================================================================
00097 void Gaudi::Parsers::Parser::matchInclude
00098 (const std::string& fileName,const Position& pos)
00099 { parseFile(fileName,pos).ignore(); }
00100 // ============================================================================
00101 void Gaudi::Parsers::Parser::matchUnits
00102 (const std::string& fileName,const Position& pos)
00103 { parseFile(fileName,pos,true).ignore(); }
00104 
00105 // ============================================================================
00106 long double Gaudi::Parsers::Parser::matchUnit
00107 ( const std::string& unit, 
00108   const Position& pos)
00109 {
00110   UnitsStoreT::const_iterator u = m_units.find(unit);
00111   if ( u==m_units.end())
00112   {
00113     addMessage
00114       ( Message::E_ERROR ,
00115         Message::C_UNITNOTFOUND,
00116         boost::str(boost::format("Cann't find unit \"%1%\"")%unit),pos);
00117     return 1;      
00118   }
00119   return u->second;
00120 }
00121 // ============================================================================
00122 void Gaudi::Parsers::Parser::matchUnitEntry
00123 ( const std::string& newUnit , 
00124   double value,
00125   const Position& pos)
00126 {
00127   if(isPrint())
00128   {
00129     m_stream 
00130       << boost::format("%4% %2%  = %3%; %|78t|%1%") 
00131       % posString(pos.line(), pos.column()) 
00132       % newUnit 
00133       % value 
00134       % GPP_COMMENT 
00135       << std::endl ;
00136   }
00137   m_units[newUnit] = value ;
00138 }
00139 // ============================================================================
00140 void Gaudi::Parsers::Parser::matchAssign
00141 ( const std::string& objName  ,
00142   const std::string& propName , 
00143   const Sign& oper,
00144   const std::vector<std::string>& vectorValue,
00145   const Position& pos,bool isVector)
00146 {
00147   // --------------------------------------------------------------------------
00148   if(isPrint())
00149   {
00150     m_stream 
00151       << boost::format("%2% %3% %4%;%|72t|%5% %1%") 
00152       % posString(pos.line(),pos.column()) 
00153       % (objName+"."+propName) 
00154       % sign(oper) 
00155       % valueToString(vectorValue , isVector) 
00156       % GPP_COMMENT 
00157       << std::endl ;
00158   }
00159   // --------------------------------------------------------------------------
00160   // --------------------------------------------------------------------------
00161   if (oper == S_ASSIGN)
00162   {
00163     // ------------------------------------------------------------------------
00164     PropertyEntry* assignProp;
00165     if(isVector){
00166       assignProp = new PropertyEntry(propName,vectorValue,pos);
00167     }else{
00168       assignProp = new PropertyEntry(propName,vectorValue[0],pos);
00169     }
00170     m_catalogue.addProperty(objName,*assignProp);
00171     delete assignProp;
00172     // ------------------------------------------------------------------------
00173   }
00174   else
00175   {
00176     // += or -=
00177     // ------------------------------------------------------------------------
00178     PropertyEntry foundProp;
00179     StatusCode ok;
00180     ok = m_catalogue.findProperty(objName,propName,foundProp);
00181     if (ok.isFailure())
00182     {
00183       foundProp = PropertyEntry(propName,std::vector<std::string>());
00184     }
00185     if(oper == S_PLUSASSIGN)
00186     {
00187       ok = foundProp.addValues(vectorValue);
00188       if(ok.isFailure()){
00189         addMessage
00190           ( Message::E_ERROR, 
00191             Message::C_CANNOTADDTONOTVECTOR,
00192             boost::str
00193             ( boost::format
00194               ("Cannot add values to not vector property \"%1%.%2%\"")
00195               %  objName % propName),pos);
00196         return;
00197       }
00198       m_catalogue.addProperty(objName,foundProp);
00199     }
00200     // ------------------------------------------------------------------------
00201     if(oper == S_MINUSASSIGN)
00202     {
00203       int count=0;
00204       ok = foundProp.removeValues(vectorValue,count);
00205       if(ok.isFailure()){
00206         addMessage
00207           ( Message::E_ERROR, 
00208             Message::C_CANNOTREMOVEFROMNOTVECTOR,
00209             boost::str
00210             ( boost::format
00211               ( "Cannot remove values from not vector property \"%1%.%2%\"" ) 
00212               %  objName % propName),pos);
00213         return;
00214       }
00215       // ----------------------------------------------------------------------
00216       if (count == 0)
00217       {
00218         addMessage
00219           ( Message::E_WARNING, 
00220             Message::C_ZEROREMOVED,
00221             boost::str
00222             ( boost::format
00223               ( "Nothing removed from property \"%1%.%2%\"" ) 
00224               %  objName % propName),pos);   
00225       }
00226       else
00227       {
00228         m_catalogue.addProperty(objName,foundProp);
00229       }
00230       
00231     } 
00232     // ------------------------------------------------------------------------
00233   }
00234 }
00235 // ============================================================================
00236 void Gaudi::Parsers::Parser::setIsPrint
00237 ( bool on , const Gaudi::Parsers::Position& pos)
00238 {
00239   // ignore the printout if the full print is activated  
00240   if ( on && m_isPrintOptions ) { return ; }
00241   m_isPrint = on;
00242   m_stream 
00243     << boost::format("%3% printing is %2% %|78t|%1%") 
00244     % posString(pos.line(),pos.column()) 
00245     % (on?"ON":"OFF") 
00246     % GPP_COMMENT 
00247     << std::endl ;
00248 }
00249 // ============================================================================
00250 void Gaudi::Parsers::Parser::setIsPrintOptions
00251 ( bool on , const Position& pos)
00252 {
00253   m_isPrintOptions = on;
00254   m_stream 
00255     << boost::format ("%3% printing options is %2% %|78t|%1%") 
00256     % posString(pos.line(),pos.column()) 
00257     % (on?"ON":"OFF") 
00258     % GPP_COMMENT 
00259     << std::endl ;
00260   // deactivate the printout if the print of all options is activated 
00261   if ( m_isPrintOptions && m_isPrint ) { setIsPrint ( false , pos ) ; }
00262 }
00263 // ============================================================================
00264 void Gaudi::Parsers::Parser::initUnits()
00265 {
00266   m_units[ "mm"   ] = Gaudi::Units::mm  ;
00267   m_units[ "cm"   ] = Gaudi::Units::cm  ;
00268   m_units[ "cm2"  ] = Gaudi::Units::cm2 ;
00269   m_units[ "m"    ] = Gaudi::Units::m   ;
00270   m_units[ "m2"   ] = Gaudi::Units::m2  ;
00271   //
00272   m_units[ "ns"   ] = Gaudi::Units::nanosecond ;
00273   m_units[ "ps"   ] = Gaudi::Units::picosecond ;
00274   m_units[ "fs"   ] = Gaudi::Units::picosecond * 0.001 ;
00275   //
00276   m_units[ "MeV"  ] = Gaudi::Units::MeV ;
00277   m_units[ "GeV"  ] = Gaudi::Units::GeV ;
00278   m_units[ "keV"  ] = Gaudi::Units::keV ;
00279 }
00280 // ============================================================================
00281 StatusCode Gaudi::Parsers::Parser::parseFile
00282 ( const std::string& fileName ,
00283   const Position& pos,
00284   bool isUnitsFile)
00285 {
00286   StatusCode  ok;  
00287   std::vector<std::string> sp = m_searchPath;
00288   if(pos.fileName().length()>0){
00289     // Add current file directory to search path
00290     sp.insert(sp.begin(),
00291               fs::path(pos.fileName(),fs::native).branch_path()
00292               .native_directory_string());
00293   }
00294   std::string fileToParse;
00295   ok = Gaudi::Parsers::Utils::searchFile(fileName,true,sp,fileToParse);
00296   if(ok.isFailure()){
00297     addMessage( Message::E_ERROR, Message::C_FILENOTFOUND,
00298                boost::str(boost::format("Couldn't find file \"%1%\"") % fileName),pos);
00299     return StatusCode::FAILURE;
00300   }
00301   
00302   ok = isIncluded(fileToParse);
00303   if(ok.isSuccess())
00304   {
00305     const std::string _msg = 
00306       ( boost::format("Skip already included file  \"%1%\"") % fileToParse ).str() ;
00307     addMessage ( Message::E_WARNING , Message::C_OK , _msg , pos ) ;
00308     if ( isPrint() ) 
00309     { 
00310       m_stream 
00311         << boost::format("%3% skip already included file  \"%2%\" %|78t|%1%") 
00312         % posString(pos.line(), pos.column()) 
00313         % fileToParse 
00314         % GPP_COMMENT
00315         << std::endl ; 
00316     }
00317     return StatusCode::SUCCESS;
00318   }
00319   std::string input;
00320   ok = Gaudi::Parsers::Utils::readFile(fileToParse,input);
00321   if(ok.isFailure())
00322   {
00323     addMessage
00324       ( Message::E_ERROR, Message::C_FILENOTOPENED,
00325        boost::str
00326        (boost::format("Couldn't open file \"%1%\"") % fileToParse),pos);
00327     return StatusCode::FAILURE;
00328   }  
00329   m_included.push_back(fileToParse);
00330   
00331   
00332   IteratorT beginpos(input.begin(), input.end(), fileToParse);
00333   IteratorT endpos;
00334   
00335   boost::spirit::parse_info<IteratorT> info; 
00336   SkipperGrammar grSkipper;      
00337   
00338   if(!isUnitsFile){
00339     m_stream 
00340       << boost::format("%3% include \"%2%\" %|78t|%1%") 
00341       % posString(pos.line(), pos.column()) 
00342       % fileToParse 
00343       % GPP_COMMENT 
00344       << std::endl ;
00345     ParserGrammar grParser(this);
00346     info = boost::spirit::parse(beginpos, endpos, grParser >> end_p,grSkipper);
00347   }else{
00348     m_stream 
00349       << boost::format("#units \"%3%\" %|72t|%2% %1%") 
00350       % posString(pos.line(), pos.column()) 
00351       % GPP_COMMENT 
00352       % fileToParse 
00353       << std::endl ;
00354     UnitsFileGrammar grParser(this);
00355     info = boost::spirit::parse(beginpos, endpos, grParser >> end_p,grSkipper);    
00356   }
00357   boost::spirit::file_position stoppos = info.stop.get_position();
00358   if (!info.full) {
00359     addMessage(Message::E_ERROR, Message::C_SYNTAXERROR,
00360                "Syntax error",Position(stoppos.file,stoppos.line,stoppos.column));
00361     return StatusCode::FAILURE;      
00362   }
00363   {
00364     std::string _msg =
00365       ( boost::format("Parsed file \"%2%\" %|78t|%1%")  
00366         % posString(stoppos.line, stoppos.column) 
00367         % fileToParse ) .str() ;
00368     addMessage ( Message::E_VERBOSE , 
00369                  Message::C_OK , 
00370                  _msg ,
00371                  Position(stoppos.file,stoppos.line,stoppos.column) ) ;
00372     if ( isPrint() )
00373     { 
00374       m_stream 
00375         << boost::format("%3% end  \"%2%\" %|78t|%1%")
00376         % posString(stoppos.line, stoppos.column) 
00377         % fileToParse 
00378         % GPP_COMMENT 
00379         << std::endl ; 
00380     }
00381   }
00382   return StatusCode::SUCCESS;  
00383 }
00384 // ============================================================================
00385 std::string Gaudi::Parsers::Parser::severityName
00386 (Message::Severity severity){
00387   switch(severity)
00388   {
00389   case Message::E_ERROR   :
00390     return "ERROR"     ;
00391   case Message::E_WARNING :
00392     return "WARNING"   ;
00393   case Message::E_NOTICE  :
00394     return "NOTICE"    ;
00395   case Message::E_VERBOSE :
00396     return "VERBOSE"   ;
00397   default:
00398     return "UNDEFINED" ; 
00399   }
00400 }
00401 // ============================================================================
00402 void Gaudi::Parsers::Parser::addMessage
00403 ( const Message::Severity& severity ,
00404   const Message::Code&     code     , 
00405   const std::string&       message  , 
00406   const Position&          pos      )
00407 {
00408   Message result
00409     ( severity , code,
00410       boost::str(boost::format("%1%(%2%,%3%) : %4% #%5% : %6%") % pos.fileName()
00411                  % pos.line() % pos.column() % severityName(severity) % code 
00412                  % message));
00413   m_messages.push_back(result);
00414 }
00415 // ============================================================================
00416 // Purpose: Implementation of Parser::isIncluded()
00417 // Comment: Test if file already included
00418 // Parameters:
00419 //  - fileName File name
00420 // Return: true if file already included
00421 // ============================================================================
00422 bool Gaudi::Parsers::Parser::isIncluded(const std::string& fileName)
00423 {
00424   for(std::vector<std::string>::const_iterator cur=m_included.begin();
00425       cur!=m_included.end();cur++)
00426   { if(fileName==*cur){ return true; } }
00427   return false;
00428 }
00429 // ============================================================================
00430 // Purpose: Implementation of Parser::resolveReferences()
00431 // Comment: Resolve references
00432 // TODO: Refactor?
00433 // ============================================================================
00434 void Gaudi::Parsers::Parser::resolveReferences()
00435 {
00436   Catalogue::CatalogueT cat = m_catalogue.catalogue();
00437   // ----------------------------------------------------------------------------
00438   for( Catalogue::CatalogueT::const_iterator curObj = cat.begin();  
00439        curObj!=cat.end();curObj++)
00440   {
00441     std::string objName = curObj->first;
00442     // ------------------------------------------------------------------------
00443     for( std::vector<PropertyEntry>::const_iterator curProp = 
00444            curObj->second.begin();curProp != curObj->second.end(); curProp++)
00445     {
00446       std::string value = curProp->value();
00447       if ( (value.length()>0) && (value[0]=='@'))
00448       {
00449         // --------------------------------------------------------------------
00450         std::vector<std::string> objAndProp;
00451         std::string refprop(value.begin()+1,value.end());
00452         ba::split(objAndProp,
00453                   refprop,
00454                   ba::is_any_of("."));            
00455         PropertyEntry foundProperty;
00456         StatusCode ok;
00457         ok = m_catalogue.findProperty(objAndProp[0],objAndProp[1],
00458                                       foundProperty);
00459         if(ok.isFailure())
00460         {
00461           addMessage
00462             ( Message::E_ERROR,
00463               Message::C_PROPERTYNOTFOUND,
00464               boost::str(boost::format("Cannot find property \"%1%.%2%\"")
00465                          % objAndProp[0] % objAndProp[1]),curProp->position());
00466         }
00467         else
00468         {
00469           // -------------------------------------------------------------------
00470           if((ba::to_lower_copy(objAndProp[0]) == objName)
00471              && 
00472              (ba::to_lower_copy(objAndProp[1]) 
00473               == curProp->name()))
00474           {
00475             // ----------------------------------------------------------------
00476             addMessage
00477               ( Message::E_ERROR,
00478                 Message::C_BADREFERENCE,
00479                 boost::str(boost::format("Reference to self \"%1%.%2%\"")
00480                            % objAndProp[0] % objAndProp[1]),curProp->position());
00481             // ----------------------------------------------------------------
00482           }
00483           else
00484           {
00485             PropertyEntry property = foundProperty;
00486             property.setName(curProp->name());
00487             m_catalogue.addProperty(objName,property);
00488           }
00489           // ------------------------------------------------------------------
00490         }
00491         // --------------------------------------------------------------------
00492       }
00493     }
00494     // ------------------------------------------------------------------------
00495   }
00496 }
00497 // ============================================================================
00498 // String representation of sign
00499 // ============================================================================
00500 std::string Gaudi::Parsers::Parser::sign(Sign aSign)
00501 {
00502   switch(aSign)
00503   {
00504   case S_ASSIGN:
00505     return "=";
00506   case S_PLUSASSIGN:
00507     return "+=";
00508   case S_MINUSASSIGN:
00509     return "-=";
00510   default:
00511     return "unknown_operation";
00512   }
00513 }
00514 // ============================================================================
00515 // String representation of value vector
00516 // ============================================================================
00517 std::string Gaudi::Parsers::Parser::valueToString
00518 ( std::vector<std::string> value, bool isVector )
00519 {
00520   if ( !isVector){ return value[0]; }
00521   //
00522   std::string result;
00523   std::string delim;
00524   result+=" [ ";
00525   for ( std::vector<std::string>::const_iterator cur = value.begin();
00526         cur != value.end(); cur++ )
00527   {
00528     result += delim + *cur;
00529     delim = " , ";
00530   }
00531   return result + " ] ";
00532 }
00533 // ============================================================================
00534 // Print options
00535 // ============================================================================
00536 void Gaudi::Parsers::Parser::printOptions() { m_stream << m_catalogue ; }
00537 // ============================================================================
00538 /*  Implementation of Gaudi::Parsers::Utils::posString()
00539  *  Comment: Convert position to string
00540  *  Parameters:
00541  *    - line Line
00542  *    - column Column
00543  */
00544 // ============================================================================
00545 std::string Gaudi::Parsers::Parser::posString(int line, int column)
00546 { return boost::str(boost::format("(%1%,%2%)") % line % column); }
00547 // ============================================================================
00548 
00549 // ============================================================================
00550 // The END 
00551 // ============================================================================

Generated at Mon Nov 24 14:38:49 2008 for Gaudi Framework, version v20r3 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004