I have a more complicated rule, but this is enough for this question (hopefully). Consider the rule:
result = double_ >> *(char_ > int_);
where the result is declared in terms of the result of the structure in the ast namespace:
qi::rule<Iterator, ast::result(), qi::space_type> result;
Then what does it look like ast::result? According to boost :: spirit docs ( http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/spirit/abstracts/attributes/compound_attributes.html ), the attribute
char_ > int_is tuple<char, int>or std::pair<char, int>. So I tried:
namespace ast
{
using second_type = std::vector<std::pair<char, int>>;
struct result
{
double first;
second_type second;
};
}
in addition to
BOOST_FUSION_ADAPT_STRUCT(
ast::result,
(double, first),
(ast::second_type, second)
)
But this gives me a compilation error:
error: no matching function for call to 'std::pair<char, int>::pair(const char&)'
This rule is simple, creating the AST structure in which the result will be stored should also be simple ... but how?
Here is the complete test program with my attempt:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace ast
{
using second_type = std::vector<std::pair<char, int>>;
struct result
{
double first;
second_type second;
friend std::ostream& operator<<(std::ostream& os, result const& result);
};
std::ostream& operator<<(std::ostream& os, second_type::value_type val)
{
return os << val.first << ' ' << val.second;
}
std::ostream& operator<<(std::ostream& os, result const& result)
{
os << result.first;
for (auto& i : result.second)
os << ' ' << i;
return os;
}
}
BOOST_FUSION_ADAPT_STRUCT(
ast::result,
(double, first),
(ast::second_type, second)
)
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
class test_grammar : public qi::grammar<Iterator, ast::result(), qi::space_type>
{
private:
qi::rule<Iterator, ast::result(), qi::space_type> result;
public:
test_grammar() : test_grammar::base_type(result, "result_grammar")
{
using qi::double_;
using qi::char_;
using qi::int_;
result = double_ >> *(char_ > int_);
}
};
}
int main()
{
std::string const input{"3.4 a 5 b 6 c 7"};
using iterator_type = std::string::const_iterator;
using test_grammar = client::test_grammar<iterator_type>;
namespace qi = boost::spirit::qi;
test_grammar program;
iterator_type iter{input.begin()};
iterator_type const end{input.end()};
ast::result out;
bool r = qi::phrase_parse(iter, end, program, qi::space, out);
if (!r || iter != end)
{
std::cerr << "Parsing failed." << std::endl;
return 1;
}
std::cout << "Parsed: " << out << std::endl;
}