boost :: spirit и генерация разных узлов - PullRequest
2 голосов
/ 23 октября 2009

привет.

Мне было интересно узнать, как заставить boost :: spirit создавать узлы разных классов при разборе грамматики и генерации AST. скажем, я хочу иметь разные узлы, такие как VariableNode (в качестве члена которого указано имя переменной), ValueNode (в качестве члена которого указано значение) и т. д.

было бы очень полезно при работе с древоходом. в этом случае мы бы написали базовый абстрактный класс для обхода всех различных узлов (применяя шаблон «посетитель») и расширили его при работе с фазой проверки семантики, фазой генерации кода и тому подобным.

boost :: spirit позволяет нам параметризировать фабрику, используемую для деревьев, но я не смог найти правильный способ настроить ее поведение.

есть идеи, код? заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 23 октября 2009

Я не уверен, что понимаю ваш вопрос, вы имеете в виду что-то подобное? :

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

Затем вы можете использовать boost :: apply_visitor (смотрите документацию boost :: option) с классом посетителя, чтобы выполнить желаемое поведение.

1 голос
/ 27 октября 2009

Чтобы ответить на ваш комментарий (возможно, вы захотите начать новый вопрос для этого): идентификаторы, вероятно, должны храниться в классе, производном от qi :: символов, а ключевые слова - в других ваших правилах qi :: rules.

Что касается 2), это будет что-то вроде этого (не проверено):

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

Я мог бы, вероятно, потратить больше, если вам нужно, но вы, вероятно, должны начать новый вопрос, если у вас есть конкретные проблемы, чтобы другие люди тоже могли помочь, так как я только начинающий пользователь boost :: spirit и у них могли бы быть лучшие ответы.

Приветствия

...