我可以解决这个特殊情况的问题(实际上是we discussed options on the list),但实际上,这种
Boost Spirit 会更频繁地出现“神秘”错误,这会很好
处理一般问题。
您的第一个资源应该是优秀精神文档,它
详细说明给定解析器的合成属性是什么
原语、运算符或指令。见the Reference
section
到Spirit Qi Docs。
在某些情况下,我已将重点从“试图撬开
信息从编译器错误列表'到'主动查询 Spirit
它通过的类型'。我使用的技术是多态可调用类型
(参见 Spirit/Fusion 文档)。
这是一个使用 GCC 特定的 API 来漂亮 [原文] 打印它检测到的类型:
函子what_is_the_attr
#include <cxxabi.h>
#include <stdlib.h>
#include <string>
#include <iostream>
template <typename T> std::string nameofType(const T& v) {
int status;
char *realname = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
std::string name(realname? realname : "????");
free(realname);
return name;
}
struct what_is_the_attr {
template <typename> struct result { typedef bool type; };
template <typename T> bool operator()(T& attr) const {
std::cerr << "what_is_the_attr: " << nameofType(attr) << std::endl;
return true;
}
};
示例使用:检测合成属性类型
您可以使用它来准确检测一个合成属性类型是什么类型
解析器表达式实际上最终是:
template <typename Exp>
void detect_attr_type(const Exp& exp)
{
using namespace boost::spirit::qi;
const char input[] = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input)-1);
bool dummy = phrase_parse(
f, l,
exp [ what_is_the_attr() ],
space);
}
(注意: 这表明该方法的局限性 - 该技术假设您
有一个“否则”的工作语法,你知道如何传递一个输入
满足表达足以触发语义动作。在大多数情况下,
但是,当您破解 Spirit 解析器时,这将是真的)
让我们测试一下。例如。让我们看看有什么区别和表达
中等复杂度,同样包裹在 qi::raw[] 指令中:
int main()
{
detect_attr_type( -(int_ >> *int_) );
detect_attr_type( raw [ -(int_ >> *int_) ] );
}
输出:
what_is_the_attr: boost::optional<boost::fusion::vector2<int, std::vector<int, std::allocator<int> > > >
what_is_the_attr: boost::iterator_range<char const*>
在底部,我们将把它应用于 OP 中的问题。
使用示例:检测传入语义动作的类型
我们可以使用相同的一元函数对象 (what_is_the_attr) 来检测
然而,这些语义动作可以接受任意数量的参数,所以我们需要
概括。如果不是 variadic,这将是一项乏味的工作
模板 (woot! for c++0x):
struct what_are_the_arguments {
template <typename...> struct result { typedef bool type; };
template <typename... T> bool operator()(const T&... attr) const {
std::vector<std::string> names { nameofType(attr)... };
std::cerr << "what_are_the_arguments:\n\t";
std::copy(names.begin(), names.end(), std::ostream_iterator<std::string>(std::cerr, "\n\t"));
std::cerr << '\n';
return true;
}
};
对上述测试用例的重复表明 Spirit 实际上试图调用
如果可能的话,带有三个参数的语义动作(如documented):
what_are_the_arguments:
boost::optional<boost::fusion::vector2<int, std::vector<int, std::allocator<int> > > >
boost::spirit::unused_type
bool
what_are_the_arguments:
boost::iterator_range<char const*>
boost::spirit::unused_type
bool
但好消息是,您现在可以将其应用于任何语义操作:
template <typename ExpWSA> void test(const ExpWSA& exp)
{
const char input[] = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input)-1);
qi::phrase_parse(f, l, exp, qi::space);
}
int main()
{
test(-(-double_ >> *int_) [ phx::bind(what_are_the_arguments(), _1, _2, _0, phx::ref(std::cout), 42) ]);
}
打印,对于这个(对不起)非常人为的例子:
what_are_the_arguments:
boost::optional<double>
std::vector<int, std::allocator<int> >
boost::fusion::vector2<boost::optional<double>, std::vector<int, std::allocator<int> > >
std::ostream
int
应用于 OP
derived 规则的综合属性不与int_>>int_>>int_>>int_ 相同:
auto base_expr = int_ >> int_; // avoids assigning to struct attribute
rule<const char*, mybase(), space_type> base_ = base_expr;
test(base_ >> int_ >> int_ [ what_is_the_attr() ] );
test(base_expr >> int_ >> int_ [ what_is_the_attr() ] );
将打印
what_is_the_attr: boost::fusion::vector3<mybase, int, int>
what_is_the_attr: boost::fusion::vector4<int, int, int, int>
你的问题。我们在original thread 中讨论了一些基于此诊断的解决方法(并在此处查看其他答案)。但这篇文章应该有助于回答一般案例问题。
完整代码清单
集成形式,使用 gcc 4.6.1 --std=c++0x 和 boost 1_48 编译:
#include <cxxabi.h>
#include <iostream>
#include <iterator>
#include <stdlib.h>
#include <string>
#include <vector>
template <typename T> std::string nameofType(const T& v)
{
int status;
char *realname = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
std::string name(realname? realname : "????");
free(realname);
return name;
}
struct what_is_the_attr {
template <typename> struct result { typedef bool type; };
template <typename T> bool operator()(T& attr) const {
std::cerr << "what_is_the_attr: " << nameofType(attr) << std::endl;
return true;
}
};
struct what_are_the_arguments {
template <typename...> struct result { typedef bool type; };
template <typename... T> bool operator()(const T&... attr) const {
std::vector<std::string> names { nameofType(attr)... };
std::cerr << "what_are_the_arguments:\n\t";
std::copy(names.begin(), names.end(), std::ostream_iterator<std::string>(std::cerr, "\n\t"));
std::cerr << '\n';
return true;
}
};
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
struct mybase { int a,b; };
struct myderived : mybase { int c,d; };
BOOST_FUSION_ADAPT_STRUCT(mybase, (int,a)(int,b));
BOOST_FUSION_ADAPT_STRUCT(myderived, (int,a)(int,b)(int,c)(int,d));
template <typename ExpWSA>
void test(const ExpWSA& exp)
{
using namespace boost::spirit::qi;
const char input[] = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input)-1);
bool dummy = phrase_parse(f, l, exp, space);
}
int main()
{
using namespace boost::spirit::qi;
// Diagnostics for the OP case
auto base_expr = int_ >> int_; // avoids assigning to struct attribute
rule<const char*, mybase(), space_type> base_ = base_expr;
// Derived rule, different formulations
test((base_ >> int_ >> int_) [ what_is_the_attr() ] );
test((base_expr >> int_ >> int_) [ what_is_the_attr() ] );
// Applied to attribute types
test(raw [ -(int_ >> *int_) ] [ what_is_the_attr() ] );
test(-(int_ >> *int_) [ what_is_the_attr() ] );
// applied to semantic actions - contrived example
namespace phx = boost::phoenix;
test(-(-double_ >> *int_) [ phx::bind(what_are_the_arguments(), _1, _2, _0, phx::ref(std::cout), 42) ]);
return 0;
}