2015-04-29 1 views
1

Я студент, и мне нужно написать Parser на C++ с Boost-Library.Boost Spirit Parser с вектором трех строк, скомпилированных в структуру, не адаптируется к работе

Поэтому я пишу грамматик в QI, потому что мне нужно проанализировать структуру. Все идет нормально.

Я приведу вам примерный код. Я думаю, что это проще, чем записать всю программу.

Описание: Итак, сначала мы берем txt-файл и читаем его, а затем анализируем его, говорит: «Разбор в порядке!». и проанализируйте структуру. Наш вывод - это структура в консоли.

Это хорошо работает, теперь к некоторым примерам кода. Здесь вы можете увидеть грамматику в Boost Духа QI:

subject %= lexeme[lit("Fach: ") >> +(char_("a-zA-Z")) >> lit("\n")]; //works! 

     dozent %= lexeme[lit("Dozent: ") >> +(char_("a-zA-Z")) >> lit("\n")]; 

     date %= lexeme[lit("Datum: ") >> digit >> digit >> lit("-") >> digit >> digit >> lit("-") >> digit >> digit >> digit >> digit >> lit("\n")]; 

     count %= lexeme[lit("Anzahl: ") >> +digit >> lit("\n")]; 

     points %= lexeme[+digit >> lit("\t")]; 

     mark %= lexeme[digit >> lit("\n")]; 

     matnumber %= lexeme[(digit >> digit >> digit >> punct >> digit >> digit >> digit) >> lit("\t")]; 

     student %= matnumber >> points >> mark; 

     start %= subject >> dozent >> date >> count >> student; 

Это прекрасно работает, правило для студентов приносит проблему, что у нас есть элемент с тремя частями. Matnumber, Points и mark. Что вы можете себе представить, что я имею в виду, здесь TXT-файл, который мы пытаемся разобрать:

Subject: Physics 
Dozent: Wayne 
Datum: 20-10-2014 
Anzahl: 20 
729.888 33 5 
185.363 35 5 

Последние две строки студент правило. И в txt-файле у нас больше этих двух строк.

То, что мы можем взять эти строки, как «студент» мы написали вектор в нашей структуре с ЬурейиМ:

typedef boost::fusion::vector<string, string, string> student_t; 

, то мы будем использовать его в нашей структуре:

struct klausur 
{ 
    string str_subject; 
    string str_dozent; 
    string str_date; 
    string count; 
    string matr_nr; 
    string points; 
    string mark; 
    string ende; 
    student_t student; 

    void ToString() 
    { 
     cout << "Struct.Fach: " << str_subject << endl; 
     cout << "Struct.Dozent: " << str_dozent << endl; 
     cout << "Struct.Datum: " << str_date << endl; 
     cout << "Struct.Anzahl: " << count << endl; 
     cout << "Struct.Mat_Nr: " << matr_nr << endl; 
     cout << "Struct.Punkte: " << points << endl; 
     cout << "Struct.Note: " << mark << endl; 
     cout << "Struct.Student<0>: " << vec::at_c<0>(student); 
     cout << "Struct.Student<1>: " << vec::at_c<1>(student); 
     cout << "Struct.Student<2>: " << vec::at_c<2>(student); 

    } 
}; 

Тогда мы имеем наш BOOST_ADAPT_STRUCT так:

BOOST_FUSION_ADAPT_STRUCT(
client::klausur, 
(string, str_subject) 
(string, str_dozent) 
(string, str_date) 
(string, count) 
(string, matr_nr) 
(string, points) 
(string, mark) 
(student_t, student) 

)

Вы видите, что там есть typedef.

И тогда у нас есть наши правила в грамматике.

