为什么这个提神元气规则作为复合规则的一部分解析失败,单独使用却解析成功?

问题描述 投票:0回答:1

我正在尝试将多个 boost::spirit 解析规则组合成更大的复合规则,并具有以下代码:

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/adt/adapt_adt.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/variant.hpp>

#include <string> 
#include <vector>
#include <fstream>


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

struct PdCanvas {
    int topX;
    int topY;
    int wX;
    int wY;
    std::string name;
    int openOnLoad; 
};


struct PdArrayData {
    std::vector<float> data; 
};


BOOST_FUSION_ADAPT_STRUCT(
    PdCanvas,
    (int, topX)
    (int, topY)
    (int, wX) 
    (int, wY)
    (std::string, name)
    (int, openOnLoad));


BOOST_FUSION_ADAPT_STRUCT(
    PdArrayData,
    (std::vector<float>, data)); 


using PdRecord = boost::variant<
PdArrayData,
PdCanvas
>;


template <typename Iterator> struct PdCanvasGrammar : qi::grammar<Iterator, PdCanvas()> {
    PdCanvasGrammar() : PdCanvasGrammar::base_type(start) {
        using namespace qi;
        start      = skip(space)[canvasRule >> eoi];
        name       = +(('\\' >> space) |graph);
        canvasRule = "#N canvas" >> int_ >> int_ >> int_ >> int_ >> name >> int_ >> ';';

        BOOST_SPIRIT_DEBUG_NODES((start)(canvasRule)(name))
    }

  private:
    qi::rule<Iterator, PdCanvas()> start;
    qi::rule<Iterator, PdCanvas(), qi::space_type> canvasRule;
    qi::rule<Iterator, std::string()> name;
};


template <typename Iterator> 
struct PdRecordGrammar : qi::grammar<Iterator, PdRecord(), ascii::space_type> {
    PdRecordGrammar () : PdRecordGrammar::base_type(recordRule) {         
        using namespace qi;
        
        arrayDataRule = (lit("#A") >>  +(qi::float_) >> ";");
        canvasRule = PdCanvasGrammar<Iterator>();
        recordRule = (canvasRule |  (arrayDataRule)  );
        BOOST_SPIRIT_DEBUG_NODES((arrayDataRule)(canvasRule)(recordRule))
    }

    
    qi::rule<Iterator, PdArrayData(), ascii::space_type> arrayDataRule; 
    qi::rule<Iterator, PdCanvas()> canvasRule;     
    qi::rule<Iterator, PdRecord(), ascii::space_type> recordRule;     
};



int main(int argc, char** argv)
{
  if(argc != 2)
    {
        std::cout << "Usage: "  <<argv[0] << " <PatchFile>" << std::endl;
        exit(1); 
    }

    std::ifstream inputFile(argv[1]); 
    std::string inputString(std::istreambuf_iterator<char>(inputFile), {}); 

    PdRecord root;
    PdRecordGrammar<std::string::iterator> parser;
    std::cout << "Loaded file:\n " << inputString << std::endl;


    PdCanvas canvObj;
    PdCanvasGrammar<std::string::iterator> canvParse;
    bool canvSuccess = qi::phrase_parse(inputString.begin(), inputString.end(), canvParse, boost::spirit::ascii::space, canvObj);
    std::cout << "Canvas success: " << canvSuccess << std::endl; 

    bool success = qi::phrase_parse(inputString.begin(), inputString.end(), parser, boost::spirit::ascii::space, root); 
    std::cout << "Success: " << success << std::endl;

    return 0; 

}

然后我测试了以下字符串的代码,应该解析:

#N canvas 0 0 400 300 moo 1;

运行代码给出以下输出:

Loaded file:
 #N canvas 0 0 400 300 moo 1;

<start>
  <try>#N canvas 0 0 400 30</try>
  <canvasRule>
    <try>#N canvas 0 0 400 30</try>
    <name>
      <try>moo 1;\n</try>
      <success> 1;\n</success>
      <attributes>[[m, o, o]]</attributes>
    </name>
    <success>\n</success>
    <attributes>[[0, 0, 400, 300, [m, o, o], 1]]</attributes>
  </canvasRule>
  <success></success>
  <attributes>[[0, 0, 400, 300, [m, o, o], 1]]</attributes>
</start>
Canvas success: 1
<recordRule>
  <try>#N canvas 0 0 400 30</try>
  <canvasRule>
    <try>#N canvas 0 0 400 30</try>
    <fail/>
  </canvasRule>
  <arrayDataRule>
    <try>#N canvas 0 0 400 30</try>
    <fail/>
  </arrayDataRule>
  <fail/>
</recordRule>
Success: 0

可以看到,文件被独立的 PdCanvasGrammar 规则成功解析,但是当我尝试使用复合 PdRecordGrammar 规则时解析失败。

我假设我在将规则组合在一起时做错了什么,但我不知道是什么。

顺便说一句,定义为 PdRecordGrammar 一部分的 arrayDataRule 成功解析了它的输入:

Loaded file:
 #A 1 2 3 4 5;
<start>
  <try>#A 1 2 3 4 5;</try>
  <canvasRule>
    <try>#A 1 2 3 4 5;</try>
    <fail/>
  </canvasRule>
  <fail/>
