我在编写语法时遇到了麻烦。假设我有一个继承自Derived
的班级Base
。 GrammarDerived
具有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;
};
答案 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";
}
}