为什么这个boost spirit qi规则作为复合规则的一部分时解析失败,而单独使用时却成功? &g



我正在尝试将多个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 version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

This:

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

  • 我之前已经简化了一些部分。没有理由撤销它。
  • 您没有使用adapt_adt标头(这是最好的)。为什么要包括这个?
  • 为什么使用c++11之前版本的Fusion ADAPT_XXXX宏?
  • 为什么使用phrase_parse时,语法没有跳过(或覆盖它内部)。参见Boost spirit spipper问题。
  • 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

相关内容

最新更新