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]
où expr
peut être n'importe quoi. proto::shift_right
: correspond à expr1 >> expr2
où expr1
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
^
||
Des choses qui ont une sémantique différente dans Karma:
qi::skip
&
!