提升精神X3 eol意外行为

时间:2017-08-18 09:51:02

标签: c++ boost boost-spirit boost-spirit-x3

此问题与boost-spirit-x3-parse-into-structs

严格相关

我有这个语法

     #include <iostream>
 //#define BOOST_SPIRIT_X3_DEBUG
 #include <boost/spirit/home/x3.hpp>
 #include <boost/fusion/include/adapt_struct.hpp>
 #include <boost/fusion/include/io.hpp>

 struct sectionInfo
 {
     std::string name;
    int number = 0;
    float pitch = 0.0f;
    int visible = 0;
    float minCutsTblSize = 0.0f;
    //technology section attributes
     float gridResolution = 0.0f;
     float lengthPrecision = 0.0f;
 };

 const char START_SECTION = '{';
 const char END_SECTION = '}';
 const char QUOTE = '"';
 const char EQUALS = '=';
 const char* LAYER_SECTION = "Layer";
 const char* TECHNOLOGY_SECTION = "Technology";
 const char* NUMBER_ATTR = "layerNumber";
 const char* VISIBLE_ATTR = "visible";
 const char* COLOR_ATTR = "color";
 const char* PITCH_ATTR = "pitch";
 const char* MIN_CUTS_TBL_SIZE_ATTR = "minCutsTblSize";
 const char* GRID_RESOLUTION_ATTR = "gridResolution";
 const char* LENGTH_PRECISION_ATTR = "lengthPrecision";

 namespace Parser {
     namespace x3 = boost::spirit::x3;

     namespace detail {
         template <typename T> auto propagate(T member) {
             return [=](auto& ctx) { x3::traits::move_to(x3::_attr(ctx), x3::_val(ctx).*member); };
         }

         template <typename T = sectionInfo, typename P>
         auto rule(const char* debug, P p) { return x3::rule<struct _, T> {debug} = x3::skip(x3::space)[p]; };

         auto quoted = rule<std::string>("quoted", x3::lexeme[QUOTE >> +(x3::char_ - QUOTE) >> QUOTE]);

         template <typename T> auto make_member_parser(bool T::* const member) { return x3::bool_[propagate(member)]; }
         template <typename T> auto make_member_parser(int T::* const member) { return x3::int_[propagate(member)]; }
         template <typename T> auto make_member_parser(double T::* const member) { return x3::double_[propagate(member)]; }
         template <typename T> auto make_member_parser(float T::* const member) { return x3::double_[propagate(member)]; }
         template <typename T> auto make_member_parser(std::string T::* const member) { return quoted[propagate(member)]; }

         auto property = [](auto label, auto member) {
             return x3::as_parser(label) >> EQUALS >> make_member_parser(member);
         };
     }

     using detail::rule;
     using detail::propagate;
     using detail::property;
     using detail::quoted;

     auto number = property(NUMBER_ATTR, &sectionInfo::number);
     auto visible = property(VISIBLE_ATTR, &sectionInfo::visible);
     auto pitch = property(PITCH_ATTR, &sectionInfo::pitch);
     auto minCutsTblSize = property(MIN_CUTS_TBL_SIZE_ATTR, &sectionInfo::minCutsTblSize);
     auto lengthPrecision = property(LENGTH_PRECISION_ATTR, &sectionInfo::lengthPrecision);
     auto gridResolution = property(GRID_RESOLUTION_ATTR, &sectionInfo::gridResolution);

     auto skipLine = *(x3::char_ - x3::eol);

     x3::rule<struct sectionInfoId, sectionInfo> const layer = "layer";
     x3::rule<struct mainRuleId, std::vector<sectionInfo>> const mainRule = "mainRule";

     auto layer_def =
         LAYER_SECTION >> quoted[propagate(&sectionInfo::name)] >> START_SECTION >> x3::eol
         >> *( (number | visible | pitch | minCutsTblSize | lengthPrecision | gridResolution) >> +x3::eol )
         >> END_SECTION;

     auto skipper = x3::blank;

     auto mainRule_def = *(*x3::eol >> layer >> *x3::eol);

     BOOST_SPIRIT_DEFINE(layer, mainRule);
 }

 std::ostream& operator<<(std::ostream& os, const sectionInfo& s)
 {

         os
             << "name=" << " " << s.name << "\n"
             << "number=" << " " << s.number << "\n"
             << "visible=" << " " << s.visible << "\n"
             << "pitch=" << " " << s.pitch << "\n"
             << "minCutsTblSize=" << " " << s.minCutsTblSize << "\n"
             << "lengthPrecision=" << " " << s.lengthPrecision << "\n"
             << "gridResolution=" << " " << s.gridResolution << "\n\n";

     return os;
 }

 int main() {

     std::stringstream ss;

     ss 
        <<"\r\nLayer \"UBMB\" {\r\n"
        << "       layerNumber = 170\r\n"
        << "       pitch = 33.6\r\n"
        << "}\r\n"
        << "\r\n"
        << "Layer \"RV\" {\r\n"
        << "       gridResolution = 0.34\r\n"
        << "        minCutsTblSize = 22.7\r\n"
        << "       layerNumber = 85\r\n"
        << "        visible = 2\r\n"
        << "       pitch = 331\r\n"
        << "}\r\n"
        << " \r\n"
        << "Layer \"foffo\" {\r\n"
        << "       layerNumber = 125\r\n"
        << "       pitch = 0.005\r\n"
        << "        gridResolution = 21.7\r\n"
        << "        lengthPrecision = 0.15\r\n"
        << "}\r\n"
        << "\r\n";

     std::vector<sectionInfo> sections;
     auto sample = ss.str();
     auto f = sample.begin(), l = sample.end();
     bool ok = boost::spirit::x3::phrase_parse(
         f, l, 
         Parser::mainRule, 
         Parser::skipper,
         sections
     );


     if (ok && f==l)
     {
         std::cout << "\n\n Parsed successfully \n\n";
         for(auto& s : sections)
         {
             std::cout << s;
         }
     }
     else
         std::cout << "Parse failed\n";

 }

