I would like to define a rule based on a previously parsed value, i. e. the input string has the following structure: D <double number>
or I <integer number>
. I keep in a local boolean variable whether the first read character is D
or I
. The complete code is:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::ref;
template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
{
using namespace qi;
bool is_int = false;
start_rule = lit("I")[ref(is_int) = true] | lit("D")[ref(is_int) = false] > digit_rule;
if(ref(is_int)()) {
digit_rule = int_[std::cout << "int " << _1 << ".\n"];
} else {
digit_rule = double_[std::cout << "double " << _1 << ".\n"];
}
}
private:
qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
qi::rule<Iterator, std::string(), ascii::space_type> digit_rule;
};
int main()
{
typedef std::string::const_iterator iter;
std::string storage("I 5");
iter it_begin(storage.begin());
iter it_end(storage.end());
std::string read_data;
using boost::spirit::ascii::space;
x_grammar<iter> g;
try {
bool r = qi::phrase_parse(it_begin, it_end, g, space, read_data);
if(r) {
std::cout << "Pass!\n";
} else {
std::cout << "Fail!\n";
}
} catch (const qi::expectation_failure<iter>& x) {
std::cout << "Fail!\n";
}
return 0;
}
The output is: double Pass!
!! It neither recognizes the if
statement, nor prints the parsed number!
Note: I know that there are other straightforward ways to parse the example above. The actual string I have to parse looks quite complicated, and this example just illustrates what I want to achieve. The general goal is to use local variables and define other rules based on those variables.
I have used 4.6.1 and Boost 1.55 versions.
here you evaluate condition during construction. This is not how it works. The rule will always take the same branch.
Instead, look at the Nabialek trick: http://boost-spirit.com/home/articles/qi-example/nabialek-trick/
Here's the full Nabialek Trick applied to your sample Live On Coliru:
you needed to make
std::cout << "int"
lazy actors (by wrapping at leastphx::ref(std::cout)
orphx::val("int")
as a Phoenix Actor)you still have no use for the attribute propagation (
std::string()
) since it is disabled in the presence of Semantic Actions (see the previous answer). You can propagate values from Nabialek subrules, though: