I am trying to parse and capture this string "{ABC,HIJ}:{10,15,20}" into struct indicator_rec.
The parse is successful, however, only the first set {ABC,HIJ} is captured into the std::vector<std::string> field.
The second part, {10,15,20} is parsed correctly, but fails to make it into the second field std::vector<unsigned>.
What am I doing wrong?
Output:
<equation>
<try>{ABC,HIJ}:{10,15,20}</try>
<indicator>
<try>{ABC,HIJ}:{10,15,20}</try>
<fail/>
</indicator>
<indicators>
<try>{ABC,HIJ}:{10,15,20}</try>
<indicator>
<try>ABC,HIJ}:{10,15,20}</try>
<success>,HIJ}:{10,15,20}</success>
<attributes>[[A, B, C]]</attributes>
</indicator>
<indicator>
<try>HIJ}:{10,15,20}</try>
<success>}:{10,15,20}</success>
<attributes>[[H, I, J]]</attributes>
</indicator>
<success>:{10,15,20}</success>
<attributes>[[[A, B, C], [H, I, J]]]</attributes>
</indicators>
<parameters>
<try>{10,15,20}</try>
<parameter>
<try>10,15,20}</try>
<success>,15,20}</success>
<attributes>[]</attributes>
</parameter>
<parameter>
<try>15,20}</try>
<success>,20}</success>
<attributes>[]</attributes>
</parameter>
<parameter>
<try>20}</try>
<success>}</success>
<attributes>[]</attributes>
</parameter>
<success></success>
<attributes>[[]]</attributes>
</parameters>
<success></success>
<attributes>[[[[A, B, C], [H, I, J]], []]]</attributes>
</equation>
Code:
#define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp> // std::regex not fully implemented in stdc++ yet
#include <string>
#include <map>
#include <utility>
#include <functional>
// -----------------------------------------------------------------------------
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace spirit = boost::spirit;
namespace phoenix = boost::phoenix;
// ---------------------------------------------------------------------------
struct indicator_rec
{
public:
indicator_rec() { }
std::vector<std::string> m_indicators;
std::vector<unsigned> m_parameters;
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::indicator_rec,
(std::vector<std::string>, m_indicators)
(std::vector<unsigned>, m_parameters)
)
namespace client
{
// ---------------------------------------------------------------------------
template <typename Iterator>
struct system_parser :
qi::grammar<Iterator, ascii::space_type, indicator_rec()>
{
system_parser() :
system_parser::base_type(equation)
{
using qi::double_;
using qi::_val;
using qi::_1;
using boost::spirit::ascii::string;
equation %=
(indicator | indicators)
>> ':'
>> (parameters | parameter)
;
indicator %= (string("ABC")|string("HIJ"))
;
indicators %= '{' >> (indicator % ',') >> '}'
;
parameter %= qi::uint_
;
parameters %= '{' >> (parameter % ',') >> '}'
;
BOOST_SPIRIT_DEBUG_NODE(equation);
BOOST_SPIRIT_DEBUG_NODE(parameter);
BOOST_SPIRIT_DEBUG_NODE(parameters);
BOOST_SPIRIT_DEBUG_NODE(indicator);
BOOST_SPIRIT_DEBUG_NODE(indicators);
}
qi::rule<Iterator, ascii::space_type, indicator_rec()>
equation;
qi::rule<Iterator, ascii::space_type, std::vector<std::string>()>
indicators;
qi::rule<Iterator, ascii::space_type, std::string()>
designator, indicator;
qi::rule<Iterator, ascii::space_type, unsigned>
parameter;
qi::rule<Iterator, ascii::space_type, std::vector<unsigned>()>
parameters;
};
template <typename Iterator>
bool parse_system( Iterator first, Iterator last, client::indicator_rec& rec )
{
system_parser<Iterator> parser;
bool r = qi::phrase_parse( first, last, parser, ascii::space, rec );
if (first != last) // fail if we did not get a full match
return false;
return r;
}
template <typename Iterator>
bool parse_universe(Iterator first, Iterator last, std::vector<std::string>& v)
{
bool r = qi::phrase_parse(first, last,
// Begin grammar -------------------------------------
(
(+(qi::alpha|qi::char_( "_" ))) >> ':' >> '{' >>
(+~qi::char_(",}")) % ','
>> '}'
)
,
// End grammar ---------------------------------------
ascii::space, v);
if (first != last) // fail if we did not get a full match
return false;
return r;
}
}
main( int argc, char* argv[] )
{
std::string calculator( "{ABC,HIJ}:{10,15,20}" );
client::indicator_rec rec;
client::parse_system( calculator.begin(), calculator.end(), rec );
}
This question from yesterday it’s about the same. The signature of every rule needs to use this function declarator syntax. The type before the parenthesis is the attribute “returned” from the rule (its synthesized attribute) and the types inside are the inherited attributes (you can find a simple example using them here).
So if you are not using these inherited attributes, you must use
rule_attribute_type()in your rule declaration. Ideally a failure to do so would result in a compiler error but, apparently due to the heterogeneous nature of the rule’s template parameters, unfortunately it’s not what happens.