gpt4 book ai didi

c++ - 编译 boost spirit 解析器时出现奇怪的 static_cast 编译错误

转载 作者:行者123 更新时间:2023-11-30 03:53:00 27 4
gpt4 key购买 nike

解析表达式如下:

"asd {img} {ref I}sdkflsdlk {img} wmrwerml"

我有这样的代码:

struct CMyTag
{
std::string tagName;
std::string tagData;
};
BOOST_FUSION_ADAPT_STRUCT(::CMyTag, (std::string, tagName) (std::string, tagData));

struct fillMyTag
{
template <typename A, typename B = boost::spirit::unused_type, typename C = boost::spirit::unused_type, typename D = boost::spirit::unused_type>
struct result { typedef void type; };


void operator()(::CMyTag& _tag, const std::string& _name, const std::string& _type) const
{
_tag.tagName = _name;
_tag.tagData = _type;
}
};

template <typename Iterator>
struct testTag_grammar : qi::grammar<Iterator, std::vector<CMyTag>()>
{
testTag_grammar() :
testTag_grammar::base_type(data)
{
data = (text | imgtag | vartag | inctag | blktag | reftag) >> *data;

imgtagraw %= '{' >> qi::lit("img") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
imgtag = imgtagraw[op(qi::labels::_val, "img", boost::spirit::_1)];

vartagraw %= '{' >> qi::lit("var") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
vartag = vartagraw[op(qi::labels::_val, "var", boost::spirit::_1)];

inctagraw %= '{' >> qi::lit("inc") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
inctag = inctagraw[op(qi::labels::_val, "inc", boost::spirit::_1)];

blktagraw %= '{' >> qi::lit("blank") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
blktag = blktagraw[op(qi::labels::_val, "blk", boost::spirit::_1)];

reftagraw %= '{' >> lexeme[("ref")] >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
reftag = reftagraw[op(qi::labels::_val, "ref", boost::spirit::_1)];

textraw %= lexeme[+(char_ - '{' - '}')];
text = textraw[op(qi::labels::_val, "text", boost::spirit::_1)];
}

qi::rule<Iterator, std::string()> imgtagraw, vartagraw, inctagraw, blktagraw, reftagraw, textraw;
qi::rule<Iterator, CMyTag()> imgtag, vartag, inctag, blktag, reftag, text;
qi::rule<Iterator, std::vector<CMyTag>()> data;

boost::phoenix::function<fillMyTag> op;
};

解析器的使用:

testTag_grammar<std::string::iterator> l_gramar;
std::string l_test = "asd {img} {ref I}sdkflsdlk {img} wmrwerml";

std::vector<CMyTag> l_result;
bool result = qi::parse(l_test.begin(), l_test.end(), l_gramar, l_result);

因此,我希望获得 CmyTag 结构列表,但代码编译失败:

Error   1   error C2440: 'static_cast' : cannot convert from 'const std::vector<CMyTag,std::allocator<_Ty>>' to 'CMyTag'    d:\lib\boost\include\boost-1_57\boost\spirit\home\qi\detail\assign_to.hpp   152 1   TestSpiritParser

当我更改要遵循的数据规则时:

data = ((text | imgtag | vartag | inctag | blktag | reftag)[opvec(qi::labels::_val, boost::spirit::_1)]) >> *data;

opvec 的定义:

struct fillMyVec
{
template <typename A, typename B = boost::spirit::unused_type, typename C = boost::spirit::unused_type, typename D = boost::spirit::unused_type>
struct result { typedef void type; };


void operator()(std::vector<CMyTag>& _tagvec, const CMyTag& _name) const
{
_tagvec.push_back(_name);
}

void operator()(std::vector<CMyTag>& _tagvec, std::vector<CMyTag>& _name) const
{
_tagvec.insert(_tagvec.end(), _name.begin(), _name.end());
}
};

boost::phoenix::function<fillMyVec> opvec;

代码开始编译成功,但作为运行的结果,我得到的列表中只有一项。同样在修改之前,当 CMytag 类型仅为 std::string 时,我得到了一个 std::string 列表,其中包含正确的项目数,

现在我不知道出了什么问题,也不知道如何解决问题

