2015-02-20 2 views
2

Здравствуйте, я новичок в Boost Spirit, и у меня возникают проблемы с объектом qi :: symbol.Boost Spirit Symbol бросает нарушение доступа

#include <iostream> 
#include <vector> 

#define BOOST_SPIRIT_DEBUG 
#define BOOST_SPIRIT_DEBUG_OUT std::cerr 

#include <boost/config/warning_disable.hpp> 
#include <boost/fusion/adapted/struct/adapt_struct.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/fusion/include/io.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_object.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/spirit/include/phoenix_object.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/qi_symbols.hpp> 
#include <boost/spirit/include/qi_nonterminal.hpp> 
struct Thing 
{ 
    Thing() = default; 

    Thing(std::string s, std::string t) 
    : 
     one(s), 
     two(t) 
    { 
    } 


    std::string one; 
    std::string two; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    Thing, 
    (std::string, one) 
    (std::string, two) 
) 

namespace qi = boost::spirit::qi; 
namespace phx = boost::phoenix; 
namespace ascii = boost::spirit::ascii; 

template <typename Iterator> 
struct parse_things : qi::grammar<Iterator, Thing(), ascii::space_type> 
{ 
    parse_things() : parse_things::base_type(keyword) 
    { 
     qi::symbols<char, Thing> keywords; 
     keywords.add 
      ("One", Thing("ThingOne","ThingTwo")) 
      ("Two", Thing("ThingTwo","ThingOne")); 

     keyword %= keywords; 
     BOOST_SPIRIT_DEBUG_NODE(keyword); 
    } 

    qi::rule<Iterator, Thing(), ascii::space_type> keyword; 
}; 

int main(int argc, const char *argv[]) 
{ 
    Thing t; 
    std::string s("One"); 
    std::string s2("Two"); 
    parse_things<std::string::const_iterator> parser; 

    bool r = qi::phrase_parse(
      std::cbegin(s), 
      std::cend(s), 
      parser, 
      ascii::space, 
      t); 

    assert(r == true); 
    assert(t.one == "ThingOne"); 
    assert(t.two == "ThingTwo"); 
    assert(t.two == "ThingOne"); 
    assert(t.one == "ThingTwo"); 

    return 0; 
} 

Это компилирует для меня на Visual Studio 2014 Update 4, но выдает нарушение прав доступа во время синтаксического анализа. Что я делаю не так?

ответ

2

Вы должны сделать

qi::symbols<char, Thing> keywords; 

являющемуся членом структуры, а не временный локальный конструктор. Ваш парсер будет иметь устаревшие ссылки на структуру данных trie в объекте symbols.

Несколько упрощена программа с большим количеством тестов:

Live On Coliru

//#define BOOST_SPIRIT_DEBUG 
#define BOOST_SPIRIT_DEBUG_OUT std::cerr 

#include <boost/fusion/adapted/struct.hpp> 
#include <boost/fusion/include/io.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/qi_symbols.hpp> 
#include <iostream> 
#include <vector> 

struct Thing 
{ 
    std::string one; 
    std::string two; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    Thing, 
    (std::string, one) 
    (std::string, two) 
) 

namespace qi = boost::spirit::qi; 
namespace phx = boost::phoenix; 
namespace ascii = boost::spirit::ascii; 

template <typename Iterator> 
struct parse_things : qi::grammar<Iterator, Thing(), ascii::space_type> 
{ 
    parse_things() : parse_things::base_type(keyword) 
    { 
     keywords.add 
      ("One", Thing{"ThingOne","ThingTwo"}) 
      ("Two", Thing{"ThingTwo","ThingOne"}); 

     keyword %= keywords; 
     BOOST_SPIRIT_DEBUG_NODE(keyword); 
    } 

    qi::symbols<char, Thing> keywords; 
    qi::rule<Iterator, Thing(), ascii::space_type> keyword; 
}; 

int main() 
{ 
    const parse_things<std::string::const_iterator> parser; 

    for (std::string const s : { "One", "Two", "Three" }) 
    { 
     auto f = begin(s), l = end(s); 
     Thing data; 

     bool ok = qi::phrase_parse(f,l,parser,ascii::space,data); 

     std::cout << s << ": " << std::boolalpha << ok << ", " << boost::fusion::as_vector(data) << '\n'; 
     if (f != l) 
      std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n"; 
    } 
} 

Печать

One: true, (ThingOne ThingTwo) 
Two: true, (ThingTwo ThingOne) 
Three: false, () 
Remaining unparsed: 'Three' 
+0

Теперь кажется очевидным! Большое спасибо! –

+0

Спасибо, вы помогаете мне с аналогичной проблемой. Не могли бы вы объяснить, почему символы <> парсеров должны быть объявлены в области полномочий, в то время как другие многозадачные парсеры (такие как «qi :: uint_type uint_;» в грамматике [этого учебника] (http://www.boost.org/ doc/libs/1_61_0/libs/spirit/example/qi/compiler_tutorial/calc5.cpp)) можно объявить временным локальным в конструкторе парсера? –

+0

@die_hoernse Символы с точки зрения состояния и используются «по-ref». Я не уверен, что использование этой ссылки в учебнике полностью безопасно. Я думаю, что это может быть технически UB, если каким-то образом партизаны без учета состояния не принимаются по-ref. Если вы не сделаете символы членами, вы получите следующее: http://stackoverflow.com/questions/30744000/parsing-into-stdvectorstring-with-spirit-qi-getting-segfaults-or-assert-fai/30744484 # 30744484 – sehe