我有一个格式如下的文件
metal 1 1.2 2.2
wire 1.1 2.3
metal 2 3.2 12.2
...
这是一种非常简单的格式。 "金属"和"电线"是关键字。和"金属"之后是1 uint和2 double,而" wire"之后是2双。 我尝试使用Boost :: Qi来解析它,但结果很奇怪,我无法弄清楚原因。
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
using std::cout;
using std::endl;
using std::string;
using namespace boost::spirit;
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace spirit = boost::spirit;
namespace phoenix = boost::phoenix;
// grammar
template <typename Iterator>
struct TimingLibGrammar :
qi::grammar<Iterator, ascii::space_type>
{
qi::rule<Iterator, ascii::space_type> expression;
TimingLibGrammar() : TimingLibGrammar::base_type(expression)
{
using qi::uint_;
using qi::int_;
using qi::double_;
using qi::char_;
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_val;
using qi::lexeme;
using qi::lit;
expression =
+(
((
"metal"
>> uint_
>> double_
>> double_)[cout << "metal" << " "<< _1 << " " << _2 << " " << _3 << endl])
|
((
"wire"
>> double_
>> double_)[cout << "wire" << " "<< _1 << " " << _2 << endl])
);
}
};
}
int main()
{
using boost::spirit::ascii::space;
using namespace client;
string str = "metal 3 1.0 2.0";
TimingLibGrammar<string::const_iterator> tlg;
string::const_iterator iter = str.begin();
string::const_iterator end = str.end();
client::qi::phrase_parse(iter, end, tlg, space);
return 0;
}
代码的主要部分实际上很短。请忽略那些无用的包含。
当我尝试解析一行
时metal 3 1.0 2.0,
解析器给我的结果如下:
wire metal 3 1 2
此结果不正确。它应该输出&#34;金属3 1 2&#34;但我不知道这个&#34; wire&#34;来自。我还尝试按照boost库中的几个示例代码进行操作。但它仍未能做到正确。 代码使用g ++ 4.7.2编译,-std = c ++ 11 flag。
任何建议都会有所帮助。我是一个提升精神的新人,所以我希望能够学到一些东西。提前谢谢。
答案 0 :(得分:1)
罪魁祸首就是这样的行:
cout << "metal" << " "<< _1 << " " << _2 << " " << _3 << endl
cout << "wire" << " "<< _1 << " " << _2 << endl
请记住,Boost中的lambdas(Boost.Phoenix和Boost.Lambda变种)都是运算符重载的结果。 cout << _1
(相当于operator<<(cout, _1)
)创建一个lambda,因为_1
由Phoenix定义(并导入Spirit.Qi的命名空间)。但是,cout << "wire" << _1
是operator<<(operator<<(cout, "wire"), _1)
。它将立即打印出“wire”,并使用operator<<(cout, "wire")
- cout
的返回值来构造lambda。内部operator<<
是标准库函数。
要解决此问题,请将它们包装在phoenix::val
:
cout << phoenix::val("metal") << " "<< _1 << " " << _2 << " " << _3 << endl
cout << phoenix::val("wire") << " "<< _1 << " " << _2 << endl