2012-11-13 37 views
5

Tôi cố gắng học cách sử dụng boost :: spirit. Để làm điều đó, tôi muốn tạo ra một số từ vựng đơn giản, kết hợp chúng và sau đó bắt đầu phân tích cú pháp bằng cách sử dụng tinh thần. Tôi đã thử sửa đổi ví dụ, nhưng nó không chạy như mong đợi (kết quả r không đúng).Tăng gấp đôi với tăng :: tinh thần :: lex & khoảng trắng

Đây là lexer:

#include <boost/spirit/include/lex_lexertl.hpp> 

namespace lex = boost::spirit::lex; 

template <typename Lexer> 
struct lexer_identifier : lex::lexer<Lexer> 
{ 
    lexer_identifier() 
     : identifier("[a-zA-Z_][a-zA-Z0-9_]*") 
     , white_space("[ \\t\\n]+") 
    { 
     using boost::spirit::lex::_start; 
     using boost::spirit::lex::_end; 

     this->self = identifier; 
     this->self("WS") = white_space; 
    } 
    lex::token_def<> identifier; 
    lex::token_def<> white_space; 
    std::string identifier_name; 
}; 

Và đây là ví dụ tôi đang cố gắng để chạy:

#include "stdafx.h" 

#include <boost/spirit/include/lex_lexertl.hpp> 
#include "my_Lexer.h" 

namespace lex = boost::spirit::lex; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    typedef lex::lexertl::token<char const*,lex::omit, boost::mpl::false_> token_type; 
    typedef lex::lexertl::lexer<token_type> lexer_type; 

    typedef lexer_identifier<lexer_type>::iterator_type iterator_type; 

    lexer_identifier<lexer_type> my_lexer; 

    std::string test("adedvied das934adf dfklj_03245"); 

    char const* first = test.c_str(); 
    char const* last = &first[test.size()]; 

    lexer_type::iterator_type iter = my_lexer.begin(first, last); 
    lexer_type::iterator_type end = my_lexer.end(); 

    while (iter != end && token_is_valid(*iter)) 
    { 
     ++iter; 
    } 

    bool r = (iter == end); 

    return 0; 
} 

r là đúng chừng chỉ có một dấu hiệu bên trong chuỗi. Tại sao điều này là trường hợp?

Trân Tobias

Trả lời

10

Bạn đã tạo ra một trạng thái lexer thứ hai, nhưng không bao giờ gọi nó.

Đơn giản hóa và lợi nhuận:


Đối với hầu hết các trường hợp, cách dễ nhất để có hiệu quả mong muốn sẽ được sử dụng đơn nhà nước Lexing với một lá cờ pass_ignore trên tokens thể bỏ qua:

this->self += identifier 
       | white_space [ lex::_pass = lex::pass_flags::pass_ignore ]; 

Lưu ý rằng điều này yêu cầu một số actor_lexer để cho phép hành động ngữ nghĩa:

typedef lex::lexertl::actor_lexer<token_type> lexer_type; 
.210

Full mẫu:

#include <boost/spirit/include/lex_lexertl.hpp> 
#include <boost/spirit/include/lex_lexertl.hpp> 
namespace lex = boost::spirit::lex; 

template <typename Lexer> 
struct lexer_identifier : lex::lexer<Lexer> 
{ 
    lexer_identifier() 
     : identifier("[a-zA-Z_][a-zA-Z0-9_]*") 
     , white_space("[ \\t\\n]+") 
    { 
     using boost::spirit::lex::_start; 
     using boost::spirit::lex::_end; 

     this->self += identifier 
        | white_space [ lex::_pass = lex::pass_flags::pass_ignore ]; 
    } 
    lex::token_def<> identifier; 
    lex::token_def<> white_space; 
    std::string identifier_name; 
}; 

