gpt4 book ai didi

c++ - spirit 解析器属性传播规则的问题

转载 作者:太空狗 更新时间:2023-10-29 21:02:50 25 4
gpt4 key购买 nike

我有一个 spirit 上的小解析器。问题在于属性规则。该规则应该能够解析两者

@ATTRIBUTE num NUMERIC

@ATTRIBUTE 测试{你好,世界}

typedef std::string::iterator string_iter_t;
qi::rule<string_iter_t, string()> ident_r= lexeme['"' >> +(char_("a-zA-Z0-9- ")) >> '"'] | lexeme[+char_("a-zA-Z0-9-")];
qi::rule<string_iter_t, string(), space_type> relation_rule =
no_case["@RELATION"] >> ident_r;
qi::rule<string_iter_t, optional<vector<string>>(), space_type> attr_val_rule =
no_case["NUMERIC"] |
('{' >> ident_r % ',' >> '}');

qi::rule<string_iter_t, tuple<string, optional<vector<string>>>(), space_type> attr_rule =
no_case["@ATTRIBUTE"] >> ident_r >> attr_val_rule;

当我尝试使用上面的代码进行编译时,出现了一个很大的编译错误,提示类型与最后一条规则不匹配。

当我将最后一条规则更改为 read 时,错误消失了

qi::rule<string_iter_t, vector<string>(), space_type> attr_rule =
no_case["@ATTRIBUTE"] >> ident_r >> attr_val_rule;

但是当我尝试解析时出现运行时错误

@ATTRIBUTE 测试数字

boost::optional 中的断言被触发,因为未设置参数。我得到以下信息

Assertion failed: this->is_initialized(), file c:\Libs\boost_1_52_0\boost/option
al/optional.hpp, line 630

任何人都可以帮助我了解我所缺少的东西吗?

编译时出现的错误

c:\Libs\boost_1_52_0\boost/spirit/home/qi/detail/assign_to.hpp(152) : error C244
0: 'static_cast' : cannot convert from 'const std::basic_string<_Elem,_Traits,_A
lloc>' to 'std::tuple<<unnamed-symbol>,_V0_t>'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
and
[
<unnamed-symbol>=std::string,
_V0_t=boost::optional<std::vector<std::string>>
]
No constructor could take the source type, or constructor overload resol
ution was ambiguous
c:\Libs\boost_1_52_0\boost/spirit/home/qi/detail/assign_to.hpp(170) : se
e reference to function template instantiation 'void boost::spirit::traits::assi
gn_to_attribute_from_value<Attribute,T>::call<T>(const T_ &,Attribute &,boost::m
pl::false_)' being compiled
with
[
Attribute=std::tuple<std::string,boost::optional<std::vector<std::st
ring>>>,
T=std::basic_string<char,std::char_traits<char>,std::allocator<char>
>,
T_=std::basic_string<char,std::char_traits<char>,std::allocator<char
>>
] ..... and goes on and on

我正在使用的程序的拷贝

    int main(void)
{
using boost::trim_left;
using boost::istarts_with;
using boost::optional;
namespace qi = boost::spirit::qi;
using qi::no_case;
using qi::ascii::space;
using qi::char_;
using qi::lexeme;
using qi::ascii::space_type;

typedef std::string::iterator string_iter_t;
qi::rule<string_iter_t, string()> ident_r= lexeme['"' >> +(char_("a-zA-Z0-9- ")) >> '"'] | lexeme[+char_("a-zA-Z0-9-")];
qi::rule<string_iter_t, string(), space_type> relation_rule =
no_case["@RELATION"] >> ident_r;
qi::rule<string_iter_t, optional<vector<string>>(), space_type> attr_val_rule =
no_case["NUMERIC"] |
('{' >> ident_r % ',' >> '}');
qi::rule<string_iter_t, vector<string>(), space_type> attr_rule =
no_case["@ATTRIBUTE"] >> ident_r >> attr_val_rule;
string ss1 = "@ATTRIBUTE test NUMERIC";

vector<string> ans1;
bool ret1 = qi::phrase_parse(ss1.begin(), ss1.end(), attr_rule, space, ans1);
cout << boolalpha << ret1 << endl;

optional<vector<string>> ss;
string ss2 = "{hello, world}";
bool ret2 = qi::phrase_parse(ss2.begin(), ss2.end(), attr_val_rule, space, ss);
cout << ret2 << endl;

return 0;
}

