J’utilise Spirit Qi comme parsingur syntaxique pour parsingr les expressions mathématiques dans un arbre d’expression. Je garde trace de choses telles que les types de symboles rencontrés lors de l’parsing, et qui doivent être déclarés dans le texte que j’parsing. En particulier, je suis en train d’parsingr les fichiers d’entrée Bertini , un exemple assez simple est ici , un exemple compliqué est ici , et par souci d’exhaustivité, comme ci-dessous:
%input: our first input file variable_group x,y; function f,g; f = x^2 - 1; g = y^2 - 4; END;
La grammaire sur laquelle j’ai travaillé sera idéalement
variable_group x, y;
f = x^2 - 1;
Cette partie que j’ai surtout sous contrôle. =
et parsingz-le comme une sous-fonction. Je pense que je peux gérer cela aussi. Le problème que je me suis efforcé de résoudre semble être si sortingvial. Pourtant, après des heures de recherche, je n’y suis toujours pas arrivé. J’ai lu des douzaines de publications sur la liste de diffusion de Boost Spirit, des publications de SO, le manuel et les en-têtes de Spirit eux-mêmes, mais je ne comprends toujours pas certaines choses critiques à propos de l’parsing syntaxique de Spirit Qi.
Voici la définition problématique de la grammaire de base, qui irait dans system_parser.hpp
:
#define BOOST_SPIRIT_USE_PHOENIX_V3 1 #include #include #include #include #include #include namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; template struct SystemParser : qi::grammar<Iterator, std::vector(), boost::spirit::ascii::space_type> { SystemParser() : SystemParser::base_type(variable_group_) { namespace phx = boost::phoenix; using qi::_1; using qi::_val; using qi::eps; using qi::lit; qi::symbols encountered_variables; qi::symbols declarative_symbols; declarative_symbols.add("variable_group",0); // wraps the vector between its appropriate declaration and line termination. BOOST_SPIRIT_DEBUG_NODE(variable_group_); debug(variable_group_); variable_group_.name("variable_group_"); variable_group_ %= lit("variable_group") >> genericvargp_ >> lit(';'); // creates a vector of ssortingngs BOOST_SPIRIT_DEBUG_NODE(genericvargp_); debug(genericvargp_); genericvargp_.name("genericvargp_"); genericvargp_ %= new_variable_ % ','; // will in the future make a shared pointer to an object using the ssortingng BOOST_SPIRIT_DEBUG_NODE(new_variable_); debug(new_variable_); new_variable_.name("new_variable_"); new_variable_ %= unencountered_symbol_; // this rule gets a ssortingng. BOOST_SPIRIT_DEBUG_NODE(unencountered_symbol_); debug(unencountered_symbol_); unencountered_symbol_.name("unencountered_symbol"); unencountered_symbol_ %= valid_variable_name_ - ( encountered_variables | declarative_symbols); // get a ssortingng which fits the naming rules. BOOST_SPIRIT_DEBUG_NODE(valid_variable_name_); valid_variable_name_.name("valid_variable_name_"); valid_variable_name_ %= +qi::alpha >> *(qi::alnum | qi::char_('_') | qi::char_('[') | qi::char_(']') ); } // rule declarations. these are member variables for the parser. qi::rule<Iterator, std::vector(), ascii::space_type > variable_group_; qi::rule<Iterator, std::vector(), ascii::space_type > genericvargp_; qi::rule new_variable_; qi::rule unencountered_symbol_;// , ascii::space_type // the rule which determines valid variable names qi::rule valid_variable_name_; };
et du code qui l’utilise:
#include "system_parsing.hpp" int main(int argc, char** argv) { std::vector V; std::ssortingng str = "variable_group x, y, z;"; std::ssortingng::const_iterator iter = str.begin(); std::ssortingng::const_iterator end = str.end(); SystemParser S; bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V); std::cout << "the unparsed string:\n" << std::string(iter,end); return 0; }
Il comstack sous Clang 4.9.x sur OSX parfaitement. Quand je le lance, je reçois:
Assertion failed: (px != 0), function operator->, file /usr/local/include/boost/smart_ptr/shared_ptr.hpp, line 648.
Alternativement, si j’utilise l’opérateur d’attente >
plutôt que >>
dans la définition de la règle variable_group_
, j’obtiens notre cher vieil ami Segmentation fault: 11
.
Dans mon processus d’apprentissage, j’ai rencontré d’excellents articles sur la façon de dire que le type essaie de générer , sur la propagation d’atsortingbuts , sur la façon d’interagir avec des symboles , un exemple de récursion infinie à gauche qui conduit à une erreur de segmentation, des informations sur l’parsing dans classes, pas des structures qui ont un lien vers l’utilisation de points de personnalisation (mais les liens ne contiennent aucun exemple), l’astuce de Nabialek qui associe des mots-clés à des actions, et peut-être la plus pertinente pour ce que j’essaie de faire, l’parsing dynamic des différences est certainement quelque chose dont j’ai besoin étant donné que le nombre de symboles augmente et que, par la suite, leur utilisation en est un autre, les jeux de symboles déjà vus commencent à être vides et s’agrandissent. Les règles d’parsing sont dynamics.
Alors, voici où je suis. Mon problème actuel est l’assert / segfault généré par cet exemple particulier. Cependant, je ne suis pas sûr de certaines choses et j’ai besoin de conseils, que je n’ai tout simplement pas compilés parmi les sources que j’ai consultées, et la demande qui, espérons-le, rend cette question SO disjointe de celle posée précédemment par d’autres personnes:
lexeme
? Je ne sais pas quand utiliser le lexème, et non. >
plutôt que >>
? Tous les conseils utiles pour ce débutant sont les bienvenus.
Vous référencez les variables de symbols
. Mais ce sont des locaux, ils n’existent donc pas une fois que le constructeur est revenu. Cela appelle un comportement indéfini . Tout peut arriver.
Faites les tables de symmbol membres de la classe.
Aussi simplifier la danse autour
lexeme[]
? Dans votre exemple, il vous manquait le lexeme[]
autour des encountered_variables|declarative_symbols
, par exemple. operator%=
, et quelques trucs généralement inutilisés symbols<>
(car l’ int
n’a pas été consommé), l’initialisation y a été simplifiée Live On Coliru
#define BOOST_SPIRIT_USE_PHOENIX_V3 1 #define BOOST_SPIRIT_DEBUG 1 #include #include #include #include #include #include namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; template struct SystemParser : qi::grammar(), Skipper> { SystemParser() : SystemParser::base_type(variable_group_) { declarative_symbols += "variable_group"; variable_group_ = "variable_group" >> genericvargp_ >> ';'; genericvargp_ = new_variable_ % ','; valid_variable_name_ = qi::alpha >> *(qi::alnum | qi::char_("_[]")); unencountered_symbol_ = valid_variable_name_ - (encountered_variables|declarative_symbols); new_variable_ = unencountered_symbol_; BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_)) } private: qi::symbols encountered_variables, declarative_symbols; // rule declarations. these are member variables for the parser. qi::rule(), Skipper> variable_group_; qi::rule(), Skipper> genericvargp_; qi::rule new_variable_; qi::rule unencountered_symbol_; // , Skipper // the rule which determines valid variable names qi::rule valid_variable_name_; }; //#include "system_parsing.hpp" int main() { using It = std::ssortingng::const_iterator; std::ssortingng const str = "variable_group x, y, z;"; SystemParser S; It iter = str.begin(), end = str.end(); std::vector V; bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V); if (s) { std::cout << "Parse succeeded: " << V.size() << "\n"; for (auto& s : V) std::cout << " - '" << s << "'\n"; } else std::cout << "Parse failed\n"; if (iter!=end) std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n"; }
Impressions
Parse succeeded: 3 - 'x' - 'y' - 'z'