2013-07-18 25 views
10

Làm theo một số hướng dẫn (ví dụ: http://boost-spirit.com/home/articles/qi-example/nabialek-trick/) Tôi muốn sử dụng mẹo Nabialek để có trình phân tích cú pháp động. Phân tích cú pháp đã hoạt động tốt, nhưng tôi không nhận được các thuộc tính được vận chuyển. Các giải thích như https://stackoverflow.com/a/9109972/2524462 đề xuất, các thuộc tính đó sẽ có thể nhưng không phải là đối số.Boost.Spirit.Qi: Cách trả lại thuộc tính bằng mẹo Nabialek

Đây chỉ là một ví dụ nhỏ phân tích một chuỗi và một số thành một cấu trúc. Nó chỉ là để trưng bày vấn đề của tôi; phương pháp này nên được sử dụng trong một hệ thống lớn hơn sau này, nơi mà trình phân tích cú pháp động thực sự cần thiết.

Câu hỏi: Làm cách nào để chuyển các thuộc tính bằng thủ thuật Nabialek?

Tôi không phải là chuyên gia về tinh thần, vì vậy hãy chịu đựng với tôi. Tôi đang sử dụng gcc 4.8.1 và tăng 1.54.

#define BOOST_SPIRIT_DEBUG 
#define BOOST_SPIRIT_USE_PHOENIX_V3 
#include <boost/fusion/adapted/struct.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

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

//------------------------------------------------------------------------------ 
// Data structure 
struct myline { 
    myline() 
     : _n(0), _s("") { 
    } 

    myline(int n, std::string s) 
     : _n(n), _s(s) { 
    } 

    void set(int n, std::string s) { 
    _n = n; 
    _s = s; 
    } 

    int _n; 
    std::string _s; 
}; 

BOOST_FUSION_ADAPT_STRUCT(::myline, (int, _n) (std::string, _s)) 

//------------------------------------------------------------------------------ 
// Parser grammar 
template<typename It, typename Skipper = qi::space_type> 
struct parser: qi::grammar<It, myline(), Skipper> { 
    parser() 
     : parser::base_type(start) { 
    using namespace qi; 

    start = line; 

    string %= qi::lexeme["'" >> *~qi::char_("'") >> "'"]; 

    one = (string >> "@" >> qi::int_)[_val = phx::construct<myline>(_2, _1)]; 
    two = (qi::int_ >> "@" >> string); 

    keyword.add("one", &one)("two", &two); 

    line = keyword[_a = _1] >> qi::lazy(*_a); 

    on_error<fail>(
     start, 
     std::cout << phx::val("Error! Expecting ") << _4 
     << phx::val(" here: \"") << phx::construct<std::string>(_3, _2) 
     << phx::val("\"\n")); 

    BOOST_SPIRIT_DEBUG_NODES((start)(line)(one)(two)) 
    } 

private: 
    template<typename Attr> using Rule = qi::rule<It, Attr(), Skipper>; 

    Rule<myline> start, one, two; 
    qi::rule<It, myline, Skipper, qi::locals<Rule<myline>*> > line; 

    Rule<std::string> string; 

    qi::symbols<char, Rule<myline>*> keyword; 
}; 

//------------------------------------------------------------------------------ 
int main() { 
    for (const std::string input : std::vector<std::string> { "one 'test'@1", 
                  "two [email protected]'test'" }) { 
    auto f(std::begin(input)), l(std::end(input)); 
    const static parser<decltype(f)> p; 

    myline parsed_script; 
    bool ok = qi::phrase_parse(f, l, p, qi::space, parsed_script); 

    if (!ok) { 
     std::cout << "invalid input\n"; 
    } 

    std::cout << parsed_script._n << ": " << parsed_script._s << std::endl; 

    if (f != l) { 
     std::cout << "unparsed: '" << std::string(f, l) << "'" << std::endl; 
    } 
    } 
} 

kết quả phân tích cú pháp:

<start> 
    <try>one 'test'@1</try> 
    <line> 
    <try>one 'test'@1</try> 
    <one> 
     <try> 'test'@1</try> 
     <success></success> 
     <attributes>[[1, [t, e, s, t]]]</attributes> 
    </one> 
    <success></success> 
    <attributes>[]</attributes><locals>(0x43b0e0)</locals> 
    </line> 
    <success></success> 
    <attributes>[[0, []]]</attributes> 
</start> 
<start> 
    <try>two [email protected]'test'</try> 
    <line> 
    <try>two [email protected]'test'</try> 
    <two> 
     <try> [email protected]'test'</try> 
     <success></success> 
     <attributes>[[2, [t, e, s, t]]]</attributes> 
    </two> 
    <success></success> 
    <attributes>[]</attributes><locals>(0x43b110)</locals> 
    </line> 
    <success></success> 
    <attributes>[[0, []]]</attributes> 
</start> 

Trả lời

14

Bạn đã được trả tiền nhiều sự chú ý trong Thần Lớp :)

