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

huangapple go评论97阅读模式
英文:

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

问题

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

现在我开始得很简单(假设我只有两个可能的命令,不需要消耗任何参数),但我已经陷入困境。

我读到了nabialek技巧,它也在boost示例中列出,我尝试了以下代码:

#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_;
}

这段代码给我带来了编译错误("no matching function for call to 'do_call'"),我不知道如何解释。为什么不起作用?我没有看到示例和我的代码之间的概念上的区别。还是说这个已经不起作用了?这个示例来自一个较旧的版本。

英文:

I want to parse command line arguments with boost::spirit. Instead of listing all possible commands in an or combination it seems more elegant to use a symbol table.

Now I started very simple (lets assume I only have 2 possible commands that do not consume any arguments) and I am already stuck.

I read about the nabialek trick that is also listed in the boost examples and I tried:

#include &lt;boost/spirit/home/qi/nonterminal/rule.hpp&gt;
#include &lt;boost/spirit/include/qi.hpp&gt;

namespace qi = boost::spirit::qi;

template &lt;typename Tag&gt;
struct GenericCommand
{};

namespace tag {
    struct none
    {};
    struct stop
    {};
    struct limit
    {};
} // namespace tag

using None = GenericCommand&lt;tag::none&gt;;
using Stop = GenericCommand&lt;tag::stop&gt;;
using Limit = GenericCommand&lt;tag::limit&gt;;

using Command = std::variant&lt;None, Stop, Limit&gt;;

struct Grammar :
  qi::grammar&lt;std::string::const_iterator, Command (), qi::ascii::space_type&gt;
{
    using Iterator = std::string::const_iterator;
    using Skipper = qi::ascii::space_type;

    Grammar ();

    using Rule = qi::rule&lt;Iterator, Command (), Skipper&gt;;

    qi::symbols&lt;char, const Rule*&gt; commands;
    qi::rule&lt;Iterator, Command (), Skipper&gt; command;
    qi::rule&lt;Iterator, Stop (), Skipper&gt; stop_;
    qi::rule&lt;Iterator, Limit (), Skipper&gt; limit_;

    Rule parse, stop, limit, rest;

    struct SetRest
    {
        explicit SetRest (Rule&amp; rule) : rule {rule} {}

        void operator() (Rule* real_rule) const { rule = *real_rule; }

        Rule&amp; rule;
    };
};

Grammar::Grammar () : Grammar::base_type {parse}
{
    using namespace qi;

    parse = command;
    commands.add (&quot;stop&quot;, &amp;stop) (&quot;limit&quot;, &amp;limit);

    command = no_case[commands[SetRest {rest}]] &gt;&gt; rest;

    stop_ = eps;
    limit_ = eps;

    stop = stop_;
    limit = limit_;
}

This code gives me compile errors («no matching function for call to 'do_call'») I have no clue how to interpret. Why does this not work? I don't see a conceptual difference between the example and my code. Or is it that this stopped working? The example is from an older version.

答案1

得分: 1

感谢Marek,我发现我可以使用惰性解析器来跟踪符号,该解析器使用符号的属性。而且我忘记包含boost/phoenix/operator.hpp。所以我的命令规则现在看起来像这样:

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

这个代码按预期工作。

展示这个示例的例子可以在boost.org网站上找到。

英文:

Thanks to Marek I found out that I can follow the symbols with the lazy parser that uses the attribute of the symbol. And I missed to include boost/phoenix/operator.hpp. So my command rule now looks like this:

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

This works as expected.

The example showing this can be found on the boost.org Website.

huangapple
  • 本文由 发表于 2023年8月8日 23:02:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76860822.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定