необработанное исключение, использующее Boost Spirit для разбора грамматики

Я пытаюсь использовать Boost Spirit для разбора следующей грамматики:
предложение:
существительное глагол
предложение соединение предложение

конъюнкция:
«а также»

имя существительное:
«птицы», «кошки»

глагол:
«Летать» «мяу»

Разбор успешен, когда грамматика включает только существительное >> правило глагола.
когда грамматика изменена, чтобы включить предложение >> соединение >> правило предложения, и я предоставляю неверный ввод, такой как «птицы летают» вместо «птицы», я получаю необработанное исключение при запуске программы.

вот код, который модифицирован из примеров, найденных на Boost Doc

#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <iostream>
#include <string>

using namespace boost::spirit;
using namespace boost::spirit::ascii;

template <typename Lexer>
struct token_list : lex::lexer<Lexer>
{
token_list()
{
noun = "birds|cats";
verb =  "fly|meow";
conjunction = "and";

this->self.add
(noun)
(verb)
(conjunction)
;
}
lex::token_def<std::string> noun, verb, conjunction;
};

template <typename Iterator>
struct Grammar : qi::grammar<Iterator>
{
template <typename TokenDef>
Grammar(TokenDef const& tok)
: Grammar::base_type(sentence)
{
sentence = (tok.noun>>tok.verb)
|
(sentence>>tok.conjunction>>sentence)>>eoi
;
}
qi::rule<Iterator> sentence;
};

int main()
{
typedef lex::lexertl::token<char const*, boost::mpl::vector<std::string>> token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef token_list<lexer_type>::iterator_type iterator_type;

token_list<lexer_type> word_count;
Grammar<iterator_type> g (word_count);

std::string str = "birdsfly";
//std::string str = "birds fly"; this input caused unhandled exception

char const* first = str.c_str();
char const* last = &first[str.size()];

bool r = lex::tokenize_and_parse(first, last, word_count, g);

if (r) {
std::cout << "Parsing passed"<< "\n";
}
else {
std::string rest(first, last);
std::cerr << "Parsing failed\n" << "stopped at: \""<< rest << "\"\n";
}
system("PAUSE");
return 0;
}

2

Решение

Вы оставили рекурсию во второй ветви sentence править.

sentence = sentence >> ....

всегда повторяется в предложении, поэтому вы видите переполнение стека.

Я предлагаю написать правило, например:

sentence =
(tok.noun >> tok.verb)
>> *(tok.conjunction >> sentence)
>> qi::eoi
;

Теперь результат читает

g++ -Wall -pedantic -std=c++0x -g -O0 test.cpp -o test
Parsing failed
stopped at: " fly"

(и неизбежное «sh: PAUSE: команда не найдена», конечно …)

PS. не using namespace Пожалуйста. Вместо:

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

Вот очищенная версия с некоторыми другими материалами, удаленными / исправленными: http://coliru.stacked-crooked.com/view?id=1fb26ca3e8c207979eaaf4592c319316-e223fd4a885a77b520bbfe69dda8fb91

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

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

template <typename Lexer>
struct token_list : lex::lexer<Lexer>
{
token_list()
{
noun        = "birds|cats";
verb        = "fly|meow";
conjunction = "and";

this->self.add
(noun)
(verb)
(conjunction)
;
}

lex::token_def<std::string> noun, verb, conjunction;
};

template <typename Iterator>
struct Grammar : qi::grammar<Iterator>
{
template <typename TokenDef>
Grammar(TokenDef const& tok) : Grammar::base_type(sentence)
{
sentence =
(tok.noun >> tok.verb)
>> *(tok.conjunction >> sentence)
>> qi::eoi
;
}
qi::rule<Iterator> sentence;
};

int main()
{
typedef std::string::const_iterator It;
typedef lex::lexertl::token<It, boost::mpl::vector<std::string>> token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef token_list<lexer_type>::iterator_type iterator_type;

token_list<lexer_type> word_count;
Grammar<iterator_type> g(word_count);

//std::string str = "birdsfly";
const std::string str = "birds fly";

It first = str.begin();
It last  = str.end();

bool r = lex::tokenize_and_parse(first, last, word_count, g);

if (r) {
std::cout << "Parsing passed"<< "\n";
}
else {
std::string rest(first, last);
std::cerr << "Parsing failed\n" << "stopped at: \"" << rest << "\"\n";
}
}
2

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

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

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