首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >促进精神语法eol

促进精神语法eol
EN

Stack Overflow用户
提问于 2013-08-06 10:15:37
回答 1查看 1.4K关注 0票数 1

我试图解析以下形式的文件:

代码语言:javascript
复制
// comment bla bla
[sectionname]
key = value
key2=value2


// comment
key = value

[anothersection]
...

使用以下代码。不幸的是,它将最后一个eol报告为一个错误,尽管结尾的所有eol都应该被以下代码所接受:(*qi::eol > -(sectionGrammar > *(+qi::eol > sectionGrammar)) > *qi::eol),

此外,我真的不知道如何正确地解析注释,而不接受下一个键值对所需的eol,这也是为什么我没有把它放在船长(ascii::placed )中的原因。

最后一个问题是,我不知道如何在不复制部分的情况下将部分添加到boost::ptr_vector中。

这是我的密码:

代码语言:javascript
复制
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp> // for more detailed error information

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <boost/bind.hpp>
#include <boost/spirit/home/phoenix/core/argument.hpp>

#include <boost/foreach.hpp>

#include "txt.hpp"

// Only use in global namespace!
BOOST_FUSION_ADAPT_STRUCT(
    wc3lib::map::Txt::Section,
    (wc3lib::string, name)
    (wc3lib::map::Txt::Pairs, entries)
)

namespace wc3lib
{

namespace map
{

namespace client
{

    using namespace boost::spirit;
//using namespace boost::spirit::qi;
using qi::double_;
using qi::phrase_parse;
using standard::space;
using boost::phoenix::ref;

//typedef BOOST_TYPEOF(space | lit("//") >> *(standard::char_ - qi::eol) >> qi::eol) SkipperType;

/*
 * Doesn't skip eols since value pairs are separated linewise which therefore can be specified easier in the rules
 */
template<typename Iterator>
struct CommentSkipper : public qi::grammar<Iterator> {

    qi::rule<Iterator> skip;

    CommentSkipper() : CommentSkipper::base_type(skip, "PL/0")
    {
        skip = ascii::blank | lit("//") >> *(standard::char_ - qi::eol) >> qi::eol;
    }
};

template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
struct KeyValueSquence : qi::grammar<Iterator, Txt::Pairs(), Skipper>
{
    //Txt::Pairs::value_type
    qi::rule<Iterator, Txt::Pairs(), Skipper> query; // NOTE first rule used as parameter for base_type does always need the skipper type of the grammar
    qi::rule<Iterator, std::pair<string, string>(), Skipper> pair;
    qi::rule<Iterator, string()> key, value;

    KeyValueSquence() : KeyValueSquence::base_type(query)
    {
        query =  pair > *(pair); // use only > for backtracking
        pair  =  +qi::eol > key > lit('=') > -value; // -('=' >> value)
        key   =  standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9");
        value = +(standard::char_ - qi::eol); // values can be empty or all characters except eol which indicates the and of the value
    }
};

template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
struct SectionRule : qi::grammar<Iterator, Txt::Section(), Skipper>
{
    qi::rule<Iterator, Txt::Section(), Skipper> query;
    qi::rule<Iterator, string()> name;
    qi::rule<Iterator, Txt::Pairs(), Skipper> entries;

    KeyValueSquence<Iterator, Skipper> keyValueSequence;

