Boost :: spirit and creating different nodes

greetings.

I was wondering how to get boost :: spirit to create nodes of different classes when parsing grammar and creating AST. let's say I want to have different nodes such as VariableNode (which has a variable name as its member), ValueNode (which has a value as its member), etc.

it would be very helpful to deal with a trainer. in this case, we will write a base abstract class to walk through all the different nodes (using the visitor pattern) and extend it when working with a semantics check phase, code generation phase, and so on.

boost :: spirit allows us to parameterize the factory used for trees, but I couldn't find the right way to tweak its behavior.

any ideas code? thanks in advance.

+2


source to share


2 answers


I'm not sure I understand your question, do you mean something like this?

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

      



Then you can use boost :: apply_visitor (see boost :: variant documentation) with the visitor class to accomplish the desired behavior.

+3


source


To answer your comment (you might want to start a new question for this): identifiers should probably be stored in the qi :: symbol-derived class, and the keywords will be in your other qi :: rules.

As for 2) it would be something like this (not tested):

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

      

I could spend more if you need to, but you should probably start a new question if you run into specific problems, so other people can help as well as I'm just a novice boost :: spirit user and they might have the best answers.

Greetings

+1


source







All Articles