Orocos Real-Time Toolkit  2.6.0
ValueChangeParser.cpp
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 }