简体   繁体   English

通过将三个字符串的向量编译为一个结构来增强Spirit Parser,适应不起作用

[英]Boost Spirit Parser with a vector of three strings compiling into a struct, adapt not working

I´ma student and need to write a Parser in C++ with the Boost-Library. 我是一名学生,需要使用Boost-Library用C ++编写解析器。

Therefore I write a grammer in QI because I need to parse into a struct. 因此我在QI中编写了一个语法分析器,因为我需要解析为一个结构。 So far, so good. 到现在为止还挺好。

I will give you some example-code. 我会给你一些示例代码。 I think it is easier than writing the whole program down. 我认为这比编写整个程序要容易。

Description: So first we take a txt-File and read it, then the parser goes over it, says "Parsing is ok!" 说明:因此,首先我们获取一个txt文件并读取它,然后解析器对其进行检查,并说“解析没问题!” and parse into the struct. 并解析为该结构。 Our output is the struct in the console. 我们的输出是控制台中的结构。

That works fine, now to some code examples. 现在对某些代码示例来说,这很好用。 Here you can see the Grammar in Boost Spirit QI: 在这里,您可以看到Boost Spirit 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;

That works fine, the rule for student brings the problem that we have an element with three parts. 很好,学生的规则带来了一个问题,我们有一个包含三个部分的元素。 Matnumber, Points, and mark. Matnumber,点和标记。 That you can imagine what I mean, here the TXT-File which we try to parse: 您可以想象我的意思,这里是我们尝试解析的TXT文件:

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

The last two lines are the rule student. 最后两行是规则学生。 And in the txt-File we have more than these two lines. 在txt文件中,我们不仅有这两行。

That we can take these lines as "student" we wrote a vector in our struct with typedef: 为了将这些行作为“学生”,我们使用typedef在结构中编写了一个向量:

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

then we will use it in our struct: 那么我们将在我们的结构中使用它:

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);

    }
};

Then we have our BOOST_ADAPT_STRUCT like this: 然后我们有这样的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)

)

You see we have the typedef down there. 您会看到下面有typedef。

And then we have our rules in the Grammar. 然后我们在语法中有规则。

    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; 

And there is the hopefully final problem for our project... 我们的项目可能有最后的问题...

We don´t know which datatype the qi:rule needs that the BOOST_ADAPT... works fine with it. 我们不知道BOOST_ADAPT ... qi:rule需要哪种数据类型可以正常工作。 All the other points are strings, but don´t know how to implement the own vector we created. 所有其他点都是字符串,但是不知道如何实现我们创建的自己的向量。

All the other rules are working fine and are in the struct later just the vector makes problems. 所有其他规则都工作正常,并且稍后在结构中,仅矢量产生了问题。

Has somebody an idea about that? 有人对此有想法吗? I can upload more files and code-snippets if you need, but I still think that it´s maybe just a small problem that I can´t see. 如果需要,我可以上传更多文件和代码片段,但我仍然认为这可能只是我看不到的一个小问题。 I look around for many boost topics but did not found the right thing. 我到处寻找许多促进话题,但没有找到正确的东西。

I have to add the info that I am just a beginner, so maybe I did not explain everything right and... yeah. 我必须添加我只是一个初学者的信息,所以也许我没有解释所有正确的信息,是的。 Hope you understand it. 希望你能理解。 Also my english is not the best... 我的英语也不是最好的...

Thank you in advance for your help. 预先感谢您的帮助。

William 威廉

Spirit is a parser generator. Spirit是解析器生成器。 You don't seem to actually parse anything (you just "extract" character sequences, which is more like tokenizing). 您似乎并没有真正解析任何内容(您只是“提取”字符序列,这更像是标记化)。

I'd do this: 我会这样做:

  • use proper data types 使用适当的数据类型
  • use blank for skipping (doesn't include eol ) 使用blank跳过(不包含eol
  • put the eol expectation in the right spot eol期望放在正确的位置
  • put the lexemes in the right spot 将词素放在正确的位置
  • make date_t it's own type 使date_t为自己的类型
  • make student_t it's own type 使student_t为自己的类型
  • FIX the rule to use std::vector<student_t>() instead of ~ fusion::vector<student_t>() (that was a mistake) 修复使用std::vector<student_t>()而不是fusion::vector<student_t>() (这是一个错误)
  • use operator<< to do the printing 使用operator<<进行打印
  • use repeat(n) [ student >> eol ] to parse the expected number of student lines 使用repeat(n) [ student >> eol ]解析学生的预期行数
  • use qi::locals to actually pass the number of students expected into repeat() 使用qi::locals实际将预期的学生人数传递给repeat()

Live On Coliru 生活在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";
    }
}

Output: 输出:

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

As well as 72 lines of debug output: 以及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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM