Error with Phoenix placeholder _val in Boost.Spirit.Lex :( - c++

I'm newbie in Boost.Spirit.Lex.
Some strange error appears every time I try to use lex::_val in semantics actions in my simple lexer:
#ifndef _TOKENS_H_
#define _TOKENS_H_
#include <iostream>
#include <string>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
namespace lex = boost::spirit::lex;
namespace phx = boost::phoenix;
enum tokenids
{
ID_IDENTIFICATOR = 1,
ID_CONSTANT,
ID_OPERATION,
ID_BRACKET,
ID_WHITESPACES
};
template <typename Lexer>
struct mega_tokens
: lex::lexer<Lexer>
{
mega_tokens()
: identifier(L"[a-zA-Z_][a-zA-Z0-9_]*", ID_IDENTIFICATOR)
, constant (L"[0-9]+(\\.[0-9]+)?", ID_CONSTANT )
, operation (L"[\\+\\-\\*/]", ID_OPERATION )
, bracket (L"[\\(\\)\\[\\]]", ID_BRACKET )
{
using lex::_tokenid;
using lex::_val;
using phx::val;
this->self
= operation [ std::wcout
<< val(L'<') << _tokenid
// << val(L':') << lex::_val
<< val(L'>')
]
| identifier [ std::wcout
<< val(L'<') << _tokenid
<< val(L':') << _val
<< val(L'>')
]
| constant [ std::wcout
<< val(L'<') << _tokenid
// << val(L':') << _val
<< val(L'>')
]
| bracket [ std::wcout
<< val(L'<') << _tokenid
// << val(L':') << lex::_val
<< val(L'>')
]
;
}
lex::token_def<wchar_t, wchar_t> operation;
lex::token_def<std::wstring, wchar_t> identifier;
lex::token_def<double, wchar_t> constant;
lex::token_def<wchar_t, wchar_t> bracket;
};
#endif // _TOKENS_H_
and
#include <cstdlib>
#include <iostream>
#include <locale>
#include <boost/spirit/include/lex_lexertl.hpp>
#include "tokens.h"
int main()
{
setlocale(LC_ALL, "Russian");
namespace lex = boost::spirit::lex;
typedef std::wstring::iterator base_iterator;
typedef lex::lexertl::token <
base_iterator,
boost::mpl::vector<wchar_t, std::wstring, double, wchar_t>,
boost::mpl::true_
> token_type;
typedef lex::lexertl::actor_lexer<token_type> lexer_type;
typedef mega_tokens<lexer_type>::iterator_type iterator_type;
mega_tokens<lexer_type> mega_lexer;
std::wstring str = L"alfa+x1*(2.836-x2[i])";
base_iterator first = str.begin();
bool r = lex::tokenize(first, str.end(), mega_lexer);
if (r) {
std::wcout << L"Success" << std::endl;
}
else {
std::wstring rest(first, str.end());
std::wcerr << L"Lexical analysis failed\n" << L"stopped at: \""
<< rest << L"\"\n";
}
return EXIT_SUCCESS;
}
This code causes an error in Boost header 'boost/spirit/home/lex/argument.hpp' on line 167 while compiling:
return: can't convert 'const
boost::variant' to
'boost::variant &'
When I don't use lex::_val program compiles with no errors.
Obviously, I use _val in wrong way, but I do not know how to do this correctly. Help, please! :)
P.S. And sorry for my terrible English…

I believe this is a problem in the current Phoenix related to using iostreams. As a workaround I suggest to define a custom (Phoenix) function doing the actual output:
struct output_operation_impl
{
template <typename TokenId, typename Val>
struct result { typedef void type; };
template <typename TokenId, typename Val>
void operator()(T1 const& tokenid, T2 const& val) const
{
std::wcout << L'<' << tokenid << L':' << val << L'>';
}
};
boost::phoenix::function<output_operation_impl> const output_operation =
output_operation_impl();
calling it as:
this->self = operation[ output_operation(_tokenid, _val) ] ... ;
Regards Hartmut

