Parse to struct with default value - c++

My AST node is struct
struct node_type
{
type::code type_id;
boost::variant<int, std::string> value;
};
Adapter and grammar:
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, id)
(boost::variant<int, std::string>, value)
)
namespace client
{
struct or_op
{
node_type left, right;
};
namespace type
{
enum code{NUMBER, STRING, BOOL};
}
// Grammar
template <typename Iterator>
struct pair_grammar : qi::grammar<
Iterator,
node_type(), // Grammar generates node_type
ascii::space_type
>
{
pair_grammar() : pair_grammar::base_type(
expr // main 'rule'
)
{
using qi::lit;
using qi::lexeme;
using ascii::char_;
using qi::int_;
using ascii::string;
using namespace qi::labels;
using phoenix::at_c;
using phoenix::push_back;
expr = int_[at_c<0>(qi::_val) = 0, at_c<1>(qi::_val) = qi::_1];
}
qi::rule<Iterator, node_type(), ascii::space_type> expr;
};
}
The code above doesn't compile. First of all i get warning
error: macro "BOOST_FUSION_ADAPT_STRUCT_FILLER_0" passed 3 arguments, but takes just 2
and then a lot of errors, starting with
qi/nonterminal/rule.hpp:303:17: error: no match for call to '(const function_type {aka const boost::function<bool(const char*&, const char* const&, boost::spirit::context<boost::fusion::cons<client::node_type&, 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> >&)>}) (const char*&, const char* const&, boost::spirit::qi::rule<const char*, client::node_type(), 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&)'
What am I doing wrong? Thanks.
EDIT:
Macro warning appeared because of ',' in macro. Typedef solved problem
typedef boost::variant<int, std::string> node_value_t;
struct node_type
{
type::code type_id;
node_value_t value;
};
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, type_id)
(client::node_value_t, value)
)
But code still doesn't compile. I also tried
number = int_[qi::_val = phoenix::construct<node_type>(type::NUMBER, qi::_1)];
But that didnt help.
EDIT 2: Simplified original rule. Still no success.

A number of issues here.
The message
error: macro "BOOST_FUSION_ADAPT_STRUCT_FILLER_0" passed 3 arguments, but takes just 2
occurs because of the , in the template arguments for variant<>. You can fix it using a typedef:
namespace client {
namespace type { enum code{NUMBER, STRING, BOOL}; }
struct node_type {
type::code type_id;
typedef boost::variant<int, std::string> vt_type;
vt_type value;
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, type_id)
(client::node_type::vt_type, value)
)
You were assigning an int to the attribute of enum type. The implicit conversion is not allowed. Instead, supply the required enum type:
expr = int_ [at_c<0>(qi::_val) = client::type::NUMBER, at_c<1>(qi::_val) = qi::_1];
At this point, everything compiles and works: Live On Coliru
using namespace client;
pair_grammar<std::string::const_iterator> grammar;
std::string const input = "123";
auto f(input.begin()), l(input.end());
node_type node;
bool ok = qi::phrase_parse(f, l, grammar, ascii::space, node);
assert(ok);
assert(f == l);
assert(node.type_id == type::NUMBER);
assert(node.value == node_type::vt_type(123));
I don't think this solution is optimal, though.
Consider using the Spirit directives where possible, and staying away from Semantic actions that uglify the grammar, are a frequent source of errors/UB, make compile times even longer... [1]:
pair_grammar() : pair_grammar::base_type(expr)
{
expr = qi::attr(client::type::NUMBER) >> qi::int_;
}
See that Live On Coliru too:
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = qi::ascii;
namespace client
{
namespace type
{
enum code{NUMBER, STRING, BOOL};
}
struct node_type
{
type::code type_id;
typedef boost::variant<int, std::string> vt_type;
vt_type value;
};
}
/*Adapter and grammar:*/
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, type_id)
(client::node_type::vt_type, value)
)
namespace client
{
struct or_op
{
node_type left, right;
};
// Grammar
template <typename Iterator>
struct pair_grammar : qi::grammar<
Iterator,
node_type(), // Grammar generates node_type
ascii::space_type
>
{
pair_grammar() : pair_grammar::base_type(expr)
{
expr = qi::attr(client::type::NUMBER) >> qi::int_;
}
qi::rule<Iterator, node_type(), ascii::space_type> expr;
};
}
int main()
{
using namespace client;
pair_grammar<std::string::const_iterator> grammar;
std::string const input = "123";
auto f(input.begin()), l(input.end());
node_type node;
bool ok = qi::phrase_parse(f, l, grammar, ascii::space, node);
assert(ok);
assert(f == l);
assert(node.type_id == type::NUMBER);
assert(node.value == node_type::vt_type(123));
}
[1] Boost Spirit: "Semantic actions are evil"?