</start>
Canvas success: 0
<recordRule>
  <try>#A 1 2 3 4 5;</try>
  <canvasRule>
    <try>#A 1 2 3 4 5;</try>
    <fail/>
  </canvasRule>
  <arrayDataRule>
    <try>#A 1 2 3 4 5;</try>
    <success></success>
    <attributes>[[[1, 2, 3, 4, 5]]]</attributes>
  </arrayDataRule>
  <success></success>
  <attributes>[[[1, 2, 3, 4, 5]]]</attributes>
</recordRule>
Success: 1

所以我的假设是,如果我只是采用 PdCanvasGrammar 规则并将其本质上定义为 PdRecord 规则,它就会起作用。但我正在尝试了解如何正确组合规则,以免单个规则变得太大和笨拙。

所以我的问题是: 为什么定义的规则不起作用,将规则组合成复合规则的正确方法是什么?

版本:

提升:1.75.0

C++ 标准:11

GCC: gcc 版本 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

c++ parsing boost-spirit boost-spirit-qi ebnf
1个回答
0
投票

这个:

canvasRule    = PdCanvasGrammar<Iterator>();

创建对悬空临时对象的引用。修复它:

template <typename Iterator>
struct PdRecordGrammar : qi::grammar<Iterator, PdRecord(), qi::space_type> {
    PdRecordGrammar() : PdRecordGrammar::base_type(recordRule) {
        arrayDataRule = "#A" >> +qi::float_ >> ";";
        recordRule    = canvasRule | arrayDataRule;

        BOOST_SPIRIT_DEBUG_NODES((arrayDataRule)(recordRule))
    }

  private:
    qi::rule<Iterator, PdArrayData(), qi::space_type> arrayDataRule;
    PdCanvasGrammar<Iterator>                         canvasRule;
    qi::rule<Iterator, PdRecord(), qi::space_type>    recordRule;
};

简化

  • 我已经简化了一些部分before。没有理由撤消它。
  • 你没有使用
    adapt_adt
    标题(这是最好的)。为什么包括那个?
  • 为什么要使用 C++11 之前版本的 Fusion ADAPT_XXXX 宏?
  • 为什么在语法没有船长(或在内部覆盖它)时使用
    phrase_parse
    。再次参见Boost spirit skipper issues了解上下文。
  • 很多地方有多余的
    lit()
    ,括号和
    ;
  • 你有
    using namespace qi
    但仍然有资格
    qi::float_
    .
  • 一个语法声明规则私有,另一个不声明
  • 变量的作用域与用途不符(
    main
    )。这会导致生命周期/变量重用错误。或者只是难以维护的代码。
  • 您的输入可以使用
    const_iterator
    。应该。

现场演示

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

namespace qi = boost::spirit::qi;

struct PdCanvas { int topX, topY, wX, wY, openOnLoad; std::string name; };
struct PdArrayData { std::vector<float> data; };

BOOST_FUSION_ADAPT_STRUCT(PdCanvas, , topX, topY, wX, wY, name, openOnLoad)
BOOST_FUSION_ADAPT_STRUCT(PdArrayData, data)

using PdRecord = boost::variant<PdArrayData, PdCanvas>;

template <typename Iterator> struct PdCanvasGrammar : qi::grammar<Iterator, PdCanvas()> {
    PdCanvasGrammar() : PdCanvasGrammar::base_type(start) {
        using namespace qi;
        start      = skip(space)[canvasRule >> eoi];
        name       = +('\\' >> space | graph);
        canvasRule = "#N canvas" >> int_ >> int_ >> int_ >> int_ >> name >> int_ >> ';';

        BOOST_SPIRIT_DEBUG_NODES((start)(canvasRule)(name))
    }

  private:
    qi::rule<Iterator, PdCanvas()>                 start;
    qi::rule<Iterator, PdCanvas(), qi::space_type> canvasRule;
    qi::rule<Iterator, std::string()>              name;
};

template <typename Iterator>
struct PdRecordGrammar : qi::grammar<Iterator, PdRecord(), qi::space_type> {
    PdRecordGrammar() : PdRecordGrammar::base_type(recordRule) {
        arrayDataRule = "#A" >> +qi::float_ >> ";";
        recordRule    = canvasRule | arrayDataRule;

        BOOST_SPIRIT_DEBUG_NODES((arrayDataRule)(recordRule))
    }

  private:
    qi::rule<Iterator, PdArrayData(), qi::space_type> arrayDataRule;
    PdCanvasGrammar<Iterator>                         canvasRule;
    qi::rule<Iterator, PdRecord(), qi::space_type>    recordRule;
};

int main() {
    std::string const input = "#N canvas 0 0 400 300 moo 1; ";
    std::cout << "Input:\n " << quoted(input) << std::endl;

    {
        PdCanvas obj;
        PdCanvasGrammar<std::string::const_iterator> const canvParse;
        std::cout << "Canvas success: " << parse(input.begin(), input.end(), canvParse, obj) << "\n";
    }

    {
        PdRecord                                     obj;
        PdRecordGrammar<std::string::const_iterator> const parser;
        std::cout << "Success: " << phrase_parse(input.begin(), input.end(), parser, qi::space, obj) << "\n";
    }
}

输出:

Input:
 "#N canvas 0 0 400 300 moo 1; "
Canvas success: 1
Success: 1
© www.soinside.com 2019 - 2024. All rights reserved.