我在编写语法时遇到麻烦。假设我有一个Derived
类,它是从Base
继承的。 GrammarDerived
具有Derived
综合属性,而GrammarBase
具有Base
综合属性。如何在GrammarBase
解析规则中使用GrammarDerived
?我认为这应该可行,因为我可以将Base &
绑定(bind)到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;
};
最佳答案
在一个更简单的设置中,这显示了它在很大程度上是类型推导的限制:
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_
来实现base_
/ qi::attr_cast<Base, Base>
分离(但为了清晰起见,我不会这样做)。再次提供完整代码以供引用 Live On 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
的实例化