qi::rule<Iterator, string(), ascii::space_type> subject; 
    qi::rule<Iterator, string(), ascii::space_type> dozent; 
    qi::rule<Iterator, string(), ascii::space_type> date; 
    qi::rule<Iterator, string(), ascii::space_type> count; 
    qi::rule<Iterator, string(), ascii::space_type> matnumber; 
    qi::rule<Iterator, string(), ascii::space_type> points; 
    qi::rule<Iterator, string(), ascii::space_type> mark; 
    qi::rule<Iterator, boost::fusion::vector<boost::fusion::vector<std::string, std::string, std::string> >()> student; 

И есть, надеюсь, последняя проблема для нашего проекта ...

Мы не знаем, который DATATYPE й: правила необходимо, чтобы BOOST_ADAPT ... отлично работает с ним. Все остальные точки являются строками, но не знают, как реализовать собственный вектор, который мы создали.

Все остальные правила работают нормально и находятся в структуре позже, так как только вектор создает проблемы.

Есть ли у кого-то представление об этом? Я могу загрузить больше файлов и фрагментов кода, если вам нужно, но я все же думаю, что это может быть небольшая проблема, которую я не вижу. Я оглядываюсь на многие темы повышения, но не нашел правильной вещи.

Я должен добавить информацию о том, что я просто начинающий, поэтому, возможно, я не все объяснил правильно и ... да. Надеюсь, вы это понимаете. Также мой английский не лучший ...

Заранее благодарю вас за помощь.

William

+0

Почему нет шкипер на последнем правиле? Какие ошибки вы получаете? Вы пробовали правило ? Вы уверены, что student_t не находится в клиенте пространства имен? У вас проблемы с разбором нескольких учеников? В вашем стартовом правиле содержится только один студент. Попробуйте клиенскую звезду. – FRob

+0

Эй, был шкипер, но для тестирования я его удалил. Я всегда получаю ошибку, что он не может разрешить оператор в более глубокой библиотечной функции. Я уверен, что student_t находится в клиенте пространства имен, это проблема? На данный момент для тестирования был только один студент. Обычно правило было бы ... '+ student'. Заранее благодарю вас за помощь. –

ответ

0

Spirit - это генератор синтаксического анализатора. Вы, кажется, ничего не разбираете (вы просто «извлекаете» последовательности символов, что больше похоже на токенизацию).

Я хотел бы сделать это:

  • используют собственные типы данных
  • использование blank для пропуска (не включает в себя eol)
  • поставил eol ожидания в нужном месте
  • положить lexemes в нужном месте
  • date_t его собственный тип
  • сделать student_t это собственный тип
  • FIX правило использовать std::vector<student_t>() вместо ~ fusion::vector<student_t>() (это было ошибкой)
  • использование operator<< сделать печать
  • использование repeat(n) [ student >> eol ] для анализа ожидаемого количества студентов линий
  • использование qi::locals фактически передать количество студентов ожидается в repeat()

Live On Coliru

#define BOOST_SPIRIT_DEBUG 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/adapted/struct.hpp> 
#include <iostream> 
#include <iomanip> 

namespace qi = boost::spirit::qi; 
namespace vec = boost::fusion; 

struct student_t { 
    std::string matr_nr; 
    unsigned points; 
    int   mark; 
}; 

struct date_t { 
    unsigned dd, mm, yyyy; 

    friend std::ostream& operator<<(std::ostream& os, date_t const& d) { 
     std::ostream local(os.rdbuf()); 
     local << std::setw(2) << std::setfill('0') << d.dd << 
      "-" << std::setw(2) << std::setfill('0') << d.mm << 
      "-" << std::setw(4) << std::setfill('0') << d.yyyy; 
     return os; 
    } 
}; 

BOOST_FUSION_ADAPT_STRUCT(student_t, 
     (std::string,matr_nr)(unsigned,points)(int,mark)) 
BOOST_FUSION_ADAPT_STRUCT(date_t, 
     (unsigned,dd)(unsigned,mm)(unsigned,yyyy)) 

struct klausur { 
    std::string str_subject; 
    std::string str_dozent; 
    date_t date; 

    unsigned count; 
    std::vector<student_t> students; 

