2012-05-16 2 views
3

Мне интересно, есть ли способ в boost :: spirit :: lex записать значение токена обратно во входной поток (возможно, после редактирования) и повторное сканирование. В основном я ищу такую ​​функциональность, как функция unput() в Flex.Boost spirit lex записать значение токена обратно в поток ввода

Спасибо!

+0

Что вы пытаетесь достичь? Я имею в виду, в каком контексте вам нужно будет использовать unput()? Если вы покажете пример, я могу показать вам, как я это сделаю (возможно, используя состояния Lexer) – sehe

+0

В принципе, мне нужен лексер, чтобы он соответствовал идентификатору, за которым следует открытый паз «abc (« как один токен, и верните его обратно во входной поток, когда в начале строки появится параграф типа «(abc»). Следующим шагом будет лексер, который будет сканировать его снова, но как два отдельных токена (токен-маркер, а затем токен идентификатора) –

+0

Хорошо, я отправил свой ответ на этот вопрос, дайте мне знать, если я неправильно понял _goal_. – sehe

ответ

0

я в конечном итоге реализации моего собственного unput() функциональность следующим образом:

struct unputImpl 
    { 
     template <typename Iter1T, typename Iter2T, typename StrT> 
     struct result { 
     typedef void type; 
     }; 

     template <typename Iter1T, typename Iter2T, typename StrT> 
     typename result<Iter1T, Iter2T, StrT>::type operator()(Iter1T& start, Iter2T& end, StrT str) const { 
     start -= (str.length() - std::distance(start, end)); 
     std::copy(str.begin(), str.end(), start); 
     end = start; 
     } 
    }; 

    phoenix::function<unputImpl> const unput = unputImpl(); 

Это может быть использован как:

this->self += lex::token_def<lex::omit>("{SYMBOL}\\(") 
     [ 
      unput(_start, _end, "(" + construct<string>(_start, _end - 1) + " "), 
      _pass = lex::pass_flags::pass_ignore 
     ]; 

Если длина бессмысленной строки является большой r, чем согласованная длина токена, он переопределит часть ранее разобранного ввода. Вещь, о которой вам нужно позаботиться, состоит в том, чтобы убедиться, что входная строка имеет достаточно пустое пространство в самом начале, чтобы обрабатывать случай, когда вызов unput() вызывается для первого совпадающего токена.

3

Похоже, вы просто хотите принять токены в разных порядках, но с тем же значением.

Без дополнительной информации, здесь приведен полный образец, который показывает, как это будет сделано, выставляя идентификатор независимо от порядка ввода. Выход:

Input 'abc(' Parsed as: '(abc' 
Input '(abc' Parsed as: '(abc' 

Код

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/lex_lexertl.hpp> 
#include <iostream> 
#include <string> 

using namespace boost::spirit; 

///// LEXER 
template <typename Lexer> 
struct tokens : lex::lexer<Lexer> 
{ 
    tokens() 
    { 
     identifier = "[a-zA-Z][a-zA-Z0-9]*"; 
     paren_open = '('; 

     this->self.add 
      (identifier) 
      (paren_open) 
      ; 
    } 

    lex::token_def<std::string> identifier; 
    lex::token_def<lex::omit> paren_open; 
}; 

///// GRAMMAR 
template <typename Iterator> 
struct grammar : qi::grammar<Iterator, std::string()> 
{ 
    template <typename TokenDef> 
     grammar(TokenDef const& tok) : grammar::base_type(ident_w_parenopen) 
    { 
     ident_w_parenopen = 
       (tok.identifier >> tok.paren_open) 
      | (tok.paren_open >> tok.identifier) 
      ; 
    } 
    private: 
    qi::rule<Iterator, std::string()> ident_w_parenopen; 
}; 

///// DEMONSTRATION 
typedef std::string::const_iterator It; 

template <typename T, typename G> 
void DoTest(std::string const& input, T const& tokens, G const& g) 
{ 
    It first(input.begin()), last(input.end()); 

    std::string parsed; 
    bool r = lex::tokenize_and_parse(first, last, tokens, g, parsed); 

    if (r) { 
     std::cout << "Input '" << input << "' Parsed as: '(" << parsed << "'\n"; 
    } 
    else { 
     std::string rest(first, last); 
     std::cerr << "Parsing '" << input << "' failed\n" << "stopped at: \"" << rest << "\"\n"; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    typedef lex::lexertl::token<It, boost::mpl::vector<std::string> > token_type; 
    typedef lex::lexertl::lexer<token_type> lexer_type; 
    typedef tokens<lexer_type>::iterator_type iterator_type; 

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

    DoTest("abc(", tokens, g); 
    DoTest("(abc", tokens, g); 
} 
+0

Спасибо sehe. К сожалению, экспорт проблемы в парсер не является хорошим вариантом в моем случае по двум причинам: 1) I необходимо различать случай, когда открытый парен непосредственно следует идентификатору от того, где они разделены любым символом пробела (в этом случае парсер должен соответствовать другому правилу). 2) Существует много других ключевых слов, которые нужно обрабатывать одинаково (а не только идентификаторы), поэтому это приведет к удвоению количества производств, необходимых для синтаксического анализа этих ключевых слов (когда парен предшествует ключевому слову и одному, когда ему это удастся)). –

+0

@HaithamGad Позвольте мне сказать следующее: писать качественный вопрос сложно. _Вот почему. Я дам ваши новые ограничения, некоторые подумали – sehe

+0

Да, извините за это :) и спасибо за вашу помощь! –

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