Reputation: 339
I am trying to parse a log file of test results with the following grammer.
template<typename Iterator>
struct test_step_parse: qi::grammar<Iterator, TestResults(), ascii::space_type> {
test_step_parse() : test_step_parse::base_type(rqmts) {
using qi::lit;
using qi::lexeme;
using qi::omit;
using qi::int_;
using qi::eol;
using qi::char_;
test_step = lit("Test Step No.") >> int_;
pass_or_fail = lit("-") >> (string("Passed") | string("Failed"));
fdor_rqmts = -lit("OID")
>> lit("FDOR")
>> -lit("OID")
>> int_
>> *(-omit[char_(",/\\")] >> -(lit("FDOR") ^ lit("OID")) >> int_)
;
sard_rqmts = -lit("OID")
>> lit("SARD")
>> -lit("OID")
>> int_
>> *(-omit[char_(",/\\")] >> -(lit("SARD") ^ -lit("OID")) >> int_)
;
comment = lit("Comment:") >> lexeme[*(char_ - eol)] ;
rqmts = test_step
>> pass_or_fail
>> omit[*(char_ - lit("REQUIREMENT VERIFIED:"))]
>> lit("REQUIREMENT VERIFIED:")
>> (fdor_rqmts ^ sard_rqmts)
>> omit[+char_("=")]
>> -comment
;
BOOST_SPIRIT_DEBUG_NODE(test_step);
BOOST_SPIRIT_DEBUG_NODE(pass_or_fail);
BOOST_SPIRIT_DEBUG_NODE(fdor_rqmts);
BOOST_SPIRIT_DEBUG_NODE(sard_rqmts);
BOOST_SPIRIT_DEBUG_NODE(comment);
BOOST_SPIRIT_DEBUG_NODE(rqmts);
}
qi::rule<Iterator, TestResults(), ascii::space_type> rqmts;
qi::rule<Iterator, int(), ascii::space_type> test_step;
qi::rule<Iterator, std::string(), ascii::space_type> pass_or_fail;
qi::rule<Iterator, std::string(), ascii::space_type> comment;
qi::rule<Iterator, std::vector<int>(), ascii::space_type> fdor_rqmts;
qi::rule<Iterator, std::vector<int>(), ascii::space_type> sard_rqmts;
};
The grammer parses ok. However, when trying to auto-populating my user-defined struct, the attribute for the rule "comment" of type std::string is being passed into the vector as ascii numerals.
This is my user-defined struct:
struct TestResults {
int test_step_no;
std::string pass_or_fail;
std::vector<int> FDOR;
std::vector<int> SARD;
std::string comment;
};
BOOST_FUSION_ADAPT_STRUCT(
atp::TestResults,
(int, test_step_no)
(std::string, pass_or_fail)
(std::vector<int>, FDOR)
(std::vector<int>, SARD)
(std::string, comment)
)
The debug out put indicates that the rules are exposing the correct types, but somehow they are not getting placed in the struct correctly.
Any ideas what I am doing wrong? Sorry for any misuse of terminology etc.
Using gcc 4.6.3 and boost 1-47. Thank you.
Update: To clarify, so I am expecting to parse the following:
std::string test_test =
"Test Step No. 953-Failed\n"
"==============================================================================\n"
"STEP 7.7:\n"
"Test step, etc.\n"
"===============================================================================\n"
"REQUIREMENT VERIFIED: FDOR 12345"
" SARD 12345, 12356\n"
"===============================================================================\n"
"Comment: Didn't work.\n"
;
Using the debugger, it appears that all rules are exposing their attributes correctly:
<rqmts>
<try>Test Step No. 953-Fa</try>
<test_step>
<try>Test Step No. 953-Fa</try>
<success>-Failed\n============</success>
<attributes>[953]</attributes>
</test_step>
<pass_or_fail>
<try>-Failed\n============</try>
<success>\n===================</success>
<attributes>[[F, a, i, l, e, d]]</attributes>
</pass_or_fail>
<fdor_rqmts>
<try> FDOR 12345 </try>
<success> </success>
<attributes>[[12345]]</attributes>
</fdor_rqmts>
<sard_rqmts>
<try> </try>
<success>\n===================</success>
<attributes>[[12345, 12356]]</attributes>
</sard_rqmts>
<comment>
<try>Comment: Didn't work</try>
<success>\n</success>
<attributes>[[D, i, d, n, ', t, , w, o, r, k, .]]</attributes>
</comment>
<success>\n</success>
<attributes>[[953, [F, a, i, l, e, d], [12345], [68, 105, 100, 110, 39, 116, 32, 119, 111, 114, 107, 46], []]]</attributes>
</rqmts>
So everything seems to be working except that the "comments" attribute (std::string) is being stuffed in the "SARD" attribute (vector ), as a vector of ascii numerals, i.e,
[68, 105, 100, 110, 39, 116, 32, 119, 111, 114, 107, 46] = "Didn't work."
Upvotes: 1
Views: 376
Reputation: 12099
The problem is the parser (A ^ B)
returns a type that is a tuple of the A type and B type, ie in your case (fdor_rqmts ^ sard_rqmts)
returns a type boost::tuple<std::vector<int>, std::vector<int> >
.
Details of how parsers combine can be found in the Boost documentation.
So, you have a choice of modifying your struct
to suite the type the parser will return (this is the only choice for an attribute grammar)
struct TestResults {
int test_step_no;
std::string pass_or_fail;
boost::tuple<std::vector<int>, std::vector<int> > FdorOrSard;
std::string comment;
};
Or to specify actions. Then your grammar would become something like:
struct TestResults {
int test_step_no;
std::string pass_or_fail;
std::vector<int> FDOR;
std::vector<int> SARD;
std::string comment;
};
test_step [ at<0>(_val) = _1]
>> pass_or_fail [ at<1>(_val) = _1 ]
>> omit[*(char_ - lit("REQUIREMENT VERIFIED:"))]
>> lit("REQUIREMENT VERIFIED:")
>> (fdor_rqmts [at<2>(_val) = _1 ] ^ sard_rqmts [at<3>(_val) = _1] )
>> omit[+char_("=")]
>> -comment [at<4>(_val) = _1];
The actions still rely on having an adapted struct, but now they explicitly describe how to place the parsed results. Note we are doing nothing with the result of the (A ^ B)
, instead we are doing something with the A
result or the B
result.
As a side note, I've run into problems mixing >
and >>
where spirit
decides to nest the results in funny ways - personally I found it almost impossible to determine after the fact what structure was being returned and so I tend to stick to using actions when I can't get the attribute based grammar to work. There's more info on this sort of thing in this question: boost::spirit::qi Expectation Parser and parser grouping unexpected behaviour
EDIT: I'm assuming you know how actions work, and the includes and using statements you'll need. The first couple of spirit parser tutorials are good for this, otherwise comment back with any questions! You might also have to use at_c
instead of at
- I really can never figure out the details of the boost phoenix / function stuff...
Upvotes: 2