00001
00002
00003
00004
00005
00006
00007 #include <iostream>
00008
00009
00010
00011 #include <boost/filesystem/operations.hpp>
00012 #include <boost/format.hpp>
00013 #include <boost/algorithm/string.hpp>
00014
00015
00016
00017 #include <GaudiKernel/SystemOfUnits.h>
00018
00019
00020
00021 #include "ParserUtils.h"
00022 #include "ParserGrammar.h"
00023
00024
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
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
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
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
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
00417
00418
00419
00420
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
00431
00432
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
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
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
00535
00536 void Gaudi::Parsers::Parser::printOptions() { m_stream << m_catalogue ; }
00537
00538
00539
00540
00541
00542
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
00551