How to use the qi :: hold [] directive Parser. (Issue with attribute type for boost :: swap)
I have a parser that parses into boost::variant<int, double, std::string>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using namespace std;
typedef map<string, boost::variant<int, double, string> > namevalue;
typedef pair<string, boost::variant<int, double, string> > namevaluepair;
template <typename Iterator>
struct keys_and_values2
: grammar<Iterator, namevalue(), ascii::blank_type>
{
keys_and_values2()
: keys_and_values2::base_type(start)
{
start %= query >> qi::eoi;
query = +pair;
value = qi::int_ | qi::double_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
pair = key >> qi::lit(':') >> value >> qi::eol;
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
}
qi::rule<Iterator, namevalue(), ascii::blank_type> start;
qi::rule<Iterator, namevalue(), ascii::blank_type> query;
qi::rule<Iterator, namevaluepair(), ascii::blank_type> pair;
qi::rule<Iterator, std::string(), ascii::blank_type> key;
qi::rule<Iterator, boost::variant<int, double, string>(), ascii::blank_type> value;
};
the input for the syntax is here:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Janelle : 132349223
Briley : -40.905352495602
It fails on the first line "Barn". If I expand the parsing of the double and int like this:
value = qi::double_ | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
It works fine, but the integer value "Janelle" is parsed as double. Following the BOOST FAQ and BOOST documentation , I would like to use qi :: hold [] like this:
value = qi::hold[qi::int_] | qi::hold[qi::double_] | qi::lexeme[+(qi::char_ - qi::eol)] ;
But with this, I get a message about missing functions swap()
. This is actually documented in the efficiency gains documents (note). But the explanation is very short. I cannot find the correct attribute type for this paging function. Can anyone help here?
Compiler message:
E:\Boost\boost_1_58_0\boost/spirit/home/support/attributes.hpp(1036) : error C2784: 'void boost::spirit::swap(boost::spirit::multi_pass<T,Policies> &,boost::spirit::multi_pass<T,Policies> &)' : could not deduce template argument for 'boost::spirit::multi_pass<T,Policies> &' from 'int'
<h / "> Update sehe's
answer works with the data above. However, if I change the input to the following:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Rebekah : 240ad9beb53bbfafcd5
Janelle : 132349223
Cloe : 456ABCabvc
Briley : -40.905352495602
I will have a problem with the value "Rebekah". I also see that the order in which the values are evaluated is important. This time the problem is not in meaning double
anymore, it is between int
and string
. I would like to implement something like this: (policy?)
- anything that only has numbers, an optional minus sign, and contains a period is
double
- anything that only has numbers and an optional minus sign,
int
- all the rest
std::string
<h / "> Solution
Sometimes it is important to understand the question rather than the problem.
The problem is not with the parser policy, it was my definition of the parsing rules (see above). Rule 3 "everything else" actually includes "everything before EOL". Therefore, all three alternatives in the rule for value
must match this:
value = strict_double >> qi::eol
| qi::int_ >> qi::eol
| qi::lexeme[+(qi::char_ - qi::eol)] >> qi::eol;
With this change, answer , just works like a charm!
source to share
Hold is not used for this.
Think about it: how would that help? This will not cause the integer branch to not match, so it will still not parse and hold
return nothing.
hold[]
mostly useful for container attributes¹, where partial parses can change the attribute. Containers usually have a swap already. You were barking the wrong tree here.
¹ including strings, see for example
• Understanding the parsing of the Boost.spirit string
• boost :: spirit :: qi re-parsing on output
• Reconstructing the parsing
• Optional Boost Spirit parser and rollback
Solution to the problem:
You can use a strict real-world policy to parse only real values as doubles.
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
// with
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
See also int or double parameter using boost spirit (longest_d) for some unit tests
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef boost::variant<int, double, std::string> value_t;
typedef std::map<std::string, value_t> namevalue;
typedef std::pair<std::string, value_t> namevaluepair;
template <typename Iterator>
struct keys_and_values2
: qi::grammar<Iterator, namevalue(), ascii::blank_type>
{
keys_and_values2() : keys_and_values2::base_type(start)
{
start %= query >> qi::eoi;
query = +pair;
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
pair = key >> qi::lit(':') >> value >> qi::eol;
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
BOOST_SPIRIT_DEBUG_NODES((start)(query)(value)(pair)(key))
}
private:
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
qi::rule<Iterator, namevalue(), ascii::blank_type> start;
qi::rule<Iterator, namevalue(), ascii::blank_type> query;
qi::rule<Iterator, namevaluepair(), ascii::blank_type> pair;
qi::rule<Iterator, std::string(), ascii::blank_type> key;
qi::rule<Iterator, value_t(), ascii::blank_type> value;
};
int main() {
typedef boost::spirit::istream_iterator It;
It f(std::cin >> std::noskipws), l;
keys_and_values2<It> g;
namevalue data;
bool ok = qi::phrase_parse(f,l,g,ascii::blank,data);
if (ok) {
std::cout << "Parse succeeded:\n";
for(auto& p : data)
std::cout << "\t'" << p.first << "'\t-> " << p.second << "\n";
} else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
Printing
Parse succeeded:
'Briley' -> -40.9054
'Clara' -> -92.4086
'Jamiya' -> Jelly Drop
'Janelle' -> 132349223
'Sarai' -> 52.7312
And debug info (if enabled)
<start>
<try>Sarai : 52.731</try>
<query>
<try>Sarai : 52.731</try>
<pair>
<try>Sarai : 52.731</try>
<key>
<try>Sarai : 52.731</try>
<success>: 52.731199473801</success>
<attributes>[[S, a, r, a, i]]</attributes>
</key>
<value>
<try> 52.731199473801\n</try>
<success>\nJamiya : Jelly</success>
<attributes>[52.7312]</attributes>
</value>
<success>Jamiya : Jelly </success>
<attributes>[[[S, a, r, a, i], 52.7312]]</attributes>
</pair>
<pair>
<try>Jamiya : Jelly </try>
<key>
<try>Jamiya : Jelly </try>
<success>: Jelly Drop\nClar</success>
<attributes>[[J, a, m, i, y, a]]</attributes>
</key>
<value>
<try> Jelly Drop\nClara</try>
<success>\nClara : -92.4</success>
<attributes>[[J, e, l, l, y, , D, r, o, p]]</attributes>
</value>
<success>Clara : -92.40</success>
<attributes>[[[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]]]</attributes>
</pair>
<pair>
<try>Clara : -92.40</try>
<key>
<try>Clara : -92.40</try>
<success>: -92.40860586988</success>
<attributes>[[C, l, a, r, a]]</attributes>
</key>
<value>
<try> -92.408605869885</try>
<success>\nJanelle : 13234</success>
<attributes>[-92.4086]</attributes>
</value>
<success>Janelle : 132349</success>
<attributes>[[[C, l, a, r, a], -92.4086]]</attributes>
</pair>
<pair>
<try>Janelle : 132349</try>
<key>
<try>Janelle : 132349</try>
<success>: 132349223\nBrile</success>
<attributes>[[J, a, n, e, l, l, e]]</attributes>
</key>
<value>
<try> 132349223\nBriley</try>
<success>\nBriley : -40.9</success>
<attributes>[132349223]</attributes>
</value>
<success>Briley : -40.90</success>
<attributes>[[[J, a, n, e, l, l, e], 132349223]]</attributes>
</pair>
<pair>
<try>Briley : -40.90</try>
<key>
<try>Briley : -40.90</try>
<success>: -40.90535249560</success>
<attributes>[[B, r, i, l, e, y]]</attributes>
</key>
<value>
<try> -40.905352495602</try>
<success>\n</success>
<attributes>[-40.9054]</attributes>
</value>
<success></success>
<attributes>[[[B, r, i, l, e, y], -40.9054]]</attributes>
</pair>
<pair>
<try></try>
<key>
<try></try>
<fail/>
</key>
<fail/>
</pair>
<success></success>
<attributes>[[[[B, r, i, l, e, y], -40.9054], [[C, l, a, r, a], -92.4086], [[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]], [[J, a, n, e, l, l, e], 132349223], [[S, a, r, a, i], 52.7312]]]</attributes>
</query>
<success></success>
<attributes>[[[[B, r, i, l, e, y], -40.9054], [[C, l, a, r, a], -92.4086], [[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]], [[J, a, n, e, l, l, e], 132349223], [[S, a, r, a, i], 52.7312]]]</attributes>
</start>
source to share