我认为我在理解我的boost::spirit::qi
解析器应该如何编写时遇到问题。我只想通过语义动作将匹配的子串传递给函数。为了大致模仿this boost tutorial,我提出了以下代码:
template<class Iterator>
struct _Calculator : public qi::grammar<Iterator> {
qi::rule<Iterator> number, result; //and a whole bunch of other ones too
qi::rule<Iterator,std::string()> variable;
Code& code;
Variables& variables;
_Calculator(Code& code_, Variables& variables_)
: _Calculator::base_type(result),
code(code_),
variables(variables_)
{
number =
lexeme[(qi::char_("1-9") >> +qi::char_("0-9"))[boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
| lexeme[("0x" >> +qi::char_("0-9a-fA-F")) [boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
| lexeme[("0b" >> +qi::char_("0-1")) [boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
| lexeme[("0" >> +qi::char_("0-7")) [boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
//some other junk
}
};
typedef _Calculator<std::string::const_iterator> Calculator;
当fPushIntCV
的声明如下:
void fPushIntCV (vector<char> my_str, Code& c, Variables& v);
我收到此错误:
function_ptr.hpp:89: error: conversion from 'char' to non-scalar type 'std::vector<char, std::allocator<char> >' requested
当我将fPushIntCV
的声明更改为如下所示:
void fPushIntCV (char my_str, Code& c, Variables& v);
我收到此错误:
function_ptr.hpp:89: error: cannot convert 'std::vector<char, std::allocator<char> >' to 'char' in argument passing
我认为qi::_1
的属性正在发生变化,但如果我包含两个函数原型并且现在传递boost::phoenix::bind
一些模糊的重载函数指针,我会得到未解析的引用:
error: no matching function for call to 'bind(<unresolved overloaded function type>, const boost::spirit::_1_type&, ...
(我的...
跟踪无关垃圾)
我知道这可能是一个非常简单的错误和一个非常简单的修复,但是我有一个很好的时间来理解这个咒语,以使提升魔法做到这一点。这种语义行为期待的函数原型是什么?
答案 0 :(得分:3)
一些观察结果:
您似乎没有使用船长,因此使用lexeme
是多余的(请参阅Boost spirit skipper issues)
您想知道如何检测解析器表达式公开的属性类型:请参阅Detecting the parameter types in a Spirit semantic action
这些类型用解析器指令记录,例如, as_string[(qi::char_("1-9") >> +qi::char_("0-9"))]
会产生boost::fusion::vector2<char, std::vector<char> >
,这会直接反映在GCC上的错误消息中:
boost/phoenix/bind/detail/preprocessed/function_ptr_10.hpp|50 col 39| error: could not convert ‘a0’ from ‘boost::fusion::vector2<char, std::vector<char> >’ to ‘std::vector<char>’
不希望混合和匹配库占位符/包装器,例如boost::ref
和boost::phoenix::ref
您似乎正在重塑整数解析;考虑使用qi::int_parser
代替
似乎缺少解析0
的案例:)
假设您希望my_str
只是反映包含数字基本前缀的输入字符串,我建议使用:
number =
as_string[(qi::char_("1-9") >> +qi::char_("0-9"))] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
| as_string[("0x" >> +qi::char_("0-9a-fA-F")) ] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
| as_string[("0b" >> +qi::char_("0-1")) ] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
| as_string[("0" >> +qi::char_("0-7")) ] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
//some other junk
;
但是,这可以简化为:
number = as_string[
(qi::char_("1-9") >> +qi::char_("0-9"))
| ("0x" >> +qi::char_("0-9a-fA-F"))
| ("0b" >> +qi::char_("01"))
| ("0" >> +qi::char_("0-7"))
] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
;
现在,您可能只想解析一个整数值:
number =
(
("0x" >> qi::int_parser<int, 16, 1>())
| ("0b" >> qi::int_parser<int, 2, 1>())
| ("0" >> qi::int_parser<int, 8, 1>())
| qi::int_ /* accepts "0" */) [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
;
转换 [1] 非常出色,您可以选择int
:
void fPushIntCV (int my_number, Code& c, Variables& v) {
std::cout << "fPushIntCV: " << my_number << "\n";
}
[1] (还有uint_parser
,您可以解析long
,long long
等等;甚至像boost::multiprecision::cpp_int
这样的大整数应该没问题)
这是一个使用它的演示程序,显示值正确转换(并且:&#34; 0&#34;被接受:) :): Live On Coliru < / p>
int main()
{
Code code;
Variables variables;
Calculator g(code, variables);
for (std::string const input : { "0", "0xef1A", "010", "0b10101" })
{
It f(input.begin()), l(input.end());
if(qi::parse(f, l, g))
std::cout << "Parse success ('" << input << "')\n";
else std::cout << "Parse failed ('" << input << "')\n";
if (f != l)
std::cout << "Input remaining: '" << std::string(f, l) << "'\n";
}
}
打印
fPushIntCV: 0
Parse success ('0')
fPushIntCV: 61210
Parse success ('0xef1A')
fPushIntCV: 8
Parse success ('010')
fPushIntCV: 21
Parse success ('0b10101')