次のようなツリー式のような C 関数を解析しようとしています ( Spirit Parser Frameworkを使用):
F( A() , B( GREAT( SOME , NOT ) ) , C( YES ) )
このために、次の文法で 3 つの規則を使用しようとしています。
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), space_type> {
InputGrammar() : InputGrammar::base_type( ) {
tag = ( qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9") )[ push_back( at_c<0>(qi::_val) , qi::_1 ) ];
command = tag [ at_c<0>(qi::_val) = at_c<0>(qi::_1) ] >> "(" >> (*instruction >> ",")
[ push_back( at_c<1>(qi::_val) , qi::_1 ) ] >> ")";
instruction = ( command | tag ) [qi::_val = qi::_1];
}
qi::rule< Iterator , ExpressionAST() , space_type > tag;
qi::rule< Iterator , ExpressionAST() , space_type > command;
qi::rule< Iterator , ExpressionAST() , space_type > instruction;
};
このタグ ルールは、式で使用される識別子 (「関数」名) を取得しようとするだけであることに注意してください。また、ほとんどの例のように、タグ ルールの署名がExpressionAST
ではなく を返すことにも注意してください。std::string
このようにしたい理由は、実際には非常に単純です。バリアントを使用するのが嫌いで、可能であれば使用しないようにします。ケーキを持っておいて、それを食べるのもいいと思います。
コマンドは、タグ (現在のノードの名前、AST ノードの最初の文字列フィールド) と括弧で囲まれた可変数の引数で開始する必要があり、各引数はタグ自体または別のコマンドにすることができます。
ただし、この例はまったく機能しません。それはすべてコンパイルされますが、実行時にすべてのテスト文字列の解析に失敗します。そして、私を本当に悩ませているのは、少なくとも単語の伝統的な意味では、上記のコードを実際にデバッグできないため、修正方法がわからないことです。基本的に、上記のコードを修正できる唯一の方法は、自分が間違っていることを知ることです。
したがって、問題は、上記のコードの何が問題なのかわからないということです。上記の文法をどのように定義しますか?
ExpressionAST
私が使用しているタイプは次のとおりです。
struct MockExpressionNode {
std::string name;
std::vector< MockExpressionNode > operands;
typedef std::vector< MockExpressionNode >::iterator iterator;
typedef std::vector< MockExpressionNode >::const_iterator const_iterator;
iterator begin() { return operands.begin(); }
const_iterator begin() const { return operands.begin(); }
iterator end() { return operands.end(); }
const_iterator end() const { return operands.end(); }
bool is_leaf() const {
return ( operands.begin() == operands.end() );
}
};
BOOST_FUSION_ADAPT_STRUCT(
MockExpressionNode,
(std::string, name)
(std::vector<MockExpressionNode>, operands)
)