Related

Boost Spirit compilation error "error_invalid_expression"

I am trying to figure out what is wrong with this Boost Spirit code:
#include <iostream>
#include <string>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
template <typename Iterator>
struct Header
{
struct Type : boost::fusion::vector2<unsigned int, unsigned int>
{
unsigned int getFirstThing() { return boost::fusion::at_c<0>(*this); }
unsigned int getSecondThing() { return boost::fusion::at_c<1>(*this); }
};
};
template<typename Iterator>
struct HeaderParse
: boost::spirit::qi::grammar<Iterator, typename Header<Iterator>::Type() >
{
HeaderParse()
: HeaderParse::base_type(_start)
{
using boost::spirit::qi::uint_parser;
_start = '<'
>> uint_parser<unsigned int, 10, 1, 3>()
>> '>'
>> uint_parser<unsigned int, 10, 1, 3>();
_start.name("HeaderParse");
}
~HeaderParse() = default;
boost::spirit::qi::rule<Iterator, typename Header<Iterator>::Type() > _start;
};
int main()
{
const std::string d1 = "<1>2";
const HeaderParse<std::string::const_iterator> parser;
Header<std::string::const_iterator>::Type header;
std::string::const_iterator begin = d1.begin();
std::string::const_iterator end = d1.end();
assert(boost::spirit::qi::parse(begin, end, parser, header));
return 0;
}
This is the compilation error that I see when I try to compile:
$ make --jobs=8
Scanning dependencies of target testapp
[ 50%] Building CXX object CMakeFiles/testapp.dir/test.cpp.o
In file included from /Users/addy/nw/stub/test.cpp:5:
In file included from /Users/addy/Downloads/boost_1_65_1/boost/spirit/include/qi_grammar.hpp:16:
In file included from /Users/addy/Downloads/boost_1_65_1/boost/spirit/home/qi/nonterminal/grammar.hpp:18:
/Users/addy/Downloads/boost_1_65_1/boost/spirit/home/qi/nonterminal/rule.hpp:177:13: error: static_assert failed "error_invalid_expression"
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/Users/aclaure/nw/stub/test.cpp:27:16: note: in instantiation of function template specialization 'boost::spirit::qi::rule<std::__1::__wrap_iter<const char *>,
Header<std::__1::__wrap_iter<const char *> >::Type (), boost::spirit::unused_type, boost::spirit::unused_type,
boost::spirit::unused_type>::operator=<boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const
boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right,
boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector<char
const (&)[7]> > >, 0> &, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const char &>, 0> >, 2> &, const
boost::spirit::qi::uint_parser<unsigned int, 10, 1, 3> &>, 2> &, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const char &>, 0>
>, 2> &, const boost::spirit::qi::uint_parser<unsigned int, 10, 1, 3> &>, 2> >' requested here
_start =
^
/Users/aclaure/nw/stub/test.cpp:46:52: note: in instantiation of member function 'HeaderParse<std::__1::__wrap_iter<const char *> >::HeaderParse' requested here
const HeaderParse<std::string::const_iterator> parser;
Which leads me to this comment in the Spirit header files:
// Report invalid expression error as early as possible.
// If you got an error_invalid_expression error message here,
// then the expression (expr) is not a valid spirit qi expression.
But the expression I have written seems valid to me. I am not sure what could be wrong with it. Any help is much appreciated!
You're missing a header. I can't say which one but if I just include
#include <boost/spirit/home/qi.hpp>
it compiles.
Live example on Wandbox
N.B.: I couldn't find any “official” statement but I don't think including the individual headers is recommended. At least none of the Qi examples does it.
I guess you only include those headers because you hope to reduce compile-time that way. If you really want to speed things up, consider using X3 instead. This example takes about 1 sec to compile on my machine.
#include <iostream>
#include <string>
#include <tuple>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
namespace Header {
using Type = std::tuple<unsigned int, unsigned int>;
namespace x3 = boost::spirit::x3;
x3::uint_parser<unsigned int, 10, 1, 3> uint_;
x3::rule<class parser, Type> const parser = "parser";
auto const parser_def = '<' >> uint_ >> '>' >> uint_;
BOOST_SPIRIT_DEFINE(parser)
}
int main()
{
const std::string d1 = "<1>2";
Header::Type header;
auto iter = d1.begin();
auto end = d1.end();
bool r = boost::spirit::x3::parse(iter, end, Header::parser, header);
if (!r || iter != end) {
std::cerr << "Parsing failed at " << std::string{iter,end} << "\n";
} else {
std::cout << std::get<0>(header) << " " << std::get<1>(header) << "\n";
}
}
Live example on Wandbox

