boost :: spiritおよび異なるノードの生成
-
05-07-2019 - |
質問
挨拶。
私は、文法を解析してASTを生成するときに、boost :: spiritに異なるクラスのノードを生成させる方法に興味を持っています。たとえば、VariableNode(変数名をメンバーとする)、ValueNode(値をメンバーとする)などのさまざまなノードが必要です。
ツリーウォーカーを扱うときに非常に便利です。この場合、すべての異なるノード(「ビジター」パターンを適用)を歩くための基本抽象クラスを記述し、セマンティクスチェックフェーズ、コード生成フェーズなどを扱うときにそれを拡張します。
boost :: 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;
};
その後、ユーザークラスでboost :: apply_visitor(boost :: variantドキュメントを参照)を使用して、目的の動作を実行できます。
他のヒント
コメントに答えるには(これについて新しい質問を始めたいかもしれません):識別子はおそらく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の初心者ユーザーであり、より良い答えがあるかもしれません。
乾杯
所属していません StackOverflow