A follow up to this question Handling boost spirit expression on string. Again thanks #sehe! But when I try to wrap all the grammar and ast in the namespaces and call them from within a class, I get an error by the phrase_parse api saying its expecting 6 arguments instead of 5.
The code I'm trying to implement:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <iomanip>
#include <list>
#include <string>
namespace client { namespace ast {
struct signed_;
struct program;
using operand = boost::variant<unsigned int, bool,
boost::recursive_wrapper<signed_>,
boost::recursive_wrapper<program>>;
struct signed_ { char sign; operand operand_; };
struct operation { char operator_; operand operand_; };
struct program { operand first; std::list<operation> rest; };
}} // namespace client::ast
BOOST_FUSION_ADAPT_STRUCT(client::ast::signed_, sign, operand_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::operation, operator_, operand_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::program, first, rest)
namespace client { namespace ast
{
///////////////////////////////////////////////////////////////////////////
// The AST evaluator
///////////////////////////////////////////////////////////////////////////
struct eval {
using result_type = int;
int operator()(auto const& n) const { return n; }
int operator()(operation const& x, int lhs) const {
int rhs = boost::apply_visitor(*this, x.operand_);
switch (x.operator_) {
case '+': return lhs + rhs;
case '-': return lhs - rhs;
case '*': return lhs * rhs;
case '/': return lhs / rhs;
case '|': return lhs | rhs;
case '&': return lhs & rhs;
}
BOOST_ASSERT(0);
return 0;
}
int operator()(signed_ const& x) const {
int rhs = boost::apply_visitor(*this, x.operand_);
switch (x.sign) {
case '-': return -rhs;
case '+': return +rhs;
case '!': return !rhs;
}
BOOST_ASSERT(0);
return 0;
}
int operator()(program const& x) const {
int state = boost::apply_visitor(*this, x.first);
for (auto& oper : x.rest) {
state = (*this)(oper, state);
}
return state;
}
};
}} // namespace client::ast
namespace client
{
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct calculator : qi::grammar<Iterator, ast::program(), qi::space_type> {
calculator() : calculator::base_type(expression) {
using namespace qi::labels;
expression = term >> *(qi::char_("-+|&") >> term);
term = factor >> *(qi::char_("*/!") >> factor);
str = '"' >> *~qi::char_('"') >> '"';
equality_comparison = (str >> '=' >> '=' >> str)[_val = (_1 == _2)];
inequality_comparison = (str >> '!' >> '=' >> str)[_val = (_1 != _2)];
factor = inequality_comparison | equality_comparison | qi::uint_ | qi::bool_ | qi::char_("-+!") >> factor |
'(' >> expression >> ')';
}
private:
qi::rule<Iterator, ast::program(), qi::space_type> expression, term;
qi::rule<Iterator, ast::operand(), qi::space_type> factor, equality_comparison , inequality_comparison;
qi::rule<Iterator, std::string()> str;
};
}
class Expression_handler{
public:
int Execute_expression(std::string str){
using iterator_type = std::string::const_iterator;
using calculator = client::calculator<iterator_type>;
using ast_program = client::ast::program;
using ast_eval = client::ast::eval;
calculator const calc; // Our grammar
ast_eval const eval; // Evaluates the program
ast_program program;
auto f(std::begin(str)), l(std::end(str));
bool r = phrase_parse(f, l, calc, client::qi::space, program);
if (r && f == l) {
std::cout << "\nResult: " << quoted(str) << " -> " << eval(program) << std::endl;
return (eval(program));
}
else{
std::cout << "\nFailed at: " << quoted(std::string (f, l)) << "\n";
}
return 0;
};
};
int main(){
Expression_handler exp;
exp.Execute_expression("\"abc\" == \"abc\"");
return 0;
}
The error generated for this code:
ion_handler.cpp:37:24: warning: use of ‘auto’ in parameter declaration only available with ‘-std=c++20’ or ‘-fconcepts’
37 | int operator()(auto const& n) const { return n; }
| ^~~~
In file included from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:36,
from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:21,
from /usr/include/boost/spirit/include/qi.hpp:16,
from Expression_handler.cpp:5:
/usr/include/boost/spirit/home/qi/reference.hpp: In instantiation of ‘bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<client::ast::program&, boost::fusion::nil_>, boost::spirit::locals<> >; Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >; Attribute = client::ast::program; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, client::ast::program(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type>]’:
/usr/include/boost/spirit/home/qi/parse.hpp:168:45: required from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Expr = client::calculator<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > >; Skipper = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0>; Attr = client::ast::program]’
/usr/include/boost/spirit/home/qi/parse.hpp:201:32: required from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Expr = client::calculator<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > >; Skipper = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0>; Attr = client::ast::program]’
Expression_handler.cpp:114:30: required from here
/usr/include/boost/spirit/home/qi/reference.hpp:43:35: error: no matching function for call to ‘boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, client::ast::program(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type>::parse(__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&, const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<client::ast::program&, boost::fusion::nil_>, boost::spirit::locals<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, client::ast::program&) const’
43 | return ref.get().parse(first, last, context, skipper, attr_);
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:21,
from /usr/include/boost/spirit/include/qi.hpp:16,
from Expression_handler.cpp:5:
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:282:14: note: candidate: ‘template<class Context, class Skipper, class Attribute> bool boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Context = Context; Skipper = Skipper; Attribute = Attribute; Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; T1 = client::ast::program(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
282 | bool parse(Iterator& first, Iterator const& last
| ^~~~~
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:282:14: note: template argument deduction/substitution failed:
In file included from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:36,
from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:21,
from /usr/include/boost/spirit/include/qi.hpp:16,
from Expression_handler.cpp:5:
/usr/include/boost/spirit/home/qi/reference.hpp:43:35: note: cannot convert ‘first’ (type ‘__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >’) to type ‘__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&’
43 | return ref.get().parse(first, last, context, skipper, attr_);
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:21,
from /usr/include/boost/spirit/include/qi.hpp:16,
from Expression_handler.cpp:5:
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:333:14: note: candidate: ‘template<class Context, class Skipper, class Attribute, class Params> bool boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&, const Params&) const [with Context = Context; Skipper = Skipper; Attribute = Attribute; Params = Params; Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; T1 = client::ast::program(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
333 | bool parse(Iterator& first, Iterator const& last
| ^~~~~
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:333:14: note: template argument deduction/substitution failed:
In file included from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:36,
from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:21,
from /usr/include/boost/spirit/include/qi.hpp:16,
from Expression_handler.cpp:5:
/usr/include/boost/spirit/home/qi/reference.hpp:43:35: note: candidate expects 6 arguments, 5 provided
43 | return ref.get().parse(first, last, context, skipper, attr_);
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Which other argument is it expecting and how do I fix this?
Your string isn't const, so the iterator type doesn't match the one you declared. The key message is:
boost/spirit/home/qi/reference.hpp|43 col 35| note: cannot convert ‘first’ (type ‘__gnu_cxx::__normal_iterator<char*, __cxx11::basic_string<char> >’) to type ‘__gnu_cxx::__normal_iterator<const char*, __cxx11::basic_string<char> >&’
Simply add const or const&:
int Execute_expression(std::string const& str)
Or don't use auto to declare f and l:
std::string::const_iterator f = std::begin(str), l = std::end(str);
Live On Coliru
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <iomanip>
#include <list>
#include <string>
namespace client { namespace ast {
struct signed_;
struct program;
using operand = boost::variant<unsigned int, bool,
boost::recursive_wrapper<signed_>,
boost::recursive_wrapper<program>>;
struct signed_ { char sign; operand operand_; };
struct operation { char operator_; operand operand_; };
struct program { operand first; std::list<operation> rest; };
}} // namespace client::ast
BOOST_FUSION_ADAPT_STRUCT(client::ast::signed_, sign, operand_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::operation, operator_, operand_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::program, first, rest)
namespace client { namespace ast
{
///////////////////////////////////////////////////////////////////////////
// The AST evaluator
///////////////////////////////////////////////////////////////////////////
struct eval {
using result_type = int;
int operator()(auto const& n) const { return n; }
int operator()(operation const& x, int lhs) const {
int rhs = boost::apply_visitor(*this, x.operand_);
switch (x.operator_) {
case '+': return lhs + rhs;
case '-': return lhs - rhs;
case '*': return lhs * rhs;
case '/': return lhs / rhs;
case '|': return lhs | rhs;
case '&': return lhs & rhs;
}
BOOST_ASSERT(0);
return 0;
}
int operator()(signed_ const& x) const {
int rhs = boost::apply_visitor(*this, x.operand_);
switch (x.sign) {
case '-': return -rhs;
case '+': return +rhs;
case '!': return !rhs;
}
BOOST_ASSERT(0);
return 0;
}
int operator()(program const& x) const {
int state = boost::apply_visitor(*this, x.first);
for (auto& oper : x.rest) {
state = (*this)(oper, state);
}
return state;
}
};
}} // namespace client::ast
namespace client
{
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct calculator : qi::grammar<Iterator, ast::program(), qi::space_type> {
calculator() : calculator::base_type(expression) {
using namespace qi::labels;
expression = term >> *(qi::char_("-+|&") >> term);
term = factor >> *(qi::char_("*/!") >> factor);
str = '"' >> *~qi::char_('"') >> '"';
str_eq = (str >> "==" >> str)[_val = (_1 == _2)];
str_neq = (str >> "!=" >> str)[_val = (_1 != _2)];
factor = str_neq | str_eq | qi::uint_ | qi::bool_ |
qi::char_("-+!") >> factor | '(' >> expression >> ')';
}
private:
qi::rule<Iterator, ast::program(), qi::space_type> expression, term;
qi::rule<Iterator, ast::operand(), qi::space_type> factor, str_eq, str_neq;
qi::rule<Iterator, std::string()> str;
};
}
struct Expression_handler {
static int Execute_expression(std::string const& str) {
using iterator_type = std::string::const_iterator;
using calculator = client::calculator<iterator_type>;
namespace ast = client::ast;
calculator const calc; // Our grammar
ast::eval const eval; // Evaluates the program
ast::program program;
auto f(std::begin(str)), l(std::end(str));
bool r = phrase_parse(f, l, calc, client::qi::space, program);
if (r && f == l) {
std::cout << "Result: " << quoted(str, '\'') << " -> " << eval(program)
<< std::endl;
return eval(program);
} else {
std::cout << "Failed at: " << quoted(std::string(f, l), '\'') << "\n";
}
return 0;
};
};
int main(){
Expression_handler exp;
exp.Execute_expression(R"("abc" == "abc")");
exp.Execute_expression(R"("abc" != "abc")");
exp.Execute_expression(R"("abc" == "cba")");
exp.Execute_expression(R"("abc" != "cba")");
}
Prints
Result: '"abc" == "abc"' -> 1
Result: '"abc" != "abc"' -> 0
Result: '"abc" == "cba"' -> 0
Result: '"abc" != "cba"' -> 1
Related
I would like to parse key-value pairs, mapping strings to strings. Since i want to support blocks of { ... } for right hand sides i came up with a simple grammar to start with
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace grammar::map
{
using namespace boost::spirit::x3;
auto expression = rule<class expression, std::pair<std::string, std::string>>{"expression"};
auto lhs = *(~char_('='));
auto rest = *(~char_(';'));
auto block = '{' >> *expression >> '}';
auto expression_def = lhs >> '=' >> (block | rest) >> ';';
BOOST_SPIRIT_DEFINE(expression)
}
But it fails to compile in combination, unless i change the attribute of expression to be std::string.
//! Transform a string into a key-value map of strings.
template <class M, class R>
requires InputRange<R>() && _ContainerLike<M>
&& Same<value_type_t<M>, std::pair<const std::string, std::string>>()
// && Assignable<std::pair<std::string, std::string>, value_type_t<M>>()
M parse(R&& range)
{
auto begin = rng::begin(range);
auto end = rng::end(range);
auto map = M{};
auto ret = x3::phrase_parse(begin, end, *grammar::map::expression, x3::space, map);
if (!ret)
throw std::runtime_error{"parse error"};
return map;
}
I get the error
boost/spirit/home/x3/support/traits/move_to.hpp:62:18: error: cannot convert ‘std::remove_reference<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&>::type {aka std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >}’ to ‘char’ in assignment
dest = std::move(src);
located from
boost/spirit/home/x3/support/traits/move_to.hpp: In instantiation of ‘void boost::spirit::x3::traits::detail::move_to_plain(Source&&, Dest&, mpl_::false_) [with Source = std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >; Dest = char; mpl_::false_ = mpl_::bool_<false>]’:
Same thing happens if try the following expressions
auto pair = std::pair<std::string, std::string>{};
auto ret = x3::phrase_parse(begin, end, grammar::map::expression, x3::space, map);
I am coming to it since a couple of days and can not find out how to do it properly. I appreciate any help... :^)
Tested it with boost-1.60{-62} and gcc 6.1.1, 6.2 and a more less recent trunk version.
Your problem is that you have defined expression to have an attribute of pair<string,string>, but the synthesized attribute of lhs >> '=' >> (block|rest) >> ';' is synt_attr=tuple<string,variant<vector<synt_attr>,string>> which is basically synt_attr=pair<string,variant<map_of_value_type_synt_attr,string>>. So you have at least two options depending on the result you want:
Change the synthesized attribute to be pair<string,string>. This is quite easy using the x3::raw directive (running on WandBox):
auto expression_def = lhs >> '=' >> (raw[block] | rest) >> ';';
Change your definition of expression to have an attribute compatible with the synthesized attribute. This requires the use of a recursive variant and complicates the way you need to access the data in the parsed map since you'll need to create a visitor (running on WandBox).
//A value is either a `string` or a `map<string,Value>`
using Value = boost::make_recursive_variant<std::string,std::map<std::string,boost::recursive_variant_>>::type;
...
struct printer : boost::static_visitor<void>
{
printer(int indent) :indent(indent) {}
void operator()(const std::string& val) const
{
std::cout << std::string(indent, ' ') << val << std::endl;
}
void operator()(const std::map<std::string,Value>& val) const
{
for (const auto& pair : val)
{
std::cout << std::string(indent, ' ') << pair.first << ':' << std::endl;
boost::apply_visitor(printer(indent + 4), pair.second);
std::cout << std::string(indent, ' ') << std::endl;
}
}
int indent;
};
void print_map(const Value& val)
{
boost::apply_visitor(printer(0), val);
}
I am trying to create a Spirit Karma grammar that is composed of several rules. This grammar is intended to create a string of the format "(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)". The rule to print out each individual struct that I call RowData uses BOOST_FUSION_ADAPT_STRUCT to print out all of the fields of that struct. If the grammar only includes that rule, the grammar works fine. However, I am using this struct as the value of a std::map. The key in an integer but I do not care about that value and want to drop it. I have created rules to parse the std::map but the rule that handles the std::pair fails to compile for a BOOST_SPIRIT_ASSERT_MATCH. I have created a small bit of code that generates this issue. The line is pairRule = bs::karma::omit << rowDataRule; If anybody has an idea what the issue is or how I could do this differently, I would appreciate the help.
Edit: I am using gcc 4.8.3 on OpenSUSE 13.2 but get the same error with gcc 4.8.2 on Ubuntu 14.04 LTS.
main.cpp
#include <iostream>
#include <map>
#include <boost/cstdint.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/make_tuple.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/karma.hpp>
namespace bs = boost::spirit;
struct RowData
{
RowData() :
field0(0),
field1(0),
field2(0),
field3(0)
{
}
boost::uint64_t field0;
boost::uint64_t field1;
boost::uint64_t field2;
boost::uint64_t field3;
};
BOOST_FUSION_ADAPT_STRUCT(
RowData,
(boost::uint64_t, field0)
(boost::uint64_t, field1)
(boost::uint64_t, field2)
(boost::uint64_t, field3)
)
template <typename OutputIterator>
struct RowDataGrammar :
bs::karma::grammar< OutputIterator, std::map<boost::uint64_t, RowData>() >
{
RowDataGrammar() : RowDataGrammar::base_type(allRowsRule)
{
rowDataRule =
bs::karma::lit("(") <<
bs::karma::ulong_ <<
bs::karma::lit(", ") <<
bs::karma::ulong_ <<
bs::karma::lit(", ") <<
bs::karma::ulong_ <<
bs::karma::lit(", ") <<
bs::karma::ulong_ <<
bs::karma::lit(")");
// I only want the value from the map. The key is dropped.
pairRule = bs::karma::omit << rowDataRule;
allRowsRule = pairRule % ", ";
}
private:
bs::karma::rule< OutputIterator, RowData() > rowDataRule;
bs::karma::rule< OutputIterator, std::pair<boost::uint64_t, RowData>() > pairRule;
bs::karma::rule< OutputIterator, std::map<boost::uint64_t, RowData>() > allRowsRule;
};
int main(int argc, char** argv)
{
std::map<boost::uint64_t, RowData> rowMap;
RowData rowData;
rowData.field0 = 0;
rowData.field1 = 1;
rowData.field2 = 2;
rowData.field3 = 3;
rowMap.insert(std::make_pair(10, rowData));
rowData.field0 = 6;
rowData.field1 = 7;
rowData.field2 = 8;
rowData.field3 = 9;
rowMap.insert(std::make_pair(20, rowData));
std::string generatedString;
std::back_insert_iterator<std::string> sink(generatedString);
RowDataGrammar< std::back_insert_iterator<std::string> > grammar;
bs::karma::generate(sink, grammar, rowMap);
std::cout << "output :" << generatedString << std::endl;
}
Error message:
In file included from /usr/include/boost/fusion/support/tag_of.hpp:16:0,
from /usr/include/boost/fusion/support/category_of.hpp:11,
from /usr/include/boost/fusion/adapted/struct/detail/extension.hpp:13,
from /usr/include/boost/fusion/adapted/struct/adapt_struct.hpp:19,
from karmaTest.cpp:5:
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp: In instantiation of ‘static void boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::false_ = mpl_::bool_<false>]’:
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:229:19: required from ‘boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>& boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::operator=(const Expr&) [with Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
karmaTest.cpp:54:18: required from ‘RowDataGrammar<OutputIterator>::RowDataGrammar() [with OutputIterator = std::back_insert_iterator<std::basic_string<char> >]’
karmaTest.cpp:84:62: required from here
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:185:13: error: no matching function for call to ‘assertion_failed(mpl_::failed************ (boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::false_ = mpl_::bool_<false>]::error_invalid_expression::************)(boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>))’
BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr);
^
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:185:13: note: candidate is:
/usr/include/boost/mpl/assert.hpp:82:5: note: template<bool C> int mpl_::assertion_failed(typename mpl_::assert<C>::type)
int assertion_failed( typename assert<C>::type );
^
/usr/include/boost/mpl/assert.hpp:82:5: note: template argument deduction/substitution failed:
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:185:13: note: cannot convert ‘boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_)::error_invalid_expression185::assert_arg<mpl_::bool_<false>, boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l> >()’ (type ‘mpl_::failed************ (boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::false_ = mpl_::bool_<false>]::error_invalid_expression::************)(boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>)’) to type ‘mpl_::assert<false>::type {aka mpl_::assert<false>}’
BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr);
As cv_and_he said, I was using omit incorrectly. An old coworker I reached out to told me the same. The corrected code is below.
main.cpp
#include <iostream>
#include <map>
#include <boost/cstdint.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/make_tuple.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/karma.hpp>
namespace bs = boost::spirit;
struct RowData
{
RowData() :
field0(0),
field1(0),
field2(0),
field3(0)
{
}
boost::uint64_t field0;
boost::uint64_t field1;
boost::uint64_t field2;
boost::uint64_t field3;
};
BOOST_FUSION_ADAPT_STRUCT(
RowData,
(boost::uint64_t, field0)
(boost::uint64_t, field1)
(boost::uint64_t, field2)
(boost::uint64_t, field3)
)
template <typename OutputIterator>
struct RowDataGrammar :
bs::karma::grammar< OutputIterator, std::map<boost::uint64_t, RowData>() >
{
RowDataGrammar() : RowDataGrammar::base_type(allRowsRule)
{
rowDataRule =
bs::karma::lit("(") <<
bs::karma::ulong_ <<
bs::karma::lit(", ") <<
bs::karma::ulong_ <<
bs::karma::lit(", ") <<
bs::karma::ulong_ <<
bs::karma::lit(", ") <<
bs::karma::ulong_ <<
bs::karma::lit(")");
// I only want the value from the map. The key is dropped.
pairRule = bs::karma::omit[bs::karma::ulong_] << rowDataRule;
allRowsRule = pairRule % ", ";
}
private:
bs::karma::rule< OutputIterator, RowData() > rowDataRule;
bs::karma::rule< OutputIterator, std::pair<boost::uint64_t, RowData>() > pairRule;
bs::karma::rule< OutputIterator, std::map<boost::uint64_t, RowData>() > allRowsRule;
};
int main(int argc, char** argv)
{
std::map<boost::uint64_t, RowData> rowMap;
RowData rowData;
rowData.field0 = 0;
rowData.field1 = 1;
rowData.field2 = 2;
rowData.field3 = 3;
rowMap.insert(std::make_pair(10, rowData));
rowData.field0 = 6;
rowData.field1 = 7;
rowData.field2 = 8;
rowData.field3 = 9;
rowMap.insert(std::make_pair(20, rowData));
std::string generatedString;
std::back_insert_iterator<std::string> sink(generatedString);
RowDataGrammar< std::back_insert_iterator<std::string> > grammar;
bs::karma::generate(sink, grammar, rowMap);
std::cout << "output :" << generatedString << std::endl;
}
The following code doesn't compile BOOST_SPIRIT_DEBUG_NODE( expression ) where expression is a variant node (I'm not 100% certain variant nodes have anything to do with it, though).
If I comment out the line, everything seems to run ok.
Doing an eyeball-parse of the compile errors, I see:
/usr/local/include/boost/spirit/home/support/attributes.hpp:1203:13: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
If that's not enough to tell us about the cause of the error, please compile the code below, for the detailed compile dump.
Please note that the code is 95% identical to an example from the docs.
I just added an std::string to the variant type and attempted to add the ever-useful BOOST_SPIRIT_DEBUG_NODE() so I could see what's going on.
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp> // std::regex not fully implemented in stdc++ yet
#include <string>
#include <map>
#include <utility>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct binary_op;
struct unary_op;
struct nil {};
struct expression_ast
{
typedef
boost::variant<
nil // can't happen!
, double
, std::string
, boost::recursive_wrapper<expression_ast>
, boost::recursive_wrapper<binary_op>
, boost::recursive_wrapper<unary_op>
>
type;
expression_ast()
: m_expr(nil()) {}
template <typename Expr>
expression_ast(Expr const& expr)
: m_expr(expr) {}
expression_ast& operator+=(expression_ast const& rhs);
expression_ast& operator-=(expression_ast const& rhs);
expression_ast& operator*=(expression_ast const& rhs);
expression_ast& operator/=(expression_ast const& rhs);
type m_expr;
};
struct binary_op
{
binary_op(
char op
, expression_ast const& left
, expression_ast const& right)
: m_op(op), m_left(left), m_right(right) {}
char m_op;
expression_ast m_left;
expression_ast m_right;
};
struct unary_op
{
unary_op(
char op
, expression_ast const& subject)
: m_op(op), m_subject(subject) {}
char m_op;
expression_ast m_subject;
};
expression_ast& expression_ast::operator+=(expression_ast const& rhs)
{
m_expr = binary_op('+', m_expr, rhs);
return *this;
}
expression_ast& expression_ast::operator-=(expression_ast const& rhs)
{
m_expr = binary_op('-', m_expr, rhs);
return *this;
}
expression_ast& expression_ast::operator*=(expression_ast const& rhs)
{
m_expr = binary_op('*', m_expr, rhs);
return *this;
}
expression_ast& expression_ast::operator/=(expression_ast const& rhs)
{
m_expr = binary_op('/', m_expr, rhs);
return *this;
}
// We should be using expression_ast::operator-. There's a bug
// in phoenix type deduction mechanism that prevents us from
// doing so. Phoenix will be switching to BOOST_TYPEOF. In the
// meantime, we will use a phoenix::function below:
struct negate_expr
{
template <typename T>
struct result
{
typedef T type;
};
expression_ast operator()(expression_ast const& expr) const
{
return expression_ast(unary_op('-', expr));
}
};
static boost::phoenix::function<negate_expr> neg;
struct ast_print
{
typedef std::string result_type;
std::string operator()(qi::info::nil) const
{
return "";
}
std::string operator()(std::string const& str) const
{
return str;
}
std::string operator()(double d) const
{
std::ostringstream oss;
oss << d;
return oss.str();
}
std::string operator()(expression_ast const& ast) const
{
return boost::apply_visitor(*this, ast.m_expr);
}
std::string operator()(binary_op const& expr) const
{
std::ostringstream oss;
oss << "op:" << expr.m_op << "(";
oss << boost::apply_visitor(*this, expr.m_left.m_expr);
oss << ", ";
oss << boost::apply_visitor(*this, expr.m_right.m_expr);
oss << ')';
return oss.str();
}
std::string operator()(unary_op const& expr) const
{
std::ostringstream oss;
oss << "op:" << expr.m_op << "(";
oss << boost::apply_visitor(*this, expr.m_subject.m_expr);
oss << ')';
return oss.str();
}
};
template <typename Iterator>
struct ParserGenerator : qi::grammar<Iterator, expression_ast(), ascii::space_type>
{
ParserGenerator() : ParserGenerator::base_type(expression)
{
using qi::_val;
using qi::_1;
using qi::double_;
using qi::iso8859_1::char_;
using qi::iso8859_1::space;
using qi::eol;
comment =
space >> ("//" >> *(char_ - eol) >> eol)
;
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
)
;
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
)
;
factor =
symbol [_val = _1]
| double_ [_val = _1]
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = neg(_1)])
| ('+' >> factor [_val = _1])
;
symbol %= boost::spirit::lexeme[ +(qi::char_ - qi::char_("()-+*/")) ]
;
BOOST_SPIRIT_DEBUG_NODE(expression); // <--- TROUBLE COMPILING THIS LINE
BOOST_SPIRIT_DEBUG_NODE(symbol);
}
qi::rule<Iterator, expression_ast(), ascii::space_type>
expression, term, factor, comment;
qi::rule<Iterator, std::string(), ascii::space_type>
symbol;
};
}
int main(int argc, char* argv[])
{
using boost::spirit::ascii::space;
using client::expression_ast;
using client::ast_print;
typedef std::string::const_iterator iterator_type;
typedef client::ParserGenerator<iterator_type> ParserGenerator;
ParserGenerator pg; // our grammar
std::string predicate( "i_.c+x[0]" );
expression_ast ast;
ast_print printer;
iterator_type iter = predicate.begin(), end = predicate.end();
if ( phrase_parse( iter, end, pg, space, ast ))
{
std::cerr << printer( ast ) << std::endl;
}
return 0;
}
Error is here
initializing argument 1 of «std::basic_ostream<_CharT, _Traits>&
std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&)
[with _CharT = char, _Traits = std::char_traits, _Tp =
client::expression_ast]»
There is no overloading for operator << for your expression_ast.
std::ostream& operator << (std::ostream& stream, const expression_ast& expr)
{
ast_print printer;
stream << printer(expr) << std::endl;
return stream;
}
compiles for me with this simple addition.
I'm trying to write a parser using Boost::Spirit, and I have the parser written and compiling. The problem is, when I try to compile the parsing function, the compiler throws out a bunch of template errors. Here's the Qi grammar:
template<typename Iterator>
struct etf_parser : qi::grammar<Iterator, std::map<std::string, etfnode>(), ascii::space_type> {
etf_parser() : etf_parser::base_type(start) {
using qi::int_;
using qi::lit;
using qi::double_;
using qi::bool_;
using qi::lexeme;
using ascii::char_;
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
dataVal %= (quoted_string | double_ | int_ | bool_ | listObj | pairObj | mapObj);
pairObj %= ('<' >> dataVal >> ',' >> dataVal >> '>');
listObj %= '{' >> dataVal % ',' >> '}';
mapKey %= +qi::char_("a-zA-Z_-0-9.");
mapPair %= mapKey >> lit('=') >> dataVal;
mapObj %= '(' >> mapPair % ',' >> ')';
start %= mapPair >> ';';
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
// Data value parsers
qi::rule<Iterator, etfnode(), ascii::space_type> dataVal;
qi::rule<Iterator, std::vector<etfnode>(), ascii::space_type> listObj;
qi::rule<Iterator, std::pair<etfnode, etfnode>(), ascii::space_type> pairObj;
qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> mapObj;
qi::rule<Iterator, std::pair<std::string, etfnode>(), ascii::space_type> mapPair;
qi::rule<Iterator, std::string(), ascii::space_type> mapKey;
qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> start;
};
And here's the parsing function. When I comment out the qi::parse call, the code compiles fine:
ETFDocument::ETFDocument(std::string content) {
etf_parser<std::string::const_iterator> parser;
std::map<std::string, rwnode> results;
std::string::const_iterator begin = content.begin();
std::string::const_iterator end = content.end();
bool result = qi::parse(begin, end, parser, results);
if(result) printf("Parsing succeeded\n"); else printf("Parsing failed\n");
m_root = etfnode(results);
}
The compiler spits out the following error when I try to compile:
In file included from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14:0,
from /usr/include/boost/spirit/home/qi.hpp:20,
from /usr/include/boost/spirit/include/qi.hpp:16,
from libmcg/etf.cpp:8:
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp: In instantiation of ‘bool boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Context = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::spirit::locals<> >; Skipper = boost::spirit::unused_type; Attribute = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >; Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; T1 = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’:
/usr/include/boost/spirit/home/qi/reference.hpp:43:71: required from ‘bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::spirit::locals<> >; Skipper = boost::spirit::unused_type; Attribute = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>]’
/usr/include/boost/spirit/home/qi/parse.hpp:86:82: required from ‘bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; Expr = etf_parser<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> > >; Attr = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >]’
libmcg/etf.cpp:113:53: required from here
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:303:17: error: no match for call to ‘(const function_type {aka const boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>}) (__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>::context_type&, const boost::spirit::unused_type&)’
In file included from /usr/include/boost/function/detail/maybe_include.hpp:33:0,
from /usr/include/boost/function/detail/function_iterate.hpp:14,
from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:67,
from /usr/include/boost/function.hpp:64,
from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:16,
from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:20,
from /usr/include/boost/spirit/include/qi.hpp:16,
from libmcg/etf.cpp:8:
/usr/include/boost/function/function_template.hpp:1021:7: note: candidate is:
/usr/include/boost/function/function_template.hpp:754:17: note: boost::function4<R, T1, T2, T3, T4>::result_type boost::function4<R, T1, T2, T3, T4>::operator()(T0, T1, T2, T3) const [with R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::fusion::vector0<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&; boost::function4<R, T1, T2, T3, T4>::result_type = bool]
/usr/include/boost/function/function_template.hpp:754:17: note: no known conversion for argument 4 from ‘const boost::spirit::unused_type’ to ‘const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&’
As far as I can tell, it's looking for a Skipper, but getting boost::spirit::unused_type instead. I'm not sure why this would happen, since I specified a Skipper in my parser definition. I'm using boost v1.49.0 on gcc 4.7.1.
EDIT: Here's the definition for etfnode. There's a typedef at the beginning of the cpp file (containing the other code fragments) that aliases "etfnode" to "rwnode".
enum DataType {
DT_INT,
DT_STRING,
DT_FLOAT,
DT_BOOL,
DT_LIST,
DT_PAIR,
DT_MAP
};
struct etfnode;
typedef boost::recursive_wrapper<etfnode> rwnode;
typedef boost::variant<
int,
std::string,
double,
bool,
std::vector<rwnode>,
std::pair<rwnode, rwnode>,
std::map<std::string, rwnode> > etfvalue;
struct etfnode {
DataType type;
etfvalue value;
etfnode(const std::string& s);
etfnode(const int i);
etfnode(const double d);
etfnode(const bool b);
etfnode(const std::vector<rwnode>& n);
etfnode(const std::pair<rwnode, rwnode>& p);
etfnode(const std::map<std::string, rwnode>& p);
etfnode();
};
And a test string:
foo = 6;
bar = <"bar", 16.5>;
baz = {
(
foobar = "foo",
bar = 12
),
"foobar"
};
I think the most important culprit was the fact that you were using qi::parse instead of qi::phrase_parse, while your grammar explicitely uses a skipper.
I also rewrote the defintion of the etfvalue recursive variant. I'm not sure whether your version should have worked, but at least now, you can just use etfnode in all places where you'd expect to. It looks more consistent to me this way.
Here's code that compiles fine for me. It parses the sample input (see main()) with the following output:
Parsing succeeded
Unparsed remaining: ';'
If you actually wanted to accept the trailing ;, fix the main rule to be more like
start = *(mapPair >> ';'); // or *(mapPair >> (';'|qi::eoi))
Good luck!
//add streaming operators for etfnode and etfvalue if you want to debug this:
//#define BOOST_SPIRIT_DEBUG
#include <map>
#include <string>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
enum DataType {
DT_INT,
DT_STRING,
DT_FLOAT,
DT_BOOL,
DT_LIST,
DT_PAIR,
DT_MAP
};
struct etfnode;
typedef boost::variant<
int,
std::string,
double,
bool,
boost::recursive_wrapper<std::vector<etfnode> >,
boost::recursive_wrapper<std::pair<etfnode, etfnode> >,
boost::recursive_wrapper<std::map<std::string, etfnode> >
> etfvalue;
struct etfnode {
DataType type;
etfvalue value;
etfnode(const std::string& s) { value = s; type = DT_STRING; }
etfnode(const int i) { value = i; type = DT_INT; }
etfnode(const double d) { value = d; type = DT_FLOAT; }
etfnode(const bool b) { value = b; type = DT_BOOL; }
etfnode(const std::vector<etfnode>& n) { value = n; type = DT_LIST; }
etfnode(const std::pair<etfnode, etfnode>& p) { value = p; type = DT_PAIR; }
etfnode(const std::map<std::string, etfnode>& p) { value = p; type = DT_MAP; }
etfnode() { }
};
template<typename Iterator>
struct etf_parser : qi::grammar<Iterator, std::map<std::string, etfnode>(), ascii::space_type> {
etf_parser() : etf_parser::base_type(start) {
using qi::int_;
using qi::lit;
using qi::double_;
using qi::bool_;
using qi::lexeme;
using ascii::char_;
quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
dataVal = (quoted_string | double_ | int_ | bool_
| listObj | pairObj
| mapObj
);
listObj = '{' >> dataVal % ',' >> '}';
pairObj = lit('<') >> dataVal >> ',' >> dataVal >> '>';
mapKey = +qi::char_("a-zA-Z_-0-9.");
mapPair = mapKey >> lit('=') >> dataVal;
mapObj = '(' >> mapPair % ',' >> ')';
start = mapPair % ';';
BOOST_SPIRIT_DEBUG_NODE(quoted_string);
BOOST_SPIRIT_DEBUG_NODE(dataVal);
BOOST_SPIRIT_DEBUG_NODE(listObj);
//BOOST_SPIRIT_DEBUG_NODE(pairObj);
BOOST_SPIRIT_DEBUG_NODE(mapObj);
BOOST_SPIRIT_DEBUG_NODE(mapKey);
BOOST_SPIRIT_DEBUG_NODE(mapPair);
BOOST_SPIRIT_DEBUG_NODE(start);
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
// Data value parsers
qi::rule<Iterator, etfnode(), ascii::space_type> dataVal;
qi::rule<Iterator, std::vector<etfnode>(), ascii::space_type> listObj;
qi::rule<Iterator, std::pair<etfnode, etfnode>(), ascii::space_type> pairObj;
qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> mapObj;
qi::rule<Iterator, std::pair<std::string, etfnode>(), ascii::space_type> mapPair;
qi::rule<Iterator, std::string(), ascii::space_type> mapKey;
qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> start;
};
int main()
{
etf_parser<std::string::const_iterator> parser;
std::map<std::string, etfnode> results;
std::string content = "foo = 6;\n"
"bar = <\"bar\", 16.5>;\n"
"baz = {\n"
" (\n"
" foobar = \"foo\",\n"
" bar = 12\n"
" ),\n"
" \"foobar\"\n"
"};";
std::string::const_iterator begin = content.begin();
std::string::const_iterator end = content.end();
bool result = qi::phrase_parse(begin, end, parser, ascii::space, results);
if(result) printf("Parsing succeeded\n"); else printf("Parsing failed\n");
if (begin!=end)
std::cout << "Unparsed remaining: '" << std::string(begin,end) << "'\n";
//m_root = etfnode(results);
}
I'm having trouble getting a small boost::spirit grammar to compile. It's a small part of a larger grammar that I'm having trouble with and I'm trying to test smaller parts to find my problem.
Basicly what this grammar should do is parse a double value which has any number of leading/trailing spaces. However when I try to compile I get a whole list of problems which I don't understand. Any help would be welcome!
The code:
grammar.h
#ifndef GRAMMAR_H
#define GRAMMAR_H
#include <boost/spirit/include/qi.hpp>
template <typename Iterator>
struct point_double_grammar : boost::spirit::qi::grammar<Iterator, double()>
{
/**
* Constructor used to create the grammar.
* #param is_point boolean indicating if the point is used as decimal.
* #author Luc Kleeven
**/
point_double_grammar() : point_double_grammar::base_type(d)
{
d = *boost::spirit::qi::lit(' ') >> boost::spirit::qi::double_ >> *boost::spirit::qi::lit(' ');
}
boost::spirit::qi::rule<Iterator, double()> d;
};
#endif // GRAMMAR_H
main.cpp
#include "grammar.h"
int main(int argc, char *argv[])
{
point_double_grammar<std::string::iterator> point_grammar();
bool result = false;
double d = 0.0;
std::string p1 = "575040.3400";
std::string p2 = "117380.1200";
std::string p3 = "-001.22916765";
std::string p4 = "063.39171738";
std::string p5 = "2.5";
std::string::iterator it;
std::string::iterator last;
it = p1.begin();
last = p1.end();
result = (boost::spirit::qi::parse(it, last, point_grammar, d) && it ==
last);
if(result)
{
std::cout << p1 << " == " << d << std::endl;
}
else
{
std::cout << "Parsing failed!" << std::endl;
}
it = p2.begin();
last = p2.end();
result = (boost::spirit::qi::parse(it, last, point_grammar, d) && it ==
last);
if(result)
{
std::cout << p2 << " == " << d << std::endl;
}
else
{
std::cout << "Parsing failed!" << std::endl;
}
it = p3.begin();
last = p3.end();
result = (boost::spirit::qi::parse(it, last, point_grammar, d) && it == last);
if(result)
{
std::cout << p3 << " == " << d << std::endl;
}
else
{
std::cout << "Parsing failed!" << std::endl;
}
it = p4.begin();
last = p4.end();
result = (boost::spirit::qi::parse(it, last, point_grammar, d) && it == last);
if(result)
{
std::cout << p4 << " == " << d << std::endl;
}
else
{
std::cout << "Parsing failed!" << std::endl;
}
it = p5.begin();
last = p5.end();
result = (boost::spirit::qi::parse(it, last, point_grammar, d) && it == last);
if(result)
{
std::cout << p5 << " == " << d << std::endl;
}
else
{
std::cout << "Parsing failed!" << std::endl;
}
return EXIT_SUCCESS;
}
When I try to compile I get the following errors:
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/detail/parse_auto.hpp:14:0,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/auto.hpp:16,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi.hpp:15,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/include/qi.hpp:16,
from ../test/grammar.h:4,
from ../test/main.cpp:1:
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/parse.hpp: In function 'bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Expr = point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >(), Attr = double]':
../test/main.cpp:20:63: instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/parse.hpp:83:9: error: no matching function for call to 'assertion_failed(mpl_::failed************ (boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Expr = point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >(), Attr = double]::error_invalid_expression::************)(point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > > (*)()))'
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/parse.hpp:83:9: note: candidate is:
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/mpl/assert.hpp:79:48: note: template<bool C> int mpl_::assertion_failed(typename mpl_::assert<C>::type)
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/detail/expr.hpp:6:0,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/expr.hpp:120,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/core.hpp:17,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/proto.hpp:12,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/support/meta_compiler.hpp:19,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/meta_compiler.hpp:14,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/action/action.hpp:14,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/action.hpp:14,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi.hpp:14,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/include/qi.hpp:16,
from ../test/grammar.h:4,
from ../test/main.cpp:1:
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/detail/preprocessed/expr.hpp: At global scope:
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/detail/preprocessed/expr.hpp: In instantiation of 'boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >()>, 0l>':
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/utility/enable_if.hpp:59:10: instantiated from 'boost::disable_if<boost::proto::is_expr<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >()>, 0l>, void>, void>'
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/support/meta_compiler.hpp:212:16: instantiated from 'boost::spirit::result_of::compile<boost::spirit::qi::domain, point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >(), boost::spirit::unused_type, void>'
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/parse.hpp:86:82: instantiated from 'bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Expr = point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >(), Attr = double]'
../test/main.cpp:20:63: instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/proto/detail/preprocessed/expr.hpp:50:49: error: field 'boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >()>, 0l>::child0' invalidly declared function type
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/detail/parse_auto.hpp:14:0,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/auto.hpp:16,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi.hpp:15,
from c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/include/qi.hpp:16,
from ../test/grammar.h:4,
from ../test/main.cpp:1:
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/parse.hpp: In function 'bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Expr = point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >(), Attr = double]':
../test/main.cpp:20:63: instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.6.1/../../../../include/boost/spirit/home/qi/parse.hpp:86:82: error: request for member 'parse' in 'boost::spirit::compile [with Domain = boost::spirit::qi::domain, Expr = point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >(), typename boost::spirit::result_of::compile<Domain, Expr, boost::spirit::unused_type>::type = point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > > (&)()]((* & expr))', which is of non-class type 'point_double_grammar<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> > >()'
Note that I'm compiling using boost 1.48.0 and mingw 4.6.1 on a windows 7 machine.
Change this line:
point_double_grammar<std::string::iterator> point_grammar();
To:
point_double_grammar<std::string::iterator> point_grammar;
You've declared a function taking no arguments that returns a grammar. Instead, you want to instantiate the grammar.
Sharth has already answered your question, you should accept that answer of course.
I wanted to share a few other things, you might find helpful.
as I mentioned: format your code (code is for humans)
Try using a loop instead of duplicating your code. You weren't parsing a list of doubles. You were parsing a single double, 5 times
Avoid C-isms (declare and initialize at the top?)
Look at Qi Skippers: you were manually 'ignoring' whitespace. Qi has Skippers for that purpose (see qi::phrase_parse in below sample)
Consider using Boost Karma for output generation. At least use <iomanip> to control the output format (see std::setprecision below)
Here is the full example
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
template <typename Iterator, typename Skipper>
struct point_double_grammar : qi::grammar<Iterator, double(), Skipper>
{
point_double_grammar() : point_double_grammar::base_type(d)
{
d = qi::double_;
}
qi::rule<Iterator, double(), Skipper> d;
};
static const char *const testcases[] = {
"575040.3400",
"117380.1200",
"-001.22916765",
"063.39171738",
"2.5",
NULL
};
int main()
{
typedef std::string::const_iterator It;
point_double_grammar<It, qi::space_type> point_grammar;
for(const char* const* it=testcases; *it; ++it)
{
const std::string input(*it);
It it = input.begin(), last = input.end();
double d = 0.0;
bool result = (qi::phrase_parse(it, last, point_grammar, qi::space, d) && it ==
last);
if(result)
std::cout << input << " == "
<< std::setprecision(10) << d << std::endl;
else
std::cerr << "Parsing failed!" << std::endl;
}
}
With C++11 you'd even write:
for (const std::string input : {
"575040.3400", "117380.1200", "-001.22916765", "063.39171738", "2.5" })
{
auto it = input.begin(), last = input.end();
etc. For the record, the output is:
575040.3400 == 575040.34
117380.1200 == 117380.12
-001.22916765 == -1.22916765
063.39171738 == 63.39171738
2.5 == 2.5
Without std::setprecision(10) the output would be, e.g. 575040.3400 == 575040 for the first line. Consider using Boost Karma for output generation.