【发布时间】:2014-06-11 13:23:10
【问题描述】:
我希望我的基于 boost::spirit 的解析器能够解析文件,将解析后的规则转换为不同的类型,并发出一个包含它找到的所有匹配项的向量。作为属性发出的所有类型都应该从基类型继承,例如:
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapt_struct.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
struct CommandBase
{
virtual void commandAction()
{
std::cout << "This is a base command. You should never see this!" << std::endl;
//Boost::spirit seems to get mad if I make this purely virtual. Clearly I'm doing it wrong.
}
};
struct CommandTypeA : public CommandBase
{
int valueA;
int valueB;
virtual void commandAction()
{
std::cout << "CommandType A! ValueA: " << valueA << " ValueB: " << valueB << std::endl;
}
};
struct CommandTypeB : public CommandBase
{
double valueA;
std::vector<char> valueB;
virtual void commandAction()
{
std::cout << "CommandType B! valueA: " << valueA << " string: " << std::string(valueB.begin(), valueB.end()) << std::endl;
}
};
struct CommandTypeC : public CommandBase
{
//Represents a sort of "subroutine" type where multiple commands can be grouped together
std::vector<char> labelName;
std::vector<boost::shared_ptr<CommandBase> > commands;
virtual void commandAction()
{
std::cout << "Subroutine: " << std::string(labelName.start(), labelName.end())
<< " has " << commands.size() << " commands:" << std::endl;
BOOST_FOREACH(boost::shared_ptr<CommandBase> c, commands)
{
c->commandAction();
}
}
};
现在,我的尝试解析器代码:
namespace ascii = boost::spirit::ascii;
namespace qi = boost::spirit::qi;
using qi::lit_;
BOOST_FUSION_ADAPT_STRUCT(
CommandTypeA,
(int, valueA)
(int, valueB)
)
BOOST_FUSION_ADAPT_STRUCT(
CommandTypeB,
(double, valueA)
(std::vector<char>, valueB)
)
BOOST_FUSION_ADAPT_STRUCT(
CommandTypeC,
(std::vector<char>, labelName)
(std::vector<boost::shared_ptr<CommandBase> >, commands)
)
template<typename Iterator, typename Skipper = ascii::space_type>
struct CommandParser : qi::grammar<Iterator, std::vector<boost::shared_ptr<CommandBase> >(), Skipper>
{
public:
CommandParser() : CommandParser()::base_type(commands)
{
CommandARule = qi::int_ >> qi::int_ >> lit("CMD_A");
CommandBRule = qi::int_ >> +(qi::char_) >> lit("CMD_B");
CommandCRule = qi::char_(':') >> lexeme[+(qi::char_ - ';' - ascii::space) >> +ascii::space] >> commands >> qi::char_(';');
commands = +(CommandARule | CommandBRule | CommandCRule);
}
protected:
qi::rule<Iterator, boost::shared_ptr<CommandTypeA>, Skipper> CommandARule;
qi::rule<Iterator, boost::shared_ptr<CommandTypeB>, Skipper> CommandBRule;
qi::rule<Iterator, boost::shared_ptr<CommandTypeC>, Skipper> CommandCRule;
qi::rule<Iterator, std::vector<boost::shared_ptr<CommandBase> >, Skipper> commands;
};
std::vector<boost::shared_ptr<CommandBase> > commandList;
bool success = qi::phrase_parse(StartIterator, EndIterator, CommandParser, ascii::space, commandList);
BOOST_FOREACH(boost::shared_ptr<CommandBase> c, commandList)
{
c->commandAction();
}
现在,这段代码肯定不会编译,但我希望它能理解我正在尝试做的事情的要点。
主要的问题是 qi::rules 似乎想要发出实际的结构,而不是对它的引用。
我的问题是:
是否可以像我尝试的那样强制 qi::rule 发出多态兼容的引用(如果是,如何),这是我尝试完成的最佳方法(即表示已解析命令及其参数的可执行对象列表)?
【问题讨论】:
-
您知道即使解析器公开了
std::vector<char>,您也可以使用std::string?它是内置属性转换之一
标签: c++ boost polymorphism boost-spirit boost-spirit-qi