2

別のQi文法を利用するQi文法を書くのに問題があります。ここでも同様の質問がありましたが、phoenix ::constructを使用しようとしていて、コンパイルが困難です。

これが私がやろうとしていることの簡略版です。この例はおそらくを使用して簡単に実行できることを理解していますBOOST_FUSION_ADAPT_STRUCTが、実際のコードはより複雑なオブジェクトタイプを扱っているため、セマンティックアクションを使用してこれを実現する方法があることを期待しています。

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <cstdlib>
#include <iostream>


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

// grammar for real numbers
template <typename Iterator>
struct Real : qi::grammar<Iterator, long double()>
{
    qi::rule<Iterator, long double()> r;
    Real() : Real::base_type(r)
    {
        r %= qi::long_double;
    }
};

// grammar for complex numbers of the form a+bi
template <typename Iterator>
struct Complex : qi::grammar<Iterator, std::complex<long double>()>
{
    qi::rule<Iterator, std::complex<long double>()> r;
    Real<Iterator> real;
    Complex() : Complex::base_type(r)
    {
        r = real [qi::_a = qi::_1] >> (qi::lit("+") | qi::lit("-")) 
            >> real [qi::_b = qi::_1] >> -qi::lit("*") >> qi::lit("i")
            [
                qi::_val = phx::construct<std::complex<long double> >(qi::_a, qi::_b)
            ];
    }
};

int main()
{
    // test real parsing
    std::cout << "Parsing '3'" << std::endl;
    std::string toParse = "3";
    Real<std::string::iterator> real_parser;
    long double real_val;
    std::string::iterator beginIt = toParse.begin();
    std::string::iterator endIt = toParse.end();
    bool r = qi::parse(beginIt, endIt, real_parser, real_val);
    if(r && beginIt == endIt)
        std::cout << "Successful parse: " << real_val << std::endl;
    else
        std::cout << "Could not parse" << std::endl;

    // test complex parsing
    std::cout << "Parsing '3+4i'" << std::endl;
    toParse = "3+4i";
    Complex<std::string::iterator> complex_parser;
    std::complex<long double> complex_val;
    beginIt = toParse.begin();
    endIt = toParse.end();
    r = qi::parse(beginIt, endIt, complex_parser, complex_val);
    if(r && beginIt == endIt)
        std::cout << "Successful parse: " << real_val << std::endl;
    else
        std::cout << "Could not parse" << std::endl;
}

Spiritのドキュメントに示されているphrase_parseアプローチを使用してComplexを解析することはできますが、Complex文法を他のパーサー(たとえば、式パーサー)に簡単に統合できるようにしたいと思います。他のルール/文法で効果的に使用しながら、RealオブジェクトとComplexオブジェクトを別個のエンティティとして解析できるようにするために欠けているものはありますか?

4

1 に答える 1

2

qi::_aqi::_bルールの 1 番目と 2 番目のローカル変数を表します。qi::locals<long double, long double>これらの変数は、規則の宣言でテンプレート パラメータとして追加する場合にのみ使用できますr(この場合qi::grammar...、文法のコンストラクタに渡される開始規則は文法と互換性がある必要があるため、つまり、同じテンプレート パラメータを持つ必要があるため)。 .

以下に、ローカル変数を必要としない別の方法を示します。

// grammar for complex numbers of the form a+bi
template <typename Iterator>
struct Complex : qi::grammar<Iterator, std::complex<long double>()>
{
    qi::rule<Iterator, std::complex<long double>()> r;
    Real<Iterator> real;
    Complex() : Complex::base_type(r)
    {
        r = (
                real  >> (qi::lit("+") | qi::lit("-"))
                >> real  >> -qi::lit("*") >> qi::lit("i")
            )
            [
                qi::_val = phx::construct<std::complex<long double> >(qi::_1, qi::_2)
            ];
    }
};

この場合、セマンティック アクションはパーサー シーケンス全体に関連付けられており、_N プレースホルダーで必要な属性を取得できます。ここで、qi::_1 は最初の Real パーサーで一致した属性を参照し、qi::_2 は 2 番目の Real パーサーで一致した属性を参照します。

代替のいずれかを使用すると、それらの文法を通常どおり使用できます。

//using complex_parser, real_parser, complex_val and real_val declared in your code
std::cout << "Parsing 'variable=3+4i-2'" << std::endl;
toParse = "variable=3+4i-2";
beginIt = toParse.begin();
endIt = toParse.end();
std::string identifier;
r = qi::parse(beginIt, endIt, *qi::char_("a-z") >> '=' >> complex_parser >> '-' >> real_parser, identifier, complex_val, real_val);
if(r && beginIt == endIt)
    std::cout << "Successful parse: " << identifier << complex_val.real() << " " << complex_val.imag() << " " << real_val << std::endl;
else
    std::cout << "Could not parse" << std::endl;
于 2012-07-07T13:39:03.847 に答える