Orocos Real-Time Toolkit  2.8.3
ValueChangeParser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 ValueChangeParser.cxx
3 
4  ValueChangeParser.cxx - description
5  -------------------
6  begin : Mon May 10 2004
7  copyright : (C) 2004 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2.1 of the License, or (at your option) any later version. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19  * Lesser General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU Lesser General Public *
22  * License along with this library; if not, write to the Free Software *
23  * Foundation, Inc., 59 Temple Place, *
24  * Suite 330, Boston, MA 02111-1307 USA *
25  * *
26  ***************************************************************************/
27 
28 #include "parser-debug.hpp"
29 #include "parse_exception.hpp"
30 #include "ValueChangeParser.hpp"
31 
32 #include "../Service.hpp"
33 #include "../types/Types.hpp"
34 #include "../Attribute.hpp"
35 #include "../TaskContext.hpp"
36 #include "../types/GlobalsRepository.hpp"
37 //#include "DumpObject.hpp"
38 
39 #include <boost/bind.hpp>
40 #include <boost/lambda/bind.hpp>
41 #include <boost/lambda/construct.hpp>
42 
43 #include <Logger.hpp>
44 
45 #include <sstream>
46 #include <iostream>
47 
48 namespace RTT
49 {
50  using namespace detail;
51 
52  using namespace std;
53 
54  using namespace boost;
55 
56  namespace {
57  boost::spirit::classic::assertion<std::string> expect_open("Open brace expected.");
58  boost::spirit::classic::assertion<std::string> expect_close("Closing brace expected (or could not find out what this line means).");
59  boost::spirit::classic::assertion<std::string> expect_type("Unknown type. Please specify a type.");
60  boost::spirit::classic::assertion<std::string> expect_def("Expected a type definition. Please specify a type.");
61  boost::spirit::classic::assertion<std::string> expect_expr("Expected a valid expression.");
62  boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
63  boost::spirit::classic::assertion<std::string> expect_init("Expected an initialisation value of the variable.");
64  boost::spirit::classic::assertion<std::string> expect_cis("Expected a initialisation ('=') of const.");
65  boost::spirit::classic::assertion<std::string> expect_ais("Expected a initialisation ('=') of alias.");
66  boost::spirit::classic::assertion<std::string> expect_index("Expected an index: [index].");
67  boost::spirit::classic::assertion<std::string> expect_integer("Expected a positive integer expression.");
68  boost::spirit::classic::assertion<std::string> expect_change("Expected a variable assignment after 'set'.");
69  boost::spirit::classic::assertion<std::string> expect_decl("Expected a declaration list.");
70  }
71 
72 
74  : type( 0 ), context( pc ), mstore( storage ? storage : pc->provides() ),
75  expressionparser( pc, caller, cp ), commonparser(cp), sizehint(-1),
76  typerepos( TypeInfoRepository::Instance() )
77  {
78  BOOST_SPIRIT_DEBUG_RULE( constantdefinition );
79  BOOST_SPIRIT_DEBUG_RULE( aliasdefinition );
80  BOOST_SPIRIT_DEBUG_RULE( variabledefinition );
81  BOOST_SPIRIT_DEBUG_RULE( paramdefinition );
82  BOOST_SPIRIT_DEBUG_RULE( baredefinition );
83  BOOST_SPIRIT_DEBUG_RULE( constdecl );
84  BOOST_SPIRIT_DEBUG_RULE( vardecl );
85  BOOST_SPIRIT_DEBUG_RULE( baredecl );
86 
87  // a macro using GCC's C++ extension typeof that is used to not have
88  // to specify impossibly long type names.. See the Boost.Spirit
89  // documentation for more details, as that's where I got it from..
90  // we use __typeof__ instead of typeof because it is not disabled by
91  // using gcc -ansi
92 
93  //TODO: this typeof replaced by boost header might not work.
94 # define RULE( name, def ) \
95  boost_spirit::contiguous<boost_spirit::positive<boost_spirit::chset<char> > > name = (def)
96  //BOOST_TYPE_OF(( (def) ) name = (def)
97  // typeof is not a native c/c++ construct and is gcc specific
98  //__typeof__( (def) ) name = (def)
99 
100  // we can't use commonparser.identifier to parse a type name,
101  // because that one is meant to be used for identifier used by the
102  // user, and excludes keywords such as "int", "string" etc.
103  chset<> identchar( "a-zA-Z-_0-9/<>." );
104  RULE( type_name, lexeme_d[ +identchar ] );
105 
106  valuechange_parsers = constantdefinition
107  | variabledefinition
108  | aliasdefinition;
109 
110  constantdefinition =
111  keyword_p("const")
112  // the type
113  >> expect_type( type_name[boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ])
114  >> constdecl[boost::bind( &ValueChangeParser::seenconstantdefinition, this )]
115  >> *(ch_p(',') >> constdecl[boost::bind( &ValueChangeParser::seenconstantdefinition, this )] );
116 
117 
118  aliasdefinition =
119  keyword_p("alias")
120  // the type
121  >> expect_type(type_name [ boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ])
122  // next the name for the alias
123  >> expect_ident( commonparser.identifier[ boost::bind( &ValueChangeParser::storedefinitionname, this, _1, _2 ) ])
124  >> expect_ais( ch_p('=') )
125  // and a value to assign to it
126  >> expect_init( expressionparser.parser() )[ boost::bind( &ValueChangeParser::seenaliasdefinition, this ) ];
127 
128  variabledefinition =
129  keyword_p("var")
130  >> expect_type( type_name[boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ])
131  >> vardecl[boost::bind( &ValueChangeParser::seenvariabledefinition, this ) ]
132  >> *(ch_p(',') >> vardecl[boost::bind( &ValueChangeParser::seenvariabledefinition, this ) ] );
133 
134  paramdefinition =
135  keyword_p("param")
136  >> expect_type( type_name[boost::bind( &ValueChangeParser::seentype, this, _1, _2 ) ])
137  >> baredecl[boost::bind( &ValueChangeParser::seenbaredefinition, this ) ]
138  >> *(ch_p(',') >> baredecl[boost::bind( &ValueChangeParser::seenbaredefinition, this ) ] );
139 
140  baredefinition =
141  type_name[ boost::bind( &ValueChangeParser::seentype, this, _1, _2 )]
142  >> baredecl[boost::bind( &ValueChangeParser::seenbaredefinition, this )];
143 
144  baredecl =
145  expect_ident( commonparser.identifier[ boost::bind( &ValueChangeParser::storedefinitionname, this, _1, _2 )] )
146  >> !( ch_p('(') >> expect_integer( expressionparser.parser()[boost::bind( &ValueChangeParser::seensizehint, this)]) >> expect_close( ch_p(')')) ) ;
147 
148  vardecl =
149  baredecl >> !( ch_p('=') >> expect_init( expressionparser.parser() ) );
150 
151  constdecl =
152  baredecl >> expect_cis( ch_p('=') ) >> expect_init( expressionparser.parser() );
153 
154  }
155 
156  void ValueChangeParser::seensizehint()
157  {
158  DataSourceBase::shared_ptr expr = expressionparser.getResult();
159  expressionparser.dropResult();
160  assert( expr.get() );
161  //assert( !expressionparser.hasResult() );
162  DataSource<int>::shared_ptr i = dynamic_cast<DataSource<int>* >( expr.get() );
163  std::string typen = type->getTypeName();
164  if ( i.get() == 0 ) {
165  this->cleanup();
167  ("Attempt to initialize "+typen+" "+valuename+" with a "+expr->getTypeName()+", expected an integer expression. Use ' = "+expr->getTypeName()+"( arg )' instead to use the constructor." );
168  }
169  if ( i->get() < 0 ) {
170  std::stringstream value;
171  value << i->get();
172  this->cleanup();
174  ("Attempt to initialize "+typen+" "+valuename+" with an expression leading to a negative number "+value.str()
175  +". Initialization expressions are evaluated once at parse time !" );
176  }
177  if ( i->get() == 0 ) {
179  "Attempt to initialize "<<typen<<" "<<valuename<<" with an expression leading to zero (0)"
180  <<". Initialization expressions are evaluated once at parse time !" << Logger::endl;
181  }
182  sizehint = i->get();
183  }
184 
185  void ValueChangeParser::seenconstantdefinition()
186  {
187  DataSourceBase::shared_ptr expr = expressionparser.getResult();
188  expressionparser.dropResult();
189  //assert( !expressionparser.hasResult() );
190  AttributeBase* var;
191  if (sizehint == -1 )
192  var = type->buildConstant(valuename, expr);
193  else {
194  var = type->buildConstant(valuename, expr, sizehint);
195  }
196  if ( var == 0 ) // bad assignment.
197  {
198  Logger::log() << " failed !"<<Logger::endl;
199  this->cleanup();
201  ("Attempt to initialize a const "+type->getTypeName()+" with a "+expr->getTypeName()+"." );
202  }
203 
204  mstore->setValue( var );
205  definedvalues.push_back( var );
206  definednames.push_back( valuename );
207  alldefinednames.push_back( valuename );
208  }
209 
210  void ValueChangeParser::storedefinitionname( iter_t begin, iter_t end )
211  {
212  std::string name( begin, end );
213  if ( mstore->getValue( name ) ) {
214  this->cleanup();
215  throw parse_exception_semantic_error( "Identifier \"" + name +
216  "\" is already defined in " + mstore->getName() );
217  }
218 
219  valuename = name;
220  }
221 
222  void ValueChangeParser::seentype( iter_t begin, iter_t end )
223  {
224  std::string name( begin, end );
225  type = typerepos->type( name );
226  if ( type == 0 )
227  throw parse_exception_semantic_error( "\"" + name + "\" is an unknown type..." );
228  }
229 
230  void ValueChangeParser::seenaliasdefinition()
231  {
232  DataSourceBase::shared_ptr expr = expressionparser.getResult();
233  expressionparser.dropResult();
234  //assert( !expressionparser.hasResult() );
235  AttributeBase* alias;
236  alias = type->buildAlias( valuename, expr.get() );
237  if ( ! alias ) {
238  this->cleanup();
240  "Attempt to define an alias of type "+type->getTypeName()+" to an expression of type "+expr->getTypeName()+"." );
241  }
242  mstore->setValue( alias );
243  definedvalues.push_back( alias );
244  definednames.push_back( valuename );
245  alldefinednames.push_back( valuename );
246  ActionInterface* nc(0);
247  assigncommands.push_back( nc );
248  }
249 
250  void ValueChangeParser::seenbaredefinition()
251  {
252  // type has been stored by calling 'seentype'
253  // valuename has been stored by calling 'storename'
254  AttributeBase* var;
255  if (sizehint == -1 )
256  var = type->buildVariable(valuename);
257  else {
258  var = type->buildVariable(valuename,sizehint);
259  }
260  sizehint = -1;
261  mstore->setValue( var );
262  definedvalues.push_back( var );
263  definednames.push_back( valuename );
264  alldefinednames.push_back( valuename );
265  }
266 
267  void ValueChangeParser::seenvariabledefinition()
268  {
269  // build type.
270  AttributeBase* var;
271  if (sizehint == -1 )
272  var = type->buildVariable(valuename);
273  else {
274  var = type->buildVariable(valuename,sizehint);
275  }
276  sizehint = -1;
277  mstore->setValue( var );
278  definedvalues.push_back( var );
279  definednames.push_back( valuename );
280  alldefinednames.push_back( valuename );
281 
282  if ( expressionparser.hasResult() ) {
283  DataSourceBase::shared_ptr expr = expressionparser.getResult();
284  expressionparser.dropResult();
285  //assert( !expressionparser.hasResult() );
286  try {
287  ActionInterface* ac = var->getDataSource()->updateAction( expr.get() );
288  assert(ac);
289  assigncommands.push_back( ac );
290  }
291  catch( const bad_assignment& ) {
292  this->cleanup();
294  ( "Attempt to initialize a var "+var->getDataSource()->getTypeName()+" with a "+ expr->getTypeName() + "." );
295  }
296  }
297  }
298 
300  {
301  if (!o)
302  return;
303  for(std::vector<std::string>::iterator it = alldefinednames.begin();
304  it != alldefinednames.end(); ++it) {
305  // only add new values (which didn't come from 'load')
306  if ( o->getValue( *it ) == 0 ) {
307  o->setValue( mstore->getValue(*it)->clone() );
308  //cout << "Storing var "+*it+" from " << mstore->getName() << " into " << o->getName() <<endl;
309  }
310  }
311  }
312 
314  {
315  if (!s)
316  return;
317  vector<string> predefinednames = s->getAttributeNames();
318  for(std::vector<std::string>::iterator it = predefinednames.begin();
319  it != predefinednames.end(); ++it) {
320  if (mstore->getValue(*it) == 0) {
321  //cout << "Loading new var "+*it+" from " << s->getName() << " into " << mstore->getName() <<endl;
322  mstore->setValue( s->getValue(*it)->clone() );
323  alldefinednames.push_back( *it ); // such that it is also again removed from mstore !
324  }
325  }
326  }
327 
328  void ValueChangeParser::cleanup()
329  {
330  for_each(assigncommands.begin(), assigncommands.end(), boost::lambda::bind(boost::lambda::delete_ptr(), boost::lambda::_1));
331  }
332 
334  {
335  assigncommands.clear();
336 
337  definedvalues.clear();
338 
339  definednames.clear();
340  }
341 
343  {
344  // erase/delete added values from the context:
345  for(std::vector<std::string>::iterator it = alldefinednames.begin();
346  it != alldefinednames.end(); ++it) {
347  mstore->removeValue( *it );
348  }
349  alldefinednames.clear();
350  this->cleanup();
351  this->clear();
352  valuename = "";
353  type = 0;
354  sizehint = -1;
355  }
356 
358  {
359  return valuechange_parsers;
360  }
361 
363  {
364  return constantdefinition;
365  }
366 
368  {
369  return aliasdefinition;
370  }
371 
373  {
374  return variabledefinition;
375  }
376 
378  {
379  return paramdefinition;
380  }
381 
383  {
384  return baredefinition;
385  }
386 }
#define keyword_p(word)
Returns a rule which parses a keyword followed by a non-identifier character, newline or semicolon...
rule_t & parser()
Returns the full parser, as it is used most.
DataSource is a base class representing a generic way to read data of type T.
Definition: DataSource.hpp:94
void load(Service::shared_ptr source)
Loads all defined names from a service.
rule_t & aliasDefinitionParser()
The parser that parses alias definitions.
const std::string & getTypeName() const
Return the type name which was first registered.
Definition: TypeInfo.hpp:82
rule_t & bareDefinitionParser()
The parser that parses a bare variable definition.
#define RULE(name, def)
STL namespace.
This class contains all known types to Orocos.
void reset()
Completely clear all data and erase all parsed definitions from the taskcontext given in the construc...
parse_exception class that is used for various semantic errors for which it was not worth defining a ...
virtual DataSourceBase::shared_ptr getDataSource() const =0
Return a internal::DataSource which contains the same contents.
This class contains some very common parser definitions.
This exception is thrown if the target and source type of an assignment of a DataSource with a base::...
Definition: DataSource.hpp:62
An execution engine serialises (executes one after the other) the execution of all commands...
boost::shared_ptr< Service > shared_ptr
Definition: Service.hpp:101
void store(Service::shared_ptr other)
Store allDefinedNames() in a service.
An attribute is a minimalistic, named placeholder for data.
base::AttributeBase * buildConstant(std::string name, base::DataSourceBase::shared_ptr source, int sizehint) const
Build a non modifyable instance of this type.
Definition: TypeInfo.hpp:172
static std::ostream & endl(std::ostream &__os)
Definition: Logger.cpp:383
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
base::DataSourceBase::shared_ptr getResult()
rule< scanner_t > rule_t
base::AttributeBase * buildAlias(std::string name, base::DataSourceBase::shared_ptr b) const
build an alias with b as the value.
Definition: TypeInfo.hpp:205
boost::intrusive_ptr< DataSource< T > > shared_ptr
Definition: DataSource.hpp:115
base::AttributeBase * buildVariable(std::string name, int sizehint) const
Build a modifyable instance of this type.
Definition: TypeInfo.cpp:82
void clear()
Clear assignCommands(), definedValues() and definedNames().
rule_t & paramDefinitionParser()
The parser that parses state context parameter definitions.
rule_t & constantDefinitionParser()
the parser that parses definitions of constants.
rule_t & variableDefinitionParser()
the parser that parses variable definitions, don&#39;t forget to check assignCommand after a variable def...
static Logger & log()
As Instance(), but more userfriendly.
Definition: Logger.cpp:117
The TaskContext is the C++ representation of an Orocos component.
Definition: TaskContext.hpp:93
boost::intrusive_ptr< DataSourceBase > shared_ptr
Use this type to store a pointer to a DataSourceBase.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:51
our_pos_iter_t iter_t
ValueChangeParser(TaskContext *tc, CommonParser &cp, Service::shared_ptr storage, ExecutionEngine *caller)
Create a ValueChangeParser which operates and stores values in a task.