1

精霊初心者です

スピリットを使用して、インペリアル文字列値を構造体に解析したいと思います。

入力は次の構文を受け入れる必要があります。

    5'3"1/2
    5'1/2
    3インチ1/2

struct imp_constant以下のストリーム演算子に注意してください。この演算子と同じように結果を出力します。

struct imp_constant
{
    explicit imp_constant(unsigned int feet=0
                         ,unsigned int inch=0
                         ,unsigned int fracn=0
                         ,unsigned int fracd=1)
        :feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){}
    unsigned int feet_,inches_,fracn_,fracd_;
};
std::ostream& operator<<(std::ostream& os, imp_constant const& cst)
{
    if (cst.feet_)
        os << cst.feet_ << '\''; 
    if (cst.inches_)    
        os << cst.inches_ << '"';
    if (cst.fracn_)
        os << cst.fracn_ << '/' << cst.fracd_;
    return os;
}

私の疑似文法は非常に単純で、次のようになります。

myrule = (
    (
        (qi::uint_ >> L'\'')
        ||
        (qi::uint_ >> L'"') 
    ) 
    >> -(
            qi::uint_ 
            >> L'/' >> 
            qi::uint_
        )
    );

これは、構造体にデータを入力するための非常に素朴な最初の試みです。

BOOST_FUSION_ADAPT_STRUCTマクロを追加してから、struct imp_constant次の文法を試しました:

qi::rule<std::string::const_iterator, imp_constant()> 
    impconst = qi::lexeme[ //not sure this is required since no skipper precised
        (
            (qi::uint_[phx::at_c<0>(qi::_val)=qi::_1] >> L'\'')
            ||
            (qi::uint_[phx::at_c<1>(qi::_val)=qi::_1] >> L'"') 
        ) 
        >> -(
            qi::uint_[phx::at_c<2>(qi::_val)=qi::_1] 
            >> L'/' >> 
            qi::uint_[phx::at_c<3>(qi::_val)=qi::_1]
            )
        ];

結果は次のとおりです。

input:5'3"1/2  ==> output:5'3"1/2  (ok)
input:5'1/2    ==> output:5'1"1/2  (__nok__)

_1その場合、プレースホルダーがどのように動作するかわかりません。

霊界初心者なのでアドバイスよろしくお願いします

どうもありがとうございました

ここに完全なコードがあります。これが役立つはずです

#define BOOST_SPIRIT_DONT_USE_MPL_ASSERT_MSG 1
//#define BOOST_SPIRIT_DEBUG << uncomment to enable debug
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/fusion/adapted.hpp>

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

struct imp_constant
{
    explicit imp_constant(unsigned int feet=0
                         ,unsigned int inch=0
                         ,unsigned int fracn=0
                         ,unsigned int fracd=1)
        :feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){}
    unsigned int feet_,inches_,fracn_,fracd_;
};

std::ostream& operator<<(std::ostream& os, imp_constant const& cst)
{
    if (cst.feet_)
        os << cst.feet_ << '\''; 
    if (cst.inches_)    
        os << cst.inches_ << '"';
    if (cst.fracn_)
        os << cst.fracn_ << '/' << cst.fracd_;
    return os;
}

BOOST_FUSION_ADAPT_STRUCT(imp_constant, 
                          (unsigned int, feet_)
                          (unsigned int, inches_)
                          (unsigned int, fracn_)
                          (unsigned int, fracd_))

int _tmain(int argc, _TCHAR* argv[])
{
    std::string input;

    std::cout << "\n----------------------\n> ";
    while (std::getline(std::cin, input))
    {
        if (input.empty() || input[0] == 'q' || input[0] == 'Q')
            break;

        std::string::const_iterator f(input.begin()),l(input.end());
        try
        {
            imp_constant result;
            std::cout << "parsing: " << input << "\n";
            bool ok;


            qi::rule<std::string::const_iterator, imp_constant()> 
                impconst = qi::lexeme[ //not sure this is required since
                            //no skipper precised
                    (
                        (qi::uint_[phx::at_c<0>(qi::_val)=qi::_1]
                        >> L'\'')
                        ||
                        (qi::uint_[phx::at_c<1>(qi::_val)=qi::_1]
                        >> L'"') 
                        ) 
                        >> -(
                        qi::uint_[phx::at_c<2>(qi::_val)=qi::_1] 
                    >> L'/' >> 
                        qi::uint_[phx::at_c<3>(qi::_val)=qi::_1]
                    )
                ];

            ok=qi::phrase_parse(f,l,impconst ,qi::space,result);

            if (!ok)
                std::cerr << "invalid input\n";
            else
            {

                std::cout << "\n---------------------------\n";
                std::cout << "result="<< result;
            }
        } 
        catch (const qi::expectation_failure<const char *>& e)
        {
            std::cerr << "expect failure at '" 
                      << std::string(e.first, e.last) << "'\n";
        }
        catch (...)
        {
            std::cerr << "parse error\n";
        }
        if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
        std::cout << "\n-----------------------\n> ";
    }
    std::getchar();
    return 0;
}
4

