Impulso :: espíritu y generando diferentes nodos.
-
05-07-2019 - |
Pregunta
saludos.
He estado interesado en cómo forzar boost :: spirit para producir nodos de diferentes clases al analizar la gramática y generar AST. digamos, quiero tener nodos diferentes como VariableNode (que tiene el nombre de la variable como su miembro), ValueNode (que tiene un valor como su miembro), etc.
sería muy útil cuando se trata de un caminante de árboles. en este caso, escribiríamos una clase abstracta de base para recorrer todos los nodos diferentes (aplicando " el patrón de visitante) y lo extenderíamos cuando se tratara de la fase de verificación semántica, la fase de generación de código y demás.
boost :: spirit nos permite parametrizar la fábrica que se usa para los árboles, pero no he podido encontrar una forma adecuada de ajustar su comportamiento.
alguna idea, codigo? gracias de antemano.
Solución
No estoy seguro de entender tu pregunta, ¿te refieres a algo como esto? :
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;
};
Luego puede usar boost :: apply_visitor (consulte la documentación de boost :: variant) con una clase de visitante para realizar el comportamiento que desea.
Otros consejos
Para responder a su comentario (es posible que desee comenzar una nueva pregunta para esto): los identificadores probablemente deberían almacenarse en una clase derivada de qi :: symbols y las palabras clave estarían en sus otras reglas qi ::.
En cuanto a 2) esto sería algo como esto (no probado):
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;
};
Probablemente podría gastar más si lo necesita, pero probablemente debería comenzar una nueva pregunta si tiene problemas específicos para que otras personas también puedan ayudar, ya que solo soy un usuario principiante de boost :: spirit y es posible que tengan mejores respuestas.
Saludos