Est-il possible de réutiliser une grammaire Spirit Qi en tant que grammaire Spirit Karma?

J’ai une définition de la grammaire Qi que j’utilise pour parsingr une entrée. Plus tard, j’ai un générateur de Karma pour produire une sortie qui devrait être similaire à l’entrée.

Est-ce possible? Il semble qu’une syntaxe de syntaxe syntaxique puisse être transformée automatiquement en une grammaire générasortingce (??).

#include  #include  #include  #include  int main(){ //test input std::ssortingng s = "Xx 1.233 pseudo"; //input variables std::ssortingng element; double mass; std::ssortingng pseudo; auto GRAMMAR = boost::spirit::qi::lexeme[+(boost::spirit::qi::char_ - ' ' - '\n')] >> boost::spirit::qi::double_ >> boost::spirit::qi::lexeme[+(boost::spirit::qi::char_ - ' ' - '\n')]; bool r = boost::spirit::qi::phrase_parse( s.begin(), s.end(), GRAMMAR, boost::spirit::qi::space, element, mass, pseudo ); std::cout << boost::spirit::karma::format( GRAMMAR ??? is it possible? , element, mass, pseudo ); } 

Malheureusement, il est impossible de réaliser ce que vous voulez de manière générale (ou du moins je ne sais pas comment), mais si vous êtes prêt à utiliser un sous-ensemble limité de Spirit.Qi, l’approche ci-dessous pourrait fonctionner.

La première chose à savoir est que lorsque vous utilisez quelque chose comme:

 int_ >> double_ 

Vous venez d’avoir une expression Boost.Proto qui décrit plusieurs terminaux et leur relation. Cette expression en soi ne “sait” rien sur la façon d’parsingr un int et ensuite un double. Chaque fois que vous utilisez parse / phrase_parse ou assignez l’une de ces expressions Proto à une rule Spirit “comstack” cette expression pour un domaine (Qi ou Karma) et crée les parsingurs / générateurs qui effectuent le travail réel.

Ici vous pouvez voir un petit exemple montrant les types exacts d’expressions Proto et Qi compilées:

 Raw proto type: boost::proto::exprns_::expr const&, boost::spirit::terminal const&>, 2l> "Pretty" proto type: shift_right( terminal(boost::spirit::tag::int_) , terminal(boost::spirit::tag::double_) ) Comstackd Qi type: boost::spirit::qi::sequence, boost::fusion::cons >, boost::fusion::nil_> > > 

Tant que vous avez access à l’expression d’origine, vous pouvez utiliser les transformations / grammaires Proto pour la convertir en une expression Karma appropriée.

Dans l’exemple ci-dessous, j’ai utilisé les transformations suivantes:

 Qi |Karma |Reason ------------|---------------|------ lexeme[expr]|verbatim[expr] | lexeme does not exist in Karma omit[expr] |no_delimit[eps]| omit consumes an atsortingbute in Karma a >> b |a << b | a > b |a << b | < does not exist in Karma a - b |a | - does not exist in Karma 

Afin de réaliser ces transformations, vous pouvez utiliser boost::proto::or_ obtenir quelque chose de similaire à:

 struct Grammar : proto::or_< proto::when, proto::when, Matcher3, Matcher4 >{}; 

Je vais essayer d'expliquer comment cela fonctionne.
MatcherN dans l'exemple ci-dessous peut être:

  • proto::terminal : correspond uniquement à ce terminal spécifique.
  • proto::terminal : correspond à tout terminal non spécifiquement identifié auparavant.
  • proto::subscript,proto::_> : correspond à omit[expr]expr peut être n'importe quoi.
  • proto::shift_right : correspond à expr1 >> expr2expr1 et expr2 doivent se conformer récursivement à la grammaire de ToKarma .
  • proto::nary_expr > : correspond à n'importe quel n-aire (unaire, binary ou réellement n-aire comme un appel de fonction a(b,c,d,e) ) où chacun l'un des éléments de l'expression est conforme à la grammaire ToKarma.

Tous les TransformN dans cet exemple sont des générateurs d’expression, voici quelques explications:

  • _make_terminal(boost::spirit::tag::lexeme()) : construit un proto::terminal (notez qu'il est nécessaire d'append () après le tag, vous ' Vous obtiendrez une terrible erreur si vous les oubliez).
  • _make_subscript(_make_terminal(tag::no_delimit()), _make_terminal(tag::eps())) : construit un proto::subscript, proto::terminal > no_delimit[eps] , ou l'équivalent de no_delimit[eps] .
  • _make_shift_left(ToKarma(proto::_left), ToKarma(proto::_right)) : proto::_left signifie de prendre les lhs de l'expression d'origine. ToKarma(proto::_left) signifie appliquer récursivement la grammaire / transformation de ToKarma aux lhs de l'expression d'origine. L'ensemble _make_shift_left construit fondamentalement transformed_lhs << transformed_rhs .

Un MatcherN par lui-même (pas dans proto::when ) est un raccourci pour construire une expression du même type en utilisant comme éléments le résultat de l'application récursive de la transformation aux éléments d'origine.


Échantillon complet (fonctionnement sur WandBox)

 #include  #include  #include  #include  #include  #include  #include  namespace proto= boost::proto; struct ToKarma: proto::or_< //translation of directives proto::when, proto::_make_terminal(boost::spirit::tag::verbatim())>, //lexeme -> verbatim proto::when< proto::subscript,proto::_>, //omit[expr] -> no_delimit[eps] proto::_make_subscript(proto::_make_terminal(boost::spirit::tag::no_delimit()),proto::_make_terminal(boost::spirit::tag::eps())) >, proto::terminal, //if the expression is any other terminal leave it as is //translation of operators proto::when, proto::_make_shift_left(ToKarma(proto::_left),ToKarma(proto::_right)) >, //changes '>>' into '<<' proto::when, proto::_make_shift_left(ToKarma(proto::_left),ToKarma(proto::_right)) >, //changes '>' into '<<' proto::when, ToKarma(proto::_left)>, //changes 'expr-whatever' into 'expr' proto::nary_expr > //if it's anything else leave it unchanged and recurse into the expression tree >{}; template  void test(const std::ssortingng& input, const Parser& parser) { std::cout << "Original: \"" << input << "\"\n"; std::tuple attr; std::ssortingng::const_iterator iter = input.begin(), end = input.end(); bool result = boost::spirit::qi::phrase_parse(iter,end,parser,boost::spirit::qi::space,attr); if(result && iter==end) { ToKarma to_karma; std::cout << "Generated: \"" << boost::spirit::karma::format_delimited(to_karma(parser), boost::spirit::karma::space, attr) << '"' << std::endl; } else { std::cout << "Parsing failed. Unparsed: ->" << std::string(iter,end) << "<-" << std::endl; } } int main(){ using namespace boost::spirit::qi; test("Xx 1.233 pseudo", lexeme[+(char_-' '-'\n')] >> double_ >> lexeme[+(char_-' '-'\n')]); test("foo 1 2.5", omit[lexeme[+alpha]] > int_ > double_); } 

PS:
Choses qui ne fonctionneront certainement pas:

  • qi::rule
  • qi::grammar
  • qi::symbols

Des choses qui n'existent pas dans le karma:

  • qi::attr
  • qi::matches
  • qi::hold
  • Analyseur de permutation ^
  • Séquentiel ou parsingur ||

Des choses qui ont une sémantique différente dans Karma:

  • qi::skip
  • Et parsingur de prédicats &
  • Analyseur non-prédicat !