    friend std::ostream& operator<<(std::ostream& os, klausur const& k) 
    { 
     os << "Fach: " << k.str_subject << '\n'; 
     os << "Dozent: " << k.str_dozent << '\n'; 
     os << "Datum: " << k.date  << '\n'; 
     os << "Anzahl: " << k.count  << '\n'; 
     for (auto& s : k.students) { 
      os << "Mat_Nr: " << s.matr_nr << '\n'; 
      os << "Punkte: " << s.points << '\n'; 
      os << "Note: " << s.mark << '\n'; 
     } 
     return os; 
    } 
}; 

BOOST_FUSION_ADAPT_STRUCT(klausur, 
     (std::string      , str_subject) 
     (std::string      , str_dozent) 
     (date_t       , date) 
     (unsigned      , count) 
     (std::vector<student_t>   , students) 
    ) 

template <typename Iterator, typename Skipper = qi::ascii::blank_type> 
struct grammar : qi::grammar<Iterator, klausur(), Skipper> { 
    grammar() : grammar::base_type(start) { 
     using namespace qi; 
     subject = "Fach:" >> lexeme [ +~char_('\n') ] >> eol; 
     dozent = "Dozent:" >> lexeme [ +~char_('\n') ] >> eol; 
     date  = "Datum:" >> lexeme [uint_ >> '-' >> uint_ >> '-' >> uint_] >> eol; 
     count  = "Anzahl:" >> uint_ >> eol; 
     points = uint_; 
     mark  = int_parser<int, 10, 1, 1>(); // single base-10 digit 

     // no clue about this format; what is it? Just a real number? 
     matnumber = lexeme[digit >> digit >> digit >> punct >> digit >> digit >> digit]; 

     student = matnumber >> points >> mark; 

     _a_type expected; 
     klausur_ %= subject 
       >> dozent 
       >> date 
       >> count   [ expected = _1 ] 
       >> repeat(expected) [ student >> (eol|eoi) ] 
       ; 

     start  = klausur_; 

     BOOST_SPIRIT_DEBUG_NODES((start)(klausur_)(student)(matnumber)(mark)(points)(count)(date)(dozent)(subject)) 
    } 

    private: 
    qi::rule<Iterator, klausur(), Skipper> start; 
    qi::rule<Iterator, klausur(), Skipper, qi::locals<unsigned> > klausur_; 

    qi::rule<Iterator, std::string() , Skipper> subject; 
    qi::rule<Iterator, std::string() , Skipper> dozent; 
    qi::rule<Iterator, date_t(),   Skipper> date; 
    qi::rule<Iterator, unsigned()  , Skipper> count; 
    qi::rule<Iterator, std::string() , Skipper> matnumber; 
    qi::rule<Iterator, unsigned()  , Skipper> points; 
    qi::rule<Iterator, int()   , Skipper> mark; 
    qi::rule<Iterator, student_t()  , Skipper> student; 
}; 

int main() { 
    using It = std::string::const_iterator; 
    std::string const input = 
R"(Fach: Physics 
Dozent: Wayne 
Datum: 20-10-2014 
Anzahl: 2 
729.888 33 5 
185.363 35 5)"; 

    It f = input.begin(), l = input.end(); 

    grammar<It> g; 
    klausur k; 
    bool ok = qi::phrase_parse(f, l, g, qi::ascii::blank, k); 

    if (ok) { 
     std::cout << "Parse success\n"; 
     std::cout << k; 
    } else { 
     std::cout << "Parse failed\n"; 
    } 

    if (f!=l) { 
     std::cout << "Remaining input: '" << std::string(f,l) << "'\n"; 
    } 
} 

Выход:

Parse success 
Fach: Physics 
Dozent: Wayne 
Datum: 20-10-2014 
Anzahl: 2 
Mat_Nr: 729.888 
Punkte: 33 
Note: 5 
Mat_Nr: 185.363 
Punkte: 35 
Note: 5 

