2

问候。

我对如何强制 boost::spirit 在解析语法和生成 AST 时生成不同类的节点很感兴趣。比如说,我想要不同的节点,例如 VariableNode(其成员为变量的名称)、ValueNode(其成员为 value)等。

在处理 tree-walker 时会非常有用。在这种情况下,我们将编写一个基本抽象类来遍历所有不同的节点(应用“访问者”模式),并在处理语义检查阶段、代码生成阶段等时对其进行扩展。

boost::spirit 允许我们参数化用于树的工厂,但我一直无法找到合适的方法来调整其行为。

任何想法,代码?提前致谢。

4

2 回答 2

3

我不确定我是否理解你的问题,你的意思是这样的吗?:

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::variant 文档)与访问者类一起使用来执行您想要的行为。

于 2009-10-23T19:23:05.063 回答
1

要回答您的评论(您可能想为此提出一个新问题):标识符可能应该存储在 qi::symbols 派生类中,而关键字应该在您的其他 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 的初学者,他们可能有更好的答案。

干杯

于 2009-10-26T21:27:33.667 回答