2

ご挨拶。

文法を解析して AST を生成するときに、boost::spirit に異なるクラスのノードを強制的に生成させる方法に興味がありました。たとえば、VariableNode (メンバーとして変数の名前を持つ)、ValueNode (メンバーとして値を持つ) などのさまざまなノードが必要です。

ツリーウォーカーを扱うときに非常に便利です。この場合、すべての異なるノードをウォークするための基本抽象クラスを作成し (「ビジター」パターンを適用)、セマンティクス チェック フェーズ、コード生成フェーズなどを処理するときにそれを拡張します。

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 に答える