Orocos Real-Time Toolkit  2.9.0
ScriptParser.cpp
Go to the documentation of this file.
1 #include "parser-debug.hpp"
2 #include "parse_exception.hpp"
3 #include "ScriptParser.hpp"
4 #include "CommonParser.hpp"
5 #include "StateGraphParser.hpp"
6 #include "ProgramGraphParser.hpp"
7 #include "../TaskContext.hpp"
8 #include "../internal/Exceptions.hpp"
9 #include "ScriptingService.hpp"
10 
11 #include <iostream>
12 #include <functional>
13 #include <algorithm>
14 #include <boost/bind.hpp>
15 #include <boost/lambda/lambda.hpp>
16 #include <boost/call_traits.hpp>
17 #include <iostream>
18 #include <memory>
19 #include "../internal/mystd.hpp"
20 #include "../internal/GlobalEngine.hpp"
21 #include "ParsedStateMachine.hpp"
22 
23 namespace RTT
24 {
25  using namespace boost;
26  using namespace detail;
27  using boost::bind;
28 
29  using namespace std;
30 
31  namespace {
32  boost::spirit::classic::assertion<std::string> expect_eof("Invalid input in file.");
33  guard<std::string> no_function_guard;
34 
35  }
36 
37  error_status<> ScriptParser::handle_no_function(scanner_t const& scan, parser_error<std::string, iter_t>&e )
38  {
39  // only fail if the parser could not make sense of it, otherwise, rethrow:
40  if ( programparser->parserUsed() == false )
41  return error_status<>( error_status<>::fail );
42  else
43  return error_status<>( error_status<>::rethrow );
44  }
45 
47  ExecutionEngine* tcaller) :
48  context(tc), caller(tcaller), storage( Service::Create("stack") ),
49  mpositer(positer), ln_offset(0),
50  commonparser(new CommonParser),
51  // Both state and programs are executed (called) in the target context (see seenprogram, seenstatemachine):
52  stateparser(new StateGraphParser(mpositer, context, context->engine(), commonparser)),
53  programparser(new ProgramGraphParser(mpositer, context, context->engine(), *commonparser)),
54  // statements are directly executed:
55  statementparser(new ProgramGraphParser(mpositer, context, caller, *commonparser))
56  {
57  BOOST_SPIRIT_DEBUG_RULE( production );
58  BOOST_SPIRIT_DEBUG_RULE( statemachine );
59  BOOST_SPIRIT_DEBUG_RULE( program );
60  BOOST_SPIRIT_DEBUG_RULE( function );
61  BOOST_SPIRIT_DEBUG_RULE( statement );
62 
63  production
64  = *(
65  statemachine[bind(&ScriptParser::seenstatemachine, this)]
66  | program[bind(&ScriptParser::seenprogram, this)]
67  | no_function_guard(function[bind(&ScriptParser::seenfunction, this)])[boost::bind(&ScriptParser::handle_no_function,this,_1,_2)]
68  | statement[bind(&ScriptParser::seenstatement, this)]
69  | commonparser->notassertingeos
70  )
71  >> expect_eof(end_p);
72 
73  statemachine = stateparser->parser();
74  program = programparser->programParser();
75  function = programparser->functionParser();
76  statement = statementparser->statementParser();
77 
78  // prepare parser to parse statements right away:
79  programparser->initBodyParser("script", storage, 0);
80  statementparser->initBodyParser("script", storage, 0);
81  //mpositer.get_position().line);
82  stateparser->storeOffset();
83  }
84 
85  void ScriptParser::seenstatement()
86  {
87  ProgramInterfacePtr ret = statementparser->bodyParserResult();
88  int steps = 0;
89  // we execute the result directly.
90  ret->loaded( GlobalEngine::Instance() );
91  ret->start();
92  while (ret->execute() && ret->isRunning())
93  {
94  if (ret->inError())
95  {
96  log(Error)
97  << "Script encountered an error during execution of line "
98  << ret->getLineNumber() << endlog();
99  }
100  ++steps;
101  if (steps > 10000)
102  {
103  log(Error)
104  << "Parser refuses to execute more than 10000 yield statements. Fix your program."
105  << endlog();
106  break;
107  }
108  }
109  ret->unloaded();
110  statementparser->initBodyParser("script", storage, 0);
111  //mpositer.get_position().line);
112  stateparser->storeOffset();
113  }
114 
115  void ScriptParser::seenprogram()
116  {
117  // Load the programs in the Scripting Service of this component:
118  assert( context->provides()->hasService("scripting"));
119  ScriptingService::shared_ptr ss = dynamic_pointer_cast<ScriptingService>( context->provides("scripting") );
120  assert(ss);
121  ProgramInterfacePtr ret = programparser->programParserResult();
122  try {
123  FunctionGraphPtr func = dynamic_pointer_cast<FunctionGraph>(ret);
124  if (func)
125  func->setText(program_text);
126  log(Info) << "Loading Program '"<< ret->getName() <<"'" <<endlog();
127  if ( ss->loadProgram( ret ) == false)
128  throw program_load_exception( "Could not load Program '"+ ret->getName() +"' :\n failed to load in ScriptingService.\n");
129  } catch (program_load_exception& e ) {
130  log(Error) << "Could not load Program '"<< ret->getName() <<"' :" << endlog();
131  log(Error) << e.what() << endlog();
132  throw;
133  }
134  programparser->initBodyParser("script", storage, 0);
135  //mpositer.get_position().line);
136  stateparser->storeOffset();
137  }
138 
139  void ScriptParser::seenfunction()
140  {
141  programparser->initBodyParser("script", storage, 0);
142  //mpositer.get_position().line);
143  stateparser->storeOffset();
144  }
145 
146  void ScriptParser::seenstatemachine()
147  {
148  // Load the statemachines in the Scripting Service of this component:
149  assert( context->provides()->hasService("scripting"));
150  ScriptingService::shared_ptr ss = dynamic_pointer_cast<ScriptingService>( context->provides("scripting") );
151  assert(ss);
152  ParsedStateMachinePtr ret = stateparser->getParserResult();
153  if (ret) {
154  try {
155  log(Info) << "Loading StateMachine '"<< ret->getName() <<"'" <<endlog();
156  ss->loadStateMachine( ret ); // throws load_exception
157  } catch (program_load_exception& e ) {
158  log(Error) << "Could not load StateMachine'"<< ret->getName() <<"' :" << endlog();
159  log(Error) << e.what() << endlog();
160  throw;
161  }
162  }
163  programparser->initBodyParser("script", storage, 0);
164  //mpositer.get_position().line);
165  stateparser->storeOffset();
166  }
167 
169  {
170  //skip_parser_t skip_parser = SKIP_PARSER;
171  //iter_pol_t iter_policy( skip_parser );
172  //#define SKIP_PARSER
173  skip_parser_t skippers = (comment_p("#") | comment_p("//")
174  | comment_p("/*", "*/")
175  | (space_p - eol_p)
176  | (commonparser->skipper));
177 
178  iter_pol_t iter_policy(skippers);
179  scanner_pol_t policies(iter_policy);
180  scanner_t scanner(begin, end, policies);
181 
182  ln_offset = mpositer.get_position().line - 1;
183  program_text = std::string( begin, end ); // begin is by reference.
184 
185  stateparser->storeOffset();
186  try
187  {
188  if (!production.parse(scanner))
189  {
190  // on error, we clear all remaining data, cause we can't
191  // guarantee consistency...
192  clear();
194  "Syntax error"), mpositer.get_position().file,
195  mpositer.get_position().line,
196  mpositer.get_position().column);
197  }
198  return;
199  } catch (const parser_error<std::string, iter_t>& e)
200  {
201  // on error, we clear all remaining data, cause we can't
202  // guarantee consistency...
203  clear();
205  e.descriptor), mpositer.get_position().file,
206  mpositer.get_position().line,
207  mpositer.get_position().column);
208  } catch (const parse_exception& e)
209  {
210  // on error, we clear all remaining data, cause we can't
211  // guarantee consistency...
212  clear();
213  throw file_parse_exception(e.copy(), mpositer.get_position().file,
214  mpositer.get_position().line,
215  mpositer.get_position().column);
216  } catch (...)
217  {
218  assert( false );
219  }
220  }
221 
223  {
224  clear();
225  delete statementparser;
226  delete programparser;
227  delete stateparser;
228  delete commonparser;
229  }
230 
231  void ScriptParser::clear()
232  {
233 
234  }
235 
236 }
rule_t notassertingeos
End Of Statement Parser.
boost::shared_ptr< ScriptingService > shared_ptr
boost::shared_ptr< ParsedStateMachine > ParsedStateMachinePtr
boost::shared_ptr< FunctionGraph > FunctionGraphPtr
Service::shared_ptr provides()
Returns this Service.
This is not a parser in the Boost.spirit sense of the word, it&#39;s just a class used to hold the parser...
void parse(iter_t &begin, iter_t end)
Parses and executes the script from begin to end.
STL namespace.
A Parser for Orocos Program Scripts.
boost::shared_ptr< ProgramInterface > ProgramInterfacePtr
virtual parse_exception * copy() const =0
void initBodyParser(const std::string &name, Service::shared_ptr stck, int offset)
Initialize the bodyParser to parse and store each statement it sees.
This is an exception class that keeps a parse_exception pointer along with the location in the file a...
This class contains some very common parser definitions.
void storeOffset()
Stores the current position in the input stream (iterator received from the constructor) in order to ...
parse_exception class that is used for various syntactic errors for which it was not worth defining a...
An execution engine serialises (executes one after the other) the execution of all commands...
ProgramInterfacePtr programParserResult()
Returns the last program parsed by programParser()
This class allows storage and retrieval of operations, ports, attributes and properties provided by a...
Definition: Service.hpp:93
rule_t & programParser()
Returns a program foo {} parser.
ScriptParser(iter_t &positer, TaskContext *tc, ExecutionEngine *caller)
Initialize with an initial position, the TaskContext in which context to parse the scripts and the Ta...
scanner< iter_t, scanner_pol_t > scanner_t
rule_t & functionParser()
Parses a function foo {} definition.
ParsedStateMachinePtr getParserResult()
Returns the last state machine instantiation of parser() or null if no instantiations were seen...
skip_parser_iteration_policy< skip_parser_t > iter_pol_t
static RTT_API ExecutionEngine * Instance()
This is an overloaded member function, provided for convenience. It differs from the above function o...
functor_parser< eol_skip_functor > skipper
End Of Statement Parser.
This is the uppermost exception class in the parser system.
rule_t & statementParser()
Parses a single-line statement.
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
This exception is thrown when a program or state machine could not be loaded into a ProgramProcessor ...
The TaskContext is the C++ representation of an Orocos component.
Definition: TaskContext.hpp:93
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
This interface allows to load program scripts and state machines and allows execution of code...
rule_t & parser()
Returns the top-level parser for state machines.
This class represents a function.
our_pos_iter_t iter_t
scanner_policies< iter_pol_t > scanner_pol_t
void setText(const std::string &t)
Set the program text.