Orocos Real-Time Toolkit
2.6.0
|
00001 /*************************************************************************** 00002 tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 ValueChangeParser.cxx 00003 00004 ValueChangeParser.cxx - description 00005 ------------------- 00006 begin : Mon May 10 2004 00007 copyright : (C) 2004 Peter Soetens 00008 email : peter.soetens@mech.kuleuven.ac.be 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU Lesser General Public * 00013 * License as published by the Free Software Foundation; either * 00014 * version 2.1 of the License, or (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00019 * Lesser General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation, Inc., 59 Temple Place, * 00024 * Suite 330, Boston, MA 02111-1307 USA * 00025 * * 00026 ***************************************************************************/ 00027 00028 #include "parser-debug.hpp" 00029 #include "parse_exception.hpp" 00030 #include "ValueChangeParser.hpp" 00031 00032 #include "../Service.hpp" 00033 #include "../types/Types.hpp" 00034 #include "../Attribute.hpp" 00035 #include "../TaskContext.hpp" 00036 #include "../types/GlobalsRepository.hpp" 00037 //#include "DumpObject.hpp" 00038 00039 #include <boost/bind.hpp> 00040 #include <boost/lambda/bind.hpp> 00041 #include <boost/lambda/construct.hpp> 00042 00043 #include <Logger.hpp> 00044 00045 #include <sstream> 00046 #include <iostream> 00047 00048 namespace RTT 00049 { 00050 using namespace detail; 00051 00052 using namespace std; 00053 00054 using namespace boost;; 00055 00056 namespace { 00057 boost::spirit::classic::assertion<std::string> expect_open("Open brace expected."); 00058 boost::spirit::classic::assertion<std::string> expect_close("Closing brace expected (or could not find out what this line means)."); 00059 boost::spirit::classic::assertion<std::string> expect_type("Unknown type. Please specify a type."); 00060 boost::spirit::classic::assertion<std::string> expect_def("Expected a type definition. Please specify a type."); 00061 boost::spirit::classic::assertion<std::string> expect_expr("Expected a valid expression."); 00062 boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier."); 00063 boost::spirit::classic::assertion<std::string> expect_init("Expected an initialisation value of the variable."); 00064 boost::spirit::classic::assertion<std::string> expect_cis("Expected a initialisation ('=') of const."); 00065 boost::spirit::classic::assertion<std::string> expect_ais("Expected a initialisation ('=') of alias."); 00066 boost::spirit::classic::assertion<std::string> expect_index("Expected an index: [index]."); 00067 boost::spirit::classic::assertion<std::string> expect_integer("Expected a positive integer expression."); 00068 boost::spirit::classic::assertion<std::string> expect_change("Expected a variable assignment after 'set'."); 00069 boost::spirit::classic::assertion<std::string> expect_decl("Expected a declaration list."); 00070 } 00071 00072 00073 ValueChangeParser::ValueChangeParser( TaskContext* pc, CommonParser& cp, Service::shared_ptr storage, ExecutionEngine* caller ) 00074 : type( 0 ), context( pc ), mstore( storage ? storage : pc->provides() ), 00075 expressionparser( pc, caller, cp ), commonparser(cp), sizehint(-1), 00076 typerepos( TypeInfoRepository::Instance() ) 00077 { 00078 BOOST_SPIRIT_DEBUG_RULE( constantdefinition ); 00079 BOOST_SPIRIT_DEBUG_RULE( aliasdefinition ); 00080 BOOST_SPIRIT_DEBUG_RULE( variabledefinition ); 00081 BOOST_SPIRIT_DEBUG_RULE( paramdefinition ); 00082 BOOST_SPIRIT_DEBUG_RULE( baredefinition ); 00083 BOOST_SPIRIT_DEBUG_RULE( constdecl ); 00084 BOOST_SPIRIT_DEBUG_RULE( vardecl ); 00085 BOOST_SPIRIT_DEBUG_RULE( baredecl ); 00086 00087 // a macro using GCC's C++ extension typeof that is used to not have 00088 // to specify impossibly long type names.. See the Boost.Spirit 00089 // documentation for more details, as that's where I got it from.. 00090 // we use __typeof__ instead of typeof because it is not disabled by 00091 // using gcc -ansi 00092 00093 //TODO: this typeof replaced by boost header might not work. 00094 # define RULE( name, def ) \ 00095 boost_spirit::contiguous<boost_spirit::positive<boost_spirit::chset<char> > > name = (def) 00096 //BOOST_TYPE_OF(( (def) ) name = (def) 00097 // typeof is not a native c/c++ construct and is gcc specific 00098 //__typeof__( (def) ) name = (def) 00099 00100 // we can't use commonparser.identifier to parse a type name, 00101 // because that one is meant to be used for identifier used by the 00102 // user, and excludes keywords such as "int", "string" etc. 00103 chset<> identchar( "a-zA-Z-_0-9/<>." ); 00104 RULE( type_name, lexeme_d[ +identchar ] ); 00105 00106 valuechange_parsers = constantdefinition 00107 | variabledefinition 00108 | aliasdefinition; 00109 00110 constantdefinition = 00111 keyword_p("const") 00112 // the type 00113 >> expect_type( type_name[boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ]) 00114 >> constdecl[boost::bind( &ValueChangeParser::seenconstantdefinition, this )] 00115 >> *(ch_p(',') >> constdecl[boost::bind( &ValueChangeParser::seenconstantdefinition, this )] ); 00116 00117 00118 aliasdefinition = 00119 keyword_p("alias") 00120 // the type 00121 >> expect_type(type_name [ boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ]) 00122 // next the name for the alias 00123 >> expect_ident( commonparser.identifier[ boost::bind( &ValueChangeParser::storedefinitionname, this, _1, _2 ) ]) 00124 >> expect_ais( ch_p('=') ) 00125 // and a value to assign to it 00126 >> expect_init( expressionparser.parser() )[ boost::bind( &ValueChangeParser::seenaliasdefinition, this ) ]; 00127 00128 variabledefinition = 00129 keyword_p("var") 00130 >> expect_type( type_name[boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ]) 00131 >> vardecl[boost::bind( &ValueChangeParser::seenvariabledefinition, this ) ] 00132 >> *(ch_p(',') >> vardecl[boost::bind( &ValueChangeParser::seenvariabledefinition, this ) ] ); 00133 00134 paramdefinition = 00135 keyword_p("param") 00136 >> expect_type( type_name[boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ]) 00137 >> baredecl[boost::bind( &ValueChangeParser::seenbaredefinition, this ) ] 00138 >> *(ch_p(',') >> baredecl[boost::bind( &ValueChangeParser::seenbaredefinition, this ) ] ); 00139 00140 baredefinition = 00141 type_name[ boost::bind( &ValueChangeParser::seentype, this, _1, _2 )] 00142 >> baredecl[boost::bind( &ValueChangeParser::seenbaredefinition, this )]; 00143 00144 baredecl = 00145 expect_ident( commonparser.identifier[ boost::bind( &ValueChangeParser::storedefinitionname, this, _1, _2 )] ) 00146 >> !( ch_p('(') >> expect_integer( expressionparser.parser()[boost::bind( &ValueChangeParser::seensizehint, this)]) >> expect_close( ch_p(')')) ) ; 00147 00148 vardecl = 00149 baredecl >> !( ch_p('=') >> expect_init( expressionparser.parser() ) ); 00150 00151 constdecl = 00152 baredecl >> expect_cis( ch_p('=') ) >> expect_init( expressionparser.parser() ); 00153 00154 } 00155 00156 void ValueChangeParser::seensizehint() 00157 { 00158 DataSourceBase::shared_ptr expr = expressionparser.getResult(); 00159 expressionparser.dropResult(); 00160 assert( expr.get() ); 00161 //assert( !expressionparser.hasResult() ); 00162 DataSource<int>::shared_ptr i = dynamic_cast<DataSource<int>* >( expr.get() ); 00163 std::string typen = type->getTypeName(); 00164 if ( i.get() == 0 ) { 00165 this->cleanup(); 00166 throw parse_exception_semantic_error 00167 ("Attempt to initialize "+typen+" "+valuename+" with a "+expr->getTypeName()+", expected an integer expression. Use ' = "+expr->getTypeName()+"( arg )' instead to use the constructor." ); 00168 } 00169 if ( i->get() < 0 ) { 00170 std::stringstream value; 00171 value << i->get(); 00172 this->cleanup(); 00173 throw parse_exception_semantic_error 00174 ("Attempt to initialize "+typen+" "+valuename+" with an expression leading to a negative number "+value.str() 00175 +". Initialization expressions are evaluated once at parse time !" ); 00176 } 00177 if ( i->get() == 0 ) { 00178 Logger::log() << Logger::Warning << 00179 "Attempt to initialize "<<typen<<" "<<valuename<<" with an expression leading to zero (0)" 00180 <<". Initialization expressions are evaluated once at parse time !" << Logger::endl; 00181 } 00182 sizehint = i->get(); 00183 } 00184 00185 void ValueChangeParser::seenconstantdefinition() 00186 { 00187 DataSourceBase::shared_ptr expr = expressionparser.getResult(); 00188 expressionparser.dropResult(); 00189 //assert( !expressionparser.hasResult() ); 00190 AttributeBase* var; 00191 if (sizehint == -1 ) 00192 var = type->buildConstant(valuename, expr); 00193 else { 00194 var = type->buildConstant(valuename, expr, sizehint); 00195 } 00196 if ( var == 0 ) // bad assignment. 00197 { 00198 Logger::log() << " failed !"<<Logger::endl; 00199 this->cleanup(); 00200 throw parse_exception_semantic_error 00201 ("Attempt to initialize a const "+type->getTypeName()+" with a "+expr->getTypeName()+"." ); 00202 } 00203 00204 mstore->setValue( var ); 00205 definedvalues.push_back( var ); 00206 definednames.push_back( valuename ); 00207 alldefinednames.push_back( valuename ); 00208 } 00209 00210 void ValueChangeParser::storedefinitionname( iter_t begin, iter_t end ) 00211 { 00212 std::string name( begin, end ); 00213 if ( mstore->getValue( name ) ) { 00214 this->cleanup(); 00215 throw parse_exception_semantic_error( "Identifier \"" + name + 00216 "\" is already defined in " + mstore->getName() ); 00217 } 00218 00219 valuename = name; 00220 } 00221 00222 void ValueChangeParser::seentype( iter_t begin, iter_t end ) 00223 { 00224 std::string name( begin, end ); 00225 type = typerepos->type( name ); 00226 if ( type == 0 ) 00227 throw parse_exception_semantic_error( "\"" + name + "\" is an unknown type..." ); 00228 } 00229 00230 void ValueChangeParser::seenaliasdefinition() 00231 { 00232 DataSourceBase::shared_ptr expr = expressionparser.getResult(); 00233 expressionparser.dropResult(); 00234 //assert( !expressionparser.hasResult() ); 00235 AttributeBase* alias; 00236 alias = type->buildAlias( valuename, expr.get() ); 00237 if ( ! alias ) { 00238 this->cleanup(); 00239 throw parse_exception_semantic_error( 00240 "Attempt to define an alias of type "+type->getTypeName()+" to an expression of type "+expr->getTypeName()+"." ); 00241 } 00242 mstore->setValue( alias ); 00243 definedvalues.push_back( alias ); 00244 definednames.push_back( valuename ); 00245 alldefinednames.push_back( valuename ); 00246 ActionInterface* nc(0); 00247 assigncommands.push_back( nc ); 00248 } 00249 00250 void ValueChangeParser::seenbaredefinition() 00251 { 00252 // type has been stored by calling 'seentype' 00253 // valuename has been stored by calling 'storename' 00254 AttributeBase* var; 00255 if (sizehint == -1 ) 00256 var = type->buildVariable(valuename); 00257 else { 00258 var = type->buildVariable(valuename,sizehint); 00259 } 00260 sizehint = -1; 00261 mstore->setValue( var ); 00262 definedvalues.push_back( var ); 00263 definednames.push_back( valuename ); 00264 alldefinednames.push_back( valuename ); 00265 } 00266 00267 void ValueChangeParser::seenvariabledefinition() 00268 { 00269 // build type. 00270 AttributeBase* var; 00271 if (sizehint == -1 ) 00272 var = type->buildVariable(valuename); 00273 else { 00274 var = type->buildVariable(valuename,sizehint); 00275 } 00276 sizehint = -1; 00277 mstore->setValue( var ); 00278 definedvalues.push_back( var ); 00279 definednames.push_back( valuename ); 00280 alldefinednames.push_back( valuename ); 00281 00282 if ( expressionparser.hasResult() ) { 00283 DataSourceBase::shared_ptr expr = expressionparser.getResult(); 00284 expressionparser.dropResult(); 00285 //assert( !expressionparser.hasResult() ); 00286 try { 00287 ActionInterface* ac = var->getDataSource()->updateAction( expr.get() ); 00288 assert(ac); 00289 assigncommands.push_back( ac ); 00290 } 00291 catch( const bad_assignment& ) { 00292 this->cleanup(); 00293 throw parse_exception_semantic_error 00294 ( "Attempt to initialize a var "+var->getDataSource()->getTypeName()+" with a "+ expr->getTypeName() + "." ); 00295 } 00296 } 00297 } 00298 00299 void ValueChangeParser::store(Service::shared_ptr o) 00300 { 00301 if (!o) 00302 return; 00303 for(std::vector<std::string>::iterator it = alldefinednames.begin(); 00304 it != alldefinednames.end(); ++it) { 00305 // only add new values (which didn't come from 'load') 00306 if ( o->getValue( *it ) == 0 ) { 00307 o->setValue( mstore->getValue(*it)->clone() ); 00308 //cout << "Storing var "+*it+" from " << mstore->getName() << " into " << o->getName() <<endl; 00309 } 00310 } 00311 } 00312 00313 void ValueChangeParser::load(Service::shared_ptr s) 00314 { 00315 if (!s) 00316 return; 00317 vector<string> predefinednames = s->getAttributeNames(); 00318 for(std::vector<std::string>::iterator it = predefinednames.begin(); 00319 it != predefinednames.end(); ++it) { 00320 if (mstore->getValue(*it) == 0) { 00321 //cout << "Loading new var "+*it+" from " << s->getName() << " into " << mstore->getName() <<endl; 00322 mstore->setValue( s->getValue(*it)->clone() ); 00323 alldefinednames.push_back( *it ); // such that it is also again removed from mstore ! 00324 } 00325 } 00326 } 00327 00328 void ValueChangeParser::cleanup() 00329 { 00330 for_each(assigncommands.begin(), assigncommands.end(), boost::lambda::bind(boost::lambda::delete_ptr(), boost::lambda::_1)); 00331 } 00332 00333 void ValueChangeParser::clear() 00334 { 00335 assigncommands.clear(); 00336 00337 definedvalues.clear(); 00338 00339 definednames.clear(); 00340 } 00341 00342 void ValueChangeParser::reset() 00343 { 00344 // erase/delete added values from the context: 00345 for(std::vector<std::string>::iterator it = alldefinednames.begin(); 00346 it != alldefinednames.end(); ++it) { 00347 mstore->removeValue( *it ); 00348 } 00349 alldefinednames.clear(); 00350 this->cleanup(); 00351 this->clear(); 00352 valuename = ""; 00353 type = 0; 00354 sizehint = -1; 00355 } 00356 00357 rule_t& ValueChangeParser::parser() 00358 { 00359 return valuechange_parsers; 00360 } 00361 00362 rule_t& ValueChangeParser::constantDefinitionParser() 00363 { 00364 return constantdefinition; 00365 } 00366 00367 rule_t& ValueChangeParser::aliasDefinitionParser() 00368 { 00369 return aliasdefinition; 00370 } 00371 00372 rule_t& ValueChangeParser::variableDefinitionParser() 00373 { 00374 return variabledefinition; 00375 } 00376 00377 rule_t& ValueChangeParser::paramDefinitionParser() 00378 { 00379 return paramdefinition; 00380 } 00381 00382 rule_t& ValueChangeParser::bareDefinitionParser() 00383 { 00384 return baredefinition; 00385 } 00386 }