2012-11-13 1 views
5

Я стараюсь использовать boost :: spirit. Для этого я хотел создать простой лексер, объединить их и затем начать синтаксический анализ с использованием духа. Я попытался изменить пример, но он работает не так, как ожидалось (результат r не соответствует действительности).Смуты с boost :: spirit :: lex & whitespace

Вот лексер:

#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; 
}; 

И это пример, который я пытаюсь запустить:

#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; 
} 

г верно до тех пор, пока существует только один маркер внутри строки. Почему это так?

С уважением Tobias

ответ

10

Вы создали второе состояние лексического анализатора, но никогда не вызывается его.

Simplify и прибыль:


В большинстве случаев, самый простой способ, чтобы иметь желаемый эффект будет использовать одно-состояние Lexing с pass_ignore флагом на возможности пропуска лексем:

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

Заметим, что для этого требуется actor_lexer:

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

Полный пример:

#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"; 
} 

Печать

true 

"WS", как состояние Skipper


Это также возможно, что вы пришли на образце, который использует второе состояние анализатора для шкипер (lex::tokenize_and_phrase_parse). Позвольте мне потратить минуту или 10, чтобы создать для этого рабочий образец.

Update Взял меня немного больше, чем 10 минут (waaaah) :) Вот сравнительный тест, показывающий, как лексер состояния взаимодействуют между собой, и как использовать Дух Skipper синтаксический вызвать второе состояние анализатора:

#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"; 
    } 
} 

выход

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

Добавлен "WS" государственный подход с демо под ** ' "WS", как state' Skipper **. Cheers – sehe

+0

К сожалению. Я скопировал неправильное объявление token_type. Для '' HasState' 'требуется 'mpl :: true_' (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), когда речь идет о лексиконах с естественным состоянием - очевидно! *** Исправлено *** – sehe

+0

в первую очередь - спасибо за ваш обширный пример. У меня все еще есть некоторые вопросы: что делает lex :: omit? И в отношении вызова tokenize_and_parse: что такое my_lexer.self & qi :: in_state ("WS") [my_lexer.self]? –

 Смежные вопросы

  • Нет связанных вопросов^_^