potenzia lo spirito – incapace di ottenere attributi

Ho il codice seguente:

#define BOOST_SPIRIT_DEBUG #include  #include  #include  #include  #include  #include  struct parameter { std::string type; std::string name; }; BOOST_FUSION_ADAPT_STRUCT( parameter, (std::string, type) (std::string, name) ) inline std::ostream& operator<<(std::ostream& os, const parameter& param) { os << param.type << ' ' << param.name; return os; } inline std::ostream& operator<<(std::ostream& os, const std::vector& parameters) { for (const auto& param : parameters) { os << param; } return os; } struct function { std::vector parameters; }; BOOST_FUSION_ADAPT_STRUCT( ::function, (std::vector, parameters) ) template  struct function_parser : boost::spirit::qi::grammar { function_parser() : function_parser::base_type(start) { using boost::spirit::qi::alnum; using boost::spirit::qi::alpha; string %= alpha >> *alnum; BOOST_SPIRIT_DEBUG_NODE(string); param %= string >> string; BOOST_SPIRIT_DEBUG_NODE(param); start %= *(param % ','); BOOST_SPIRIT_DEBUG_NODE(start); } boost::spirit::qi::rule string; boost::spirit::qi::rule param; boost::spirit::qi::rule start; }; int main() { std::string input_data("int bar, int baz"); function fn; auto itr = input_data.begin(); auto end = input_data.end(); function_parser 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"; } } 

Produzione

  int bar, int baz  int bar, int baz  int bar, int baz  bar, int baz [[i, n, t]]   bar, int baz , int baz [[b, a, r]]  , int baz []    int baz  int baz  baz [[i, n, t]]   baz  [[b, a, z]]   []           [[[]]]  Parsing succeeded got: [] 

Perché non ci sono parametri elencati dopo il messaggio “got:” durante l’analisi riuscita? Che cosa sto facendo di sbagliato?

Tre problemi:

  1. Ti mancano le parentesi qui:

     boost::spirit::qi::rule param; ^^ 

    Sono d’accordo che fa schifo che non sia apparentemente facile migliorare la diagnostica per gli argomenti del template “vaganti”. Tuttavia, questo è qualcosa a cui ci si abituerà abbastanza rapidamente, poiché è idiomatico per qualsiasi definizione di grammatica / regola.

  2. La struttura della funzione contiene solo un elemento e ci sono limitazioni che “interrompono” l’astrazione con tuple a elemento singolo. Questo è un / molto ben noto / problema, e dovrebbe essere sollevato in Spirit V3. Per ora, salta la struttura:

     using function = std::vector; 

    o utilizzare la soluzione “canonica”:

     start %= eps >> (params % ','); 
  3. La tua regola di partenza ha una stella kleen spuria. Se si desidera consentire gli elenchi dei parametri vu, fare

     start %= eps >> -(params % ','); 

    Sottilmente diverso (permettendo più consecutivi,:

     start %= eps >> (-params % ','); 
  4. Elemento rimanente di stile: %= è ridondante su regole senza azioni semantiche

Guardalo dal vivo su Coliru

Produzione:

  int bar, int baz   [[[i, n, t], [b, a, z]]]   [[[[[i, n, t], [b, a, r]], [[i, n, t], [b, a, z]]]]]  Parsing succeeded got: [int bar; int baz; ] 

Codice completo

 #define BOOST_SPIRIT_DEBUG #include  #include  #include  #include  #include  #include  struct parameter { std::string type; std::string name; }; BOOST_FUSION_ADAPT_STRUCT( parameter, (std::string, type) (std::string, name) ) inline std::ostream& operator<<(std::ostream& os, const parameter& param) { return os << param.type << ' ' << param.name; } inline std::ostream& operator<<(std::ostream& os, const std::vector& parameters) { for (const auto& param : parameters) { os << param << "; "; } return os; } struct function { std::vector parameters; }; BOOST_FUSION_ADAPT_STRUCT( ::function, (std::vector, parameters) ) template  struct function_parser : boost::spirit::qi::grammar { function_parser() : function_parser::base_type(start) { using boost::spirit::qi::alnum; using boost::spirit::qi::alpha; string %= alpha >> *alnum; BOOST_SPIRIT_DEBUG_NODE(string); param %= string >> string; BOOST_SPIRIT_DEBUG_NODE(param); start = boost::spirit::qi::eps >> (param % ','); BOOST_SPIRIT_DEBUG_NODE(start); } boost::spirit::qi::rule string; boost::spirit::qi::rule param; boost::spirit::qi::rule start; }; int main() { std::string input_data("int bar, int baz"); function fn; auto itr = input_data.begin(); auto end = input_data.end(); function_parser 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; //std::cout << "got: " << fn << std::endl; } else { std::cout << "Parsing failed \n"; } }