boost::bind does not compile

I am new to boost spirit and I have the following problem:
#include <string>
#include <vector>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/bind.hpp>
using namespace boost::spirit;
using namespace std;
struct MyGrammar
: qi::grammar<string::const_iterator, string(), ascii::space_type> {
MyGrammar();
void myFun(const string& s);
private:
qi::rule<string::const_iterator, string(), ascii::space_type> myRule;
};
using namespace boost::spirit;
using namespace std;
MyGrammar::MyGrammar() : MyGrammar::base_type(myRule) {
using qi::_1;
myRule = int_ [boost::bind(&MyGrammar::myFun, this, _1)]; // fails
myRule = int_ [_val = _1]; // fine
}
void MyGrammar::myFun(const string& s){
cout << "read: " << s << endl;
}
int
main(){
}
With the first assignment of myRule I get compile errors while the second assignment compiles fine.
In the first case the compiler outputs huge error messages that I don't understand.
At the end it says:
boost_1_49_0/include/boost/bind/bind.hpp:318:9: error: no match for call to '(const boost::_mfi::mf1<void, MyGrammar, const std::basic_string<char>&>) (MyGrammar* const&, const boost::phoenix::actor<boost::spirit::argument<0> >&)'
boost_1_49_0/include/boost/bind/mem_fn_template.hpp:163:7: note: candidates are: R boost::_mfi::mf1<R, T, A1>::operator()(T*, A1) const [with R = void, T = MyGrammar, A1 = const std::basic_string<char>&]
boost_1_49_0/include/boost/bind/mem_fn_template.hpp:184:7: note: R boost::_mfi::mf1<R, T, A1>::operator()(T&, A1) const [with R = void, T = MyGrammar, A1 = const std::basic_string<char>&]
Any ideas?
Thanks a lot for any help!
You can't use placeholders from different bind implementations. There are currently three bind functions in Boost:
boost::bind, superseded by
boost::lambda::bind, superseded by
boost::phoenix::bind, which is what you should use for Boost.Spirit
The placeholders under boost::spirit::qi (and boost::spirit::karma) are the same as the ones used by boost::phoenix::bind, so just use that.
Oh, and pro tip: Stop your using namespace std; and preferrably any other using directive in global namespace.
The first problem is that you specifiy std::string as your synthesized attribute, but then define your rule in terms of qi::int_, which has a synthesized attribute of int.
The second problem is that, as the Spirit docs state directly, non-Phoenix functors take three arguments, not one:
You can use Boost.Bind to bind member functions. For function objects, the allowed signatures are:
void operator()(Attrib const&, unused_type, unused_type) const;
void operator()(Attrib const&, Context&, unused_type) const;
void operator()(Attrib const&, Context&, bool&) const;
The third problem is that you're using Spirit's Phoenix _1 placeholder rather than boost::bind's placeholder (which is effectively in the global namespace).
In summary, this should work:
#include <string>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct MyGrammar :
qi::grammar<std::string::const_iterator, int(), ascii::space_type>
{
MyGrammar();
void myFun(int i, qi::unused_type, qi::unused_type);
private:
qi::rule<std::string::const_iterator, int(), ascii::space_type> myRule;
};
MyGrammar::MyGrammar() : MyGrammar::base_type(myRule)
{
myRule = qi::int_[boost::bind(&MyGrammar::myFun, this, _1, _2, _3)];
}
void MyGrammar::myFun(int const i, qi::unused_type, qi::unused_type)
{
std::cout << "read: " << i << '\n';
}
int main()
{
std::string const input = "42";
std::string::const_iterator first = input.begin(), last = input.end();
qi::phrase_parse(first, last, MyGrammar(), ascii::space);
}
That being said, unless you have a very specific reason to use boost::bind here, you should be using boost::phoenix::bind instead:
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct MyGrammar :
qi::grammar<std::string::const_iterator, int(), ascii::space_type>
{
MyGrammar();
void myFun(int i);
private:
qi::rule<std::string::const_iterator, int(), ascii::space_type> myRule;
};
MyGrammar::MyGrammar() : MyGrammar::base_type(myRule)
{
myRule = qi::int_[boost::phoenix::bind(&MyGrammar::myFun, this, qi::_1)];
}
void MyGrammar::myFun(int const i)
{
std::cout << "read: " << i << '\n';
}
int main()
{
std::string const input = "42";
std::string::const_iterator first = input.begin(), last = input.end();
qi::phrase_parse(first, last, MyGrammar(), ascii::space);
}
This allows your bound member function to take only a single argument – the synthesized attribute – as you originally wanted.

