2013-10-04 1 views
2

Редактировать: Я вырвал лексер, так как он не интегрируется с Qi и просто сфабрирует грамматики (см. here).повысить дух lex и qi. Интеграция анализатора пропусков


Я пытаюсь вырастить грамматику на вершине рамки lex. Когда я пытаюсь переместить анализатор пропусков в грамматику, я начинаю получать ошибки.

Итак, сменив qi::grammar<> и qi::rule<> event подписи от <Iterator> до <Iterator,void(),ascii::space_type>. В структуре грамматики. Что мне нужно сделать?

Кроме того, я установил token_def, чтобы опустить его атрибут для токена optional и некоторых других. Почему он по-прежнему предоставляет мне действительный _val в семантическом действии для необязательного в lexer? Причина, о которой я прошу, состоит в том, что я думал, что проблема связана со строковым атрибутом необязательного токена на rhs правила события в qi, не объединяющемся с сигнатурой атрибута void() правила.

#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/lex_lexertl.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/cstdint.hpp> 
#include <string> 
#include<exception> 

namespace lex = boost::spirit::lex; 
namespace px = boost::phoenix; 
namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 

template <typename Lexer> 
struct tokens : lex::lexer<Lexer> 
{ 
    tokens() 
     : left_paranthesis("\"{\""), 
     right_paranthesis("\"}\""), 
     colon(":"), 
     namespace_("(?i:namespace)"), 
     event("(?i:event)"), 
     optional("(?i:optional)"), 
     required("(?i:required)"), 
     ordinal("\\d+"), 
     identifier("\\w+") 

    { 
     using boost::spirit::lex::_val; 

     this->self 
      = " " 
      | left_paranthesis [ std::cout << px::val("lpar") << std::endl] 
      | right_paranthesis [ std::cout << px::val("rpar") << std::endl] 
      | colon    [ std::cout << px::val("colon") << std::endl] 
      | namespace_   [ std::cout << px::val("kw namesapce") << std::endl] 
      | event    [ std::cout << px::val("kw event") << std::endl] 
      | optional   [ std::cout << px::val("optional ") << "-->" << _val << "<--" << std::endl] 
      | required   [ std::cout << px::val("required") << std::endl] 
      | ordinal    [ std::cout << px::val("val ordinal (") << _val << ")" << std::endl] 
      | identifier   [std::cout << px::val("val identifier(") << _val << ")" << std::endl]; 
    } 

    lex::token_def<> left_paranthesis, right_paranthesis, colon; 
    lex::token_def<lex::omit> namespace_, event, optional, required; 
    lex::token_def<boost::uint32_t> ordinal; 
    lex::token_def<> identifier; 
}; 

template <typename Iterator> 
struct grammar : qi::grammar<Iterator> 
{ 
    template <typename TokenDef> 
    grammar(TokenDef const& tok) 
     : grammar::base_type(event) 
    { 
     //start = event; 
     event = tok.optional [ std::cout << px::val("== OPTIONAL") << std::endl]; 
    } 

    qi::rule<Iterator> start; 
    qi::rule<Iterator> event; 
}; 

// std::string test = "namespace{ event { OPtiONAL 124:hello_world RequireD} } "; 

std::string test = "OPTIONAL"; 