成功解析输入:

输出是:

  

name = UBMB   数字= 170   visible = 0   pitch = 33.6   minCutsTblSize = 0   lengthPrecision = 0   gridResolution = 0

     

name = RV   数字= 85   可见= 2   pitch = 331   minCutsTblSize = 22.7   lengthPrecision = 0   gridResolution = 0.34

     

name = foffo   数= 125   visible = 0   间距= 0.005   minCutsTblSize = 0   lengthPrecision = 0.15   gridResolution = 21.7

问题出现是因为我需要跳过一些行,即具有不感兴趣的属性的行(未在我的语法中定义)

编辑:例如,可能有一个属性dummy =&#34; foo&#34;我想跳过。

要实现此目的,图层规则

auto layer_def = LAYER_SECTION >> quoted[propagate(&sectionInfo::name)] >> START_SECTION >> x3::eol
             >> *( (number | visible | pitch | minCutsTblSize | lengthPrecision | gridResolution ) >> +x3::eol )
             >> END_SECTION;

变为

auto layer_def = LAYER_SECTION >> quoted[propagate(&sectionInfo::name)] >> START_SECTION >> x3::eol
             >> *( (number | visible | pitch | minCutsTblSize | lengthPrecision | gridResolution | skipLine) >> +x3::eol )
             >> END_SECTION;

解析器成功,但输出现在是

  

name = UBMB number = 125 visible = 2 pitch = 0.005 minCutsTblSize = 22.7   lengthPrecision = 0.15 gridResolution = 21.7

这是错误的(只有一个部分,这里和那里采取的属性......)

很明显,问题在于skipLine规则

auto skipLine = *(x3::char_ - x3::eol);

我无法弄清楚原因。 我认为很明显规则*(char - eol)&gt;&gt; EOL 会匹配任何一行,但我想它不是......

任何线索?

1 个答案:

答案 0 :(得分:1)

首先,我简化了跳过。船长不属于呼叫站点,因为它对语法很重要。将其封装到mainRule中,并简化:

auto mainRule_def = x3::skip(x3::blank) [ -layer % x3::eol ];

-layer表达式是接受空行的技巧。现在使用解析器变为:

bool ok = boost::spirit::x3::parse(f, l, Parser::mainRule, sections);

下一步:skipLine也会吃'}',让一切都崩溃:之后的所有内容都被视为同一层的(无效)属性,最后没有END_SECTION所以语法不匹配。

简单地:

auto skipLine = *(x3::char_ - x3::eol - END_SECTION);
  

专业提示:

     

如有疑问,请调试: Live On Coliru

// debug it
auto skipLine = x3::rule<struct skipLine_> {"skipLine"} = *(x3::char_ - x3::eol/* - END_SECTION*/);

完整演示

稍作简化

<强> Live On Coliru

#include <iostream>
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>

struct sectionInfo {
    std::string name;
    int number            = 0;
    float pitch           = 0.0f;
    int visible           = 0;
    float minCutsTblSize  = 0.0f;
    // technology section attributes
    float gridResolution  = 0.0f;
    float lengthPrecision = 0.0f;
};

char const  START_SECTION          = '{';
char const  END_SECTION            = '}';
char const  QUOTE                  = '"';
char const  EQUALS                 = '=';
char const* LAYER_SECTION          = "Layer";
char const* TECHNOLOGY_SECTION     = "Technology";
char const* NUMBER_ATTR            = "layerNumber";
char const* VISIBLE_ATTR           = "visible";
char const* COLOR_ATTR             = "color";
char const* PITCH_ATTR             = "pitch";
char const* MIN_CUTS_TBL_SIZE_ATTR = "minCutsTblSize";
char const* GRID_RESOLUTION_ATTR   = "gridResolution";
char const* LENGTH_PRECISION_ATTR  = "lengthPrecision";