2 に答える 2

4

seheの回答の代替として(受け入れる必要があります):

ルールを次のように変更した場合、ソリューションは機能します。

qi::rule<std::string::const_iterator, imp_constant()> 
        impconst = 
                 (
                     (qi::uint_ >> L'\'')[phx::at_c<0>(qi::_val)=qi::_1]
                     ||
                     (qi::uint_ >> L'"')[phx::at_c<1>(qi::_val)=qi::_1]
                 )
                 >> 
                     -(qi::uint_ >> L'/' >> qi::uint_)
                     [phx::at_c<2>(qi::_val)=qi::_1,phx::at_c<3>(qi::_val)=qi::_2]
        ;

これを行う方法:

あなたのわずかに変更imp_constant

struct fraction
{
   unsigned int n_,d_;
};

struct imp_constant
{
    unsigned int feet_,inches_;
    fraction frac_;
};

BOOST_FUSION_ADAPT_STRUCT(fraction,
                          (unsigned int, n_)
                          (unsigned int, d_)
)

BOOST_FUSION_ADAPT_STRUCT(imp_constant, 
                          (unsigned int, feet_)
                          (unsigned int, inches_)
                          (fraction    , frac_)

そして、ルールは次のようになります。

qi::rule<std::string::const_iterator,unsigned int()> feet = (qi::uint_ >> L'\'') | qi::attr(0);
qi::rule<std::string::const_iterator,unsigned int()> inches = (qi::uint_ >> L'"') | qi::attr(0);
qi::rule<std::string::const_iterator,fraction()> fract = (qi::uint_ >> L'/' >> qi::uint_) | (qi::attr(0)>> qi::attr(1));
qi::rule<std::string::const_iterator, imp_constant()> impconst=feet>>inches>>fract;

LWS の例

于 2013-04-10T12:14:06.330 に答える
2

あなたはバックトラックを見ています。

'1'5'1/2は最初に潜在的なインチ ブランチとして解析されqi::uint_、属性が割り当てられます。

その場合にのみ「/」が検出され、「inch ブランチ」からのバックトラックが発生します。しかし、属性はすでに設定されています。この場合、明示的なデフォルトまたはそれqi::holdを修正できます。

これは、おそらく私が自分で物事を表現する方法のようなものです。

qi::rule<std::string::const_iterator, unsigned(char)> 
    component = qi::hold [ qi::uint_ >> qi::lit(qi::_r1) ];

qi::rule<std::string::const_iterator, imp_constant()> 
    impconst = 
        component(L'\'') ||
        component(L'"')  ||
        component(L'/')  ||
        qi::uint_
;

BOOST_SPIRIT_DEBUG_NODE(component);
BOOST_SPIRIT_DEBUG_NODE(impconst);

これは良い出発点になると思いますか?

その他の注意事項:

  1. f!=l解析されていない残りの入力を検出するテスト
  2. 完全なコード サンプルのセマンティック アクションは冗長でした
  3. 確かに、lexemeそこは冗長でした

ここでライブを参照してください: http://liveworkspace.org/code/Rpydy$0

テスト出力:

----------------------
> parsing: 5'1/2
<impconst>
  <try>5'1/2</try>
  <component>
    <try>5'1/2</try>
    <success>1/2</success>
    <attributes>[5, ']</attributes>
  </component>
  <component>
    <try>1/2</try>
    <fail/>
  </component>
  <component>
    <try>1/2</try>
    <success>2</success>
    <attributes>[1, /]</attributes>
  </component>
  <success></success>
  <attributes>[[5, 0, 1, 2]]</attributes>
</impconst>

---------------------------
result=5'1/2
-----------------------
> 
于 2013-04-10T11:10:11.730 に答える