Проблемы с boost :: spirit :: lex & amp; пробельные

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

Вот лексер:

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

Значение r верно, если в строке есть только один токен. Почему это так?

С уважением
Тобиас

5

Решение

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


В большинстве случаев самый простой способ получить желаемый эффект — это использовать лексизм с одним состоянием с 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

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

Обновить Это заняло у меня чуть больше 10 минут (вааааа) 🙂 Вот сравнительный тест, показывающий, как взаимодействуют состояния лексера, и как использовать разбор Spirit 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
10

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]