最佳答案

Anand 发布的解决方法在某种程度上有效。然而,一个更方便的答案就在眼前。

#include <boost/fusion/adapted.hpp>
// or specificly for std::tuple:
#include <boost/fusion/adapted/std_tuple.hpp>

例如,考虑一下您不想或不能更改属性数据类型的情况。

这是一个删除了一些样式问题的演示http://liveworkspace.org/code/Mwpah上直播.

输出:

=======================================
Trying to parse '@attribute ident1 numeric'
parse success
data: ident1
=======================================
Trying to parse '@attribute ident2 { field1, field2, field3 }'
parse success
data: ident2 field1 field2 field3
=======================================
Trying to parse '@attribute ident3 { }'
parse failed: '@attribute ident3 { }'
trailing unparsed: '@attribute ident3 { }'

完整代码:

#include <boost/fusion/adapted.hpp>
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>

namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;

typedef std::string rel_t;
typedef boost::optional<std::vector<std::string>> fields_t;
typedef std::tuple<std::string, fields_t> attr_t;
typedef boost::variant<attr_t, rel_t> parsed_t;

template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, attr_t(), Skipper>
{
parser() : parser::base_type(attr_rule)
{
using namespace qi;

ident_r = lexeme // technically redundant since the rule is skipperless
[
('"' >> +char_("a-zA-Z0-9- ") >> '"')
| +char_("a-zA-Z0-9-")
];

relation_rule = no_case["@RELATION"] >> ident_r;
attr_val_rule = no_case["NUMERIC"] | ('{' >> ident_r % ',' >> '}');
attr_rule = no_case["@ATTRIBUTE"] >> ident_r >> attr_val_rule;
start = attr_rule | relation_rule;

BOOST_SPIRIT_DEBUG_NODE(start);
BOOST_SPIRIT_DEBUG_NODE(attr_rule);
BOOST_SPIRIT_DEBUG_NODE(attr_val_rule);
BOOST_SPIRIT_DEBUG_NODE(relation_rule);
BOOST_SPIRIT_DEBUG_NODE(ident_r);
}

private:
qi::rule<It, std::string()> ident_r;
qi::rule<It, fields_t(), Skipper> attr_val_rule;
qi::rule<It, rel_t() , Skipper> relation_rule;
qi::rule<It, attr_t() , Skipper> attr_rule;

qi::rule<It, parsed_t(), Skipper> start;
};

bool doParse(std::string const& input)
{
auto f(std::begin(input)), l(std::end(input));

parser<decltype(f), qi::space_type> p;

std::cout << "=======================================\n";
std::cout << "Trying to parse '" << input << "'\n";

try
{
attr_t data;
bool ok = qi::phrase_parse(f,l,p,qi::space,data);
if (ok)
{
std::cout << "parse success\n";
std::cout << "data: " << karma::format_delimited(karma::auto_, ' ', data) << "\n";
}
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
return ok;
} catch(const qi::expectation_failure<decltype(f)>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'\n";
}

return false;
}

int main()
{
assert(true == doParse("@attribute ident1 numeric"));
assert(true == doParse("@attribute ident2 { field1, field2, field3 }"));
assert(false== doParse("@attribute ident3 { }"));
//// enable relation_rule (requires tuple IO streaming for test output)
// assert(true == doParse("@relation rel1"));
}

关于c++ - spirit 解析器属性传播规则的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14601416/

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