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 文档中演示的短语解析方法来解析 Complex,但我希望能够轻松地将 Complex 语法集成到其他解析器(例如表达式解析器)中。有什么我遗漏的东西可以让我将 Real 和 Complex 对象解析为不同的实体,同时仍然能够在其他规则/语法中有效地使用它们?

4

1 回答 1

2

qi::_aqi::_b表示规则的第一个和第二个局部变量。这些变量只有在您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 指的是第二个解析器匹配的属性。

使用任何替代方法,我们就可以正常使用这些语法:

//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 回答