最佳答案

  1. 首先,我只能假设

    data = (text | imgtag | vartag | inctag | blktag | reftag) >> *data;

    是/meant/作为 (...) 表达式的 1 次或多次重复。写成

    data = +(text | imgtag | vartag | inctag | blktag | reftag);

    表示相同,但​​允许属性传播以匹配暴露属性类型。

  2. 有许多 lexeme[] 指令在不使用 skipper 时毫无用处

  3. 存在可疑的空格手动跳过,使用 skipper 可能会更好

  4. 如果您确实希望在“标签名称”后要求一个强制性空格,请考虑使用 operator& 运算符。这样你仍然可以使用 skipper 。

    无论如何,您可能正在寻找类似 Qi Repository distinct()[] parser directive 的内容

  5. 即使有 skipper

    *(+lit(' ') >> lexeme[+(char_ - '{' - '}')])

    没有意义,因为 lexeme[...] 会占用任何空间直到关闭 '}',因此第二次重复 *() 会永远不要申请。

    See also Boost spirit skipper issues

  6. 规则之间有很多手动重复。考虑使用 qi::symbols 将输入映射到标签类型。

  7. 如果这样做,就更容易避免语义操作(好东西:Boost Spirit: "Semantic actions are evil"?)。即使没有,您也可以使用 qi::attr 将特定值公开为 type 值。

  8. 考虑添加调试信息(参见下面演示中的 BOOST_SPIRIT_DEBUG)

语法简化

我会将整个语法缩减为:

data = +( ('{' >> tag >> '}') | text );

tag = lexeme[type >> &char_(" {}")] >> lexeme[*~char_("{}")];
text = attr("text") >> lexeme[+~char_("{}")];

完成!不再有语义 Action ,不再有数十条基本相同的规则。不再有多重性不明确的复杂嵌套重复。 type 现在是一个 qi::symbols 解析器,它包含标签名称的映射:

type.add
("img", "img")
("var", "var")
("inc", "inc")
("blank", "blk")
("ref", "ref");

这是一个完整的演示:

演示

Live On Coliru

//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

struct CMyTag
{
std::string tagName;
std::string tagData;
};
BOOST_FUSION_ADAPT_STRUCT(::CMyTag, (std::string, tagName) (std::string, tagData))

template <typename Iterator, typename Skipper = qi::space_type>
struct testTag_grammar : qi::grammar<Iterator, std::vector<CMyTag>(), Skipper>
{
testTag_grammar() :
testTag_grammar::base_type(data)
{
using namespace qi;

data = +( ('{' >> tag >> '}') | text );

type.add
("img", "img")
("var", "var")
("inc", "inc")
("blank", "blk")
("ref", "ref");

tag = lexeme[type >> &char_(" {}")] >> lexeme[*~char_("{}")];
text = attr("text") >> lexeme[+~char_("{}")];

BOOST_SPIRIT_DEBUG_NODES( (data) (tag) (text))
}

private:
qi::symbols<char, std::string> type;
qi::rule<Iterator, CMyTag(), Skipper> tag, text;
qi::rule<Iterator, std::vector<CMyTag>(), Skipper> data;
};

int main() {
testTag_grammar<std::string::const_iterator> l_gramar;
std::string const l_test = "asd {img} {ref I}sdkflsdlk {img} wmrwerml";

std::vector<CMyTag> l_result;
auto f = l_test.begin(), l = l_test.end();
bool result = qi::phrase_parse(f, l, l_gramar, qi::space, l_result);

if (result) {
std::cout << "Parse success: " << l_result.size() << "\n";

for (auto& v : l_result)
std::cout << "Name '" << v.tagName << "', Data '" << v.tagData << "'\n";
}
else {
std::cout << "Parse failed\n";
}

if (f!=l) {
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}

打印

Parse success: 6
Name 'text', Data 'asd '
Name 'img', Data ''
Name 'ref', Data 'I'
Name 'text', Data 'sdkflsdlk '
Name 'img', Data ''
Name 'text', Data 'wmrwerml'

关于c++ - 编译 boost spirit 解析器时出现奇怪的 static_cast 编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30361656/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com