I'm new to both C++ and Boost spirit.
I'm stuck on this for a day now. I want to parse two strings separated by a dot. basically, I need following strings to be parsed to an integer.
eg: [field] --> integer // working
eg2: [instance.field] --> integer // not working
For the 2nd one, I need to take two strings as parameters and evaluate them and return the relevant integer value.
I must have missed a basic thing, but I can't figure it out.
Please let me know the error in my code or a better way to do it. calling a method and getting the value is needed. I can't change that.
this is the code peace.
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <iostream>
#include <string>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace spirit = boost::spirit;
namespace phx = boost::phoenix;
int fieldVal(std::vector<char> fieldName) {
std::string fieldValue(fieldName.begin(), fieldName.end());
std::cout << "Field Name Recieved.::: " << fieldValue << std::endl;
int i = 50; //just for test
return i;
}
int instanceFieldVal(std::string instance, std::string fieldName) {
std::cout << "Recieved ::: " << instance <<" : "<< fieldName << std::endl;
int i = 60; //just for test
return i;
}
namespace client
{
template <typename Iterator>
struct calculator : qi::grammar<Iterator, ascii::space_type, int()>
{
calculator() : calculator::base_type(instanceFieldValue)
/*change base type to "field" and comment everything relevant to
"instanceFieldValue", then it's working */
{
using qi::int_;
using qi::_val;
using qi::_1;
using qi::char_;
using qi::lexeme;
field = lexeme[
'['
>> +(~char_(".]["))
>> ']'
][qi::_val = phx::bind(&fieldVal, qi::_1)]; // this is working
instanceField = '['
>> +(~char_(".]["))
>> '.'
>> +(~char_(".]["))
>> ']';
instanceFieldValue
= instanceField[qi::_val = phx::bind(&instanceFieldVal, qi::_1)];
// how ^this line should be changed??
}
qi::rule<Iterator, ascii::space_type, int()> field, instanceFieldValue;
qi::rule<Iterator, ascii::space_type, std::string(), std::string()>instanceField;
};
}
int main()
{
std::cout << "Type an expression...or [q or Q] to quit\n\n";
using boost::spirit::ascii::space;
using boost::spirit::utree;
typedef std::string::const_iterator iterator_type;
typedef client::calculator<iterator_type> calculator;
calculator calc; // Our grammar
std::string str;
while (std::getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
int val;
bool r = phrase_parse(iter, end, calc, space, val);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded: " << val << "\n";
std::cout << "-------------------------\n";
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << rest << "\"\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
Well, you say it's a function with multiple arguments, but then you only pass one arg:
_1.How can that work? It can't. It's also completely what you even want to pass, because the second parameter is likely from the
instanceFieldexpression, but the first is ... magical context.Like always, I'd try to minimize state and semantic actions. In fact, I'd suggest separation of concerns:
std:vector<std::string>firstThat would lead to a grammar like
You can of course combine it using a semantic action if you insist:
Now, just implement a function
As an example, let's imagine a sample context:
Now, an implementation of
lookupcould be as simple as:Full Demo
Live On Coliru
Prints: