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!

+3


source to share


1 answer


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

Live On Coliru

#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>

      


+1


source







All Articles