int main(int argc, const char *argv[]) 
{ 
    typedef lex::lexertl::token<char const*,lex::omit, boost::mpl::false_> token_type; 
    typedef lex::lexertl::actor_lexer<token_type> lexer_type; 

    typedef lexer_identifier<lexer_type>::iterator_type iterator_type; 

    lexer_identifier<lexer_type> my_lexer; 

    std::string test("adedvied das934adf dfklj_03245"); 

    char const* first = test.c_str(); 
    char const* last = &first[test.size()]; 

    lexer_type::iterator_type iter = my_lexer.begin(first, last); 
    lexer_type::iterator_type end = my_lexer.end(); 

    while (iter != end && token_is_valid(*iter)) 
    { 
     ++iter; 
    } 

    bool r = (iter == end); 
    std::cout << std::boolalpha << r << "\n"; 
} 

Prints

true 

"WS" như một trạng thái Skipper


Cũng có thể bạn đã xem qua một mẫu sử dụng trạng thái phân tích cú pháp thứ hai cho người đội trưởng (lex::tokenize_and_phrase_parse). Hãy để tôi mất một phút hoặc 10 để tạo ra một mẫu làm việc cho điều đó.

Cập nhật Đã cho tôi một chút hơn 10 phút (waaaah) :) Dưới đây là một thử nghiệm so sánh, cho thấy cách các bang lexer tương tác, và làm thế nào để sử dụng Spirit Skipper phân tích cú pháp để gọi trạng thái phân tích cú pháp thứ hai:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/lex_lexertl.hpp> 
namespace lex = boost::spirit::lex; 
namespace qi = boost::spirit::qi; 

template <typename Lexer> 
struct lexer_identifier : lex::lexer<Lexer> 
{ 
    lexer_identifier() 
     : identifier("[a-zA-Z_][a-zA-Z0-9_]*") 
     , white_space("[ \\t\\n]+") 
    { 
     this->self  = identifier; 
     this->self("WS") = white_space; 
    } 
    lex::token_def<> identifier; 
    lex::token_def<lex::omit> white_space; 
}; 

int main() 
{ 
    typedef lex::lexertl::token<char const*, lex::omit, boost::mpl::true_> token_type; 
    typedef lex::lexertl::lexer<token_type> lexer_type; 

    typedef lexer_identifier<lexer_type>::iterator_type iterator_type; 

    lexer_identifier<lexer_type> my_lexer; 

    std::string test("adedvied das934adf dfklj_03245"); 

    { 
     char const* first = test.c_str(); 
     char const* last = &first[test.size()]; 

     // cannot lex in just default WS state: 
     bool ok = lex::tokenize(first, last, my_lexer, "WS"); 
     std::cout << "Starting state WS:\t" << std::boolalpha << ok << "\n"; 
    } 

    { 
     char const* first = test.c_str(); 
     char const* last = &first[test.size()]; 

     // cannot lex in just default state either: 
     bool ok = lex::tokenize(first, last, my_lexer, "INITIAL"); 
     std::cout << "Starting state INITIAL:\t" << std::boolalpha << ok << "\n"; 
    } 

    { 
     char const* first = test.c_str(); 
     char const* last = &first[test.size()]; 

     bool ok = lex::tokenize_and_phrase_parse(first, last, my_lexer, *my_lexer.self, qi::in_state("WS")[my_lexer.self]); 
     ok = ok && (first == last); // verify full input consumed 
     std::cout << std::boolalpha << ok << "\n"; 
    } 
} 

Đầu ra là

Starting state WS: false 
Starting state INITIAL: false 
true 
+0

gia tăng các "WS" cách tiếp cận nhà nước với bản demo dưới ** ' "WS" như một state' Skipper **. Chúc mừng – sehe

+0

Rất tiếc. Tôi đã sao chép khai báo token_type sai. Nó cần 'mpl :: true_' cho [' HasState'] (http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/lex/abstracts/lexer_primitives/lexer_token_values.html # spirit.lex.abstracts.lexer_primitives.lexer_token_values.the_anatomy_of_a_token), khi giao dịch với những người đứng đầu nhà nước - rõ ràng! *** Cố định *** – sehe

+0

trước hết - cảm ơn bạn vì ví dụ mở rộng của bạn. Tôi vẫn có một số câu hỏi mặc dù: những gì hiện lex :: bỏ qua làm gì? Và liên quan đến lời gọi tokenize_and_parse: my_lexer.self & qi :: in_state ("WS") [my_lexer.self] là gì? –