我是精神初学者
我想使用精神将一个帝国字符串值解析为一个结构。
输入应接受以下语法:
5'3"1/2 5'1/2 3"1/2
struct imp_constant
看起来像这样,请注意下面的流操作符,我将打印结果,如此操作符所示:
struct imp_constant
{
explicit imp_constant(unsigned int feet=0
,unsigned int inch=0
,unsigned int fracn=0
,unsigned int fracd=1)
:feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){}
unsigned int feet_,inches_,fracn_,fracd_;
};
std::ostream& operator<<(std::ostream& os, imp_constant const& cst)
{
if (cst.feet_)
os << cst.feet_ << '\'';
if (cst.inches_)
os << cst.inches_ << '"';
if (cst.fracn_)
os << cst.fracn_ << '/' << cst.fracd_;
return os;
}
我的伪语法很简单,看起来像这样:
myrule = (
(
(qi::uint_ >> L'\'')
||
(qi::uint_ >> L'"')
)
>> -(
qi::uint_
>> L'/' >>
qi::uint_
)
);
这是我非常天真的第一次尝试填充我的结构:
我已将BOOST_FUSION_ADAPT_STRUCT
宏添加到我的struct imp_constant
,然后尝试遵循语法:
qi::rule<std::string::const_iterator, imp_constant()>
impconst = qi::lexeme[ //not sure this is required since no skipper precised
(
(qi::uint_[phx::at_c<0>(qi::_val)=qi::_1] >> L'\'')
||
(qi::uint_[phx::at_c<1>(qi::_val)=qi::_1] >> L'"')
)
>> -(
qi::uint_[phx::at_c<2>(qi::_val)=qi::_1]
>> L'/' >>
qi::uint_[phx::at_c<3>(qi::_val)=qi::_1]
)
];
结果是:
input:5'3"1/2 ==> output:5'3"1/2 (ok)
input:5'1/2 ==> output:5'1"1/2 (__nok__)
我想我不知道_1
占位符在这种情况下的行为。
由于我是精神世界的初学者,欢迎任何建议
非常感谢
这是完整的代码,这应该有帮助
#define BOOST_SPIRIT_DONT_USE_MPL_ASSERT_MSG 1
//#define BOOST_SPIRIT_DEBUG << uncomment to enable debug
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/fusion/adapted.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
struct imp_constant
{
explicit imp_constant(unsigned int feet=0
,unsigned int inch=0
,unsigned int fracn=0
,unsigned int fracd=1)
:feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){}
unsigned int feet_,inches_,fracn_,fracd_;
};
std::ostream& operator<<(std::ostream& os, imp_constant const& cst)
{
if (cst.feet_)
os << cst.feet_ << '\'';
if (cst.inches_)
os << cst.inches_ << '"';
if (cst.fracn_)
os << cst.fracn_ << '/' << cst.fracd_;
return os;
}
BOOST_FUSION_ADAPT_STRUCT(imp_constant,
(unsigned int, feet_)
(unsigned int, inches_)
(unsigned int, fracn_)
(unsigned int, fracd_))
int _tmain(int argc, _TCHAR* argv[])
{
std::string input;
std::cout << "\n----------------------\n> ";
while (std::getline(std::cin, input))
{
if (input.empty() || input[0] == 'q' || input[0] == 'Q')
break;
std::string::const_iterator f(input.begin()),l(input.end());
try
{
imp_constant result;
std::cout << "parsing: " << input << "\n";
bool ok;
qi::rule<std::string::const_iterator, imp_constant()>
impconst = qi::lexeme[ //not sure this is required since
//no skipper precised
(
(qi::uint_[phx::at_c<0>(qi::_val)=qi::_1]
>> L'\'')
||
(qi::uint_[phx::at_c<1>(qi::_val)=qi::_1]
>> L'"')
)
>> -(
qi::uint_[phx::at_c<2>(qi::_val)=qi::_1]
>> L'/' >>
qi::uint_[phx::at_c<3>(qi::_val)=qi::_1]
)
];
ok=qi::phrase_parse(f,l,impconst ,qi::space,result);
if (!ok)
std::cerr << "invalid input\n";
else
{
std::cout << "\n---------------------------\n";
std::cout << "result="<< result;
}
}
catch (const qi::expectation_failure<const char *>& e)
{
std::cerr << "expect failure at '"
<< std::string(e.first, e.last) << "'\n";
}
catch (...)
{
std::cerr << "parse error\n";
}
if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
std::cout << "\n-----------------------\n> ";
}
std::getchar();
return 0;
}
答案 0 :(得分:4)
作为sehe答案的替代品(你应该接受):
如果您刚刚将规则更改为:
,那么您的解决方案就可以使用qi::rule<std::string::const_iterator, imp_constant()>
impconst =
(
(qi::uint_ >> L'\'')[phx::at_c<0>(qi::_val)=qi::_1]
||
(qi::uint_ >> L'"')[phx::at_c<1>(qi::_val)=qi::_1]
)
>>
-(qi::uint_ >> L'/' >> qi::uint_)
[phx::at_c<2>(qi::_val)=qi::_1,phx::at_c<3>(qi::_val)=qi::_2]
;
我将如何做到这一点:
略微改变您的imp_constant
:
struct fraction
{
unsigned int n_,d_;
};
struct imp_constant
{
unsigned int feet_,inches_;
fraction frac_;
};
BOOST_FUSION_ADAPT_STRUCT(fraction,
(unsigned int, n_)
(unsigned int, d_)
)
BOOST_FUSION_ADAPT_STRUCT(imp_constant,
(unsigned int, feet_)
(unsigned int, inches_)
(fraction , frac_)
然后规则是:
qi::rule<std::string::const_iterator,unsigned int()> feet = (qi::uint_ >> L'\'') | qi::attr(0);
qi::rule<std::string::const_iterator,unsigned int()> inches = (qi::uint_ >> L'"') | qi::attr(0);
qi::rule<std::string::const_iterator,fraction()> fract = (qi::uint_ >> L'/' >> qi::uint_) | (qi::attr(0)>> qi::attr(1));
qi::rule<std::string::const_iterator, imp_constant()> impconst=feet>>inches>>fract;
答案 1 :(得分:2)
你正在寻找回溯。
5'1/2
中的'1'首先被解析为潜在英寸分支中的qi::uint_
,从而导致分配属性。
只有然后遇到“/”,这会导致从“英寸分支”回溯。但是该属性已经设置好了。在这种情况下,显式默认值或qi::hold
可以修复它。
这就像我自己可能会说的那样:
qi::rule<std::string::const_iterator, unsigned(char)>
component = qi::hold [ qi::uint_ >> qi::lit(qi::_r1) ];
qi::rule<std::string::const_iterator, imp_constant()>
impconst =
component(L'\'') ||
component(L'"') ||
component(L'/') ||
qi::uint_
;
BOOST_SPIRIT_DEBUG_NODE(component);
BOOST_SPIRIT_DEBUG_NODE(impconst);
我认为这可能是一个很好的起点?
补充说明:
f!=l
以检测未解析的剩余输入lexeme
在那里是多余的在此处观看: http://liveworkspace.org/code/Rpydy$0 。
测试输出:
----------------------
> parsing: 5'1/2
<impconst>
<try>5'1/2</try>
<component>
<try>5'1/2</try>
<success>1/2</success>
<attributes>[5, ']</attributes>
</component>
<component>
<try>1/2</try>
<fail/>
</component>
<component>
<try>1/2</try>
<success>2</success>
<attributes>[1, /]</attributes>
</component>
<success></success>
<attributes>[[5, 0, 1, 2]]</attributes>
</impconst>
---------------------------
result=5'1/2
-----------------------
>