    SectionRule() : SectionRule::base_type(query)
    {
        query =  name > -entries;
        name  =  lit('[') > standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9") > lit(']');
        entries = keyValueSequence;
    }
};

template <typename Iterator>
bool parse(Iterator first, Iterator last, Txt::Sections &sections)
{
    SectionRule<Iterator> sectionGrammar;
    CommentSkipper<Iterator> commentSkipper;
    std::vector<Txt::Section> tmpSections;

    bool r = boost::spirit::qi::phrase_parse(
    first,
    last,
    (*qi::eol > -(sectionGrammar > *(+qi::eol > sectionGrammar)) > *qi::eol),
    // comment skipper
    commentSkipper,
    tmpSections //sections store into "sections"!
    );

    if (first != last) // fail if we did not get a full match
    {
        return false;
    }

    // TODO temporary workaround, add sections directly from heap to vector
    BOOST_FOREACH(std::vector<Txt::Section>::const_reference ref, tmpSections) {
        std::auto_ptr<Txt::Section> s(new Txt::Section());
        s->name = ref.name;
        s->entries = ref.entries;
        sections.push_back(s);
    }

    return r;
}

}
</code>
EN

回答 1

Stack Overflow用户

发布于 2013-08-06 13:23:13

从评论中

代码语言:javascript
复制
// use only > for backtracking

我觉得你理解错了。实际上,>将防止回溯超过该点,因为它要求下一个令牌。

为了展示一些技巧,我模拟了假定丢失的标题:

代码语言:javascript
复制
// #include "txt.hpp"
// minimal mockup
namespace wc3lib { 
    using std::string;

    namespace map { namespace Txt { 
            typedef std::map<string, string> Pairs;

            struct Section
            {
                string name;
                Pairs entries;
            };

            typedef std::vector<Section> Sections;
    } }
}

现在,我已经“修正”了您的代码,以演示如何做

  • 调试
  • 错误处理
  • 期望值(我选择了“非严格”的解决方案,因为我没有时间仔细观察哪些期望是有意义的)

看到它在 柯尔鲁现场直播

备注

  • 请不要在命名空间范围内使用using namespace。相反,使用方便的命名空间别名: 命名空间气=增强::灵:气;命名空间ascii = boost::spirit::ascii;
  • 请不要(不要)使用auto_ptr<>。它容易出错、过时、过时、不建议使用、不灵活:/如果您的unique_ptr必须在堆中包含节,那么请使用(为什么?)
  • 期望流的结束以及eol终止您的行.
  • 小心点名。
代码语言:javascript
复制
- `query` was double used as a rule name
- are you parsing sections or queries or `KeyValueSquence`s? 
- consider using `section_header` instead of `name` etc. 

我确实有一种感觉,如果用更仔细的名字命名,就不会出现一些混乱。

  • 考虑将语法合并为一个语法,除非
代码语言:javascript
复制
- your real grammar is way more complicated (at this level, that seems to be irrelevant, since you could still group these three grammars into one subgrammar)
- you absolutely need to split the grammars across translation units

不加进一步的限制:

代码语言:javascript
复制
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>

#include <boost/fusion/adapted.hpp>
#include <boost/foreach.hpp>
#include <map>

// #include "txt.hpp"
// minimal mockup
namespace wc3lib { 
    using std::string;

    namespace map { namespace Txt { 
            typedef std::map<string, string> Pairs;

            struct Section
            {
                string name;
                Pairs entries;
            };

            typedef std::vector<Section> Sections;
    } }
}

// Only use in global namespace!
BOOST_FUSION_ADAPT_STRUCT(
    wc3lib::map::Txt::Section,
    (wc3lib::string, name)
    (wc3lib::map::Txt::Pairs, entries)
)

namespace wc3lib { namespace map { namespace client {

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

    /*
     * Doesn't skip eols since value pairs are separated linewise which therefore can be specified easier in the rules
     */
    template<typename Iterator>
    struct CommentSkipper : public qi::grammar<Iterator> {

        qi::rule<Iterator> skip;

        CommentSkipper() : CommentSkipper::base_type(skip, "PL/0")
        {
            using namespace qi;
            skip = ascii::blank | (lit("//") >> *(standard::char_ - eol) >> eol);

            BOOST_SPIRIT_DEBUG_NODES((skip));
        }
    };

