2

以前に解析した値に基づいてルールを定義したいと思います。つまり、入力文字列の構造はD <double number>orI <integer number>です。最初に読み取った文字が か かどうかをローカルのブール変数に保持しDますI。完全なコードは次のとおりです。

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>

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

template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
    x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
    {
        using namespace qi;
        bool is_int = false;
        start_rule = lit("I")[ref(is_int) = true] | lit("D")[ref(is_int) = false] > digit_rule;
        if(ref(is_int)()) {
            digit_rule = int_[std::cout << "int " << _1 << ".\n"];
        } else {
            digit_rule = double_[std::cout << "double " << _1 << ".\n"];
        }
    }
private:
    qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
    qi::rule<Iterator, std::string(), ascii::space_type> digit_rule;
};

int main()
{
    typedef std::string::const_iterator iter;
    std::string storage("I 5");
    iter it_begin(storage.begin());
    iter it_end(storage.end());
    std::string read_data;
    using boost::spirit::ascii::space;
    x_grammar<iter> g;
    try {
        bool r = qi::phrase_parse(it_begin, it_end, g, space, read_data);
        if(r) {
            std::cout << "Pass!\n";
        } else {
            std::cout << "Fail!\n";
        }
    } catch (const qi::expectation_failure<iter>& x) {
        std::cout << "Fail!\n";
    }
    return 0;
}                                                                                                                                                    

出力は次のとおりですdouble Pass!。ステートメントを認識せifず、解析された数値を出力しません!

: 上記の例を解析する簡単な方法が他にもあることはわかっています。解析する必要がある実際の文字列は非常に複雑に見えますが、この例は私が達成したいことを示しています。一般的な目標は、ローカル変数を使用し、それらの変数に基づいて他のルールを定義することです。

私は 4.6.1 と Boost 1.55 のバージョンを使用しました。

4

1 に答える 1

2
    if(ref(is_int)()) {

ここでは、建設中の状態を評価します。これはどのように機能するかではありません。ルールは常に同じ分岐を取ります。

代わりに、ナビアレックのトリックを見てください: http://boost-spirit.com/home/articles/qi-example/nabialek-trick/

サンプルLive On Coliruに適用された完全な Nabialek Trick は次のとおりです。

  1. std::cout << "int" 怠惰なアクターを作成する必要がありました(少なくともラップするphx::ref(std::cout)phx::val("int")、Phoenix アクターとして)

  2. 属性の伝播 ( ) は、セマンティック アクションがあると無効になるため、まだ使用できませんstd::string()(前の回答を参照)。ただし、Nabialek サブルールから値を伝播できます。

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>

namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;
using boost::phoenix::ref;


template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, ascii::space_type, qi::locals<qi::rule<Iterator, ascii::space_type>*> >
{
public:
    x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
    {
        using namespace qi;

        int_rule = int_   [std::cout << phx::val("int ") << _1 << ".\n"];
        dbl_rule = double_[std::cout << phx::val("double ") << _1 << ".\n"];
        subrules.add
            ("I", &int_rule)
            ("D", &dbl_rule);

        start_rule = subrules[_a = _1] >> lazy(*_a);
    }
private:
    typedef qi::rule<Iterator, ascii::space_type> subrule;

    qi::symbols<char, subrule*> subrules;
    qi::rule<Iterator, ascii::space_type, qi::locals<subrule*> > start_rule;
    qi::rule<Iterator, ascii::space_type> int_rule, dbl_rule;
};

int main()
{
    typedef std::string::const_iterator iter;
    std::string storage("I 5");
    iter it_begin(storage.begin());
    iter it_end(storage.end());
    using boost::spirit::ascii::space;
    x_grammar<iter> g;
    try {
        bool r = qi::phrase_parse(it_begin, it_end, g, space);
        if (r) {
            std::cout << "Pass!\n";
        }
        else {
            std::cout << "Fail!\n";
        }
    }
    catch (const qi::expectation_failure<iter>&) {
        std::cout << "Fail!\n";
    }
    return 0;
}
于 2014-05-20T15:39:31.913 に答える