【问题标题】:Boost Spirit X3 eol unexpected behaviourBoost Spirit X3 eol 意外行为
【发布时间】:2017-08-18 09:51:01
【问题描述】:

这个问题与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";

 }

成功解析输入:

输出是:

名称= UBMB 数字= 170 可见= 0 间距= 33.6 minCutsTblSize= 0 长度精度= 0 网格分辨率= 0

名称=房车 数字= 85 可见= 2 间距= 331 minCutsTblSize=22.7 长度精度= 0 网格分辨率= 0.34

名称= foffo 数字= 125 可见= 0 间距= 0.005 minCutsTblSize= 0 长度精度= 0.15 网格分辨率= 21.7

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

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

为了实现这一点,层规则

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;

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

名称= UBMB 编号= 125 可见= 2 间距= 0.005 minCutsTblSize= 22.7 lengthPrecision= 0.15 gridResolution= 21.7

这是错误的(只有一节,这里和那里的属性......)

很明显问题出在skipLine规则中

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

我不知道为什么。 我认为很明显规则 *(char - eol) >> eol 会匹配任何行,但我想它不是..

有什么线索吗?

【问题讨论】:

  • 我注意到了 - 尚未使用的 - TECHNOLOGY_SECTION。你能告诉我们你真正想要解析的最终目标吗?我认为你可以更简单地完成这一切。并更好地匹配您的域。
  • @sehe 我真的不能 :) 顺便说一句,非常感谢您的贡献,您无法想象您的帮助有多大。

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


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    相关资源
    最近更新 更多