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.

¿Fue útil?

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top