Check parsed values before they are assigned to the variable #743
-
Hello everyone, I would like to know if it is possible with Qi-Spirit to check the successfully parsed values before assigning them to the target list of variable/struct. Example: The pair of values shall only be assigned and stored into the vector<2values>, only if the first value is less than second value. And the pair of values does not exist in the vector <2values> After parsing the vector<2value> shall contain { {3 , 5}, {6 , 7} , { 6 , 8} }. The pair "9 , 6" does not satisfy the condition and "3,5" already exist . hier my solution, but it is not generic. Thanks in advance for some ideas
output:
the first pair 0x3 and ox05 does not belong to the vector |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Hello everyone, #include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/support/container.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <vector>
#include <iostream>
using namespace boost::spirit;
struct vMinMaxValue
{
int valuMin;
int valuMax;
};
BOOST_FUSION_ADAPT_STRUCT(
vMinMaxValue,
(int, valuMin)
(int, valuMax)
)
namespace boost { namespace spirit { namespace traits
{
template <>
struct push_back_container<std::vector<vMinMaxValue>, vMinMaxValue>
{
static bool call(std::vector<vMinMaxValue> &c, vMinMaxValue const& val)
{
bool found = false;
for (const vMinMaxValue &elem : c)
{
if (
(elem.valuMin == val.valuMin) &&
(elem.valuMax == val.valuMax)
)
{
found = true;
break;
}
}
if (
(found == false) &&
(val.valuMin < val.valuMax)
)
{
c.push_back(val);
}
return true;
}
};
}}}
template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator, std::vector<vMinMaxValue>(),Skipper>
{
my_grammar() : my_grammar::base_type{values}
{
mxnV = qi::no_case[qi::lit("0x")] >> qi::uint_parser<int,16>();
value = mxnV >> -( qi::lit(',') ) >> mxnV;
values = value % ';';
}
qi::rule<Iterator, int()> mxnV;
qi::rule<Iterator, vMinMaxValue(), Skipper> value;
qi::rule<Iterator, std::vector<vMinMaxValue>(), Skipper> values;
};
int main()
{
std::string s;
std::getline(std::cin, s);
auto it = s.begin();
my_grammar<std::string::iterator, ascii::space_type> g;
std::vector<vMinMaxValue> v;
if (qi::phrase_parse(it, s.end(), g, ascii::space, v))
{
for (const auto &elem : v)
{
std::cout << "valueMin=\"" << boost::lexical_cast<std::string>(elem.valuMin) << "\" "
<< "valueMax=\"" << boost::lexical_cast<std::string>(elem.valuMax) << "\" "
<< std::endl;
}
}
else
{
}
return 0;
} Output:
|
Beta Was this translation helpful? Give feedback.
-
You may want to use set-like container if you need to preserve only unique values, and validation could be done via semantic actions: #include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <compare>
#include <string>
#include <set>
#include <iostream>
using namespace boost::spirit;
struct vMinMaxValue
{
int valuMin;
int valuMax;
auto operator<=>(vMinMaxValue const&) const = default;
};
BOOST_FUSION_ADAPT_STRUCT(
vMinMaxValue,
(int, valuMin)
(int, valuMax)
)
template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator, std::set<vMinMaxValue>(),Skipper>
{
my_grammar() : my_grammar::base_type{values}
{
mxnV = qi::no_case[qi::lit("0x")] >> qi::uint_parser<int,16>();
value %= mxnV >> -qi::lit(',') >> mxnV[([](unused_type, auto const& ctx, bool& pass) {
vMinMaxValue const& val = boost::fusion::at_c<0>(ctx.attributes);
pass = val.valuMin < val.valuMax;
})];
values = value % ';';
}
qi::rule<Iterator, int()> mxnV;
qi::rule<Iterator, vMinMaxValue(), Skipper> value;
qi::rule<Iterator, std::set<vMinMaxValue>(), Skipper> values;
};
int main()
{
std::string s;
std::getline(std::cin, s);
auto it = s.begin();
my_grammar<std::string::iterator, ascii::space_type> g;
std::set<vMinMaxValue> v;
if (qi::phrase_parse(it, s.end(), g, ascii::space, v) && it == s.end())
{
for (const auto &elem : v)
{
std::cout << "valueMin=\"" << elem.valuMin << "\" "
<< "valueMax=\"" << elem.valuMax << "\" "
<< std::endl;
}
}
else
{
std::cout << "parsing stopped at '" << std::string(it, s.end()) << "'\n";
}
} |
Beta Was this translation helpful? Give feedback.
Hello everyone,
I am sorry for the question. I think , i found the solution in the documentation "Store a Parsed Attribute Value into a Container (Qi)". The solution may be (See below). If you have other suggestion to do it more generic. Please lead me know