    template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
    struct KeyValueSquence : qi::grammar<Iterator, Txt::Pairs(), Skipper>
    {
        qi::rule<Iterator, Txt::Pairs(), Skipper> pairs; // NOTE first rule used as parameter for base_type does always need the skipper type of the grammar
        qi::rule<Iterator, std::pair<string, string>(), Skipper> pair;
        qi::rule<Iterator, string()> key, value;

        KeyValueSquence() : KeyValueSquence::base_type(pairs)
        {
            using namespace qi;

            pairs = +pair; // use only > for backtracking

            // these had a problem with backtracking (failing the rule at the end of a section)
            pair  = +eol > key > lit('=') > value; // -('=' >> value)
            key   = standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9");

            // using this removes that problem:
            pair  = +eol >> key >> lit('=') >> value; // -('=' >> value)
            key   = standard::char_("a-zA-Z_") >> *standard::char_("a-zA-Z_0-9");

            value = *(standard::char_ - (eol|eoi)); // values can be empty or all characters except eol which indicates the end of the value

            BOOST_SPIRIT_DEBUG_NODES((pairs)(pair)(key)(value));
        }
    };

    template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
    struct SectionRule : qi::grammar<Iterator, Txt::Section(), Skipper>
    {
        qi::rule<Iterator, Txt::Section(), Skipper> query;
        qi::rule<Iterator, string()> name;

        KeyValueSquence<Iterator, Skipper> keyValueSequence;

        SectionRule() : SectionRule::base_type(query)
        {
            using namespace qi;

            name  =  lit('[') > standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9") > lit(']');
            query =  name > -keyValueSequence;

            BOOST_SPIRIT_DEBUG_NODES((query)(name));
        }
    };

