子解析器属性

3
我在撰写语法时遇到了问题。假设我有一个继承自 Base 的类DerivedGrammarDerived有一个合成属性 Derived,而GrammarBase则有一个合成属性 Base。 我该如何在GrammarDerived的解析规则中使用GrammarBase?我认为这应该是可能的,因为我可以将Base&绑定到Derived&,但似乎没有什么作用。
换句话说,在下面的代码中,我该如何通过引用让grammarBase_val交互?
template<typename Iterator>
struct GrammarDerived : public grammar <Iterator, Derived()> {
    GrammarDerived() : GrammarDerived::base_type(start) {
        start = rule1[bind(someFunc, _val)] >> grammarBase;
        rule1 = /* ... */;
    }
    rule<Iterator, Derived()> start;
    rule<Iterator, Derived()> rule1;
    GrammarBase grammarBase;
};
1个回答

2
在一个更简单的环境中,这表明这主要是类型推断的限制:
Derived parse_result;
bool ok = qi::phrase_parse(f, l, base_, qi::space, data);

当解析器暴露一个Base时,该方法将无法工作,但是您可以通过为模板实例化添加“类型提示”来修复它[1]:

bool ok = qi::phrase_parse(f, l, base_, qi::space, static_cast<Base&>(data));

完整演示在Coliru上实时演示

#include <algorithm>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi      = boost::spirit::qi;
namespace phoenix = boost::phoenix;

struct Base {
    int x;
    double y;
};

BOOST_FUSION_ADAPT_STRUCT(Base, (int,x)(double,y))

struct Derived : Base { };

int main()
{
    typedef std::string::const_iterator It;
    qi::rule<It, Base(), qi::space_type> base_ = qi::int_ >> qi::double_;

    std::string const input = "1 3.14";
    auto f(input.begin()), l(input.end());

    Derived parse_result;
    bool ok = qi::phrase_parse(f, l, base_, qi::space, static_cast<Base&>(parse_result));
    if (ok)
    {
        std::cout << "Parsed: " << parse_result.x << " " << parse_result.y << "\n";
    } else
    {
        std::cout << "Parse failed\n";
    }

    if (f != l)
    {
        std::cout << "Input remaining: '" << std::string(f,l) << "'\n";
    }
}

或者

您可以通过显式传递可公开属性的引用给基本解析器/规则来避免混淆:

template <typename It, typename Skipper = qi::space_type>
struct derived_grammar : qi::grammar<It, Derived(), Skipper>
{
    derived_grammar() : derived_grammar::base_type(start) {
        base_ = qi::int_ >> qi::double_;
        glue_ = base_ [ qi::_r1 = qi::_1 ];
        start = "derived:" >> glue_(qi::_val); // passing the exposed attribute for the `Base&` reference
    }
  private:
    qi::rule<It, Derived(),   Skipper> start;
    qi::rule<It, void(Base&), Skipper> glue_;
    qi::rule<It, Base(),      Skipper> base_; // could be a grammar instead of a rule
};

如果你坚持的话,可以使用 qi::attr_cast<Base, Base> 来避免使用 glue_/base_ 分离 (但为了可读性,我不会这样做)。
以下是完整代码以供参考:在Coliru上实时运行
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <algorithm>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi  = boost::spirit::qi;
namespace phx = boost::phoenix;

struct Base {
    int x;
    double y;
};

BOOST_FUSION_ADAPT_STRUCT(Base, (int,x)(double,y))

struct Derived : Base { };

template <typename It, typename Skipper = qi::space_type>
struct derived_grammar : qi::grammar<It, Derived(), Skipper>
{
    derived_grammar() : derived_grammar::base_type(start) {
        base_ = qi::int_ >> qi::double_;
        glue_ = base_ [ qi::_r1 = qi::_1 ];
        start = "derived:" >> glue_(qi::_val); // passing the exposed attribute for the `Base&` reference
    }
  private:
    qi::rule<It, Derived(),   Skipper> start;
    qi::rule<It, void(Base&), Skipper> glue_;
    qi::rule<It, Base(),      Skipper> base_; // could be a grammar instead of a rule
};

int main()
{
    typedef std::string::const_iterator It;
    derived_grammar<It> g;

    std::string const input = "derived:1 3.14";
    auto f(input.begin()), l(input.end());

    Derived parse_result;
    bool ok = qi::phrase_parse(f, l, g, qi::space, parse_result);
    if (ok)
    {
        std::cout << "Parsed: " << parse_result.x << " " << parse_result.y << "\n";
    } else
    {
        std::cout << "Parse failed\n";
    }

    if (f != l)
    {
        std::cout << "Input remaining: '" << std::string(f,l) << "'\n";
    }
}

[1] 此处指的是 qi::phrase_parse 函数模板的实例化过程,其中包括 函数模板实例化


谢谢,sehe,粘合类很好用。但是,为了我自己的理解,你能否解释一下我如何在自己的环境中使用第一个备选项(带有static_cast的那个),而不是立即使用phrase_parse吗? - user2913094

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接