1

入力文字列: を指定するA = 23; B = 5と、現在 (期待される) 出力が得られます。

Output: 0xa0000023
Output: 0xa0010005
-------------------------

代わりにこれを見たい:

Output: 0xa0000023           // A = 23
Output: 0xa0010005           // B = 5
-------------------------

コードのコア行は次のとおりです。

statement   = eps[_val = 0x50000000] >> identifier[_val += _1<<16] >>
                     "=" >> hex[_val += (_1 & 0x0000FFFF)];

identifier は qi::symbols テーブル ルックアップです。

私のコードの残りの部分は次のようになります。

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <iostream>
#include <iomanip>
#include <ios>
#include <string>
#include <complex>

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

struct reg16_ : qi::symbols<char,unsigned> {
    reg16_() {
        add ("A", 0) ("B", 1) ("C", 2) ("D", 3) ;
    }
} reg16;

template <typename Iterator>
struct dash_script_parser : qi::grammar<Iterator, std::vector<unsigned>(), ascii::space_type> {
    dash_script_parser() : dash_script_parser::base_type(start) {
        using qi::hex;
        using qi::_val;
        using qi::_1;
        using qi::eps;

        identifier %= reg16;

        start      %= (statement % ";" );
        statement   = eps[_val = 0x50000000] >> identifier[_val += _1<<16]>> "=" >> hex[_val += (_1 & 0x0000FFFF)];
    }
    qi::rule<Iterator, std::vector<unsigned>(), ascii::space_type> start;
    qi::rule<Iterator, unsigned(), ascii::space_type> statement;
    qi::rule<Iterator, unsigned()> identifier;
};

int
main()
{
    std::cout << "\t\tA parser for Spirit...\n\n" << "Type [q or Q] to quit\n\n";

    dash_script_parser<std::string::const_iterator> g;
    std::string str;
    while (getline(std::cin, str))

    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q') break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        std::vector<unsigned> strs;
        bool r = phrase_parse(iter, end, g, boost::spirit::ascii::space, strs);
        if (r && iter == end) {
            for(std::vector<unsigned>::const_iterator it=strs.begin(); it<strs.end(); ++it)
                std::cout << "Output: 0x" << std::setw(8) << std::setfill('0') << std::hex <<*it << "\n";
        } else
            std::cout << "Parsing failed\n";
    }
    return 0;
}
4

1 に答える 1

4

更新iter_pos(Boost Spiritリポジトリから)私の注意を引いた新しい答え:

これは基本的に以下と同じですが、セマンティックアクションを「乱用」することはありません(特に自動属性伝播を使用すると、より適切に適合します)。


私の直感では、最初にステートメントを生のソースイテレーター範囲に分離してから、ステートメントを分離して解析する方がおそらく簡単だと思います。そうすれば、最初に対応するソーステキストが表示されます。

これが邪魔にならないように、サンプルコードをあまり破壊せずに機能するようにテストしたアプローチを次に示します。


1.属性タイプを構造体にします

プリミティブを、ソーススニペットを逐語的unsigned含む構造体に置き換えます。string

struct statement_t
{
    unsigned    value;
    std::string source;
};

BOOST_FUSION_ADAPT_STRUCT(statement_t, (unsigned, value)(std::string, source));

2.パーサーに両方のフィールドを入力させます

良いことは、あなたはすでにセマンティックアクションを使用していたので、それは単にそれに基づいているだけです。結果はあまりきれいではなく、(融合された)ファンクターに変換することで大きなメリットが得られることに注意してください。しかし、それはテクニックを非常に明確に示しています:

start      %= (statement % ";" );
statement   = qi::raw [ 
        raw[eps]      [ at_c<0>(_val)  = 0x50000000 ] 
        >> identifier [ at_c<0>(_val) += _1<<16 ]
        >> "=" >> hex [ at_c<0>(_val) += (_1 & 0x0000FFFF) ]
    ] 
    [ at_c<1>(_val) = construct<std::string>(begin(_1), end(_1)) ]
;

3.印刷

したがって、にat_c<0>(_val)対応しstatement::value、にat_c<1>(_val)対応しstatement::sourceます。このわずかに変更された出力ループ:

for(std::vector<statement_t>::const_iterator it=strs.begin(); it<strs.end(); ++it)
    std::cout << "Output: 0x" << std::setw(8) << std::setfill('0') << std::hex << it->value << " // " << it->source << "\n";

出力:

Output: 0x50000023 // A = 23
Output: 0x50010005 // B = 5

完全なサンプル

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <iostream>
#include <iomanip>
#include <ios>
#include <string>
#include <complex>

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

#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
namespace phx   = boost::phoenix;

struct reg16_ : qi::symbols<char,unsigned> {
    reg16_() {
        add ("A", 0) ("B", 1) ("C", 2) ("D", 3) ;
    }
} reg16;

struct statement_t
{
    unsigned    value;
    std::string source;
};

BOOST_FUSION_ADAPT_STRUCT(statement_t, (unsigned, value)(std::string, source));

template <typename Iterator>
struct dash_script_parser : qi::grammar<Iterator, std::vector<statement_t>(), ascii::space_type> {
    dash_script_parser() : dash_script_parser::base_type(start) {
        using qi::hex;
        using qi::_val;
        using qi::_1;
        using qi::eps;
        using qi::raw;

        identifier %= reg16;

        using phx::begin;
        using phx::end;
        using phx::at_c;
        using phx::construct;

        start      %= (statement % ";" );
        statement   = raw [ 
                raw[eps]      [ at_c<0>(_val)  = 0x50000000 ] 
                >> identifier [ at_c<0>(_val) += _1<<16 ]
                >> "=" >> hex [ at_c<0>(_val) += (_1 & 0x0000FFFF) ]
            ] 
            [ at_c<1>(_val) = construct<std::string>(begin(_1), end(_1)) ]
        ;
    }
    qi::rule<Iterator, std::vector<statement_t>(), ascii::space_type> start;
    qi::rule<Iterator, statement_t(), ascii::space_type> statement;
    qi::rule<Iterator, unsigned()> identifier;
};

int
main()
{
    std::cout << "\t\tA parser for Spirit...\n\n" << "Type [q or Q] to quit\n\n";

    dash_script_parser<std::string::const_iterator> g;
    std::string str;
    while (getline(std::cin, str))

    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q') break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        std::vector<statement_t> strs;
        bool r = phrase_parse(iter, end, g, boost::spirit::ascii::space, strs);
        if (r && iter == end) {
            for(std::vector<statement_t>::const_iterator it=strs.begin(); it<strs.end(); ++it)
                std::cout << "Output: 0x" << std::setw(8) << std::setfill('0') << std::hex << it->value << " // " << it->source << "\n";
        } else
            std::cout << "Parsing failed\n";
    }
    return 0;
}
于 2012-02-04T00:56:36.373 に答える