2012-04-08 47 views
2

我在編寫使用另一個Qi語法的Qi語法時遇到了困難。一個類似的問題被問到here,但我也試圖使用phoenix ::構造和編譯困難。boost:spirit :: qi parser using multiple grammars and 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; 
} 

我可以在使用精神的文檔中表現出的phrase_parse方法來解析複雜,但我希望能夠輕鬆地集成複雜的語法到其它解析器(一個表達式解析器,例如)。是否有我錯過的東西可以讓我將Real和Complex對象解析爲不同的實體,同時還能夠在其他規則/語法中有效地使用它們?

回答

2

qi::_aqi::_b代表規則的第一和第二局部變量。這些變量僅適用於在規則r的聲明中添加qi::locals<long double, long double>作爲模板參數(因爲傳遞給語法構造函數的開始規則需要與語法兼容,所以這些變量也可用於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; 
+0

之前不知怎的,錯過了這個質量答案。我很高興看到一位「專家」(哈哈)對Boost(精神)問題感興趣。歡迎來到社區,@llonesmiz – sehe 2012-09-11 07:39:33

相關問題