boost :: spirit et générer différents nœuds
-
05-07-2019 - |
Question
salutations.
J'ai été intéressant de savoir comment forcer boost :: spirit à produire des nœuds de différentes classes lors de l'analyse syntaxique de la grammaire et de la génération d'AST. disons, je veux avoir différents nœuds tels que VariableNode (qui porte le nom de la variable en tant que membre), ValueNode (qui a la valeur en tant que membre), etc.
cela serait très utile quand on a affaire à un trotteur. dans ce cas, nous écririons une classe abstraite de base pour parcourir tous les différents nœuds (en appliquant le motif "visiteur") et l'étendrions en cas de phase de vérification sémantique, de phase de génération de code, etc.
boost :: spirit nous permet de paramétrer l’usine utilisée pour les arbres, mais j’ai été incapable de trouver un moyen approprié d’ajuster son comportement.
des idées, code? merci d'avance.
La solution
Je ne suis pas sûr de comprendre votre question. Voulez-vous dire quelque chose comme ça? :
typedef boost::variant<VariableNode, ValueNode> AbstractNode;
template <typename Iterator>
struct NodeGrammar: public boost::spirit::qi::grammar<Iterator, AbstractNode(), boost::spirit::ascii::space_type>
{
NodeGrammar: NodeGrammar::base_type(start)
{
start %= variableNode | valueNode >> eps;
variableNode %= /*something*/;
valueNode %= /*something*/;
}
//start
boost::spirit::qi::rule<Iterator, AbstractNode(), boost::spirit::ascii::space_type> start;
boost::spirit::qi::rule<Iterator, VariableNode(), boost::spirit::ascii::space_type> variableNode;
boost::spirit::qi::rule<Iterator, ValueNode(), boost::spirit::ascii::space_type> valueNode;
};
Vous pouvez ensuite utiliser boost :: apply_visitor (voir la documentation de boost :: variant) avec une classe de visiteurs pour obtenir le comportement souhaité.
Autres conseils
Pour répondre à votre commentaire (vous voudrez peut-être poser une nouvelle question à ce sujet): les identifiants devraient probablement être stockés dans une classe dérivée de qi :: symboles et les mots clés figureraient dans vos autres règles qi ::.
En ce qui concerne 2), cela ressemblerait à ceci (non testé):
class ScriptNodes
{
//this will enable fusion_adapt_struct to access your private members
template < typename, int>
friend struct boost::fusion::extension::struct_member;
private:
typdef std::vector<boost::shared_ptr<UserFuncNode> > Nodes
Nodes nodes;
};
//when using fusion_adapt_struct, try to typedef any type that contain a ,
//since it will confuse the macro (ex std::pair<int, int>)
BOOST_FUSION_ADAPT_STRUCT(
ScriptNode,
(ScriptNodes::Nodes, nodes)
)
..
using boost::spirit::qi::grammar;
using boost::spirit::ascii::space_type;
template <typename Iterator>
struct NodeGrammar: public grammar<Iterator, ScriptNodes(), space_type>
{
NodeGrammar: NodeGrammar::base_type(start)
{
using namespace boost::spirit::arg_names;
using boost::spirit::arg_names::_1;
//the %= should automatically store the user_func nodes in start
//for more complex rules you might need to do the push_back manually
//using phoenix::push_back
start %= *user_func >> eps;
//this should parse a double and create a new UserFuncNode with the
//parsed argument and the result will be assigned in the shared_ptr
//variable stored in a user_func
user_func = double_[_val = new UserFuncNode(_1)];
}
using boost::spirit::qi::rule;
using boost::shared_ptr;
//start
rule<Iterator, ScriptNodes(), space_type> start;
rule<Iterator, shared_ptr<UserFuncNode>(), space_type> user_func;
};
Je pourrais probablement en dépenser plus si vous en aviez besoin, mais vous devriez probablement commencer une nouvelle question si vous rencontrez des problèmes spécifiques afin que d'autres personnes puissent aussi vous aider, car je ne suis qu'un utilisateur débutant de boost :: spirit et qu'elles auront peut-être de meilleures réponses.
A bientôt