Related

Need help using member functions as action with Boost Spirit QI

I'm having trouble getting member functions to bind inside grammar definitions. Compile errors result.
In short:
struct my_functor_word
{
// This code
void print ( std::string const& s, qi::unused_type, qi::unused_type ) const
// Gives the compiler error seen below.
// This code works fine:
// void operator()( std::string const& s, qi::unused_type, qi::unused_type ) const
{
std::cout << "word:" << s << std::endl;
}
};
template <typename Iterator>
struct bd_parse_grammar : qi::grammar<Iterator>
{
template <typename TokenDef> bd_parse_grammar( TokenDef const& tok )
: bd_parse_grammar::base_type( start )
{
my_functor_word mfw;
start = *(
// This code
tok.word [boost::bind(&my_functor_word::print, &mfw, qi::_1)]
// gives:
// {aka void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const}' is not a class, struct, or union type
// function_apply;
// ^~~~~~~~~~~~~~
///usr/include/boost/spirit/home/phoenix/core/detail/function_eval.hpp:126:13: error: 'boost::remove_reference<void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const>::type {aka void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const}' is not a class, struct, or union type
// type;
// ^~~~
// This:
// tok.word [boost::bind(&my_functor_word::print, &mfw, qi::_1)]
// similarly gives:
// /usr/include/boost/bind/bind.hpp:69:37: error: 'void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const' is not a class, struct, or union type
// typedef typename F::result_type type;
// This works OK:
// tok.word [my_functor_word()]
) ;
}
qi::rule<Iterator> start;
};
Here's the whole program. It compiles and functions correctly with functors but not member functions:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
using namespace boost::spirit::ascii;
template <typename Lexer>
struct bd_parse_tokens : lex::lexer<Lexer>
{
bd_parse_tokens()
{
// define patterns (lexer macros) to be used during token definition
this->self.add_pattern( "WORD", "[a-zA-Z._]+" );
// define tokens and associate them with the lexer
word = "{WORD}"; // reference the pattern 'WORD' as defined above
this->self.add ( word );
}
// the token 'word' exposes the matched string as its parser attribute
lex::token_def<std::string> word;
};
///////////////////////////////////////////////////////////////////////////////
// Grammar definition
///////////////////////////////////////////////////////////////////////////////
struct my_functor_word
{
// This code
void print ( std::string const& s, qi::unused_type, qi::unused_type ) const
// Gives the compiler error seen below.
// This code works fine:
// void operator()( std::string const& s, qi::unused_type, qi::unused_type ) const
{
std::cout << "word:" << s << std::endl;
}
};
template <typename Iterator>
struct bd_parse_grammar : qi::grammar<Iterator>
{
template <typename TokenDef> bd_parse_grammar( TokenDef const& tok )
: bd_parse_grammar::base_type( start )
{
my_functor_word mfw;
start = *(
// This code
tok.word [boost::bind(&my_functor_word::print, &mfw, qi::_1)]
// gives:
// {aka void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const}' is not a class, struct, or union type
// function_apply;
// ^~~~~~~~~~~~~~
///usr/include/boost/spirit/home/phoenix/core/detail/function_eval.hpp:126:13: error: 'boost::remove_reference<void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const>::type {aka void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const}' is not a class, struct, or union type
// type;
// ^~~~
// This:
// tok.word [boost::bind(&my_functor_word::print, &mfw, qi::_1)]
// similarly gives:
// /usr/include/boost/bind/bind.hpp:69:37: error: 'void (my_functor_word::*)(const std::basic_string<char>&, boost::spirit::unused_type, boost::spirit::unused_type) const' is not a class, struct, or union type
// typedef typename F::result_type type;
// This works OK:
// tok.word [my_functor_word()]
) ;
}
qi::rule<Iterator> start;
};
///////////////////////////////////////////////////////////////////////////////
int main( int argc, char* argv[] )
{
// Define the token type to be used: `std::string` is available as the
// type of the token attribute
typedef lex::lexertl::token < char const*, boost::mpl::vector<std::string> > token_type;
// Define the lexer type to use implementing the state machine
typedef lex::lexertl::lexer<token_type> lexer_type;
// Define the iterator type exposed by the lexer type */
typedef bd_parse_tokens<lexer_type>::iterator_type iterator_type;
// now we use the types defined above to create the lexer and grammar
// object instances needed to invoke the parsing process
bd_parse_tokens<lexer_type> bd_parse; // Our lexer
bd_parse_grammar<iterator_type> g( bd_parse ); // Our parser
// read in the file int memory
std::string str( argv[1] );
char const* first = str.c_str();
char const* last = &first[str.size()];
bool r = lex::tokenize_and_parse( first, last, bd_parse, g );
if ( ! r )
{
std::string rest( first, last );
std::cerr << "Parsing failed\n" << "stopped at: \""
<< rest << "\"\n";
}
return 0;
}
There are many aspects to this puzzle.
Firstly, to bind a member function you have to pass the extra leading instance parameter (the this object).
Secondly, semantic actions are Phoenix Actors, so deferred functors. boost::bind are likely not what you wantL you cannot call my_functor_word::print with qi::_1_type anyways. Instead you might use phoenix::bind, in which case you don't even have to deal with the "magic" context parameters:
struct my_functor_word {
void print(std::string const& s) const {
std::cout << "word:" << s << std::endl;
}
};
And
start = *(tok.word[ //
boost::phoenix::bind(&my_functor_word::print, &mfw, qi::_1)]);
That Was It?
I won't let you go without some more observations.
Firstly, the bind is still broken! You bound mfw as the this instance, but mfw is a local variable. The nature of the semantic action (being a defferred actor as said above) is that it will be called during parse: long after the constructor is finished. The mfw needs to be a member variable. Or better, not be a part of the grammar at all. I'd suggest
///////////////////////////////////////////////////////////////////////////////
// Grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct bd_parse_grammar : qi::grammar<Iterator>
{
template <typename TokenDef>
bd_parse_grammar(TokenDef const& tok) : bd_parse_grammar::base_type(start)
{
using namespace qi::labels;
start = *tok.word[px::bind(&my_functor_word::print, &mfw, _1)];
}
private:
struct my_functor_word {
void print(std::string const& s)
{
std::cout << "word:" << s << std::endl;
}
};
mutable my_functor_word mfw;
qi::rule<Iterator> start;
};
///////////////////////////////////////////////////////////////////////////////
I see a lot of old-fashioned and questionable style. E.g. why are you including boost/bind.hpp (or even boost/bind/bind.hpp) and even boost/lambda.hpp?
Why are you using Lex?
You're using using namespace liberally, which is a bad idea, especially when mixing all these libraries (that literally all have their own idea of placeholders named 1 etc). Instead just make some aliases:
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
namespace px = boost::phoenix;
You have a comment
// read in the file int memory
That doesn't match the code given:
std::string str(argv[1]);
char const* first = str.c_str();
char const* last = &first[str.size()];
That is just weird all around. Why are you using raw char* with a string (it has proper iterators with begin() and end()?). Also, maybe you really wanted to read a file?
By the way, let's make sure argv[1] is actually valid:
for (std::string fname : std::vector(argv + 1, argv + argc)) {
std::ifstream ifs(fname);
// read in the file into memory
std::string const str(std::istreambuf_iterator<char>(ifs), {});
auto first = str.begin(), //
last = str.end();
So here's a demo Live On Coliru
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <fstream>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
namespace px = boost::phoenix;
template <typename Lexer> struct bd_parse_tokens : lex::lexer<Lexer> {
bd_parse_tokens() {
this->self.add_pattern("WORD", "[a-zA-Z._]+");
word = "{WORD}";
this->self.add(word);
}
// the token 'word' exposes the matched string as its parser attribute
lex::token_def<std::string> word;
};
///////////////////////////////////////////////////////////////////////////////
// Grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct bd_parse_grammar : qi::grammar<Iterator>
{
template <typename TokenDef>
bd_parse_grammar(TokenDef const& tok) : bd_parse_grammar::base_type(start) {
using namespace qi::labels;
start = *tok.word[px::bind(&my_functor_word::print, &mfw, _1)];
}
private:
struct my_functor_word {
void print(std::string const& s) const { std::cout << "word:" << s << std::endl; }
};
mutable my_functor_word mfw;
qi::rule<Iterator> start;
};
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
// type of the token attribute
using token_type = lex::lexertl::token<std::string::const_iterator,
boost::mpl::vector<std::string>>;
using lexer_type = lex::lexertl::/*actor_*/lexer<token_type>;
using iterator_type = bd_parse_tokens<lexer_type>::iterator_type;
bd_parse_tokens<lexer_type> bd_parse;
bd_parse_grammar<iterator_type> g(bd_parse);
for (std::string fname : std::vector(argv + 1, argv + argc)) {
std::ifstream ifs(fname);
// read in the file into memory
std::string const str(std::istreambuf_iterator<char>(ifs), {});
auto first = str.begin();
auto last = str.end();
bool ok = lex::tokenize_and_parse(first, last, bd_parse, g);
std::cerr << "Parsing " << fname << " (length " << str.length() << ") "
<< (ok ? "succeeded" : "failed") << "\n";
if (first != last)
std::cerr << "Stopped at #" << std::distance(str.begin(), first)
<< "\n";
}
}
Prints
word:includeboostspiritincludelex_lexertl.hppincludeboostspiritincludephoenix.hppincludeboostspiritincludeqi.hppincludefstreamincludeiomanipnamespaceqiboostspiritqinamespacelexboostspiritlexnamespacepxboostphoenixtemplatetypenameLexerstructbd_parse_tokenslexlexerLexerbd_parse_tokensthisself.add_patternWORDazAZ._wordWORDthisself.addwordthetokenwordexposesthematchedstringasitsparserattributelextoken_defstdstringwordGrammardefinitiontemplatetypenameIteratorstructbd_parse_grammarqigrammarIteratortemplatetypenameTokenDefbd_parse_grammarTokenDefconsttokbd_parse_grammarbase_typestartusingnamespaceqilabelsstarttok.wordpxbindmy_functor_wordprintmfw_privatestructmy_functor_wordvoidprintstdstringconstsconststdcoutwordsstdendlmutablemy_functor_wordmfwqiruleIteratorstartintmainintargccharargvtypeofthetokenattributeusingtoken_typelexlexertltokenstdstringconst_iteratorboostmplvectorstdstringusinglexer_typelexlexertlactor_lexertoken_typeusingiterator_typebd_parse_tokenslexer_typeiterator_typebd_parse_tokenslexer_typebd_parsebd_parse_grammariterator_typegbd_parseforstdstringfnamestdvectorargvargvargcstdifstreamifsfnamereadinthefileintomemorystdstringconststrstdistreambuf_iteratorcharifsautofirststr.beginautolaststr.endbooloklextokenize_and_parsefirstlastbd_parsegstdcerrParsingfnamelengthstr.lengthoksucceededfailedniffirstlaststdcerrStoppedatstddistancestr.beginfirstn
Parsing input.txt (length 1367) succeeded
Parsing main.cpp (length 2479) succeeded
Stopped at #0
Without Lex
I think this would be strictly simpler:
Live On Coliru
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <fstream>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
template <typename Iterator>
struct bd_parse_grammar : qi::grammar<Iterator> {
bd_parse_grammar() : bd_parse_grammar::base_type(start)
{
using namespace qi::labels;
word = +qi::char_("a-zA-Z_.");
start = *word[px::bind(&my_functor_word::print, &mfw, _1)];
}
private:
struct my_functor_word {
void print(std::string const& s) const { std::cout << "word:" << s << std::endl; }
};
mutable my_functor_word mfw;
qi::rule<Iterator> start;
qi::rule<Iterator, std::string()> word;
};
int main(int argc, char* argv[]) {
bd_parse_grammar<std::string::const_iterator> const g;
for (std::string fname : std::vector(argv + 1, argv + argc)) {
std::ifstream ifs(fname);
// read the file into memory
std::string const str(std::istreambuf_iterator<char>(ifs), {});
auto first = str.begin();
auto last = str.end();
bool ok = qi::parse(first, last, g);
std::cerr << "Parsing " << fname << " (length " << str.length() << ") "
<< (ok ? "succeeded" : "failed") << "\n";
if (first != last)
std::cerr << "Stopped at #" << std::distance(str.begin(), first)
<< "\n";
}
}
Same output
Without Phoenix Bind
Using some C++17 CTAD and phoenix::function:
Live On Coliru
template <typename Iterator> struct Parser : qi::grammar<Iterator> {
Parser() : Parser::base_type(start) {
px::function print{[](std::string const& s) {
std::cout << "word:" << s << std::endl;
}};
word = +qi::char_("a-zA-Z_.");
start = *word[print(qi::_1)];
}
qi::rule<Iterator> start;
qi::rule<Iterator, std::string()> word;
};
Only half the original code.
Using X3
If you're using C++14 anyways, consider slashing compile times:
Live On Coliru
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <fstream>
namespace x3 = boost::spirit::x3;
namespace Parser {
auto print = [](auto& ctx) {
std::cout << "word:" << _attr(ctx) << std::endl;
};
auto word = +x3::char_("a-zA-Z_.");
auto start = *word[print];
} // namespace Parser
int main(int argc, char* argv[]) {
for (std::string fname : std::vector(argv + 1, argv + argc)) {
std::ifstream ifs(fname);
// read the file into memory
std::string const str(std::istreambuf_iterator<char>(ifs), {});
auto first = str.begin();
auto last = str.end();
bool ok = x3::parse(first, last, Parser::start);
std::cerr << "Parsing " << fname << " (length " << str.length() << ") "
<< (ok ? "succeeded" : "failed") << "\n";
if (first != last)
std::cerr << "Stopped at #" << std::distance(str.begin(), first) << "\n";
}
}
Still the same output.