, а также 72 строки вывода отладки:

<start> 
    <try>Fach: Physics\nDozent</try> 
    <klausur_> 
    <try>Fach: Physics\nDozent</try> 
    <subject> 
     <try>Fach: Physics\nDozent</try> 
     <success>Dozent: Wayne\nDatum:</success> 
     <attributes>[[P, h, y, s, i, c, s]]</attributes> 
    </subject> 
    <dozent> 
     <try>Dozent: Wayne\nDatum:</try> 
     <success>Datum: 20-10-2014\nAn</success> 
     <attributes>[[W, a, y, n, e]]</attributes> 
    </dozent> 
    <date> 
     <try>Datum: 20-10-2014\nAn</try> 
     <success>Anzahl: 2\n729.888 33</success> 
     <attributes>[[20, 10, 2014]]</attributes> 
    </date> 
    <count> 
     <try>Anzahl: 2\n729.888 33</try> 
     <success>729.888 33 5\n185.36</success> 
     <attributes>[2]</attributes> 
    </count> 
    <student> 
     <try>729.888 33 5\n185.36</try> 
     <matnumber> 
     <try>729.888 33 5\n185.36</try> 
     <success> 33 5\n185.363 35 5</success> 
     <attributes>[[7, 2, 9, ., 8, 8, 8]]</attributes> 
     </matnumber> 
     <points> 
     <try> 33 5\n185.363 35 5</try> 
     <success> 5\n185.363 35 5</success> 
     <attributes>[33]</attributes> 
     </points> 
     <mark> 
     <try> 5\n185.363 35 5</try> 
     <success>\n185.363 35 5</success> 
     <attributes>[5]</attributes> 
     </mark> 
     <success>\n185.363 35 5</success> 
     <attributes>[[[7, 2, 9, ., 8, 8, 8], 33, 5]]</attributes> 
    </student> 
    <student> 
     <try>185.363 35 5</try> 
     <matnumber> 
     <try>185.363 35 5</try> 
     <success> 35 5</success> 
     <attributes>[[1, 8, 5, ., 3, 6, 3]]</attributes> 
     </matnumber> 
     <points> 
     <try> 35 5</try> 
     <success> 5</success> 
     <attributes>[35]</attributes> 
     </points> 
     <mark> 
     <try> 5</try> 
     <success></success> 
     <attributes>[5]</attributes> 
     </mark> 
     <success></success> 
     <attributes>[[[1, 8, 5, ., 3, 6, 3], 35, 5]]</attributes> 
    </student> 
    <success></success> 
    <attributes>[[[P, h, y, s, i, c, s], [W, a, y, n, e], [20, 10, 2014], 2, [[[7, 2, 9, ., 8, 8, 8], 33, 5], [[1, 8, 5, ., 3, 6, 3], 35, 5]]]]</attributes><locals>(2)</locals> 
    </klausur_> 
    <success></success> 
    <attributes>[[[P, h, y, s, i, c, s], [W, a, y, n, e], [20, 10, 2014], 2, [[[7, 2, 9, ., 8, 8, 8], 33, 5], [[1, 8, 5, ., 3, 6, 3], 35, 5]]]]</attributes> 
</start> 
+0

Эй, спасибо за вашу быструю помощь и за код. Я пытаюсь протестировать его в своей visual studio 2012, и он всегда говорит, что я не могу использовать его в качестве используемой директивы. Вся другая информация, которую я буду тестировать и реализовать в своей программе. Я не специалист по этому вопросу, поэтому мне потребуется некоторое время. Спасибо 'using It = std :: string :: const_iterator;' это часть, которая создает проблемы –

+0

Просто замените ее typedef :) – sehe

+0

Теперь это работает. Спасибо :) 'typedef std :: string :: const_iterator It;' Осталась только одна ошибка: визуальная студия не разрешает строки в нескольких строках, я пытаюсь исправить это с помощью '\ n' –