namespace Parser {
    namespace x3 = boost::spirit::x3;

    namespace detail {
        template <typename T> auto propagate(T member) {
            return [=](auto &ctx) { x3::traits::move_to(x3::_attr(ctx), x3::_val(ctx).*member); };
        }

        template <typename T = sectionInfo, typename P> auto rule(const char *debug, P p) {
            return x3::rule<struct _, T>{ debug } = x3::skip(x3::space)[p];
        };

        auto quoted = rule<std::string>("quoted", x3::lexeme[QUOTE >> +(x3::char_ - QUOTE) >> QUOTE]);

#define MMP_(T, p) template <typename U> auto make_member_parser(T U::*const member) { return (p)[propagate(member)]; }
        MMP_(bool,   x3::bool_);
        MMP_(int,    x3::int_);
        MMP_(double, x3::double_);
        MMP_(float,  x3::double_);
        MMP_(std::string, quoted);
#undef MMP_

        auto property = [](auto label, auto member) { return x3::as_parser(label) >> EQUALS >> make_member_parser(member); };
    }

    using detail::rule;
    using detail::propagate;
    using detail::property;
    using detail::quoted;

    auto number          = property(NUMBER_ATTR,            &sectionInfo::number);
    auto visible         = property(VISIBLE_ATTR,           &sectionInfo::visible);
    auto pitch           = property(PITCH_ATTR,             &sectionInfo::pitch);
    auto minCutsTblSize  = property(MIN_CUTS_TBL_SIZE_ATTR, &sectionInfo::minCutsTblSize);
    auto lengthPrecision = property(LENGTH_PRECISION_ATTR,  &sectionInfo::lengthPrecision);
    auto gridResolution  = property(GRID_RESOLUTION_ATTR,   &sectionInfo::gridResolution);

    auto skipLine = *(x3::char_ - x3::eol - END_SECTION);

    x3::rule<struct sectionInfoId, sectionInfo> const layer = "layer";
    x3::rule<struct mainRuleId, std::vector<sectionInfo> > const mainRule = "mainRule";

    auto layer_def = 
        LAYER_SECTION >> quoted[propagate(&sectionInfo::name)]
        >> START_SECTION >> x3::eol
        >> *((number | visible | pitch | minCutsTblSize | lengthPrecision | gridResolution | skipLine) >> +x3::eol)
        >> END_SECTION
        ;

    auto mainRule_def = x3::skip(x3::blank) [ -layer % x3::eol ];

    BOOST_SPIRIT_DEFINE(layer, mainRule);
}

std::ostream &operator<<(std::ostream &os, const sectionInfo &s) {
    return os 
      << "name="            << " " << s.name            << "\n"
      << "number="          << " " << s.number          << "\n"
      << "visible="         << " " << s.visible         << "\n"
      << "pitch="           << " " << s.pitch           << "\n"
      << "minCutsTblSize="  << " " << s.minCutsTblSize  << "\n"
      << "lengthPrecision=" << " " << s.lengthPrecision << "\n"
      << "gridResolution="  << " " << s.gridResolution  << "\n\n";
}

int main() {

    std::string const sample = 
       "\r\nLayer \"UBMB\" {\r\n"
       "       layerNumber = 170\r\n"
       "       pitch = 33.6\r\n"
       "}\r\n"
       "\r\n"
       "Layer \"RV\" {\r\n"
       "       gridResolution = 0.34\r\n"
       "        minCutsTblSize = 22.7\r\n"
       "       layerNumber = 85\r\n"
       "        visible = 2\r\n"
       "       pitch = 331\r\n"
       "}\r\n"
       " \r\n"
       "Layer \"foffo\" {\r\n"
       "       layerNumber = 125\r\n"
       "       pitch = 0.005\r\n"
       "        gridResolution = 21.7\r\n"
       "        lengthPrecision = 0.15\r\n"
       "}\r\n"
       "\r\n";

    std::vector<sectionInfo> sections;
    {
        auto f = sample.begin(), l = sample.end();
        bool ok = boost::spirit::x3::parse(f, l, Parser::mainRule, sections);

        if (ok && f == l) {
            std::cout << "\n\n Parsed successfully \n\n";
            for (auto &s : sections) {
                std::cout << s;
            }
        } else
            std::cout << "Parse failed\n";
    }
}

打印

 Parsed successfully 

name= UBMB
number= 170
visible= 0
pitch= 33.6
minCutsTblSize= 0
lengthPrecision= 0
gridResolution= 0

name= RV
number= 85
visible= 2
pitch= 331
minCutsTblSize= 22.7
lengthPrecision= 0
gridResolution= 0.34

name= foffo
number= 125
visible= 0
pitch= 0.005
minCutsTblSize= 0
lengthPrecision= 0.15
gridResolution= 21.7