Đã có một số vấn đề:

  1. thuộc tính tuyên bố của quy tắc line sai:

    qi::rule<It, myline, Skipper, qi::locals<Rule<myline>*> > line; 
    

    cần phải được

    qi::rule<It, myline(), Skipper, qi::locals<Rule<myline>*> > line; 
    
  2. tuyên truyền thuộc tính tự động bị ức chế trong sự hiện diện của hành động ngữ nghĩa. Xem câu trả lời gần đây để biết thêm thông tin: Boost.spirit: parsing number char and string. Vì vậy, bạn cần phải explicitely tham gia vào hành vi tự động quy tắc Thần bằng cách sử dụng %=:

    line = keyword[_a = _1] >> qi::lazy(*_a); 
    

    Nees được

    // NOTE the %= 
    line %= omit [ keyword[_a = _1] ] >> qi::lazy(*_a); 
    

    Ghi chú:

    • các %= có thể tiếp tục sự cai trị string (không ngữ nghĩa các hành động ngụ ý tuyên truyền thuộc tính tự động)
    • chúng tôi cần phải explicitelyomit[] kết quả của trận đấu từ khóa, bởi vì chúng ta có thể không thực sự giao Rule<>* để myline thuộc tính của chúng tôi

Dưới đây là phiên bản cố định:

#define BOOST_SPIRIT_DEBUG 
#define BOOST_SPIRIT_USE_PHOENIX_V3 
#include <boost/fusion/adapted/struct.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

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

//------------------------------------------------------------------------------ 
// Data structure 
struct myline { 
    myline() 
     : _n(0), _s("") { 
    } 

    myline(int n, std::string s) 
     : _n(n), _s(s) { 
    } 

    void set(int n, std::string s) { 
    _n = n; 
    _s = s; 
    } 

    int _n; 
    std::string _s; 
}; 

BOOST_FUSION_ADAPT_STRUCT(::myline, (int, _n) (std::string, _s)) 

//------------------------------------------------------------------------------ 
// Parser grammar 
template<typename It, typename Skipper = qi::space_type> 
struct parser: qi::grammar<It, myline(), Skipper> { 
    parser() 
     : parser::base_type(start) { 
    using namespace qi; 

    start = line; 

    string = qi::lexeme["'" >> *~qi::char_("'") >> "'"]; 

    one = (string >> "@" >> qi::int_) [_val   = phx::construct<myline>(_2, _1)]; 
    two = (qi::int_ >> "@" >> string); 

    keyword.add("one", &one)("two", &two); 

    // NOTE the %= 
    line %= omit [ keyword[_a = _1] ] >> qi::lazy(*_a); 

    on_error<fail>(
     start, 
     std::cout << phx::val("Error! Expecting ") << _4 
     << phx::val(" here: \"") << phx::construct<std::string>(_3, _2) 
     << phx::val("\"\n")); 

    BOOST_SPIRIT_DEBUG_NODES((start)(line)(one)(two)) 
    } 

private: 
    template<typename Attr> using Rule = qi::rule<It, Attr(), Skipper>; 

    Rule<myline> start, one, two; 
    qi::rule<It, myline(), Skipper, qi::locals<Rule<myline>* > > line; 

    Rule<std::string> string; 

    qi::symbols<char, Rule<myline>* > keyword; 
}; 

//------------------------------------------------------------------------------ 
int main() { 
    for (const std::string input : std::vector<std::string> { "one 'test1'@1", 
                  "two [email protected]'test2'" }) { 
    auto f(std::begin(input)), l(std::end(input)); 
    const static parser<decltype(f)> p; 

    myline parsed_script; 
    bool ok = qi::phrase_parse(f, l, p, qi::space, parsed_script); 

    if (!ok) { 
     std::cout << "invalid input\n"; 
    } 

    std::cout << parsed_script._n << ": " << parsed_script._s << std::endl; 

    if (f != l) { 
     std::cout << "unparsed: '" << std::string(f, l) << "'" << std::endl; 
    } 
    } 
} 

Prints:

<start> 
    <try>one 'test1'@1</try> 
    <line> 
    <try>one 'test1'@1</try> 
    <one> 
     <try> 'test1'@1</try> 
     <success></success> 
     <attributes>[[1, [t, e, s, t, 1]]]</attributes> 
    </one> 
    <success></success> 
    <attributes>[[1, [t, e, s, t, 1]]]</attributes><locals>(0x6386c0)</locals> 
    </line> 
    <success></success> 
    <attributes>[[1, [t, e, s, t, 1]]]</attributes> 
</start> 
1: test1 
<start> 
    <try>two [email protected]'test2'</try> 
    <line> 
    <try>two [email protected]'test2'</try> 
    <two> 
     <try> [email protected]'test2'</try> 
     <success></success> 
     <attributes>[[2, [t, e, s, t, 2]]]</attributes> 
    </two> 
    <success></success> 
    <attributes>[[2, [t, e, s, t, 2]]]</attributes><locals>(0x6386f0)</locals> 
    </line> 
    <success></success> 
    <attributes>[[2, [t, e, s, t, 2]]]</attributes> 
</start> 
2: test2 
+1

Xem mẫu cố định ** [live on Coliru] (http://coliru.stacked-crooked.com/view?i d = 339ded0e400164a92e13f5cb65e2e54e-414c51b0c3fcfe921b347f2307ac5c70) ** – sehe

+1

Cảm ơn bạn rất nhiều, hoạt động rất tốt.Dường như tôi vẫn cần nhiều bài học hơn ;-) –

+0

Bạn đang làm tốt, không phải lo lắng. – sehe

Các vấn đề liên quan