ProgramGraphParser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 ProgramGraphParser.cxx
3 
4  ProgramGraphParser.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 General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 #include "parser-debug.hpp"
39 #include "parse_exception.hpp"
40 #include "ProgramGraphParser.hpp"
41 #include "ArgumentsParser.hpp"
42 
43 #include "CommandNOP.hpp"
44 #include "CommandDataSource.hpp"
45 #include "ConditionTrue.hpp"
46 #include "../Logger.hpp"
47 #include "DataSourceCondition.hpp"
48 
49 #include "ConditionComposite.hpp"
50 #include "ConditionFalse.hpp"
51 #include "ConditionOnce.hpp"
52 #include "CommandComposite.hpp"
53 #include "CommandBinary.hpp"
54 
55 #include "TryCommand.hpp"
56 #include "FunctionFactory.hpp"
57 #include "../TaskContext.hpp"
58 #include "../internal/GlobalService.hpp"
59 
60 #include <iostream>
61 #include <boost/bind.hpp>
62 #include <boost/lambda/lambda.hpp>
63 
64 #ifdef WIN32
65  #ifdef NDEBUG
66  #pragma optimize( "", off)
67  #endif
68 #endif
69 
70 namespace RTT
71 {
72  using namespace boost;
73  using namespace detail;
74 
75 
76 
77  namespace {
78  boost::spirit::classic::assertion<std::string> expect_opencurly("Open curly brace '{' expected.");
79  boost::spirit::classic::assertion<std::string> expect_closecurly("Closing curly brace '}' expected in statement block (or could not find out what this line means).");
80  boost::spirit::classic::assertion<std::string> expect_closefunction("Closing curly brace '}' expected at end of program or function (or could not find out what this line means).");
81  boost::spirit::classic::assertion<std::string> expect_open("Open brace '(' expected.");
82  boost::spirit::classic::assertion<std::string> expect_close("Closing brace ')' expected.");
83  boost::spirit::classic::assertion<std::string> expect_comma("Expected a comma separator.");
84  boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
85  boost::spirit::classic::assertion<std::string> expect_semicolon("Semicolon ';' expected after statement.");
86  boost::spirit::classic::assertion<std::string> expect_condition("Expected a boolean expression ( a condition ).");
87  boost::spirit::classic::assertion<std::string> expect_expression("Expected an expression.");
88  boost::spirit::classic::assertion<std::string> expect_command("Expected a command after 'do'.");
89  boost::spirit::classic::assertion<std::string> expect_nl("Expected a newline after statement.");
90  boost::spirit::classic::assertion<std::string> expect_eof("Invalid input in file.");
91  boost::spirit::classic::assertion<std::string> expect_term("No valid termination claues found in do ... until { } block.");
92  }
93 
94 
96  : rootc( t ),context(), fcontext(), mpositer( positer ),
97  mcallfunc(),
98  implcond(0), mcondition(0), try_cond(0),
99  commonparser(cp),
100  conditionparser( rootc, caller, cp ),
101  valuechangeparser( rootc, cp, t->provides(), caller ),
102  expressionparser( rootc, caller, cp ),
103  argsparser(0),
104  peerparser(rootc, commonparser),
105  program_builder( new FunctionGraphBuilder() ),
106  for_init_command(0),
107  exportf(false),globalf(false),
108  ln_offset(0)
109  {
110  // putting the code in setup() works around a GCC 4.1 bug.
111  this->setup();
112  this->setup2();
113  }
114 
116  // necessary in case we were used outside of our parse() methods.
117  // we also try to remove the service, because the user will call programParserResult()
118  // to do cleanup himself, in which case this becomes a no-op.
119  cleanup(true);
120  }
121 
123  BOOST_SPIRIT_DEBUG_RULE( newline );
124  BOOST_SPIRIT_DEBUG_RULE( openbrace );
125  BOOST_SPIRIT_DEBUG_RULE( closebrace );
126  BOOST_SPIRIT_DEBUG_RULE( opencurly );
127  BOOST_SPIRIT_DEBUG_RULE( closecurly );
128  BOOST_SPIRIT_DEBUG_RULE( semicolon );
129  BOOST_SPIRIT_DEBUG_RULE( condition );
130  BOOST_SPIRIT_DEBUG_RULE( terminationclause );
131  BOOST_SPIRIT_DEBUG_RULE( jumpdestination );
132  BOOST_SPIRIT_DEBUG_RULE( terminationpart );
133  BOOST_SPIRIT_DEBUG_RULE( dostatement );
134  BOOST_SPIRIT_DEBUG_RULE( trystatement );
135  BOOST_SPIRIT_DEBUG_RULE( catchpart );
136  BOOST_SPIRIT_DEBUG_RULE( statement );
137  BOOST_SPIRIT_DEBUG_RULE( line );
138  BOOST_SPIRIT_DEBUG_RULE( content );
139  BOOST_SPIRIT_DEBUG_RULE( program );
140  BOOST_SPIRIT_DEBUG_RULE( production );
141  BOOST_SPIRIT_DEBUG_RULE( valuechange );
142  BOOST_SPIRIT_DEBUG_RULE( function );
143  BOOST_SPIRIT_DEBUG_RULE( functions );
144  BOOST_SPIRIT_DEBUG_RULE( arguments );
145  BOOST_SPIRIT_DEBUG_RULE( returnstatement );
146  BOOST_SPIRIT_DEBUG_RULE( funcstatement );
147  BOOST_SPIRIT_DEBUG_RULE( continuepart );
148  BOOST_SPIRIT_DEBUG_RULE( callpart );
149  BOOST_SPIRIT_DEBUG_RULE( returnpart );
150  BOOST_SPIRIT_DEBUG_RULE( ifstatement );
151  BOOST_SPIRIT_DEBUG_RULE( whilestatement );
152  BOOST_SPIRIT_DEBUG_RULE( forstatement );
153  BOOST_SPIRIT_DEBUG_RULE( breakstatement );
154  BOOST_SPIRIT_DEBUG_RULE( ifblock );
155  BOOST_SPIRIT_DEBUG_RULE( funcargs );
156 
157  //newline = ch_p( '\n' );
158  openbrace = expect_open( ch_p('(') );
159  closebrace = expect_close( ch_p(')') );
160  opencurly = expect_opencurly( ch_p('{') );
161  closecurly = expect_closecurly( ch_p('}') );
162  semicolon = expect_semicolon( ch_p(';') );
163  condition = expect_condition( conditionparser.parser()[ boost::bind(&ProgramGraphParser::seencondition, this) ] );
164 
165  // program is the production rule of this grammar. The
166  // production rule is the rule that the entire input should be
167  // matched by... This line basically means that we're finished
168  // ;)
169  // Zero or n functions can precede the program.
170  production = *( program | function )[boost::bind(&ProgramGraphParser::programtext,this, _1, _2)] >> expect_eof(end_p) ;
171 
172  // a function is very similar to a program, but it also has a name
173  function = (
174  // optional visibility qualifiers:
175  !( keyword_p( "export" )[boost::bind(&ProgramGraphParser::exportdef, this)] | keyword_p( "global" )[boost::bind(&ProgramGraphParser::globaldef, this)] | keyword_p("local") )[boost::bind(&ProgramGraphParser::seenvalidinput, this)]
176  >> (keyword_p( "function" )[boost::bind(&ProgramGraphParser::seenvalidinput, this)] | commonparser.notassertingidentifier[boost::bind( &ProgramGraphParser::seenreturntype, this, _1, _2)] )
177  >> expect_ident( commonparser.identifier[boost::bind(&ProgramGraphParser::seenvalidinput, this)][ boost::bind( &ProgramGraphParser::functiondef, this, _1, _2 ) ] )
178  >> !funcargs
179  >> opencurly
180  >> content
181  >> expect_closefunction( ch_p('}') )[ boost::bind( &ProgramGraphParser::seenfunctionend, this ) ]
182  );
183 
184  // the function's definition args :
185  funcargs = ch_p('(') >> ( !str_p("void") >> ch_p(')') | ((
187  >> *(ch_p(',')>> valuechangeparser.bareDefinitionParser()[boost::bind(&ProgramGraphParser::seenfunctionarg, this)]) )
188  >> closebrace ));
189 
190  // a program looks like "program { content }".
191  program =
192  keyword_p( "program" )[boost::bind(&ProgramGraphParser::seenvalidinput, this)]
193  >> expect_ident( commonparser.identifier[ boost::bind( &ProgramGraphParser::programdef, this, _1, _2 ) ] )
194  >> opencurly
195  >> content
196  >> expect_closefunction( ch_p('}') )[ boost::bind( &ProgramGraphParser::seenprogramend, this ) ];
197 
198  // the content of a program can be any number of lines
199  content = *line;
200 
201  // a line can be empty or contain a statement. Empty is
202  // necessary, because comment's are skipped, but newline's
203  // aren't. So a line like "/* very interesting comment
204  // */\n" will reach us as simply "\n"..
205  //line = !( statement ) >> eol_p;
206  line = statement[boost::bind(&ProgramGraphParser::noskip_eol, this )] >> commonparser.eos[boost::bind(&ProgramGraphParser::skip_eol, this )];
207 
209 
211 
212  // take into account deprecated 'do' and 'set'
213  dostatement = !keyword_p("do") >> !keyword_p("set") >> !keyword_p("call") >>
214  (
215  ( keyword_p("yield") | keyword_p("nothing"))[boost::bind(&ProgramGraphParser::seenyield,this)]
217  );
218 
219  // a try statement: "try xxx catch { stuff to do once on any error} "
220  trystatement =
221  keyword_p("try")
222  >> expect_command ( expressionparser.parser()[ boost::bind( &ProgramGraphParser::seentrystatement, this ) ] )
223  >> !catchpart;
224 
225  }
226 
227  void ProgramGraphParser::initBodyParser(const std::string& name, Service::shared_ptr stck, int offset) {
228  ln_offset = offset;
229  assert(program_builder != 0 );
230  program_builder->startFunction(name);
231  this->setStack( stck );
232  this->clearParseState();
233  }
234 
236  return program;
237  }
238 
240  return function;
241  }
242 
244  // content is the bodyparser of a program or function
245  return content;
246  }
247 
249  // line is the statement parser of a program or function
250  return line;
251  }
252 
254  ProgramInterfacePtr result;
255  if (program_list.empty())
256  return result;
257  program_text = "Bug: Program Text to be set by Parser.";
258  // set the program text in each program :
259  program_list.front()->setText( program_text );
260  result=program_list.front();
261  this->cleanup(false);
262  program_list.clear();
263  return result;
264  }
265 
267 
268  // store the variables in the program's taskcontext object.
271 
272  // Fake a 'return' statement at the last line.
273  program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset );
274  program_builder->proceedToNext( mpositer.get_position().line - ln_offset);
275  return program_builder->endFunction( mpositer.get_position().line - ln_offset );
276  }
277 
278 // ProgramInterfacePtr ProgramGraphParser::statementParserResult() {
279 //
280 // // Fake a 'return' statement at the last line.
281 // program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset );
282 // program_builder->proceedToNext( mpositer.get_position().line - ln_offset);
283 // return program_builder->getFunction();
284 // }
285 
287  return parserused;
288  }
289 
291  context = st;
293  }
294 
296  exportf = false;
297  parserused = false;
298  rettype.clear();
299  }
300 
302  {
303  }
304 
306  {
307  // Now that we got the name, set everything up:
308 
309  std::string def(begin, end);
310 
311  if ( rootc->provides()->hasService( def ) )
312  throw parse_exception_semantic_error("Service with name '" + def + "' already present in task '"+rootc->getName()+"'.");
313 
314  FunctionGraphPtr pi(program_builder->startFunction( def ));
315  // ptsk becomes the owner of pi.
316  ProgramServicePtr ptsk(new ProgramService( pi, rootc ));
317  pi->setProgramService(ptsk);
318  pi->setUnloadOnStop( false ); // since we assign a service, set this to false.
319  context = ptsk;
320  rootc->provides()->addService( ptsk );
321  }
322 
324  {
325  // we set it in the parse() function. It is set to the whole script such that line numbers are correct.
326  //program_text = std::string(begin, end);
327  }
328 
330  {
331  exportf = true;
332  }
333 
335  {
336  globalf = true;
337  }
338 
340  {
341  rettype = std::string(begin, end);
342  }
344  {
345  // store the function in our map for later
346  // referencing.
347  std::string funcdef(begin, end);
348  // store the function in the TaskContext current.__functions
349 // TaskContext* __f = rootc->getPeer("__functions");
350 // if ( __f == 0 ) {
351 // // install the __functions if not yet present.
352 // __f = new TaskContext("__functions", rootc->engine() );
353 // rootc->connectPeers( __f );
354 // }
355 
356 // if ( __f->hasPeer( funcdef ) )
357  // only redefining a function twice in the same file is an error. If the function
358  // was already added to the scripting or component interface before, we replace it
359  // and warn about it in seenfunctionend():
360  if ( mfuncs.count( funcdef ) )
361  throw parse_exception_semantic_error("function " + funcdef + " redefined.");
362 
363  AttributeBase* retarg = 0;
364  if ( !rettype.empty() && rettype != "void") {
365  TypeInfo* type = TypeInfoRepository::Instance()->type( rettype );
366  if ( type == 0 )
367  throw_( iter_t(), "Return type '" + rettype + "' for function '"+ funcdef +"' is an unknown type." );
368  retarg = type->buildAttribute("result");
369  }
370 
371  mfuncs[funcdef] = program_builder->startFunction( funcdef );
372  program_builder->getFunction()->setResult( retarg );
373 
374  rettype.clear();
375 
376  // Connect the new function to the relevant contexts.
377  // 'fun' acts as a stack for storing variables.
378  fcontext.reset( new Service(funcdef) );
379  context = fcontext;
380  }
381 
383  {
384  // the ValueChangeParser stores each variable in the
385  // current stack's repository, but we need to inform the
386  // FunctionGraph itself about its arguments.
387  program_builder->getFunction()->addArgument( valuechangeparser.lastDefinedValue()->clone() );
389  }
390 
392  {
393  // Fake a 'return' statement at the last line.
394  program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset );
395  program_builder->proceedToNext( mpositer.get_position().line - ln_offset );
396  boost::shared_ptr<ProgramInterface> mfunc = program_builder->endFunction( mpositer.get_position().line - ln_offset );
397 
398  // export the function in the context's interface.
399  if (exportf) {
400  std::map<const DataSourceBase*, DataSourceBase*> dummy;
401  FunctionFactory* cfi = new FunctionFactory(ProgramInterfacePtr(mfunc->copy(dummy)), rootc->engine() ); // execute in the processor which has the command.
402  if (rootc->provides()->hasMember( mfunc->getName() ) )
403  log(Warning) << "Redefining function '"<< rootc->getName() << "." << mfunc->getName() << "': only new programs will use this new function." <<endlog();
404  rootc->provides()->add(mfunc->getName(), cfi );
405  Logger::log() << Logger::Info << "Exported Function '" << mfunc->getName() << "' added to task '"<< rootc->getName() << "'" <<Logger::endl;
406  }
407  // attach the function to the global service interface.
408  else if (globalf){
409  std::map<const DataSourceBase*, DataSourceBase*> dummy;
410  FunctionFactory* cfi = new FunctionFactory(ProgramInterfacePtr(mfunc->copy(dummy)), rootc->engine() ); // execute in the processor which has the command.
411  if (GlobalService::Instance()->provides()->hasMember( mfunc->getName() ) )
412  log(Warning) << "Redefining function '"<< GlobalService::Instance()->getName() << "."<< mfunc->getName() << "': only new programs will use this new function." <<endlog();
413  GlobalService::Instance()->provides()->add(mfunc->getName(), cfi );
414  Logger::log() << Logger::Debug << "Seen Function '" << mfunc->getName() << "' for Global Service." <<Logger::endl;
415  } else {
416  std::map<const DataSourceBase*, DataSourceBase*> dummy;
417  FunctionFactory* cfi = new FunctionFactory(ProgramInterfacePtr(mfunc->copy(dummy)), rootc->engine() ); // execute in the processor which has the command.
418  if (rootc->provides("scripting")->hasMember( mfunc->getName() ) )
419  log(Warning) << "Redefining function '"<< rootc->getName() << ".scripting."<< mfunc->getName() << "': only new programs will use this new function." <<endlog();
420  rootc->provides("scripting")->add(mfunc->getName(), cfi );
421  Logger::log() << Logger::Debug << "Seen Function '" << mfunc->getName() << "' for scripting service of '"<< rootc->getName() << "'" <<Logger::endl;
422  }
423 
424  fcontext.reset();
425  context.reset();
426 
427  // reset
428  exportf = false; globalf = false;
429 
431  }
432 
434  parserused = true;
435  }
436 
438  {
440  assert( mcondition );
441 
442  // leaves the condition in the parser, if we want to use
443  // getParseResultAsCommand();
444  // mcondition is only used with seen*label statements,
445  // when the command and condition are associated,
446  // not in the branching where the evaluation of the
447  // condition is the command.
448  }
449 
451  {
452  // return statement can happen in program and in a function
453  program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset );
454  program_builder->proceedToNext( mpositer.get_position().line - ln_offset );
455  }
456 
458  {
459  AttributeBase* ar =program_builder->getFunction()->getResult();
460  if ( ar == 0) {
461  throw parse_exception_syntactic_error("Returning a value in a function returning (void).");
462  }
465  try {
466  ActionInterface* assigncomm = ar->getDataSource()->updateAction( expr.get() );
467  // assign the return value to the return argument.
468  program_builder->setCommand( assigncomm );
469  program_builder->proceedToNext( new ConditionTrue(), mpositer.get_position().line - ln_offset );
470  }
471  catch(...) {
472  // catch exception from updateAction.
473  throw parse_exception_syntactic_error("Could not convert '" + expr->getType() + "' to '"+ ar->getDataSource()->getType() +"' in return statement.");
474  }
475  }
476 
478  {
479  if ( program_builder->inLoop() ) {
480  program_builder->breakLoop();
481  program_builder->proceedToNext( mpositer.get_position().line - ln_offset );
482  } else
483  throw parse_exception_syntactic_error("Illegal use of 'break'. Can only be used within for and while loops.");
484  }
485 
487  {
488  // store the part after 'call'
489  std::string fname(begin, end);
490  if ( mfuncs.count(fname) == 0 )
491  throw parse_exception_semantic_error("calling function " + fname + " but it is not defined ( remove the 'call' keyword ).");
492  if ( fname == program_builder->getFunction()->getName() )
493  throw parse_exception_semantic_error("calling function " + fname + " recursively is not allowed.");
494 
495  mcallfunc = mfuncs[ fname ];
496 
497  // Parse the function's args in the programs context.
499  "this", fname );
501 
502  }
503 
505  {
507  }
508 
510  {
511  log(Warning) << " 'call' has been deprecated. Please remove this keyword." << endlog();
512  // This function is called if the 'call func' is outside
513  // a termination clause.
514 
515  // add it to the main program line of execution.
516  assert( mcallfunc );
517  try
518  {
519  program_builder->setFunction( mcallfunc, callfnargs );
520  // only delete parser, when the args are used.
521  delete argsparser;
522  argsparser = 0;
523  callfnargs.clear();
524  }
525  catch( const wrong_number_of_args_exception& e )
526  {
528  ( rootc->getName(), mcallfunc->getName(), e.wanted, e.received );
529  }
530  catch( const wrong_types_of_args_exception& e )
531  {
533  ( rootc->getName(), mcallfunc->getName(), e.whicharg, e.expected_, e.received_ );
534  }
535  catch( ... )
536  {
537  assert( false );
538  }
539 
540  // The exit node of the function is already connected
541  // to program->nextNode().
542  program_builder->proceedToNext(mpositer.get_position().line - ln_offset);
543  }
544 
546  commonparser.skipeol = true;
547  }
548 
550  commonparser.skipeol = false;
551  }
552 
554  // we saved the try_cond in the previous try statement,
555  // now process like it said if ( try_cond ) then {...}
556  assert( try_cond );
557  program_builder->startIfStatement( try_cond, mpositer.get_position().line - ln_offset );
558  try_cond = 0;
559  }
560 
562  this->endifblock();
563  this->endifstatement(); // there is no 'else' part, so close the statement
564  }
565 
567  assert(mcondition);
568  // transform the evaluation in a command, and pass the result
569  // as a condition
570  std::pair<ActionInterface*, ConditionInterface*> comcon;
572  program_builder->setCommand( comcon.first );
573  program_builder->startIfStatement( comcon.second, mpositer.get_position().line - ln_offset );
574 
575  // we did not need this.
576  delete mcondition;
577  mcondition = 0;
578  }
579 
581  program_builder->endIfBlock(mpositer.get_position().line - ln_offset);
582  }
583 
584 
586  program_builder->endElseBlock(mpositer.get_position().line - ln_offset);
587  }
588 
590  // analogous to seenifstatement
591  // the evaluation is a command.
592  assert(mcondition);
593  std::pair<ActionInterface*, ConditionInterface*> comcon;
595  program_builder->setCommand( comcon.first );
596  program_builder->startWhileStatement( comcon.second, mpositer.get_position().line - ln_offset );
597 
598  delete mcondition;
599  mcondition = 0;
600  }
601 
603  program_builder->endWhileBlock(mpositer.get_position().line - ln_offset);
604  }
605 
606 
608  {
609  // the for loop is different from the while and if branch
610  // structures in that it places an init command before the loop.
611  ActionInterface* ac = 0;
612  std::vector<ActionInterface*> acv = valuechangeparser.assignCommands();
613  // and not forget to reset()..
615  if ( acv.size() == 1) {
616  ac = acv.front();
617  }
618  else if (acv.size() > 1) {
619  ac = new CommandComposite( acv );
620  }
621  for_init_command = ac;
622  }
623 
625  {
628  for_init_command = new CommandDataSource( expr );
629  }
630 
632  {
635  for_incr_command.push( new CommandDataSource( expr ) );
636  }
637 
639  {
640  for_incr_command.push( 0 );
641  }
642 
644  assert( mcondition );
645 
646  // first insert the initialisation command.
647  if ( for_init_command )
648  {
649  program_builder->setCommand( for_init_command );
650  program_builder->proceedToNext( new ConditionTrue, mpositer.get_position().line - ln_offset );
651  }
652  for_init_command = 0;
653 
654  // A for is nothing more than a while loop...
655  std::pair<ActionInterface*, ConditionInterface*> comcon;
657  program_builder->setCommand( comcon.first );
658  program_builder->startWhileStatement( comcon.second, mpositer.get_position().line - ln_offset );
659  delete mcondition;
660  mcondition = 0;
661  }
662 
664  // the last statement is a _conditional_ increment of the 'counter'
665  ActionInterface* incr = for_incr_command.top();
666  for_incr_command.pop();
667  // is null or an action to increment
668  if ( incr )
669  {
670  program_builder->setCommand( incr );
671  // Since a valuechange does not add edges, we use this variant
672  // to create one.
673  program_builder->proceedToNext( new ConditionTrue, mpositer.get_position().line - ln_offset );
674  }
675  program_builder->endWhileBlock(mpositer.get_position().line - ln_offset);
676  }
677 
679  {
680  // Fake a 'return' statement at the last line.
681  program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset );
682  program_builder->proceedToNext( mpositer.get_position().line - ln_offset );
683  program_list.push_back(program_builder->endFunction( mpositer.get_position().line - ln_offset ) );
684 
685  // store the variables in the program's taskcontext object.
688  }
689 
690  std::vector< ProgramInterfacePtr > ProgramGraphParser::parse( iter_t& begin, iter_t end )
691  {
692  // end is not used !
693  iter_t begin_copy = begin;
694  skip_parser_t skip_parser = comment_p( "#" ) | comment_p( "//" ) | comment_p( "/*", "*/" ) | (space_p - eol_p) | commonparser.skipper;
695  iter_pol_t iter_policy( skip_parser );
696  scanner_pol_t policies( iter_policy );
697  scanner_t scanner( begin, end, policies );
698  program_list.clear();
699 
700  // todo :Add a universal collect/collectIfDone/ret(sendh, args) operationfactoryparts.
701  //rootc->add("collect",&ProgramGraphParser::collectHandler, this)
702 
703  try {
704  if ( ! production.parse( scanner ) )
705  {
706  // This gets shown if we didn't even get the chance to throw an exception :
707  cleanup(true);
708  throw file_parse_exception(new parse_exception_syntactic_error( " no valid input found." ),
709  mpositer.get_position().file, mpositer.get_position().line,
710  mpositer.get_position().column );
711  }
712  program_text = std::string( begin_copy, begin ); // begin is by reference.
713  // set the program text in each program :
714  for (std::vector<FunctionGraphPtr>::iterator it= program_list.begin();it!=program_list.end();++it)
715  (*it)->setText( program_text );
716  this->cleanup(false);
717  std::vector<ProgramInterfacePtr> result;
718  for (std::vector<FunctionGraphPtr>::iterator it= program_list.begin();it!=program_list.end();++it)
719  result.push_back( *it );
720  program_list.clear();
721  return result;
722  }
723  catch( const parser_error<std::string, iter_t>& e )
724  {
725  cleanup(true);
726  program_list.clear();
727  throw file_parse_exception(
728  new parse_exception_syntactic_error( e.descriptor ),
729  mpositer.get_position().file, mpositer.get_position().line,
730  mpositer.get_position().column );
731 
732  }
733  // Catch our Orocos exceptions
734  catch( const parse_exception& e )
735  {
736  cleanup(true);
737  program_list.clear();
738  throw file_parse_exception(
739  e.copy(), mpositer.get_position().file,
740  mpositer.get_position().line, mpositer.get_position().column );
741  }
742  }
743 
744  std::vector< ProgramInterfacePtr > ProgramGraphParser::parseFunction( iter_t& begin, iter_t end )
745  {
746  // end is not used !
747  iter_t begin_copy = begin;
748  //skip_parser_t skip_parser = SKIP_PARSER;
749  //iter_pol_t iter_policy( skip_parser );
750  iter_pol_t iter_policy( ( comment_p( "#" ) | comment_p( "//" ) | comment_p( "/*", "*/" ) | (space_p - eol_p) | commonparser.skipper ) );
751  scanner_pol_t policies( iter_policy );
752  scanner_t scanner( begin, end, policies );
753 
754  std::vector< ProgramInterfacePtr > function_list;
755 
756  try {
757  if ( ! functions.parse( scanner ) )
758  {
759  // This gets shown if we didn't even get the chance to throw an exception :
760  cleanup(false);
761  throw file_parse_exception(new parse_exception_syntactic_error( " no valid input found." ),
762  mpositer.get_position().file, mpositer.get_position().line,
763  mpositer.get_position().column );
764  }
765  program_text = std::string( begin_copy, begin ); // begin is by reference.
766  // set the program text in each function :
767  for (funcmap::iterator it= mfuncs.begin();it!=mfuncs.end();++it) {
768  it->second->setText( program_text ); // set text.
769  function_list.push_back( it->second );
770  }
771 
772  this->cleanup(false);
773  return function_list;
774  }
775  // Catch Boost::Spirit exceptions
776  catch( const parser_error<std::string, iter_t>& e )
777  {
778  cleanup(false);
779  throw file_parse_exception(
780  new parse_exception_syntactic_error( e.descriptor ),
781  mpositer.get_position().file, mpositer.get_position().line,
782  mpositer.get_position().column );
783 
784  }
785  // Catch our Orocos exceptions
786  catch( const parse_exception& e )
787  {
788  cleanup(false);
789  throw file_parse_exception(
790  e.copy(), mpositer.get_position().file,
791  mpositer.get_position().line, mpositer.get_position().column );
792  }
793  }
794 
795  void ProgramGraphParser::cleanup(bool unload_service)
796  {
797  if (unload_service && rootc && context)
798  rootc->provides()->removeService( context->getName() );
799  // after an exception, we can be in any state, so cleanup
800  // all temp objects.
801  delete argsparser;
802  argsparser = 0;
803  delete implcond;
804  implcond = 0;
805  delete mcondition;
806  mcondition = 0;
807  delete try_cond;
808  try_cond = 0;
809  delete for_init_command;
810  for_init_command = 0;
811  while (!for_incr_command.empty() ) {
812  delete for_incr_command.top();
813  for_incr_command.pop();
814  }
815  // cleanup all functions :
816  fcontext.reset();
817  exportf = false; globalf = false;
818  rettype.clear();
819  if ( rootc == 0)
820  return;
821 // TaskContext* __f = rootc->getPeer("__functions");
822 // if ( __f != 0 ) {
823 // // first remove rootc from __f itself
824 // rootc->disconnectPeers( __f->getName() );
825 // delete __f;
826 // }
827  while ( ! mfuncs.empty() ) {
828  mfuncs.erase( mfuncs.begin() );
829  }
830  context.reset();
831 
834  peerparser.reset();
835  }
836 
838  {
839  // a try expression/method call.
840  ActionInterface* command;
843  DataSource<bool>* bexpr = dynamic_cast<DataSource<bool>*>(expr.get());
844  if (bexpr == 0) {
845  // if not returning a bool, the try is useless.
846  command = new CommandDataSource( expr );
847  try_cond = new ConditionFalse(); // never execute catch part.
848  program_builder->setCommand(command);
849  } else {
850  command = new CommandDataSourceBool( bexpr );
851 
852  // try-wrap the asyn or dispatch command, store the result in try_cond.
853  TryCommand* trycommand = new TryCommand( command );
854  // returns true if failure :
855  TryCommandResult* tryresult = new TryCommandResult( trycommand->result(), true );
856  program_builder->setCommand( trycommand );
857  try_cond = tryresult; // save try_cond for catch part (ie true if failure)
858  }
859  if ( program_builder->buildEdges() == 0 )
860  program_builder->proceedToNext( new ConditionTrue(), mpositer.get_position().line - ln_offset );
861  else
862  program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); // we get the data from commandparser
863  }
864 
866  {
867  // an expression/method call (former do).
871  DataSource<bool>* bexpr = dynamic_cast<DataSource<bool>*>(expr.get());
872  if (bexpr)
873  program_builder->setCommand( new CommandDataSourceBool( bexpr ) );
874  else
875  program_builder->setCommand( new CommandDataSource( expr ) );
876  if (cnd)
877  program_builder->addConditionEdge( cnd, program_builder->nextNode() );
878  if ( program_builder->buildEdges() == 0 )
879  program_builder->proceedToNext( new ConditionTrue(), mpositer.get_position().line - ln_offset );
880  else
881  program_builder->proceedToNext( mpositer.get_position().line - ln_offset );
882  }
883 
885  {
886  // a yield branch
887  program_builder->setCommand( new CommandNOP );
888  program_builder->proceedToNext( new ConditionOnce(false), mpositer.get_position().line - ln_offset );
889  }
890 
892  {
893  // some value changes generate a command, we need to add it to
894  // the program.
895  ActionInterface* ac = 0;
896  ConditionInterface* cond = 0;
897  std::vector<ActionInterface*> acv = valuechangeparser.assignCommands();
898  std::vector<ConditionInterface*> conds = valuechangeparser.assignConditions();
899  // and not forget to reset()..
901  if ( acv.size() == 1) {
902  ac = acv.front();
903  }
904  else if (acv.size() > 1) {
905  ac = new CommandComposite(acv);
906  }
907  if ( conds.size() ==1 ) {
908  cond = conds.front();
909  }
910  else if ( conds.size() > 1) {
911  cond = conds.front();
912  unsigned int i = 1;
913  while ( i != conds.size() ) {
914  cond = new ConditionBinaryCompositeAND(cond, conds[i] );
915  ++i;
916  }
917  }
918  if (ac) {
919  program_builder->setCommand( ac );
920  // check if one of the vars caused a condition:
921  if (cond == 0)
922  cond = new ConditionTrue;
923  program_builder->proceedToNext( cond, mpositer.get_position().line - ln_offset );
924  }
925  }
926 
928  {
929  // Used for "call xyz"
930  // lookup mcallfunc
931  seenfuncidentifier( begin, end );
932 
933  assert( mcondition );
934  assert( mcallfunc );
935  program_builder->appendFunction( mcondition, mcallfunc, callfnargs);
936  mcondition = 0;
937 
938  }
939 
941  {
942  // @todo complete the impl for for/while loops.
943  // Used for "continue"
944  assert ( mcondition );
945 
946  // connect to next node under given condition.
947  program_builder->addConditionEdge( mcondition, program_builder->nextNode() );
948 
949  mcondition = 0;
950  }
951 }
std::vector< base::DataSourceBase::shared_ptr > callfnargs
std::pair< base::ActionInterface *, ConditionInterface * > getParseResultAsCommand()
#define keyword_p(word)
std::vector< base::DataSourceBase::shared_ptr > result()
This class builds a program consisting of data contained in a program graph tree, based on the Boost ...
boost::shared_ptr< FunctionGraph > FunctionGraphPtr
ConditionInterface * getParseResult()
base::AttributeBase * buildAttribute(std::string name, base::DataSourceBase::shared_ptr source=0) const
Definition: TypeInfo.hpp:222
Service::shared_ptr provides()
void load(Service::shared_ptr source)
virtual AttributeBase * clone() const =0
void clearParseState()
Clears helper variables of parser.
This interface represents the concept of a condition which can be evaluated and return true or false...
void seenreturntype(iter_t begin, iter_t end)
bool skipeol
Saves eol skipping state.
boost::shared_ptr< FunctionGraphBuilder > program_builder
void programdef(iter_t begin, iter_t end)
virtual DataSourceBase::shared_ptr getDataSource() const =0
void seencallfunclabel(iter_t begin, iter_t end)
boost::shared_ptr< ProgramInterface > ProgramInterfacePtr
virtual parse_exception * copy() const =0
void initBodyParser(const std::string &name, Service::shared_ptr stck, int offset)
ConditionInterface * getCmdResult()
std::stack< base::ActionInterface * > for_incr_command
This class contains some very common parser definitions.
std::vector< scripting::ConditionInterface * > assignConditions()
boost::shared_ptr< Service > shared_ptr
Definition: Service.hpp:101
void store(Service::shared_ptr other)
scanner< iter_t, scanner_pol_t > scanner_t
ProgramGraphParser(iter_t &positer, TaskContext *context, ExecutionEngine *caller, CommonParser &cp)
skip_parser_iteration_policy< skip_parser_t > iter_pol_t
This class represents a program as an Service in the Orocos TaskContext system.
functor_parser< eol_skip_functor > skipper
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
void setStack(Service::shared_ptr st)
internal::AssignableDataSource< bool >::shared_ptr result()
Definition: TryCommand.cpp:96
void seenfuncidentifier(iter_t begin, iter_t end)
boost_spirit::alternative< boost_spirit::alternative< boost_spirit::alternative< boost_spirit::alternative< boost_spirit::confix_parser< boost_spirit::impl::string_as_parser::type, boost_spirit::kleene_star< boost_spirit::anychar_parser >, boost_spirit::alternative< boost_spirit::eol_parser, boost_spirit::end_parser >, boost_spirit::unary_parser_category, boost_spirit::non_nested, boost_spirit::is_lexeme >, boost_spirit::confix_parser< boost_spirit::impl::string_as_parser::type, boost_spirit::kleene_star< boost_spirit::anychar_parser >, boost_spirit::alternative< boost_spirit::eol_parser, boost_spirit::end_parser >, boost_spirit::unary_parser_category, boost_spirit::non_nested, boost_spirit::is_lexeme > >, boost_spirit::confix_parser< boost_spirit::impl::string_as_parser::type, boost_spirit::kleene_star< boost_spirit::anychar_parser >, boost_spirit::impl::string_as_parser::type, boost_spirit::unary_parser_category, boost_spirit::non_nested, boost_spirit::is_lexeme > >, boost_spirit::difference< boost_spirit::space_parser, boost_spirit::eol_parser > >, boost_spirit::functor_parser< eol_skip_functor > > skip_parser_t
std::vector< ProgramInterfacePtr > parse(iter_t &begin, iter_t end)
Tries to parse programs, returns the generated programs on success.
std::vector< ProgramInterfacePtr > parseFunction(iter_t &begin, iter_t end)
static Logger & log()
Definition: Logger.cpp:117
base::AttributeBase * lastDefinedValue()
base::ActionInterface * for_init_command
std::vector< base::ActionInterface * > assignCommands()
std::vector< FunctionGraphPtr > program_list
boost::intrusive_ptr< DataSourceBase > shared_ptr
rule_t notassertingidentifier
identifier with <template> marks in it
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:53
our_pos_iter_t iter_t
void functiondef(iter_t begin, iter_t end)
boost::shared_ptr< ProgramService > ProgramServicePtr
static Logger & log()
Definition: Logger.hpp:350
scanner_policies< iter_pol_t > scanner_pol_t
Based on the software pattern &#39;composite&#39;, this class RTT_SCRIPTING_API allows composing command obje...
const ExecutionEngine * engine() const
Definition: TaskCore.hpp:306
static Logger::LogFunction endlog()
Definition: Logger.hpp:362
static RTT_API Service::shared_ptr Instance()
virtual const std::string & getName() const


rtt
Author(s): RTT Developers
autogenerated on Tue Jun 25 2019 19:33:26