2

変更できないオブジェクトのツリー用のスピリットパーサーを作成したいと思います。コードを単純化するために、式の例を使用できます。

class Expr
{
public:
    virtual ~Expr() = 0;
};
Expr::~Expr() {}

class Plus : public Expr
{
public:
    Plus (Expr* e1, Expr* e2) : _e1(e1), _e2(e2) {}
    ~Plus () {}
private:
    Expr* _e1;
    Expr* _e2;
};

class Num : public Expr
{
public:
    Num(double n) : _n(n) {}
private:
    double _n;
};

ドキュメントを確認したところ、便利なBOOST_ADAPT_STRUCTが見つかりましたが、次のように宣言されたルールを使用しています。

qi::rule<Iterator, Expr()> r;

ルールがたとえばPlusオブジェクトを返すときに、オブジェクトをスライスします。だから私はこのように試します:

template <typename Iterator>
struct ExprParser : qi::grammar<Iterator, Expr*(), ascii::space_type>
{

    ExprParser()
      : ExprParser::base_type (start, "expr")
    {
        expr = qi::double_    [ qi::_val = phoenix::new_<Num>(::_1) ]
                | '('
                    >> expr
                    >> '+'
                    >> expr
                  >> ')'      [ qi::_val = phoenix::new_<Plus>(::_1, ::_2) ]
                ;

        start %= expr;
    }

    qi::rule<Iterator, Expr*(), ascii::space_type> expr;
    qi::rule<Iterator, Expr*(), ascii::space_type> start;
};

しかし、セマンティックアクション内の割り当てでコンパイルエラーが発生します。私は何が間違っているのですか?

編集

seheの答えは良いです!括弧の欠落とプレースホルダーの誤った使用があります。しかし、解析エラーが発生したときのメモリリークはどうでしょうか?

4

1 に答える 1

4

ドキュメントに記載されているように

[重要]の下で、Phoenixでqiプレースホルダーを使用する必要があります。修正されたコードをテストしました。あなたはそれをhttp://liveworkspace.org/code/48dbfb55a0b7cbd4783b2f9f9a66d6d1でライブで見ることができます。

2番目のセマンティックアクションをコンパイルするには、追加の括弧が必要であることに注意してください。

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

class Expr
{
    public:
        virtual ~Expr() = 0;
};
Expr::~Expr() {}

class Plus : public Expr
{
    public:
        Plus (Expr* e1, Expr* e2) : _e1(e1), _e2(e2) {}
        ~Plus () {}
    private:
        Expr* _e1;
        Expr* _e2;
};

class Num : public Expr
{
    public:
        Num(double n) : _n(n) {}
    private:
        double _n;
};

template <typename Iterator>
struct ExprParser : qi::grammar<Iterator, Expr*(), ascii::space_type>
{

    ExprParser()
      : ExprParser::base_type (start, "expr")
    {
        expr = qi::double_     [ qi::_val = phoenix::new_<Num>(qi::_1) ]
                | ('('
                    >> expr
                    >> '+'
                    >> expr
                  >> ')')      [ qi::_val = phoenix::new_<Plus>(qi::_1, qi::_2) ]
                ;

        start %= expr;
    }

    qi::rule<Iterator, Expr*(), ascii::space_type> expr;
    qi::rule<Iterator, Expr*(), ascii::space_type> start;
};

int main(int argc, const char *argv[])
{
    char input[] = "3.14 + 39";
    ExprParser<const char*> p;

    const char *f = std::begin(input);
    const char *l = std::end(input);
    qi::phrase_parse(f, l, p, ascii::space);
}
于 2012-09-13T17:35:20.697 に答える