2017-04-17 3 views
1

La BNF que j'implémente a une drôle de règle où, selon l'opérateur, les termes peuvent être chaînés ou pas à cette règle de production. D'où j'utilise la même structure de données AST puisque seuls les changements d'énumération:boost.spirit x3 move_to et list membre ast

#include <boost/spirit/home/x3.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 

#include <iostream> 
#include <string> 
#include <list> 


namespace ast 
{ 
    struct identifer { 
     int      name; 
    }; 
    struct expression { 
     struct chunk { 
      char    operator_; 
      ast::identifer  identifer; 
     }; 
     ast::identifer   identifer; 
     std::list<chunk>  chunk_list; 
    }; 
} 

BOOST_FUSION_ADAPT_STRUCT(ast::identifer, 
    name 
) 

BOOST_FUSION_ADAPT_STRUCT(ast::expression::chunk, 
    operator_, identifer 
) 

BOOST_FUSION_ADAPT_STRUCT(ast::expression, 
    identifer, chunk_list 
) 


namespace boost { namespace spirit { namespace x3 { namespace traits { 


void move_to(ast::expression::chunk&& chunk, std::list<ast::expression::chunk>& chunk_list, 
     mpl::identity<container_attribute>) 
{ 
    chunk_list.emplace(chunk_list.end(), std::move(chunk)); 
} 

} } } } 


namespace parser 
{ 
    namespace x3 = boost::spirit::x3; 

    auto const identifier = x3::rule<struct _, int> { "identifier" } = 
     x3::int_; 

    auto const operator_1 = x3::rule<struct _, char> { "operator" } = 
     x3::char_("ABC"); 
    auto const operator_2 = x3::rule<struct _, char> { "operator" } = 
     x3::char_("XYZ"); 

    auto const expression_chunk_1 = x3::rule<struct _, ast::expression::chunk> { "expression" } = 
     operator_1 > identifier 
     ; 
    auto const expression_chunk_2 = x3::rule<struct _, ast::expression::chunk> { "expression" } = 
     operator_2 > identifier 
     ; 
    auto const expression = x3::rule<struct _, ast::expression> { "expression" } = 
      identifier >> *expression_chunk_1 // foo { and foo } 
     // rule below fails to compile 
     | identifier >> expression_chunk_2 // foo [ nand foo ] 
     ; 
} 


struct visitor { 
    visitor(std::ostream& os) : os{ os } { } 
    void operator()(ast::expression const& node) { 
     os << "("; 
     (*this)(node.identifer); 
     for(auto const& chunk : node.chunk_list) { 
      os << "(" << chunk.operator_ << " "; 
      (*this)(chunk.identifer); 
      os << ")"; 
     } 
     os << ")\n"; 
    } 
    void operator()(ast::identifer const& node) { 
     os << "(" << node.name << ")"; 
    } 
    std::ostream& os; 
}; 


int main() 
{ 
    namespace x3 = boost::spirit::x3; 

    for(std::string const str: { 
     "1 X 2", 
     "3 A 4 A 5" 
    }) { 
     auto iter = str.begin(), end = str.end(); 

     ast::expression attr; 
     bool r = x3::phrase_parse(iter, end, parser::expression, x3::space, attr); 

     std::cout << "parse '" << str << "': "; 
     if (r && iter == end) { 
     std::cout << "succeeded:\n"; 
     visitor(std::cout)(attr); 

     } else { 
     std::cout << "*** failed ***\n"; 
     } 
    } 

    return 0; 
} 

Ce fut l'idée - l'opérateur X, Y, Z ne fait qu'ajouter un morceau à la liste. Suite aux erreurs du compilateur, je dois spécialiser x3 :: traits :: move_to, mais je n'ai trouvé aucune solution pour compiler ceci. Quel est le wayy à faire? est la liste :: emplace() et std :: move() safe ici?

Répondre

0

Je ferais sans le trait. Au lieu de cela, rendre le résultat de la grammaire dans un vector<T> artificiellement en utilisant repeat:

auto const expression = x3::rule<struct _, ast::expression> { "expression" } = 
     identifier >> *expression_chunk_1 // foo { and foo } 
    | identifier >> x3::repeat(1) [ expression_chunk_2 ] // foo [ nand foo ] 
    ; 
+0

Merci - un moyen pragamtic pour résoudre le problème. Ces solutions sont compilées comme indiqué sur [link] (http://coliru.stacked-crooked.com/a/898343ea7611a40a) mais l'analyse a échoué. Il y a seulement de petits changements (l'identifiant est un caractère maintenant, les règles ont des noms uniques). Il est évident qu'en exécutant ... DEBUG, l'identifiant est consommé et que expression_chunk_1 doit échouer. Une façon (possible) serait d'écrire – Olx

+0

Si vous me dites le résultat attendu pour «1 X 2», vous pouvez poser une question à ce sujet dans une nouvelle question, je pense. J'ai vu que cela ne passerait pas, mais en le regardant, je ne voyais aucune raison pour que cela passe la grammaire. – sehe

+0

un moyen pragmatique de résoudre le problème. Ces solutions sont compilées comme indiqué sur [link] (http://coliru.stacked-crooked.com/a/898343ea7611a40a) mais l'analyse a échoué. Il y a seulement de petits changements (l'identifiant est un caractère maintenant, les règles ont des noms uniques). Il est évident qu'en exécutant ... DEBUG, l'identifiant est consommé et que expression_chunk_1 doit échouer. Une façon (possible) serait d'écrire (identifiant >> * expression_chunk_1) | (identifiant >> x3 :: repeat (1) [expression_chunk_2]) mais ce n'est pas intelligent en raison du retour/déroulement de l'itérateur pour l'identifiant. Suivre le commentaire suivant ... – Olx