2017-07-09 7 views
1

J'essaye d'analyser un fichier et d'avoir les données copiées dans un vecteur dans un objet de classe. J'ai pris l'exemple de l'employé et l'ai modifié pour ce que j'essaie de faire. Le fichier en cours d'analyse ressemble à ceci (mais plus de lignes) ...spirit x3 comment ajouter un vecteur à un AST

1 0.2 0.3 0.4 

J'ai ajouté un vecteur à l'employé struct et je reçois échecs d'assertion sur la ligne de phrase_parse. Je pense en quelque sorte que la taille attendue a quelque chose à voir avec le vecteur. Des pensées sur où je vais mal?

namespace client { 
    namespace ast { 

    struct employee 
    { 
     int id; 
     std::vector<double> coords; 
    }; 

    using boost::fusion::operator<<; 
}} 

BOOST_FUSION_ADAPT_STRUCT(
    client::ast::employee, 
    (int, id) 
    (std::vector<double>, coords) 
) 

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

     using x3::int_; 
     using x3::double_; 

     x3::rule<class employee, ast::employee> const employee = "employee"; 
     auto const employee_def = 
      int_ >> double_ >> double_ >> double_; 
     BOOST_SPIRIT_DEFINE(employee) 
    } 
} 

int main() 
{ 
    using boost::spirit::x3::ascii::space; 
    using client::parser::employee; 

    string fil("test-file.in"); 

    mapped_file_source map(fil); 
    istringstream iss(map.data()); 
    map.close(); 

    client::ast::employee emp; 

    boost::spirit::istream_iterator iter(iss >> noskipws), eof; 

    phrase_parse(iter, eof, employee, space, emp); 
    // failure on above line 
} 
+0

"en utilisant" 'opérateur <<' ne a rien là. Pourquoi diable copier un fichier mapping dans un flux de chaîne? Pourquoi votre code est-il cassé et non autonome? – sehe

Répondre

1

Selon la documentation, double_ >> double_ >> double_ synthétise une séquence Fusion double, double, double (si fusion::tuple<double, double, double> ou fusion::list<double, double, double> etc).

Vous voulez un vecteur, vous avez donc besoin d'un analyseur répétition (opérateur)

  • la directive de répétition fera repeat(3) [double_]
  • l'étoile Kleene (operator *) ou plus (operator +) sont intéressantes (mais sans bornes)
  • l'opérateur de liste (operator %) est sans bornes, mais accepte délimiteurs (par exemple double_ % ','

Dans ce cas, je vais dans l'autre sens: utiliser un AST bon pour la grammaire:

Live On Coliru

struct coord { 
    double x,y,z; 
}; 

struct employee 
{ 
    int id; 
    coord coords; 
}; 

les adapter est plus simple que l'ancienne méthode que vous avez utilisé façonné:

BOOST_FUSION_ADAPT_STRUCT(client::ast::coord, x, y, z) 
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, id, coords) 

L'analyseur est un

propre
auto const coord_def = double_ >> double_ >> double_; 
auto const employee_def = int_ >> coord; 

démo complète:

Live On Coliru

#include <boost/spirit/home/x3.hpp> 
#include <boost/spirit/include/support_istream_iterator.hpp> 
#include <boost/fusion/adapted/struct.hpp> 
#include <iostream> 

namespace client { 
    namespace ast { 

    struct coord { 
     double x,y,z; 
    }; 

    struct employee 
    { 
     int id; 
     coord coords; 
    }; 

    using boost::fusion::operator<<; 
}} 

BOOST_FUSION_ADAPT_STRUCT(client::ast::coord, x, y, z) 
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, id, coords) 

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

     using x3::int_; 
     using x3::double_; 

     x3::rule<class employee, ast::coord> const coord = "coord"; 
     x3::rule<class employee, ast::employee> const employee = "employee"; 

     auto const coord_def = double_ >> double_ >> double_; 
     auto const employee_def = int_ >> coord; 

     BOOST_SPIRIT_DEFINE(employee, coord); 
    } 
} 

int main() 
{ 
    using boost::spirit::x3::ascii::space; 
    using client::parser::employee; 

    std::istringstream iss("1 0.2 0.3 0.4"); 

    client::ast::employee emp; 

    boost::spirit::istream_iterator iter(iss >> std::noskipws), eof; 

    bool ok = phrase_parse(iter, eof, employee, space, emp); 
    if (ok) 
     std::cout << "parsed: " 
      << emp.id  << " " 
      << emp.coords.x << " " 
      << emp.coords.y << " " 
      << emp.coords.z << "\n"; 
} 
+0

Que faut-il pour analyser plusieurs lignes de données? J'ai ajouté une autre ligne de 2 2.2 3.3 4.4 à iss et elle ne fait que analyser une ligne. – Ender

+0

Avez-vous lu la documentation? Ma réponse indique exactement les choses nécessaires. Voir https://stackoverflow.com/questions/17072987/boost-spirit-skipper-issues/17073965#17073965 pour des informations générales sur les skippers en relation avec les nouvelles lignes. Assurez-vous d'analyser un type différent, car 'employee' _ [sic] _ ne peut évidemment stocker qu'une ligne – sehe

+0

Ok, alors. Merci pour l'aide. Je vais continuer à essayer. – Ender