![]() |
|
|
Generated: 24 Nov 2008 |
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 // ============================================================================