I am trying to use Boost Spirit X3 with semantic actions when analyzing the structure in AST. If I use a rule without a separate definition and instantiation, it works fine, for example:
#include <vector> #include <string> #include <iostream> #include <boost/fusion/include/adapt_struct.hpp> #include <boost/spirit/home/x3.hpp> namespace ast { struct ast_struct { int number; std::vector<int> numbers; }; } BOOST_FUSION_ADAPT_STRUCT( ast::ast_struct, (int, number) (std::vector<int>, numbers) ) namespace x3 = boost::spirit::x3; using namespace std; void parse( const std::string &data ) { string::const_iterator begin = data.begin(); string::const_iterator end = data.end(); unsigned n(0); auto f = [&n]( auto &ctx ) { n = x3::_attr(ctx); }; ast::ast_struct ast; bool r = x3::parse( begin, end, x3::int_[f] >> +( x3::omit[+x3::blank] >> x3::int_ ), ast ); if ( r && begin == end ) { cout << "n: " << n << ", "; std::copy(ast.numbers.begin(), ast.numbers.end(), std::ostream_iterator<int>(std::cout << ast.numbers.size() << " elements: ", " ")); cout << endl; } else cout << "Parse failed" << endl; } int main() { parse( "3 1 2 3" ); parse( "4 1 2 3 4" ); return 0; }
Execution of the above code (compiled with the flags -std = C ++ 14) displays the expected result:
n: 3, 3 elements: 1 2 3 n: 4, 4 elements: 1 2 3 4
Now I am trying to make my Spirit X3 parser more or less the same as calc 9 example from Boost Spirit X3, but this does not work:
- ast.hxx: defines an abstract syntax tree.
- grammar.hxx: user interface that exposes parser methods.
- grammar.cxx: creates rules.
- grammar_def.hxx: parser grammar definition.
- config.hxx: parser configuration.
- main.cxx: an example of using the parser.
ast.hxx:
#ifndef AST_HXX #define AST_HXX #include <vector> #include <boost/fusion/include/adapt_struct.hpp> namespace ast { struct ast_struct { int number; std::vector<int> numbers; }; } BOOST_FUSION_ADAPT_STRUCT( ast::ast_struct, (int, number) (std::vector<int>, numbers) ) #endif
grammar.hxx:
#ifndef GRAMMAR_HXX #define GRAMMAR_HXX #include "ast.hxx" #include <boost/spirit/home/x3.hpp> namespace parser { namespace x3 = boost::spirit::x3; using my_rule_type = x3::rule<class my_rule_class, ast::ast_struct>; BOOST_SPIRIT_DECLARE( my_rule_type ); const my_rule_type &get_my_rule(); } #endif
grammar.cxx:
#include "grammar_def.hxx" #include "config.hxx" namespace parser { BOOST_SPIRIT_INSTANTIATE( my_rule_type, iterator_type, context_type ) }
grammar_def.hxx:
#ifndef GRAMMAR_DEF_HXX #define GRAMMAR_DEF_HXX #include <iostream> #include <boost/spirit/home/x3.hpp> #include "grammar.hxx" #include "ast.hxx" namespace parser { namespace x3 = boost::spirit::x3; const my_rule_type my_rule( "my_rule" ); unsigned n; auto f = []( auto &ctx ) { n = x3::_attr(ctx); }; auto my_rule_def = x3::int_[f] >> +( x3::omit[+x3::blank] >> x3::int_ ); BOOST_SPIRIT_DEFINE( my_rule ) const my_rule_type &get_my_rule() { return my_rule; } } #endif
config.hxx:
#ifndef CONFIG_HXX #define CONFIG_HXX #include <string> #include <boost/spirit/home/x3.hpp> namespace parser { namespace x3 = boost::spirit::x3; using iterator_type = std::string::const_iterator; using context_type = x3::unused_type; } #endif
main.cxx:
#include "ast.hxx" #include "grammar.hxx" #include "config.hxx" #include <iostream> #include <boost/spirit/home/x3.hpp> #include <string> namespace x3 = boost::spirit::x3; using namespace std; void parse( const std::string &data ) { parser::iterator_type begin = data.begin(); parser::iterator_type end = data.end(); ast::ast_struct ast; cout << "Parsing [" << string(begin,end) << "]" << endl; bool r = x3::parse( begin, end, parser::get_my_rule(), ast ); if ( r && begin == end ) { std::copy(ast.numbers.begin(), ast.numbers.end(), std::ostream_iterator<int>(std::cout << ast.numbers.size() << " elements: ", " ")); cout << endl; } else cout << "Parse failed" << endl; } int main() { parse( "3 1 2 3" ); parse( "4 1 2 3 4" ); return 0; }
Compiling main.cxx and grammar.cxx (flags: -std = C ++ 14) and running the code above the fingerprints:
Parsing [3 1 2 3] 0 elements: Parsing [4 1 2 3 4] 0 elements:
Sorry for the long source code, I tried to make it as small as possible.
Please note that I have the use of the global variable unsigned n, it will be used with a custom repeat directive (see here and one of the solutions here ). To focus the question, I removed some of the repetition from this question, so although I could remove the semantic action in this example, this is not a possible solution.
I would appreciate help in identifying this problem, it is not clear to me why the above code does not work. Thank you in advance.