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