Boost.Spirit with Boost.Variant and C++11: Expecting a zero-argument constructor

I'm trying to compile a simple grammar using Boost.Spirit. I'm using g++ 4.7.0 and boost 1.49.0-1.1 on Arch Linux x86_64.
The eventual goal here is an assembler. There will be multiple operands with one class each. All the operand types together are stored in a boost::variant type.
I've had success compiling this sample up to the direct rule when it is also the base_type of the grammar, but introducing the operand rule (and making it the base type) causes g++ 4.7.0 to complain that:
example.cpp:61:7: required from ‘Grammar<Iterator>::Grammar() [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >]’
example.cpp:76:21: required from here
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:23:63: error: no matching function for call to ‘DirectOperand::DirectOperand()’
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:23:63: note: candidates are:
example.cpp:20:12: note: DirectOperand::DirectOperand(const DirectValue&)
example.cpp:20:12: note: candidate expects 1 argument, 0 provided
example.cpp:16:7: note: DirectOperand::DirectOperand(const DirectOperand&)
example.cpp:16:7: note: candidate expects 1 argument, 0 provided
I don't understand why it should be looking for a default constructor for DirectOperand, since the semantic action should call it with the constructor.
I've tried lots of variations, including
operand = directOp[_val = _1];
and even writing a helper function to "force" the type, like:
static Operand makeDirectOperand( const DirectOperand& op ) { return op; }
// ...
operand = directOp[&makeDirectOp];
but no matter what I do, it complains about the missing default constructor.
When I actually defined a zero-argument constructor, I found that it compiled, but that that DirectOperand::value_ never changed from the default value I assigned.
Here's the code. It's as short as I could make it.
#include <cstdint>
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/variant.hpp>
typedef std::uint16_t DataWord;
typedef boost::variant<std::string, DataWord> DirectValue;
class DirectOperand {
private:
DirectValue value_;
public:
explicit DirectOperand( const DirectValue& value ) :
value_( value ) {}
const DirectValue& value() const { return value_; }
};
// For example purposes, but there will be multiple operand types
// here.
typedef boost::variant<DirectOperand> Operand;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct Grammar : qi::grammar<Iterator, Operand(), ascii::space_type> {
Grammar() : Grammar::base_type( operand ) {
using qi::lexeme;
using ascii::char_;
using qi::uint_parser;
using namespace qi::labels;
uint_parser<DataWord, 16, 1, 4> uhex_p;
uint_parser<DataWord, 10, 1, 5> uint_p;
word =
char_( "a-zA-Z._" ) [_val += _1]
>> *char_( "a-zA-Z0-9._" ) [_val += _1]
;
number = (
"0x" >> uhex_p
| uint_p
)
[_val = _1]
;
direct %= ( word | number );
directOp %= direct;
// This would be ( directOp | indirectOp | etc)
operand %= directOp;
}
qi::rule<Iterator, DataWord(), ascii::space_type> number;
qi::rule<Iterator, std::string()> word;
qi::rule<Iterator, DirectValue(), ascii::space_type> direct;
qi::rule<Iterator, DirectOperand(), ascii::space_type> directOp;
qi::rule<Iterator, Operand(), ascii::space_type> operand;
};
int main() {
std::string line;
typedef std::string::iterator iterator_type;
typedef Grammar<iterator_type> Grammar;
Grammar grammar {};
}
I believe that the instantiation of the attribute qi::rule (directOp here) requires a default constructor.
If you are loathe to include a default constructor in DirectOperand, you could try wrapping it up in a boost::optional for the purpose of deferring initialization.

