Domanda

saluti.

Sono stato interessante su come forzare boost :: spirit a produrre nodi di classi diverse durante l'analisi della grammatica e la generazione di AST. ad esempio, voglio avere nodi diversi come VariableNode (che ha il nome della variabile come membro), ValueNode (che ha valore come membro), ecc.

sarebbe molto utile quando si tratta di tree-walker. in questo caso dovremmo scrivere una classe astratta di base per camminare su tutti i diversi nodi (applicando il modello "visitatore") e estenderlo quando si ha a che fare con la fase di controllo della semantica, la fase di generazione del codice e così via.

boost :: spirit ci consente di parametrizzare la fabbrica utilizzata per gli alberi, ma non sono stato in grado di trovare un modo corretto per ottimizzare il suo comportamento.

qualche idea, codice? grazie in anticipo.

È stato utile?

Soluzione

Non sono sicuro di aver capito la tua domanda, vuoi dire qualcosa del genere? :

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;
};

È quindi possibile utilizzare boost :: apply_visitor (consultare la documentazione di boost :: variant) con una classe visitatore per eseguire il comportamento desiderato.

Altri suggerimenti

Per rispondere al tuo commento (potresti voler iniziare una nuova domanda per questo): gli identificatori dovrebbero probabilmente essere memorizzati in una classe derivata da qi :: simboli e le parole chiave sarebbero nelle altre tue qi :: regole.

Per quanto riguarda 2) questo sarebbe qualcosa del genere (non testato):

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;
};

Probabilmente potrei spendere di più se ne hai bisogno, ma probabilmente dovresti iniziare una nuova domanda se hai problemi specifici in modo che anche altre persone possano aiutare poiché sono solo un utente principiante di boost :: spirit e potrebbero avere risposte migliori.

Saluti

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top