reuse parsed variable with boost karma

I have a code base which is quite equivalent to the code below.
I try to generate a text file with two times the content of a variable.
I feel that the answer is in semantic actions and _a and _val but cannot manage to get through even with the documentation.
How will you do to have :
"toto" in str
and output :
toto some stuff toto
i.e how to reuse a parsed variable in karma ?
struct data
{
std::string str;
};
BOOST_FUSION_ADAPT_STRUCT(
data,
(std::string, str)
)
template <typename Iterator>
struct data: karma::grammar<Iterator, data() >
{
data():data::base_type(start)
{
start = karma::string << karma::lit("some stuff") << karma::string; //Second string is in fact the first one
}
karma::rule<Iterator, data()> start;
};
Solution (according to posts below :)
#include <iostream>
#include <string>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/karma.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/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/support_iso8859_1.hpp>
namespace ast
{
struct data
{
std::string str;
};
}
BOOST_FUSION_ADAPT_STRUCT(
ast::data,
(std::string, str)
)
namespace karma = boost::spirit::karma;
namespace parser
{
template <typename Iterator>
struct data: karma::grammar<Iterator, ast::data() >
{
data():data::base_type(start)
{
start =
karma::string[karma::_1 = boost::phoenix::at_c<0>(karma::_val)] <<
karma::lit("some stuff") <<
karma::string[karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
;
}
karma::rule<Iterator, ast::data()> start;
};
}
main()
{
ast::data d;
d.str = "toto";
std::string generated;
typedef std::back_insert_iterator<std::string> iterator_type;
parser::data<iterator_type> d_p;
iterator_type sink(generated);
karma::generate(sink, d_p, d);
std::cout << generated << std::endl;
}
This should do the trick:
start = karma::string[karma::_1 = karma::_val]
<< karma::lit("some stuff")
<< karma::string[karma::_1 = karma::_val];

How can I extract std::string object via boost spirit

I have the following code:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
struct function
{
std::string ret_type;
std::string name;
};
BOOST_FUSION_ADAPT_STRUCT(
::function,
(std::string, ret_type)
(std::string, name)
)
template <typename Iterator>
struct function_parser : boost::spirit::qi::grammar<Iterator, function(), boost::spirit::qi::ascii::space_type>
{
function_parser() : function_parser::base_type(start)
{
using boost::spirit::qi::ascii::char_;
using boost::spirit::qi::int_;
start %= +char_ >> +char_;
}
boost::spirit::qi::rule<Iterator, function(), boost::spirit::qi::ascii::space_type> start;
};
int main()
{
std::string input_data("void foo");
function fn;
auto itr = input_data.begin();
auto end = input_data.end();
function_parser<decltype(itr)> g;
bool res = boost::spirit::qi::phrase_parse(itr, end, g, boost::spirit::ascii::space, fn);
if (res && itr == end)
{
std::cout << boost::fusion::tuple_open('[');
std::cout << boost::fusion::tuple_close(']');
std::cout << boost::fusion::tuple_delimiter(", ");
std::cout << "Parsing succeeded\n";
std::cout << "got: " << boost::fusion::as_vector(fn) << std::endl;
}
else
{
std::cout << "Parsing failed \n";
}
}
Output
Parsing failed
What am I doing wrong? How can I fix it?
+char_
eats all input! Now, the next
+char_
requires at least a single character, which isn't there (the first kleen plus ate it) so the parse fails.
I suggest instead:
using namespace boost::spirit::qi;
start = lexeme[+graph] >> lexeme[+graph];
The documentation should be able to tell you what that does (I hope. No time to elaborate)

boost spirit qi rules' attribute question

I have the following code can not compile, however I do not know where is the problem:
#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_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
void print (std::string& s)
{
std::cout << "Get string [" << s << ']' << std::endl;
}
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct my_grammar
: qi::grammar<Iterator, std::string(), ascii::space_type>
{
my_grammar()
: my_grammar::base_type(start)
{
using qi::lit;
using qi::int_;
using qi::lexeme;
using ascii::char_;
using ascii::string;
using ascii::space_type;
using namespace qi::labels;
// Here you can see the rule oct_char with attribute type as char
// +(char) would be vector<char> which is compactable with string type
// Why the compiler still told me the type of the attribute is not right?
start %= lexeme[+(oct_char)] [&print]
;
oct_char =
lexeme["//"
>> char_('0','3') [ _a = ( _1 - '0' ) ]
|| char_('0','7') [ _a = _a << 3 + ( _1 - '0' ) ]
|| char_('0','7') [ _a = _a << 3 + ( _1 - '0' ) ]]
[ _val = _a ]
;
}
qi::rule<Iterator, std::string(), ascii::space_type> start;
qi::rule<Iterator, char(), qi::locals<char>, ascii::space_type> oct_char;
};
}
int main(int argc, char **argv)
{
typedef client::my_grammar<std::string::const_iterator> Grammer;
Grammer grm;
std::string str;
using boost::spirit::ascii::space;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
if (phrase_parse(str.begin(), str.end(), grm, space))
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "got: " << str << std::endl;
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
Here are the error messages:
Error 2 error C2664: 'void (std::basic_string<_Elem,_Traits,_Ax> )' : cannot convert parameter 1 from 'std::vector<_Ty>' to 'std::basic_string<_Elem,_Traits,_Ax> ' d:\code\boost_1_46_1\boost\spirit\home\support\action_dispatch.hpp 70
Is there anyone can give some suggestions?
Thanks
This has been discussed at length elsewhere (for instance here). If you change your print function to take a vector<char> it will work:
void print (std::vector<char> const& s)
{
std::cout << "Get string ["
<< std::string(s.begin(), s.end()) << ']'
<< std::endl;
}
There is one more error in your code, though. The rule oct_char does not need to have a skipper as it is used inside lexeme[]:
qi::rule<Iterator, char(), qi::locals<char> > oct_char;

How do you use a variable stored in a boost spirit closure as input to a boost spirit loop parser?

I would like to use a parsed value as the input to a loop parser.
The grammar defines a header that specifies the (variable) size of the following string. For example, say the following string is the input to some parser.
12\r\nTest Payload
The parser should extract the 12, convert it to an unsigned int and then read twelve characters. I can define a boost spirit grammar that compiles, but an assertion in the boost spirit code fails at runtime.
#include <iostream>
#include <boost/spirit.hpp>
using namespace boost::spirit;
struct my_closure : public closure<my_closure, std::size_t> {
member1 size;
};
struct my_grammar : public grammar<my_grammar> {
template <typename ScannerT>
struct definition {
typedef rule<ScannerT> rule_type;
typedef rule<ScannerT, my_closure::context_t> closure_rule_type;
closure_rule_type header;
rule_type payload;
rule_type top;
definition(const my_grammar &self)
{
using namespace phoenix;
header = uint_p[header.size = arg1];
payload = repeat_p(header.size())[anychar_p][assign_a(self.result)];
top = header >> str_p("\r\n") >> payload;
}
const rule_type &start() const { return top; }
};
my_grammar(std::string &p_) : result(p_) {}
std::string &result;
};
int
main(int argc, char **argv)
{
const std::string content = "12\r\nTest Payload";
std::string payload;
my_grammar g(payload);
if (!parse(content.begin(), content.end(), g).full) {
std::cerr << "there was a parsing error!\n";
return -1;
}
std::cout << "Payload: " << payload << std::endl;
return 0;
}
Is it possible to tell spirit that the closure variable should be evaluated lazily? Is this behaviour supported by boost spirit?
This is much easier with the new qi parser available in Spirit 2. The following code snippet provides a full example that mostly works. An unexpected character is being inserted into the final result.
#include <iostream>
#include <string>
#include <boost/version.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_repeat.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
using boost::spirit::qi::repeat;
using boost::spirit::qi::uint_;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::alpha;
using boost::spirit::qi::_1;
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
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;
}
static void
straight_forward()
{
std::string str;
int n;
test_parser_attr("12\r\nTest Payload",
uint_[phx::ref(n) = _1] >> "\r\n" >> repeat(phx::ref(n))[char_],
str);
std::cout << "str.length() == " << str.length() << std::endl;
std::cout << n << "," << str << std::endl; // will print "12,Test Payload"
}
template <typename P, typename T>
void
test_phrase_parser(char const* input, P const& p,
T& attr, bool full_match = true)
{
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::ascii::space;
char const* f(input);
char const* l(f + strlen(f));
if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
template <typename Iterator>
struct test_grammar
: qi::grammar<Iterator, std::string(), qi::locals<unsigned> > {
test_grammar()
: test_grammar::base_type(my_rule)
{
using boost::spirit::qi::_a;
my_rule %= uint_[_a = _1] >> "\r\n" >> repeat(_a)[char_];
}
qi::rule<Iterator, std::string(), qi::locals<unsigned> > my_rule;
};
static void
with_grammar_local_variable()
{
std::string str;
test_phrase_parser("12\r\nTest Payload", test_grammar<const char*>(), str);
std::cout << str << std::endl; // will print "Test Payload"
}
int
main(int argc, char **argv)
{
std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl;
straight_forward();
with_grammar_local_variable();
return 0;
}
What you are looking for is lazy_p, check the example here: http://www.boost.org/doc/libs/1_35_0/libs/spirit/doc/the_lazy_parser.html