    template <typename Iterator>
    bool parse(Iterator first, Iterator last, Txt::Sections &sections)
    {
        SectionRule<Iterator> sectionGrammar;
        CommentSkipper<Iterator> commentSkipper;
        std::vector<Txt::Section> tmpSections;

        try
        {
            bool r = qi::phrase_parse(
                    first, last,
                    (sectionGrammar % +qi::eol) >> *qi::eol > qi::eoi,
                    // comment skipper
                    commentSkipper,
                    tmpSections //sections store into "sections"!
                    );

            if (first != last) // fail if we did not get a full match
            {
                std::cerr << "DEBUG: Unparsed: '" << std::string(first,last) << "\n";
                return false;
            }
            // TODO temporary workaround, add sections directly from heap to vector
            sections = tmpSections;

            return r;
        } catch(qi::expectation_failure<Iterator> const& e)
        {
            std::cerr << "Unexpected: " << e.what() << " at '" << std::string(e.first,e.last) << "\n";
            return false;
        }
    }

} } }

int main()
{
    std::cin.unsetf(std::ios::skipws);
    boost::spirit::istream_iterator f(std::cin), l;

    wc3lib::map::Txt::Sections parsed;
    bool ok = wc3lib::map::client::parse(f, l, parsed);
    if (ok)
    {
        std::cout << "Parsed " << parsed.size() << " sections\n";
        for(auto& section : parsed)
        {
            std::cout << "section [" << section.name << "] has " << section.entries.size() << " pairs\n";
        }
    }
}

哪种指纹

代码语言:javascript
复制
Parsed 2 sections
section [sectionname] has 3 pairs
section [anothersection] has 1 pairs

在解析器的调试跟踪之后/之后:

代码语言:javascript
复制
<query>
  <try>// comment bla bla\n[</try>
  <skip>
    <try>// comment bla bla\n[</try>
    <success>[sectionname]\nkey = </success>
    <attributes>[]</attributes>
  </skip>
  <skip>
    <try>[sectionname]\nkey = </try>
    <fail/>
  </skip>
  <name>
    <try>[sectionname]\nkey = </try>
    <success>\nkey = value\nkey2=va</success>
    <attributes>[[s, e, c, t, i, o, n, n, a, m, e]]</attributes>
  </name>
  <pairs>
    <try>\nkey = value\nkey2=va</try>
    <pair>
      <try>\nkey = value\nkey2=va</try>
      <skip>
        <try>\nkey = value\nkey2=va</try>
        <fail/>
      </skip>
      <skip>
        <try>key = value\nkey2=val</try>
        <fail/>
      </skip>
      <skip>
        <try>key = value\nkey2=val</try>
        <fail/>
      </skip>
      <key>
        <try>key = value\nkey2=val</try>
        <success> = value\nkey2=value2</success>
        <attributes>[[k, e, y]]</attributes>
      </key>
      <skip>
        <try> = value\nkey2=value2</try>
        <success>= value\nkey2=value2\n</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>= value\nkey2=value2\n</try>
        <fail/>
      </skip>
      <skip>
        <try> value\nkey2=value2\n\n</try>
        <success>value\nkey2=value2\n\n\n</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>value\nkey2=value2\n\n\n</try>
        <fail/>
      </skip>
      <value>
        <try>value\nkey2=value2\n\n\n</try>
        <success>\nkey2=value2\n\n\n// co</success>
        <attributes>[[v, a, l, u, e]]</attributes>
      </value>
      <success>\nkey2=value2\n\n\n// co</success>
      <attributes>[[[k, e, y], [v, a, l, u, e]]]</attributes>
    </pair>
    <pair>
      <try>\nkey2=value2\n\n\n// co</try>
      <skip>
        <try>\nkey2=value2\n\n\n// co</try>
        <fail/>
      </skip>
      <skip>
        <try>key2=value2\n\n\n// com</try>
        <fail/>
      </skip>
      <skip>
        <try>key2=value2\n\n\n// com</try>
        <fail/>
      </skip>
      <key>
        <try>key2=value2\n\n\n// com</try>
        <success>=value2\n\n\n// comment</success>
        <attributes>[[k, e, y, 2]]</attributes>
      </key>
      <skip>
        <try>=value2\n\n\n// comment</try>
        <fail/>
      </skip>
      <skip>
        <try>value2\n\n\n// comment\n</try>
        <fail/>
      </skip>
      <value>
        <try>value2\n\n\n// comment\n</try>
        <success>\n\n\n// comment\nkey3 =</success>
        <attributes>[[v, a, l, u, e, 2]]</attributes>
      </value>
      <success>\n\n\n// comment\nkey3 =</success>
      <attributes>[[[k, e, y, 2], [v, a, l, u, e, 2]]]</attributes>
    </pair>
    <pair>
      <try>\n\n\n// comment\nkey3 =</try>
      <skip>
        <try>\n\n\n// comment\nkey3 =</try>
        <fail/>
      </skip>
      <skip>
        <try>\n\n// comment\nkey3 = </try>
        <fail/>
      </skip>
      <skip>
        <try>\n// comment\nkey3 = v</try>
        <fail/>
      </skip>
      <skip>
        <try>// comment\nkey3 = va</try>
        <success>key3 = value3\n\n[anot</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>key3 = value3\n\n[anot</try>
        <fail/>
      </skip>
      <skip>
        <try>key3 = value3\n\n[anot</try>
        <fail/>
      </skip>
      <key>
        <try>key3 = value3\n\n[anot</try>
        <success> = value3\n\n[anothers</success>
        <attributes>[[k, e, y, 3]]</attributes>
      </key>
      <skip>
        <try> = value3\n\n[anothers</try>
        <success>= value3\n\n[anotherse</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>= value3\n\n[anotherse</try>
        <fail/>
      </skip>
      <skip>
        <try> value3\n\n[anothersec</try>
        <success>value3\n\n[anothersect</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>value3\n\n[anothersect</try>
        <fail/>
      </skip>
      <value>
        <try>value3\n\n[anothersect</try>
        <success>\n\n[anothersection]\nk</success>
        <attributes>[[v, a, l, u, e, 3]]</attributes>
      </value>
      <success>\n\n[anothersection]\nk</success>
      <attributes>[[[k, e, y, 3], [v, a, l, u, e, 3]]]</attributes>
    </pair>
    <pair>
      <try>\n\n[anothersection]\nk</try>
      <skip>
        <try>\n\n[anothersection]\nk</try>
        <fail/>
      </skip>
      <skip>
        <try>\n[anothersection]\nke</try>
        <fail/>
      </skip>
      <skip>
        <try>[anothersection]\nkey</try>
        <fail/>
      </skip>
      <skip>
        <try>[anothersection]\nkey</try>
        <fail/>
      </skip>
      <key>
        <try>[anothersection]\nkey</try>
        <fail/>
      </key>
      <fail/>
    </pair>
    <success>\n\n[anothersection]\nk</success>
    <attributes>[[[[k, e, y], [v, a, l, u, e]], [[k, e, y, 2], [v, a, l, u, e, 2]], [[k, e, y, 3], [v, a, l, u, e, 3]]]]</attributes>
  </pairs>
  <success>\n\n[anothersection]\nk</success>
  <attributes>[[[s, e, c, t, i, o, n, n, a, m, e], [[[k, e, y], [v, a, l, u, e]], [[k, e, y, 2], [v, a, l, u, e, 2]], [[k, e, y, 3], [v, a, l, u, e, 3]]]]]</attributes>
</query>
<skip>
  <try>\n\n[anothersection]\nk</try>
  <fail/>
</skip>
<skip>
  <try>\n[anothersection]\nke</try>
  <fail/>
</skip>
<skip>
  <try>[anothersection]\nkey</try>
  <fail/>
</skip>
<query>
  <try>[anothersection]\nkey</try>
  <skip>
    <try>[anothersection]\nkey</try>
    <fail/>
  </skip>
  <name>
    <try>[anothersection]\nkey</try>
    <success>\nkey = value\n</success>
    <attributes>[[a, n, o, t, h, e, r, s, e, c, t, i, o, n]]</attributes>
  </name>
  <pairs>
    <try>\nkey = value\n</try>
    <pair>
      <try>\nkey = value\n</try>
      <skip>
        <try>\nkey = value\n</try>
        <fail/>
      </skip>
      <skip>
        <try>key = value\n</try>
        <fail/>
      </skip>
      <skip>
        <try>key = value\n</try>
        <fail/>
      </skip>
      <key>
        <try>key = value\n</try>
        <success> = value\n</success>
        <attributes>[[k, e, y]]</attributes>
      </key>
      <skip>
        <try> = value\n</try>
        <success>= value\n</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>= value\n</try>
        <fail/>
      </skip>
      <skip>
        <try> value\n</try>
        <success>value\n</success>
        <attributes>[]</attributes>
      </skip>
      <skip>
        <try>value\n</try>
        <fail/>
      </skip>
      <value>
        <try>value\n</try>
        <success>\n</success>
        <attributes>[[v, a, l, u, e]]</attributes>
      </value>
      <success>\n</success>
      <attributes>[[[k, e, y], [v, a, l, u, e]]]</attributes>
    </pair>
    <pair>
      <try>\n</try>
      <skip>
        <try>\n</try>
        <fail/>
      </skip>
      <key>
        <try></try>
        <fail/>
      </key>
      <fail/>
    </pair>
    <success>\n</success>
    <attributes>[[[[k, e, y], [v, a, l, u, e]]]]</attributes>
  </pairs>
  <success>\n</success>
  <attributes>[[[a, n, o, t, h, e, r, s, e, c, t, i, o, n], [[[k, e, y], [v, a, l, u, e]]]]]</attributes>
</query>
<skip>
  <try>\n</try>
  <fail/>
</skip>
<query>
  <try></try>
  <name>
    <try></try>
    <fail/>
  </name>
  <fail/>
</query>
<skip>
  <try>\n</try>
  <fail/>
</skip>
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18077319

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档