来自备选方案的部分匹配的综合属性
Synthesized attributes of partial matches from alternatives
当我在下面的规则中删除 x3::eps 时,第一个部分匹配的字符串结果仍在第二个匹配中,导致字符串包含重复的内容。
如果我在两者之间添加另一个案例,我仍然只会得到 1 个副本而不是两个。
- 为什么要用x3::eps,或者,我对规则和合成属性的评估有什么误解?
- 我应该改用前瞻吗?
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace x3 = boost::spirit::x3;
namespace ascii = x3::ascii;
struct AstChannel {
std::string label;
bool complement;
};
x3::rule<class AstLabel, std::string> const astLabel = "astLabel";
auto const astLabel_def = ascii::lower >> *(ascii::alnum);
BOOST_SPIRIT_DEFINE(astLabel)
x3::rule<class AstChannel, AstChannel> const astChannel = "astChannel";
auto const astChannel_def = astLabel >> '!' >> x3::attr(true)
| astLabel >> x3::eps >> x3::attr(false) ;
BOOST_SPIRIT_DEFINE(astChannel)
BOOST_FUSION_ADAPT_STRUCT(
AstChannel,
(std::string, label)
(bool, complement)
)
int main() {
std::string str("hello");
auto iter = str.begin();
auto end = str.end();
AstChannel channel;
bool r = phrase_parse(iter, end, astChannel, ascii::space, channel);
if (r) {
std::cout << channel.label << ',' << channel.complement << std::endl;
}
return 0;
}
真正的答案是:强制容器属性的原子属性传播(例如使用 x3::hold
或语义操作)。
更好的答案是:使用x3::matches
:
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
using namespace std::string_literals;
struct AstChannel {
std::string label;
bool complement;
};
BOOST_FUSION_ADAPT_STRUCT(AstChannel, label, complement)
namespace Grammar {
namespace x3 = boost::spirit::x3;
namespace ascii = x3::ascii;
auto const label = x3::rule<struct labelRule, std::string> {"label" }
= x3::lexeme[ascii::lower >> *(ascii::alnum)];
auto const channel = label >> x3::matches['!'];
auto const entry = x3::skip(ascii::space) [ channel ];
}
int main() {
auto const str = "hello"s;
AstChannel channel;
if (parse(str.begin(), str.end(), Grammar::entry, channel)) {
std::cout << channel.label << ',' << std::boolalpha << channel.complement << "\n";
}
}
版画
hello,false
当我在下面的规则中删除 x3::eps 时,第一个部分匹配的字符串结果仍在第二个匹配中,导致字符串包含重复的内容。
如果我在两者之间添加另一个案例,我仍然只会得到 1 个副本而不是两个。
- 为什么要用x3::eps,或者,我对规则和合成属性的评估有什么误解?
- 我应该改用前瞻吗?
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace x3 = boost::spirit::x3;
namespace ascii = x3::ascii;
struct AstChannel {
std::string label;
bool complement;
};
x3::rule<class AstLabel, std::string> const astLabel = "astLabel";
auto const astLabel_def = ascii::lower >> *(ascii::alnum);
BOOST_SPIRIT_DEFINE(astLabel)
x3::rule<class AstChannel, AstChannel> const astChannel = "astChannel";
auto const astChannel_def = astLabel >> '!' >> x3::attr(true)
| astLabel >> x3::eps >> x3::attr(false) ;
BOOST_SPIRIT_DEFINE(astChannel)
BOOST_FUSION_ADAPT_STRUCT(
AstChannel,
(std::string, label)
(bool, complement)
)
int main() {
std::string str("hello");
auto iter = str.begin();
auto end = str.end();
AstChannel channel;
bool r = phrase_parse(iter, end, astChannel, ascii::space, channel);
if (r) {
std::cout << channel.label << ',' << channel.complement << std::endl;
}
return 0;
}
真正的答案是:强制容器属性的原子属性传播(例如使用 x3::hold
或语义操作)。
更好的答案是:使用x3::matches
:
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
using namespace std::string_literals;
struct AstChannel {
std::string label;
bool complement;
};
BOOST_FUSION_ADAPT_STRUCT(AstChannel, label, complement)
namespace Grammar {
namespace x3 = boost::spirit::x3;
namespace ascii = x3::ascii;
auto const label = x3::rule<struct labelRule, std::string> {"label" }
= x3::lexeme[ascii::lower >> *(ascii::alnum)];
auto const channel = label >> x3::matches['!'];
auto const entry = x3::skip(ascii::space) [ channel ];
}
int main() {
auto const str = "hello"s;
AstChannel channel;
if (parse(str.begin(), str.end(), Grammar::entry, channel)) {
std::cout << channel.label << ',' << std::boolalpha << channel.complement << "\n";
}
}
版画
hello,false