#include "Parse.ih"
// Custom includes
+#include <cerrno>
#include <boost/iterator/transform_iterator.hpp>
+#include <boost/spirit/iterator/file_iterator.hpp>
+#include "../Utils/Exception.hh"
//#include "Parse.mpp"
#define prefix_
namespace console {
namespace detail {
+#ifndef DOXYGEN
+
struct ParserAccess
{
static void init(ParseCommandInfo & info)
{ info.init(); }
- static void setCommand(ParseCommandInfo & info, std::string const & commandPath)
- { info.setCommand(commandPath); }
-
- static void startArgument(ParseCommandInfo & info)
- { info.startArgument(); }
+ static void setBuiltin(ParseCommandInfo & info, ParseCommandInfo::BuiltinCommand builtin)
+ { info.setBuiltin(builtin); }
- static void endArgument(ParseCommandInfo & info)
- { info.endArgument(); }
+ static void setCommand(ParseCommandInfo & info, std::vector<Token> & commandPath)
+ { info.setCommand(commandPath); }
- static void addToken(ParseCommandInfo & info, ArgumentToken const & token)
+ static void addToken(ParseCommandInfo & info, Token const & token)
{ info.addToken(token); }
-
- static void finalize(ParseCommandInfo & info)
- { info.finalize(); }
-
- static ArgumentToken makeToken(std::string const & token)
- { return ArgumentToken(token); }
};
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::string const & command)
- { ParserAccess::init(info());
- ParserAccess::setCommand(info(), command); }
+ void beginCommand(std::vector<Token> & command)
+ { ParserAccess::init(info_);
+ ParserAccess::setCommand(info_, command); }
void endCommand()
- { ParserAccess::finalize(info()); }
-
- void pushArgument(std::string const & argument)
- { ParserAccess::startArgument(info());
- ParserAccess::addToken(info(), ParserAccess::makeToken(argument));
- ParserAccess::endArgument(info()); }
-
- void openGroup()
- { ParserAccess::startArgument(info()); }
-
- void closeGroup()
- { ParserAccess::endArgument(info()); }
-
- void pushPunctuation(std::string const & token)
- { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
-
- void pushWord(std::string const & token)
- { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
+ { cb_(info_); }
+
+ void pushToken(Token const & token)
+ { ParserAccess::addToken(info_, token); }
+
+ void builtin_cd(std::vector<Token> & path)
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD);
+ setBuiltinPathArg(path);
+ cb_(info_); }
+
+ void builtin_ls(std::vector<Token> & path)
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS);
+ setBuiltinPathArg(path);
+ cb_(info_); }
+
+ void pushDirectory(std::vector<Token> & path)
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD);
+ setBuiltinPathArg(path);
+ cb_(info_); }
+
+ void popDirectory()
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD);
+ cb_(info_); }
+
+ void builtin_exit()
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
+ cb_(info_); }
+
+ void builtin_help(std::vector<Token> & path)
+ { ParserAccess::init(info_);
+ ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP);
+ setBuiltinPathArg(path);
+ cb_(info_); }
+
+ void setBuiltinPathArg(std::vector<Token> & path)
+ {
+ pushToken(Token(Token::ArgumentGroupOpen, "("));
+ for (std::vector<Token>::const_iterator i (path.begin());
+ i != path.end(); ++i)
+ pushToken(*i);
+ pushToken(Token(Token::ArgumentGroupClose, ")"));
+ }
};
+#endif
+
}}}
///////////////////////////////////////////////////////////////////////////
-// senf::console::ParseCommandInfo
+// senf::console::Token
-struct senf::console::ParseCommandInfo::MakeRange
+prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
{
- MakeRange() {}
- MakeRange(ParseCommandInfo::token_iterator b) : b_ (b) {}
+ 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
+ static const int bitPosition[32] = {
+ 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 8,
+ 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 6, 0, 5, 10, 9 };
+ os << tokenTypeName[ token.type()
+ ? bitPosition[((token.type() & -token.type()) * 0x077CB531UL) >> 27]+1
+ : 0 ]
+ << "('"
+ << token.value()
+ << "')";
+ return os;
+}
- senf::console::ParseCommandInfo::token_iterator b_;
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ParseCommandInfo
- typedef ParseCommandInfo::argument_value_type result_type;
+prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
+ ParseCommandInfo const & info)
+{
+ 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" };
+ stream << "builtin-" << builtins[info.builtin()];
+ }
- result_type operator()(TempArguments::iterator::value_type const & v) const {
- return result_type( b_ + v.first, b_ + v.second );
+ ParseCommandInfo::ArgumentsRange args (info.arguments());
+ for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
+ ParseCommandInfo::token_iterator j (i->begin());
+ stream << " [";
+ if ( j != i->end() ) {
+ for (;;) {
+ stream << "'" << j->value() << "'";
+ if ( ++j != i->end() ) stream << ' ';
+ else break;
+ }
+ }
+ stream << "]";
}
-};
-prefix_ void senf::console::ParseCommandInfo::finalize()
-{
- arguments_.resize( tempArguments_.size() );
+ return stream;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ParseCommandInfo::ArgumentIterator
- std::copy( boost::make_transform_iterator( tempArguments_.begin(),
- MakeRange(tokens_.begin()) ),
- boost::make_transform_iterator( tempArguments_.end(),
- MakeRange() ),
- arguments_.begin() );
+prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
+ const
+{
+ if (b_->is(Token::ArgumentGroupOpen)) {
+ unsigned level (0);
+ e_ = b_;
+ for (;;) {
+ if (e_->is(Token::ArgumentGroupOpen))
+ ++ level;
+ else if (e_->is(Token::ArgumentGroupClose)) {
+ -- level;
+ if (level == 0)
+ break;
+ }
+ ++e_;
+ }
+ }
+ ++ e_;
+}
- tempArguments_.clear();
+prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
+{
+ e_ = b_;
+ --b_;
+ if (b_->is(Token::ArgumentGroupClose)) {
+ unsigned level (0);
+ for (;;) {
+ if (b_->is(Token::ArgumentGroupClose))
+ ++ level;
+ else if (b_->is(Token::ArgumentGroupOpen)) {
+ -- level;
+ if (level == 0)
+ break;
+ }
+ --b_;
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
-// senf::console::SingleCommandParser
+// senf::console::CommandParser
+
+#ifndef DOXYGEN
-struct senf::console::SingleCommandParser::Impl
+struct senf::console::CommandParser::Impl
{
+ typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
+
detail::ParseDispatcher dispatcher;
- detail::CommandGrammar<detail::ParseDispatcher>::Context context;
- detail::CommandGrammar<detail::ParseDispatcher> grammar;
- detail::SkipGrammar skipGrammar;
+ Grammar::Context context;
+ Grammar grammar;
Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
};
-prefix_ senf::console::SingleCommandParser::SingleCommandParser()
+#endif
+
+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, cb);
+ return boost::spirit::parse( command.begin(), command.end(),
+ impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
+ impl().grammar.use_parser<Impl::Grammar::SkipParser>()
+ ).full;
+}
+
+prefix_ bool senf::console::CommandParser::parseFile(std::string filename, Callback cb)
{
- detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
- return boost::spirit::parse( command.c_str(), impl().grammar, impl().skipGrammar ).full;
+ 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>(),
+ impl().grammar.use_parser<Impl::Grammar::SkipParser>()
+ ).full;
}
///////////////////////////////cc.e////////////////////////////////////////