boost::spirit 并生成不同的节点

发布于 2024-08-08 05:12:20 字数 301 浏览 3 评论 0原文

问候。

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

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

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

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

greetings.

i've been interesting in how to force boost::spirit to produce nodes of different classes when parsing the grammar and generating AST. say, i want to have different nodes such as VariableNode (which has name of variable as its member), ValueNode (which has value as its member), etc.

it would be very useful when dealing with tree-walker. in this case we would write a base abstract class for walking all the different nodes (applying "the visitor" pattern) and extend it when dealing with semantics checking phase, code generation phase and the such.

boost::spirit allows us to parameterize factory being used for trees, but i've been unable to find a proper way to tune its behavior.

any ideas, code? thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

瀞厅☆埖开 2024-08-15 05:12:20

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

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

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

You can then use boost::apply_visitor (see boost::variant documentation) with a visitor class to do the behavior you want.

岁吢 2024-08-15 05:12:20

要回答您的评论(您可能想为此开始一个新问题):标识符可能应该存储在 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 的初学者用户可能会有更好的答案。

干杯

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

As for 2) this 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 probably expend more if you need but you should probably start a new question if you got specific issues so other people can help too as I'm just a beginner user of boost::spirit and they might have better answers.

Cheers

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文