C++ spirit和生成不同的节点

C++ spirit和生成不同的节点,c++,boost-spirit,C++,Boost Spirit,你好 我一直对如何在解析语法和生成AST时强制boost::spirit生成不同类的节点感兴趣。比如说,我想要有不同的节点,比如VariableNode(它的成员是变量的名称)、ValueNode(它的成员是value)等等 这将是非常有用的,当处理树行者。在本例中,我们将编写一个基本抽象类,用于遍历所有不同的节点(应用“访问者”模式),并在处理语义检查阶段、代码生成阶段等时对其进行扩展 spirit允许我们对用于树的工厂进行参数化,但我一直无法找到调整其行为的正确方法 有什么想法吗,代码?提前

你好

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

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

spirit允许我们对用于树的工厂进行参数化,但我一直无法找到调整其行为的正确方法


有什么想法吗,代码?提前谢谢。

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

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;
};
typedef boost::variant AbstractNode;
模板
struct NodeGrammar:public boost::spirit::qi::grammar
{
NodeGrammar:NodeGrammar::基本类型(开始)
{
开始%=可变节点|值节点>>eps;
变量节点%=/*某物*/;
valueNode%=/*某物*/;
}
//开始
提升::精神::气::规则开始;
boost::spirit::qi::rule variableNode;
boost::spirit::qi::rule valueNode;
};
然后,您可以将boost::apply_visitor(请参阅boost::variant文档)与visitor类一起使用,以实现所需的行为。

回答您的评论(您可能需要为此开始一个新问题):标识符可能应存储在qi::symbols派生类中,关键字将位于其他qi::规则中

对于2)这将是这样的(未测试):

类脚本节点
{
//这将使fusion_adapt_struct能够访问您的私有成员
模板
friend struct boost::fusion::extension::struct_成员;
私人:
typdef std::向量节点
节点;
};
//使用fusion_adapt_struct时,尝试键入包含,
//因为它会混淆宏(例如std::pair)
增强融合适应结构(
脚本节点,
(ScriptNodes::节点,节点)
)

使用boost::spirit::qi::grammar;
使用boost::spirit::ascii::space\u type;
模板
struct NodeGrammar:公共语法
{
NodeGrammar:NodeGrammar::基本类型(开始)
{
使用名称空间boost::spirit::arg_名称;
使用boost::spirit::arg_名称::_1;
//%=应该自动将用户_func节点存储在start中
//对于更复杂的规则,您可能需要手动执行推回操作
//使用phoenix::推回
开始%=*用户功能>>eps;
//这将解析一个double并创建一个新的UserFuncNode,其中
//已解析的参数和结果将分配到共享的\u ptr中
//存储在用户函数中的变量
user_func=double_[_val=new UserFuncNode(_1)];
}
使用boost::spirit::qi::rule;
使用boost::shared\u ptr;
//开始
规则启动;
规则用户函数;
};
如果您需要,我可能会花费更多,但如果您有具体问题,您可能应该开始一个新问题,这样其他人也可以提供帮助,因为我只是boost::spirit的初学者,他们可能会有更好的答案


干杯,谢谢。是的,你答对了我的问题。嗯,我需要时间看看spirit 2.x版本和boost::variant docs。请保持联系。很高兴能提供帮助。这是spirit 2.x最新文档的链接,不知道您是否能够获得它,但我发现很难找到,boost网站上的文档不是我上次查看的最新文档:。boost::apply_访问者应该相对容易使用,如果您查看示例,但是如果您需要帮助,请毫不犹豫地告诉我。干杯。所有这些精神振奋的东西对我来说都是全新的。我有使用旧的boost指令(gen_pt_node_d、gen_AST_node_d等)生成AST的旧boost-spirit经典语法。现在是我使用boost::spirit::qi重写这段代码的时候了。我发现,只要在语法中对AST进行描述(借助boost::fusion),就可以快速生成AST。现在我面临几个问题:1)如何区分boost-spirit-2中的“标识符”和“关键字”?2) 假设我们有一个类,比如说ScriptNode,它将std::vector作为其私有成员。有了这些,如何创建ScriptNode的实例,正在解析一个合适的规则:script\u start=*user\u func>>eps?谢谢你的评论!谢谢你的回答。好的,我已经为我的关于关键字/标识问题的问题启动了另一个线程。
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;
};