为什么这个 nabialek 技巧在我带有 boost::spirit::qi 的简单语法中不起作用

Why does this nabialek trick not work in my simple grammar with boost::spirit::qi

提问人:David 提问时间:8/8/2023 更新时间:8/14/2023 访问量:30

问:

我想用boost::spirit解析命令行参数。与其以 or 组合列出所有可能的命令,不如使用符号表似乎更优雅。

现在我开始非常简单(假设我只有 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'的匹配函数»)我不知道如何解释。为什么这不起作用?我看不出示例和我的代码之间在概念上有什么区别。还是这停止了工作?该示例来自旧版本。

C++ 解析 boost-spirit-qi

评论

0赞 Marek R 8/9/2023
这里是MCVE
1赞 Marek R 8/9/2023
请注意,您使用的是相当古老的示例。这是新的,它在这里运行

答:

1赞 David 8/9/2023 #1

多亏了 Marek,我发现我可以使用使用符号属性的惰性解析器来跟踪符号。而且我错过了.所以我的命令规则现在看起来像这样:boost/phoenix/operator.hpp

command = no_case[commands[_a = _1]] >> lazy(*_a)[_val = _1];

这按预期工作。

可以在 boost.org 网站上找到显示这一点的示例。

评论

0赞 sehe 8/13/2023
如果您包含链接(例如,来自 @MarekR 的评论),答案会更完整。对 SO 的评论不被视为永久性的