{
# warning Implement Executor::operator()
SENF_LOG(( "Executing: " << command ));
+ if (command.builtin() == ParseCommandInfo::BuiltinEXIT)
+ throw ExitException();
return true;
}
typedef boost::iterator_range< ParseCommandInfo::argument_iterator> Arguments;
+ struct ExitException {}; // NOT derived from std::exception !
+
///////////////////////////////////////////////////////////////////////////
bool operator()(ParseCommandInfo const & command, std::ostream & output);
struct ParseDispatcher
{
- ParseDispatcher()
- : info_ (0) {}
-
- ParseCommandInfo * info_;
-
- ParseCommandInfo & info() {
- SENF_ASSERT( info_ );
- return *info_;
- }
+ ParseCommandInfo info_;
+ CommandParser::Callback cb_;
struct BindInfo {
- BindInfo( ParseDispatcher & d, ParseCommandInfo & i)
- : dispatcher (d) { dispatcher.info_ = &i; }
-
- ~BindInfo() { dispatcher.info_ = 0; }
+ BindInfo( ParseDispatcher & d, CommandParser::Callback cb)
+ : dispatcher (d) { dispatcher.cb_ = cb; }
+ ~BindInfo() { dispatcher.cb_ = 0; }
ParseDispatcher & dispatcher;
};
void beginCommand(std::vector<std::string> & command)
- { ParserAccess::init(info());
- ParserAccess::setCommand(info(), command); }
+ { ParserAccess::init(info_);
+ ParserAccess::setCommand(info_, command); }
void endCommand()
- { ParserAccess::finalize(info()); }
+ { ParserAccess::finalize(info_); cb_(info_); }
void pushArgument(std::string const & argument)
- { ParserAccess::startArgument(info());
- ParserAccess::addToken(info(), ParserAccess::makeToken(argument));
- ParserAccess::endArgument(info()); }
+ { ParserAccess::startArgument(info_);
+ ParserAccess::addToken(info_, ParserAccess::makeToken(argument));
+ ParserAccess::endArgument(info_); }
void openGroup()
- { ParserAccess::startArgument(info()); }
+ { ParserAccess::startArgument(info_); }
void closeGroup()
- { ParserAccess::endArgument(info()); }
+ { ParserAccess::endArgument(info_); }
void pushPunctuation(std::string const & token)
- { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
+ { ParserAccess::addToken(info_, ParserAccess::makeToken(token)); }
void pushWord(std::string const & token)
- { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
+ { ParserAccess::addToken(info_, ParserAccess::makeToken(token)); }
void builtin_cd(std::vector<std::string> & path)
- { ParserAccess::init(info());
- ParserAccess::setBuiltin(info(), ParseCommandInfo::BuiltinCD);
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD);
setBuiltinPathArg(path);
- ParserAccess::finalize(info()); }
+ ParserAccess::finalize(info_); cb_(info_); }
void builtin_ls(std::vector<std::string> & path)
- { ParserAccess::init(info());
- ParserAccess::setBuiltin(info(), ParseCommandInfo::BuiltinLS);
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS);
setBuiltinPathArg(path);
- ParserAccess::finalize(info()); }
+ ParserAccess::finalize(info_); cb_(info_); }
+
+ void pushDirectory(std::vector<std::string> & path)
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD);
+ setBuiltinPathArg(path);
+ ParserAccess::finalize(info_); cb_(info_); }
+
+ void popDirectory()
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD);
+ ParserAccess::finalize(info_); cb_(info_); }
+
+ void builtin_exit()
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
+ ParserAccess::finalize(info_); cb_(info_); }
void setBuiltinPathArg(std::vector<std::string> & path)
{
- ParserAccess::startArgument(info());
+ ParserAccess::startArgument(info_);
for (std::vector<std::string>::const_iterator i (path.begin());
i != path.end(); ++i)
- ParserAccess::addToken(info(), ParserAccess::makeToken(*i));
- ParserAccess::endArgument(info());
+ ParserAccess::addToken(info_, ParserAccess::makeToken(*i));
+ ParserAccess::endArgument(info_);
}
};
struct senf::console::ParseCommandInfo::MakeRange
{
+ typedef ParseCommandInfo::argument_value_type result_type;
+
MakeRange() {}
MakeRange(ParseCommandInfo::token_iterator b) : b_ (b) {}
-
+
senf::console::ParseCommandInfo::token_iterator b_;
-
- typedef ParseCommandInfo::argument_value_type result_type;
-
+
result_type operator()(TempArguments::iterator::value_type const & v) const {
return result_type( b_ + v.first, b_ + v.second );
}
if (info.builtin() == ParseCommandInfo::NoBuiltin)
stream << senf::stringJoin(info.commandPath(), "/");
else {
- char const * builtins[] = { "", "cd", "ls" };
+ char const * builtins[] = { "", "cd", "ls", "pushd", "popd", "exit" };
stream << "builtin-" << builtins[info.builtin()];
}
}
///////////////////////////////////////////////////////////////////////////
-// senf::console::SingleCommandParser
+// senf::console::CommandParser
-struct senf::console::SingleCommandParser::Impl
+struct senf::console::CommandParser::Impl
{
typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
};
-prefix_ senf::console::SingleCommandParser::SingleCommandParser()
+prefix_ senf::console::CommandParser::CommandParser()
: impl_ (new Impl())
{}
-prefix_ senf::console::SingleCommandParser::~SingleCommandParser()
+prefix_ senf::console::CommandParser::~CommandParser()
{}
-prefix_ bool senf::console::SingleCommandParser::parseCommand(std::string command,
- ParseCommandInfo & info)
+prefix_ bool senf::console::CommandParser::parse(std::string command, Callback cb)
{
- detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
+ detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb);
+# warning don't use c_str() in parse and add istream parser. Implement error checking in parser.
return boost::spirit::parse( command.c_str(),
impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
impl().grammar.use_parser<Impl::Grammar::SkipParser>()
///////////////////////////////////////////////////////////////////////////
// senf::console::SingleCommandParser
-prefix_ senf::console::SingleCommandParser::Impl & senf::console::SingleCommandParser::impl()
+prefix_ senf::console::CommandParser::Impl & senf::console::CommandParser::impl()
{
SENF_ASSERT(impl_);
return *impl_;
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/range/iterator_range.hpp>
+#include <boost/function.hpp>
//#include "Parse.mpp"
///////////////////////////////hh.p////////////////////////////////////////
typedef boost::iterator_range<argument_iterator> ArgumentsRange;
typedef boost::iterator_range<token_iterator> TokensRange;
- enum BuiltinCommand { NoBuiltin, BuiltinCD, BuiltinLS };
+ enum BuiltinCommand { NoBuiltin,
+ BuiltinCD,
+ BuiltinLS,
+ BuiltinPUSHD,
+ BuiltinPOPD,
+ BuiltinEXIT };
BuiltinCommand builtin() const;
CommandPathRange commandPath() const;
/** \brief
*/
- class SingleCommandParser
+ class CommandParser
: boost::noncopyable
{
public:
///////////////////////////////////////////////////////////////////////////
// Types
+ typedef boost::function<void (ParseCommandInfo const &)> Callback;
+
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
- SingleCommandParser();
- ~SingleCommandParser();
+ CommandParser();
+ ~CommandParser();
///@}
///////////////////////////////////////////////////////////////////////////
- bool parseCommand(std::string command, ParseCommandInfo & info);
+ bool parse(std::string command, Callback cb);
private:
struct Impl;
: public boost::spirit::grammar_def< boost::spirit::rule<Scanner>,
boost::spirit::rule<Scanner> >
{
- boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token;
- boost::spirit::rule<Scanner> punctuation, hexbyte, balanced_tokens, simple_argument;
- boost::spirit::rule<Scanner> complex_argument, builtin, skip;
-
+ boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token,
+ punctuation, hexbyte, balanced_tokens, simple_argument, complex_argument, builtin,
+ skip, commands, block, statement;
boost::spirit::chset<> special_p, punctuation_p, space_p, invalid_p, word_p;
-
boost::spirit::distinct_parser<> keyword_p;
definition(CommandGrammar const & self) :
// Characters with a special meaning within the parser
- // and characters reserved for future extensions
special_p ("/(){};"),
// Characters which are returned as punctuation tokens
punctuation_p (",="),
- // Whitespace characters (we don't want newlines in there)
- space_p (" \t"),
+ // Whitespace characters
+ space_p (" \t\n\r"),
// Invalid characters: All chars below \x20 (space) which are not space_p
// (don't put a \0 in the chset<> argument *string* ...)
using namespace boost::spirit;
typedef ParseDispatcher PD;
+ commands
+ = * command
+ ;
+
+ command
+ = builtin
+ | path >> ( block | statement )
+ ;
+
builtin
= keyword_p("cd")
>> path
boost::ref(self.context.path)) ]
| keyword_p("ls")
>> ! path
- >> eps_p [ self.dispatch(&PD::builtin_cd,
+ >> eps_p [ self.dispatch(&PD::builtin_ls,
boost::ref(self.context.path)) ]
+ | keyword_p("exit") [ self.dispatch(&PD::builtin_exit) ]
;
- command
- = builtin
- | path [ self.dispatch(&PD::beginCommand,
+ block
+ = ch_p('{') [ self.dispatch(&PD::pushDirectory,
+ boost::ref(self.context.path)) ]
+ >> * command
+ >> ch_p('}') [ self.dispatch(&PD::popDirectory) ]
+ ;
+
+ statement
+ = eps_p [ self.dispatch(&PD::beginCommand,
boost::ref(self.context.path)) ]
>> * argument
- >> ! ch_p(';')
+ >> (ch_p(';') | end_p)
>> eps_p [ self.dispatch(&PD::endCommand) ]
;
complex_argument // Argument consists of multiple tokens
= ch_p('(') [ self.dispatch(&PD::openGroup) ]
- >> * token
- >> ch_p(')') [ self.dispatch(&PD::closeGroup) ]
+ >> * token
+ >> ch_p(')') [ self.dispatch(&PD::closeGroup) ]
;
string // Returns value in context.str
;
skip
- = space_p
- | comment_p('#')
+ = space_p | comment_p('#')
;
BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
start_parsers(
- command, // CommandParser
+ commands, // CommandParser
skip // SkipParser
);
std::ostream & os_;
+ void pushDirectory(std::vector<std::string> const & path)
+ { os_ << "pushDirectory( " << senf::stringJoin(path,"/") << " )\n"; }
+ void popDirectory()
+ { os_ << "popDirectory()\n"; }
+
void beginCommand(std::vector<std::string> const & command)
{ os_ << "beginCommand( " << senf::stringJoin(command, "/") << " )\n"; }
void endCommand()
{ os_ << "builtin_cd( " << senf::stringJoin(path, "/") << " )\n"; }
void builtin_ls(std::vector<std::string> const & path)
{ os_ << "builtin_cd( " << senf::stringJoin(path, "/") << " )\n"; }
+ void builtin_exit()
+ { os_ << "builtin_exit()\n"; }
};
}
-BOOST_AUTO_UNIT_TEST(commandParser)
+BOOST_AUTO_UNIT_TEST(commandGrammar)
{
senf::console::detail::CommandGrammar<TestParseDispatcher>::Context context;
std::stringstream ss;
"endCommand()\n" );
}
-BOOST_AUTO_UNIT_TEST(singleCommandParser)
+namespace {
+ senf::console::ParseCommandInfo info;
+ void setInfo(senf::console::ParseCommandInfo const & i)
+ { info = i; }
+}
+
+BOOST_AUTO_UNIT_TEST(commandParser)
{
- senf::console::SingleCommandParser parser;
+ senf::console::CommandParser parser;
char const text[] =
"# Comment\n"
" x\"01 02 # Inner comment\n"
" 0304\"";
- senf::console::ParseCommandInfo info;
- BOOST_CHECK( parser.parseCommand(text, info) );
+ BOOST_CHECK( parser.parse(text, &setInfo) );
char const * path[] = { "doo", "bii", "doo" };
#include <boost/algorithm/string/trim.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
+#include <boost/bind.hpp>
#include "../Utils/senfassert.hh"
#include "../Utils/membind.hh"
#include "../Utils/Logger/SenfLog.hh"
tail_ = helper->tail();
boost::trim(data); // Gets rid of superfluous \r or \n characters
- if (data == "exit") {
+ try {
+ if (! parser_.parse(data, boost::bind<void>(boost::ref(executor_), _1, boost::ref(out_))))
+ out_ << "syntax error" << std::endl;
+ }
+ catch (Executor::ExitException &) {
// THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
stopClient();
return;
- }
-
- ParseCommandInfo command;
- if (parser_.parseCommand(data, command))
- executor_(command, out_);
- else
- out_ << "syntax error" << std::endl;
+ }
out_ << name_ << "# " << std::flush;
ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
ClientHandle handle_;
std::string tail_;
- SingleCommandParser parser_;
+ CommandParser parser_;
Executor executor_;
std::string name_;
senf::log::ConsoleTarget::instance().route< senf::SenfLog, senf::log::NOTICE >();
senf::console::Server::start( senf::INet4SocketAddress("127.0.0.1:23232") )
- .name("testServer ");
+ .name("testServer");
senf::Scheduler::instance().process();
}