#include <cerrno>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/spirit/iterator/file_iterator.hpp>
-#include "../Utils/String.hh"
#include "../Utils/Exception.hh"
//#include "Parse.mpp"
#ifndef DOXYGEN
- struct ParserAccess
- {
- static void init(ParseCommandInfo & info)
- { info.init(); }
-
- static void setBuiltin(ParseCommandInfo & info, ParseCommandInfo::BuiltinCommand builtin)
- { info.setBuiltin(builtin); }
-
- static void setCommand(ParseCommandInfo & info, std::vector<std::string> & commandPath)
- { info.setCommand(commandPath); }
-
- static void addToken(ParseCommandInfo & info, ArgumentToken const & token)
- { info.addToken(token); }
-
- static ArgumentToken makeToken(ArgumentToken::TokenType type, std::string const & token)
- { return ArgumentToken(type, token); }
- };
-
struct ParseDispatcher
{
- ParseCommandInfo info_;
- CommandParser::Callback cb_;
+ ParseCommandInfo * info_;
struct BindInfo {
- BindInfo( ParseDispatcher & d, CommandParser::Callback cb)
- : dispatcher (d) { dispatcher.cb_ = cb; }
- ~BindInfo() { dispatcher.cb_ = 0; }
+ BindInfo( ParseDispatcher & d, ParseCommandInfo & info)
+ : dispatcher (d) { dispatcher.info_ = &info; }
+ ~BindInfo() { dispatcher.info_ = 0; }
ParseDispatcher & dispatcher;
};
- void beginCommand(std::vector<std::string> & command)
- { ParserAccess::init(info_);
- ParserAccess::setCommand(info_, command); }
+ void beginCommand(std::vector<Token> & command)
+ { info_->clear();
+ info_->command(command); }
void endCommand()
- { cb_(info_); }
-
- void pushArgument(ArgumentToken::TokenType type, std::string const & argument)
- { ParserAccess::addToken(info_, ParserAccess::makeToken(type, argument)); }
-
- void openGroup()
- { pushPunctuation("("); }
-
- void closeGroup()
- { pushPunctuation(")"); }
-
- void pushPunctuation(std::string const & token)
- {
- ArgumentToken::TokenType type;
- switch (token[0]) {
- case '/' : type = ArgumentToken::PathSeparator; break;
- case '(' : type = ArgumentToken::ArgumentGroupOpen; break;
- case ')' : type = ArgumentToken::ArgumentGroupClose; break;
- case '{' : type = ArgumentToken::DirectoryGroupOpen; break;
- case '}' : type = ArgumentToken::DirectoryGroupClose; break;
- case ';' : type = ArgumentToken::CommandTerminator; break;
- default : type = ArgumentToken::OtherPunctuation; break;
- }
- ParserAccess::addToken(info_, ParserAccess::makeToken(type, token));
- }
+ { }
- void pushWord(ArgumentToken::TokenType type, std::string const & token)
- { ParserAccess::addToken(info_, ParserAccess::makeToken(type, token)); }
+ void pushToken(Token const & token)
+ { info_->addToken(token); }
- void builtin_cd(std::vector<std::string> & path)
- { ParserAccess::init(info_);
- ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD);
- setBuiltinPathArg(path);
- cb_(info_); }
+ void builtin_cd(std::vector<Token> & path)
+ { info_->clear();
+ info_->builtin(ParseCommandInfo::BuiltinCD);
+ setBuiltinPathArg(path); }
- void builtin_ls(std::vector<std::string> & path)
- { ParserAccess::init(info_);
- ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS);
- setBuiltinPathArg(path);
- cb_(info_); }
+ void builtin_ls(std::vector<Token> & path)
+ { info_->clear();
+ info_->builtin(ParseCommandInfo::BuiltinLS);
+ setBuiltinPathArg(path); }
- void pushDirectory(std::vector<std::string> & path)
- { ParserAccess::init(info_);
- ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD);
- setBuiltinPathArg(path);
- cb_(info_); }
+ void pushDirectory(std::vector<Token> & path)
+ { info_->clear();
+ info_->builtin(ParseCommandInfo::BuiltinPUSHD);
+ setBuiltinPathArg(path); }
void popDirectory()
- { ParserAccess::init(info_);
- ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD);
- cb_(info_); }
+ { info_->clear();
+ info_->builtin(ParseCommandInfo::BuiltinPOPD); }
void builtin_exit()
- { ParserAccess::init(info_);
- ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
- cb_(info_); }
+ { info_->clear();
+ info_->builtin(ParseCommandInfo::BuiltinEXIT); }
- void builtin_help(std::vector<std::string> & path)
- { ParserAccess::init(info_);
- ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP);
- setBuiltinPathArg(path);
- cb_(info_); }
+ void builtin_help(std::vector<Token> & path)
+ { info_->clear();
+ info_->builtin(ParseCommandInfo::BuiltinHELP);
+ setBuiltinPathArg(path); }
- void setBuiltinPathArg(std::vector<std::string> & path)
+ void setBuiltinPathArg(std::vector<Token> & path)
{
- pushPunctuation("(");
- for (std::vector<std::string>::const_iterator i (path.begin());
+ pushToken(ArgumentGroupOpenToken());
+ for (std::vector<Token>::const_iterator i (path.begin());
i != path.end(); ++i)
- ParserAccess::addToken(info_,
- ParserAccess::makeToken(ArgumentToken::Word, *i));
- pushPunctuation(")");
+ pushToken(*i);
+ pushToken(ArgumentGroupCloseToken());
}
};
}}}
///////////////////////////////////////////////////////////////////////////
+// senf::console::Token
+
+prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
+{
+ static char const * tokenTypeName[] = {
+ "None",
+ "PathSeparator",
+ "ArgumentGroupOpen",
+ "ArgumentGroupClose",
+ "DirectoryGroupOpen",
+ "DirectoryGroupClose",
+ "CommandTerminator",
+ "OtherPunctuation",
+ "BasicString",
+ "HexString",
+ "Word" };
+ // The real table is:
+ // static const int bitPosition[32] = {
+ // 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ // 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
+ // However, we have replaced all values >= sizeof(tokenTypeName) with 0
+ // and have added 1 to all the remaining values
+ static const int bitPosition[32] = {
+ 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
+ 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
+ // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
+ os << tokenTypeName[ token.type()
+ ? bitPosition[((token.type() & -token.type()) * 0x077CB531UL) >> 27]
+ : 0 ]
+ << "('"
+ << token.value()
+ << "')";
+ return os;
+}
+
+///////////////////////////////////////////////////////////////////////////
// senf::console::ParseCommandInfo
prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
ParseCommandInfo const & info)
{
- if (info.builtin() == ParseCommandInfo::NoBuiltin)
- stream << senf::stringJoin(info.commandPath(), "/");
+ if (info.builtin() == ParseCommandInfo::NoBuiltin) {
+ ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
+ ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
+ if (i != i_end) {
+ for (;;) {
+ stream << i->value();
+ if ( ++i != i_end ) stream << "/";
+ else break;
+ }
+ }
+ }
else {
- char const * builtins[] = { "", "cd", "ls", "pushd", "popd", "exit", "help" };
+ char const * builtins[] = { 0, "cd", "ls", "pushd", "popd", "exit", "help" };
stream << "builtin-" << builtins[info.builtin()];
}
prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
const
{
- if (b_->is(ArgumentToken::ArgumentGroupOpen)) {
+ if (b_->is(Token::ArgumentGroupOpen)) {
unsigned level (0);
e_ = b_;
for (;;) {
- if (e_->is(ArgumentToken::ArgumentGroupOpen))
+ if (e_->is(Token::ArgumentGroupOpen))
++ level;
- else if (e_->is(ArgumentToken::ArgumentGroupClose)) {
+ else if (e_->is(Token::ArgumentGroupClose)) {
-- level;
if (level == 0)
break;
{
e_ = b_;
--b_;
- if (b_->is(ArgumentToken::ArgumentGroupClose)) {
+ if (b_->is(Token::ArgumentGroupClose)) {
unsigned level (0);
for (;;) {
- if (b_->is(ArgumentToken::ArgumentGroupClose))
+ if (b_->is(Token::ArgumentGroupClose))
++ level;
- else if (b_->is(ArgumentToken::ArgumentGroupOpen)) {
+ else if (b_->is(Token::ArgumentGroupOpen)) {
-- level;
if (level == 0)
break;
prefix_ senf::console::CommandParser::~CommandParser()
{}
-prefix_ bool senf::console::CommandParser::parse(std::string command, Callback cb)
+// This template member is placed here, since it is ONLY called from the implementation. Otherwise,
+// we would need to expose the Impl member to the public, which we don't want to do.
+
+template <class Iterator>
+prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator b, Iterator e, Callback cb)
{
- detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb);
- return boost::spirit::parse( command.begin(), command.end(),
- impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
- impl().grammar.use_parser<Impl::Grammar::SkipParser>()
- ).full;
+ ParseCommandInfo info;
+ detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
+ boost::spirit::parse_info<Iterator> result;
+
+ for(;;) {
+ result = boost::spirit::parse(
+ b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
+ b = result.stop;
+ if (b == e)
+ return e;
+ info.clear();
+ result = boost::spirit::parse(b, e,
+ impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
+ impl().grammar.use_parser<Impl::Grammar::SkipParser>());
+ if (! result.hit)
+ return b;
+ if (! info.empty())
+ cb(info);
+ b = result.stop;
+ }
+}
+
+prefix_ bool senf::console::CommandParser::parse(std::string const & command, Callback cb)
+{
+ return parseLoop(command.begin(), command.end(), cb) == command.end();
}
-prefix_ bool senf::console::CommandParser::parseFile(std::string filename, Callback cb)
+prefix_ bool senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
{
- detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb);
boost::spirit::file_iterator<> i (filename);
if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
boost::spirit::file_iterator<> const i_end (i.make_end());
- return boost::spirit::parse( i, i_end,
- impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
+ return parseLoop(i, i_end, cb) == i_end;
+}
+
+prefix_ bool senf::console::CommandParser::parseArguments(std::string const & arguments,
+ ParseCommandInfo & info)
+{
+ detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
+ return boost::spirit::parse( arguments.begin(), arguments.end(),
+ impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
impl().grammar.use_parser<Impl::Grammar::SkipParser>()
).full;
}
+struct senf::console::CommandParser::SetIncremental
+{
+ SetIncremental(CommandParser & parser) : parser_ (parser) {
+ parser_.impl().grammar.incremental = true;
+ }
+
+ ~SetIncremental() {
+ parser_.impl().grammar.incremental = false;
+ }
+
+ CommandParser & parser_;
+};
+
+prefix_ std::string::size_type
+senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
+{
+ SetIncremental si (*this);
+ return std::distance( commands.begin(),
+ parseLoop(commands.begin(), commands.end(), cb) );
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SyntaxErrorException
+
+prefix_ char const * senf::console::SyntaxErrorException::what()
+ const throw()
+{
+ return message().empty() ? "syntax error" : message().c_str();
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "Parse.mpp"