Как использовать косую черту в шаблонах Spirit Lex?

Код ниже отлично компилируется с

clang++ -std=c++11 test.cpp -o тест

Но при запуске выбрасывается исключение

завершение, вызванное после создания экземпляра 'boost::lexer::runtime_error' what(): Lookahead ('/') пока не поддерживается.

Проблема заключается в косой черте (/) во вводе и/или регулярном выражении (строки 12 и 39), но я не могу найти решение, как правильно ее избежать. Любые подсказки?

#include <string>
#include <cstring>
#include <boost/spirit/include/lex.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

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

std::string regex("FOO/BAR");

template <typename Type>
struct Lexer : boost::spirit::lex::lexer<Type> {
    Lexer() : foobar_(regex) {
        this->self.add(foobar_);
    }
    boost::spirit::lex::token_def<std::string> foobar_;
};

template <typename Iterator, typename Def>
struct Grammar
  : qi::grammar <Iterator, qi::in_state_skipper<Def> > {
    template <typename Lexer> Grammar(const Lexer & _lexer);
    typedef qi::in_state_skipper<Def> Skipper;
    qi::rule<Iterator, Skipper> rule_;
};
template <typename Iterator, typename Def>
template <typename Lexer>
Grammar<Iterator, Def>::Grammar(const Lexer & _lexer)
  : Grammar::base_type(rule_) {
    rule_ = _lexer.foobar_;
}

int main() {
    // INPUT
    char const * first("FOO/BAR");
    char const * last(first + strlen(first));

    // LEXER
    typedef lex::lexertl::token<const char *> Token;
    typedef lex::lexertl::lexer<Token> Type;
    Lexer<Type> l;

    // GRAMMAR
    typedef Lexer<Type>::iterator_type Iterator;
    typedef Lexer<Type>::lexer_def Def;
    Grammar<Iterator, Def> g(l);

    // PARSE
    bool ok = lex::tokenize_and_phrase_parse (
        first
      , last
      , l
      , g
      , qi::in_state("WS")[l.self]
    );

    // CHECK
    if (!ok || first != last) {
        std::cout << "Failed parsing input file" << std::endl;
        return 1;
    }
    return 0;
}

person user1587451    schedule 14.07.2015    source источник
comment
Я бы сказал, упростите это, чтобы он работал без / (т.е. просто читал и анализировал FOOBAR). Затем, как только вы заработаете, попробуйте добавить / обратно.   -  person Cornstalks    schedule 14.07.2015


Ответы (1)


Как указывает sehe, /, вероятно, предназначен для использования в качестве опережающего оператора, вероятно, после синтаксис flex. К сожалению, Spirit не использует более нормальный синтаксис просмотра вперед (не то чтобы я думаю, что другой синтаксис более элегантен; он просто сбивает с толку всеми тонкими вариациями синтаксиса регулярных выражений).

Если вы посмотрите на re_tokeniser.hpp:

// Not an escape sequence and not inside a string, so
// check for meta characters.
switch (ch_)
{
    ...
    case '/':
        throw runtime_error("Lookahead ('/') is not supported yet.");
        break;
    ...
}

Он считает, что вы не находитесь ни в escape-последовательности, ни внутри строки, поэтому проверяет метасимволы. / считается метасимволом для опережающего просмотра (даже если эта функция не реализована) и должен быть экранирован, несмотря на то, что в документации Boost это вообще не упоминается.

Попробуйте экранировать / (не во входных данных) обратной косой чертой (т.е. "\\/" или "\/" при использовании необработанной строки). В качестве альтернативы другие предложили использовать [/].

Я бы посчитал это ошибкой в ​​документации Spirit Lex, потому что в ней не указано, что / нужно экранировать.


Редактировать: благодарность sehe и cv_and_he, которые помогли исправить некоторые из моих предыдущих мыслей. Если они опубликуют ответ здесь, обязательно дайте им +1.

person Cornstalks    schedule 14.07.2015
comment
Я пытался избежать косой черты с помощью \\/, \/ и []. Никакого решения не получилось. - person user1587451; 14.07.2015
comment
Однако он не работает с другой ошибкой. (Конкретно: Assertion failed: (std::size_t(~0) != state), function set_lexer_state, file /usr/local/include/boost/spirit/home/lex/qi/state_switcher.hpp, line 87.). Я не очень хорошо знаю Spirit, но похоже, что у вас есть еще одна проблема в вашем лексере/парсере. Этот ответ должен быть правильным для решения проблемы косой черты. Что касается другого вопроса... Я не уверен, что сказать. - person Cornstalks; 14.07.2015
comment
Это не упорядоченный выбор. Также ссылка на нотацию спецификации PEG является отвлекающим маневром, потому что мы не указываем здесь грамматику. Мы указываем шаблоны токенов. Они используют подмножество регулярных выражений: boost.org/doc/libs/1_58_0/libs/spirit/doc/html/spirit/lex/ (и, кстати, это то, что предлагалось в сообщении об ошибке) - person sehe; 14.07.2015
comment
@Cornstalks Новая ошибка связана с тем, что состояние WS не существует, и шкипер пытается его использовать. Этот пример пытается добавить указанное состояние и, кажется, работает. - person llonesmiz; 14.07.2015
comment
@sehe: Если это не упорядоченный выбор, то что это? По вашей ссылке / не является специальным символом, поэтому его следует распознавать. Тем не менее, это не так, и вызывает ошибку, если она не экранирована. - person Cornstalks; 14.07.2015
comment
@cv_and_he: Хорошо! Хорошее наблюдение. - person Cornstalks; 14.07.2015
comment
@Cornstalks Я не знаю. Я не написал ответ по какой-то причине :) Однако сообщение об ошибке, похоже, содержит довольно вескую подсказку. Просто потому, что вы не можете думать о чем-то другом, это не делает его упорядоченным выбором и не связано с ПЭГ. - person sehe; 14.07.2015
comment
@sehe Я тоже не знаю, но небольшое гугление заставляет меня думать, что ошибка относится к Spirit.Lex, не поддерживающему эту функцию флекс. - person llonesmiz; 14.07.2015
comment
@sehe: Что ж, я думаю, у вас есть достойная точка зрения, и вы включили свои мысли в мой ответ. - person Cornstalks; 14.07.2015