我想用 boost::spirit 解析命令行参数。使用符号表似乎更优雅,而不是在 或 组合中列出所有可能的命令。
现在我开始非常简单(假设我只有 2 个可能的命令,不消耗任何参数),但我已经陷入困境了。
我读到了 boost 示例中也列出的 nabialek 技巧,并且我尝试过:
#include <boost/spirit/home/qi/nonterminal/rule.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename Tag>
struct GenericCommand
{};
namespace tag {
struct none
{};
struct stop
{};
struct limit
{};
} // namespace tag
using None = GenericCommand<tag::none>;
using Stop = GenericCommand<tag::stop>;
using Limit = GenericCommand<tag::limit>;
using Command = std::variant<None, Stop, Limit>;
struct Grammar :
qi::grammar<std::string::const_iterator, Command (), qi::ascii::space_type>
{
using Iterator = std::string::const_iterator;
using Skipper = qi::ascii::space_type;
Grammar ();
using Rule = qi::rule<Iterator, Command (), Skipper>;
qi::symbols<char, const Rule*> commands;
qi::rule<Iterator, Command (), Skipper> command;
qi::rule<Iterator, Stop (), Skipper> stop_;
qi::rule<Iterator, Limit (), Skipper> limit_;
Rule parse, stop, limit, rest;
struct SetRest
{
explicit SetRest (Rule& rule) : rule {rule} {}
void operator() (Rule* real_rule) const { rule = *real_rule; }
Rule& rule;
};
};
Grammar::Grammar () : Grammar::base_type {parse}
{
using namespace qi;
parse = command;
commands.add ("stop", &stop) ("limit", &limit);
command = no_case[commands[SetRest {rest}]] >> rest;
stop_ = eps;
limit_ = eps;
stop = stop_;
limit = limit_;
}
这段代码给了我编译错误(“没有匹配的函数来调用'do_call'”)我不知道如何解释。为什么这不起作用?我没有看到示例和我的代码之间存在概念差异。或者这已经停止工作了?该示例来自旧版本。
感谢 Marek,我发现我可以使用使用符号属性的惰性解析器来跟踪符号。我错过了包括
boost/phoenix/operator.hpp
。所以我的命令规则现在看起来像这样:
command = no_case[commands[_a = _1]] >> lazy(*_a)[_val = _1];
这按预期工作。