int main() 
{ 
    typedef lex::lexertl::token<std::string::iterator, boost::mpl::vector<boost::uint32_t, std::string> > token_type; 
    typedef lex::lexertl::actor_lexer<token_type> lexer_type; 
    typedef tokens<lexer_type>::iterator_type iterator_type; 

    tokens<lexer_type> token_lexer; 
    grammar<iterator_type> grammar(token_lexer); 

    std::string::iterator first = test.begin(); 
    std::string::iterator last = test.end(); 
    bool r; 

    r = lex::tokenize_and_parse(first, last, token_lexer, grammar); 

    if(r) 
     ; 
    else 
    { 
     std::cout << "parsing failed" << std::endl; 
    } 
    /* 
    lexer_type::iterator_type iter; 

    try 
    { 
     iter = token_lexer.begin(first,last); 
    } 
    catch(std::exception & e) 
    { 
     std::cout << e.what() << std::endl; 
    } 

    lexer_type::iterator_type end = token_lexer.end(); 

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

Эта грамматика не может:

template <typename Iterator> 
struct grammar : qi::grammar<Iterator,void(),ascii::space_type> 
{ 
    template <typename TokenDef> 
    grammar(TokenDef const& tok) 
     : grammar::base_type(event) 
    { 
     //start = event; 
     event = tok.optional [ std::cout << px::val("== OPTIONAL") << std::endl]; 
    } 

    qi::rule<Iterator> start; 
    qi::rule<Iterator,void(),ascii::space_type> event; 
}; 

ответ

2

Как и большинство духа. Если вы хотите сделать что-то REALISTIC, вам нужно потратить часы на поиск решения, которое не задокументировано, а похоронено в примерах и списках рассылки. Серьезно рассматривая возможность перехода к ragel или flex/bison. Проблема заключается не в том, что механизм недоступен, а в том, что он не документирован.

В этом случае при взгляде на документацию lex один get's щедро вводит в заблуждение, просматривая вызовы aps lex parser, который имеет функцию tokenize_and_phrase_parse. На самом деле это не работает, когда вы пытаетесь использовать его, как qi::phrase_parse, и в документации не объясняется, как подключить шкипера, используя эту функцию.

Проводка получения шкипера пространства в парсер выполняется путем изменения lexer, а затем с использованием недокументированной конструкции qi-skipper, инициализирующей грамматику и правила. Вы можете увидеть это в действии в каталоге примера lex (пример 5). Код, который компилируется и работает:

#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/lex_lexertl.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/cstdint.hpp> 
#include <string> 
#include<exception> 

namespace lex = boost::spirit::lex; 
namespace px = boost::phoenix; 
namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 

template <typename Lexer> 
struct tokens : lex::lexer<Lexer> 
{ 
    tokens() 
     : left_paranthesis("\"{\""), 
     right_paranthesis("\"}\""), 
     colon(":"), 
     namespace_("(?i:namespace)"), 
     event("(?i:event)"), 
     optional("(?i:optional)"), 
     required("(?i:required)"), 
     ordinal("\\d+"), 
     identifier("\\w+") 

    { 
     using boost::spirit::lex::_val; 

     this->self 
      = 
       left_paranthesis [ std::cout << px::val("lpar") << std::endl] 
      | right_paranthesis [ std::cout << px::val("rpar") << std::endl] 
      | colon    [ std::cout << px::val("colon") << std::endl] 
      | namespace_   [ std::cout << px::val("kw namesapce") << std::endl] 
      | event    [ std::cout << px::val("kw event") << std::endl] 
      | optional   [ std::cout << px::val("optional ") << "-->" << _val << "<--" << std::endl] 
      | required   [ std::cout << px::val("required") << std::endl] 
      | ordinal    [ std::cout << px::val("val ordinal (") << _val << ")" << std::endl] 
      | identifier   [std::cout << px::val("val identifier(") << _val << ")" << std::endl]; 


     this->self("WS") = lex::token_def<>("[ \\t\\n]+"); 
    } 


    lex::token_def<> left_paranthesis, right_paranthesis, colon; 
    lex::token_def<lex::omit> namespace_, event, optional, required; 
    lex::token_def<boost::uint32_t> ordinal; 
    lex::token_def<> identifier; 
}; 

template <typename Iterator, typename Lexer> 
struct grammar : qi::grammar<Iterator,qi::in_state_skipper<Lexer> > 
{ 
    template <typename TokenDef> 
    grammar(TokenDef const& tok) 
     : grammar::base_type(event) 
    { 
     //start = event; 
     event = tok.optional [ std::cout << px::val("== OPTIONAL") << std::endl]; 
    } 

    qi::rule<Iterator> start; 
    qi::rule<Iterator, qi::in_state_skipper<Lexer> > event; 
}; 

// std::string test = "namespace{ event { OPtiONAL 124:hello_world RequireD} } "; 

std::string test = " OPTIONAL "; 

int main() 
{ 
    typedef lex::lexertl::token<std::string::iterator, boost::mpl::vector<boost::uint32_t, std::string> > token_type; 
    typedef lex::lexertl::actor_lexer<token_type> lexer_type; 
    typedef tokens<lexer_type>::iterator_type iterator_type; 

    tokens<lexer_type> token_lexer; 
    grammar<iterator_type,tokens<lexer_type>::lexer_def> grammar(token_lexer); 

    std::string::iterator it = test.begin(); 
    iterator_type first = token_lexer.begin(it, test.end()); 
    iterator_type last = token_lexer.end(); 

    bool r; 

    r = qi::phrase_parse(first, last, grammar, qi::in_state("WS")[token_lexer.self]); 

    if(r) 
     ; 
    else 
    { 
     std::cout << "parsing failed" << std::endl; 
    } 
    /* 
    lexer_type::iterator_type iter; 

    try 
    { 
     iter = token_lexer.begin(first,last); 
    } 
    catch(std::exception & e) 
    { 
     std::cout << e.what() << std::endl; 
    } 

    lexer_type::iterator_type end = token_lexer.end(); 

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

Однако, 'lex :: pass_flags :: pass_ignore' отлично документирован, соответствует купюре. Дело в том, что вам не нужен традиционный шкипер. – sehe

+0

Да, честно говоря, этот способ делать вещи делает грамматику еще чище, чем раньше. Если бы я использовал 'pass_ignore', я бы предположил, что мне даже не пришлось бы перескакивать через' qi :: in_state_skipper <> 'обручи в моей грамматике, и лексер молча пропустил бы токены WS? –

+0

Всегда полезно искать [огромное количество отличных (и грустно убранных) спиритических ответов, сделанных sehe] (http://stackoverflow.com/search?q=user:85371+ [boost-spirit]) на этот сайт. [Этот, в частности] (http://stackoverflow.com/search?q=user%3A85371+ [boost-spirit] + lex + skipper) представляется подходящим. – llonesmiz