Using the + operator in boost::spirit: char cast error?

In boost::spirit, I am trying to use the +(...) syntax to match one or more strings, like here:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
bool parse(Iterator first, Iterator last)
{
using qi::char_;
qi::rule< Iterator, std::string(), ascii::space_type > text;
qi::rule< Iterator, std::string() > myword;
text = '"' >> +( myword ) >> '"'; // ERROR!
myword = +char_;
bool r = qi::phrase_parse(first, last, text, ascii::space);
if (first != last)
return false;
return r;
}
}
But I'm getting the following error:
foo.cpp:20: instantiated from 'bool client::parse
boost/spirit/home/qi/detail/assign_to.hpp:109: error: \
invalid static_cast from type \
'const std::basic_string<char, std::char_traits<char>, std::allocator<char> >' \
to type 'char'
Does anyone know what I'm doing wrong?
Your code compiles just fine with Boost V1.47 (Spirit V2.5). In this version of Spirit the attribute handling has been completely rewritten which fixes this issue (and a lot of other issues).

boost spirit v2 compile error - trying to use symbols for something slightly harder and missing an important point somewhere

I have tried various approaches to fixing this issue with maps and casts, splitting the parse into different sub-pieces, using std::vector directly and trying _r1 etc. but I seem to have failed to grasp something fundamental about the use of attributes.
I want to parse a line such as:
DEFMACRO macroname param1 param2 param3 ... paramN
and add macroname into a qi::symbols parser along with its list of params.
Matching on
lit("DEFMACRO") >> (+char_) >> predicate_
and putting into a defmacro struct works fine, but when I try to use the result or store it whole as the data element of a symbols parser I get errors of the form
cannot convert from 'const boost::phoenix::actor' to 'const client::defmacro'
but whatever I try I always fail to "convert from 'const boost::phoenix::actor' to" whatever data type I am trying to use (eg straight to std::vector or other variations in structs. Also tried variations on syntax but so far drawn a blank.
Code fragment is below, followed by compiler output for this variation on my problem.
Any explanation of my failure to grasp some important concept very welcome.
Using VC++ 2008 with Spirit 1.42.
Thanks
Rick
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef std::vector<std::string> predicate;
struct defmacro
{
std::string name; // identifier for macro
predicate params; // parameters for macro
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::defmacro,
(std::string, name)
(client::predicate, params)
)
namespace client
{
template <typename Iterator>
struct awe_grammar
: qi::grammar<Iterator, awe(), qi::locals<std::string>, ascii::space_type>
{
awe_grammar()
: awe_grammar::base_type(x, "x")
{
using qi::lit;
using qi::eol;
using qi::int_;
using ascii::char_;
using namespace qi::labels;
using phoenix::at_c;
long line_no=1;
qi::symbols<std::string, defmacro> macros;
eol_ = eol[ref(line_no)++];
predicate_ %= *(+char_);
defmacro_line_ %= (lit("DEFMACRO") >> (+char_) >> predicate_ >> eol_);
// ******** This line will not compile *************************
defmacro_ = defmacro_line_[macros.add(at_c<0>(_1),_1)];
// *************************************************************
}
qi::rule<Iterator, defmacro(), ascii::space_type> defmacro_line_;
qi::rule<Iterator, void(), ascii::space_type> defmacro_;
qi::rule<Iterator, predicate(), ascii::space_type> predicate_;
};
}
2>v:\awe\parser\parser\spirit\spirit_eg.cpp(XXX) : error C2664: 'const boost::spirit::qi::symbols<Char,T>::adder &boost::spirit::qi::symbols<Char,T>::adder::operator ()<boost::phoenix::actor<Eval>>(const Str &,const T &) const' : cannot convert parameter 2 from 'const boost::phoenix::actor<Eval>' to 'const client::defmacro &'
2> with
2> [
2> Char=std::string,
2> T=client::defmacro,
2> Eval=boost::phoenix::composite<boost::phoenix::at_eval<0>,boost::fusion::vector<boost::spirit::argument<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
2> Str=boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<0>,boost::fusion::vector<boost::spirit::argument<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>>
2> ]
2> and
2> [
2> Eval=boost::spirit::argument<0>
2> ]
2> Reason: cannot convert from 'const boost::phoenix::actor<Eval>' to 'const client::defmacro'
2> with
2> [
2> Eval=boost::spirit::argument<0>
2> ]
2> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
2> v:\awe\parser\parser\spirit\spirit_eg.cpp(351) : while compiling class template member function 'client::awe_grammar<Iterator>::awe_grammar(void)'
2> with
2> [
2> Iterator=std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char>>
2> ]
2> v:\awe\parser\parser\spirit\spirit_eg.cpp(622) : see reference to class template instantiation 'client::awe_grammar<Iterator>' being compiled
2> with
2> [
2> Iterator=std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char>>
2> ]
You can add values to symbols outside of your grammar like this:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef std::vector<std::string> predicate;
struct defmacro
{
std::string name; // identifier for macro
predicate params; // parameters for macro
};
typedef std::vector<defmacro> awe;
}
BOOST_FUSION_ADAPT_STRUCT(
client::defmacro,
(std::string, name)
(client::predicate, params)
)
namespace client
{
template <typename Iterator>
struct awe_grammar
: qi::grammar<Iterator, awe()>
{
awe_grammar()
: awe_grammar::base_type(start_)
{
using qi::lit;
using qi::eol;
using ascii::char_;
using ascii::blank;
using ascii::space;
using namespace qi::labels;
using phoenix::ref;
using phoenix::at_c;
line_no = 0;
eol_ = eol[++ref(line_no)];
identifier_ %= qi::lexeme[+(char_ - space)];
predicate_ %= (identifier_ % blank) >> eol_;
defmacro_line_ %=
lit("DEFMACRO ")
>> identifier_ >> ' '
>> predicate_
;
start_ %= +defmacro_line_;
}
long line_no;
qi::rule<Iterator, void() > eol_;
qi::rule<Iterator, defmacro() > defmacro_line_;
qi::rule<Iterator, awe() > start_;
qi::rule<Iterator, std::string()> identifier_;
qi::rule<Iterator, predicate() > predicate_;
};
}
and
#include <cstdlib>
#include <iostream>
#include "awe_grammar.h"
template <typename P, typename T>
void test_parser_attr(
char const* input, P const& p, T& attr, bool full_match = true)
{
using boost::spirit::qi::parse;
char const* f(input);
char const* l(f + strlen(f));
if (parse(f, l, p, attr) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
int main( /*int _argc, char * _argv[]*/ )
{
typedef client::awe_grammar<char const *> my_grammar;
my_grammar g;
client::awe result;
test_parser_attr(
"DEFMACRO macroname param1 param2 param3\n"
"DEFMACRO macro2 param1 param2\n",
g,
result,
true
);
////////////////////
// adding
////////////////////
boost::spirit::qi::symbols<char, client::defmacro> macros;
for (size_t i = 0; i < result.size(); i++)
{
macros.add(result[i].name, result[i]);
}
return EXIT_SUCCESS;
}
After that you can do with your macros what you want (for example, pass it to another grammar).
Try this:
// ******** This line will not compile *************************
using qi::_val;
defmacro_ = defmacro_line_[macros.add(at_c<0>(_val),_1)];
// *************************************************************