Subparser属性

时间:2014-09-06 04:03:46

标签: c++ parsing boost boost-spirit boost-spirit-qi

我在编写语法时遇到了麻烦。假设我有一个继承自Derived的班级BaseGrammarDerived具有Derived合成属性,而GrammarBase具有Base合成属性。如何在GrammarBase解析规则中使用GrammarDerived?我觉得这应该是可能的,因为我可以将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 个答案:

答案 0 :(得分: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));

完整演示 Live On 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";
    }
}

替代地

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

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

如果你真的坚持,你可以在没有使用glue_的{​​{1}} / base_分离的情况下完成(但我不会这样做是为了易读)。

再次提供完整代码以供参考 Live On Coliru

qi::attr_cast<Base, Base>

[1] 在这里引用功能模板的实例化 #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"; } }