我为我的Boost Spirit Lexer编写了一个语义动作,将字符串中的转义序列转换为它们所代表的含义。它工作得很完美,我想将它转换为Boost Phoenix表达式,但无法编译它。
这是有效的:
// the semantic action
struct ConvertEscapes
{
template <typename ItT, typename IdT, typename CtxT>
void operator () (ItT& start, ItT& end, lex::pass_flags& matched, IdT& id, CtxT& ctx)
{
static boost::wregex escapeRgx(L"(\\\\r)|(\\\\n)|(\\\\t)|(\\\\\\\\)|(\\\\\")");
static std::wstring escapeRepl = L"(?1\r)(?2\n)(?3\t)(?4\\\\)(?5\")";
static std::wstring wval; // static b/c set_value doesn't seem to copy
auto const& val = ctx.get_value();
wval.assign(val.begin(), val.end());
wval = boost::regex_replace(wval,
escapeRgx,
escapeRepl,
boost::match_default | boost::format_all);
ctx.set_value(wval);
}
};
// the token declaration
lex::token_def<std::wstring, wchar_t> literal_str;
// the token definition
literal_str = L"\\\"([^\\\\\"]|(\\\\.))*\\\""; // string with escapes
// adding it to the lexer
this->self += literal_str [ ConvertEscapes() ];
这是我试图转换的内容:
this->self += literal_str
[
lex::_val = boost::regex_replace(lex::_val /* this is the place I can't figure out */,
boost::wregex(L"(\\\\r)|(\\\\n)|
(\\\\t)|(\\\\\\\\)|(\\\\\")"),
L"(?1\r)(?2\n)(?3\t)(?4\\\\)(?5\")",
boost::match_default | boost::format_all)
];
wstring
无法从_val
构建。 _val
也没有begin()
或end()
,它应该如何使用?
此std::wstring(lex::_start, lex::_end)
也失败了,因为这些参数未被识别为迭代器。
在this question中,我找到phoenix::construct<std::wstring>(lex::_start, lex::_end)
,但这也不会导致wstring
。
如何为当前令牌获取字符串或一对wchar_t
迭代器?
答案 0 :(得分:2)
我会唱经常听到的“为什么”?
这一次,有充分的理由。
通常,避免语义操作:Boost Spirit: "Semantic actions are evil"?。
凤凰演员比专用的仿函数更加复杂。他们有一个甜点(主要是简单的任务或内置操作)。但如果演员是任何一种非平凡的,你会看到复杂性迅速增加,不仅是为了人类而且对于编译器。这导致
有趣的是:尽管凤凰曾经是Spirit³的脑子,但精神X3完全放弃了凤凰。
新样式使用c ++ 14多态lambda,它看起来像原始代码中的辅助函数对象,但是内联为lambda。
无法工作。完全没有。
问题是你将懒惰/延迟的actor与直接调用混合在一起。那永远不会奏效。 phoenix::construct<std::wstring>(lex::_start, lex::_end)
的类型不是假设为std::wstring
。当然。 应该是一个懒惰的演员¹,以后可以用来创建std::wstring
。
现在我们知道(以及为什么)phoenix::construct<std::wstring>(lex::_start, lex::_end)
是一个演员类型,应该清楚为什么在它上面调用boost::regex_replace
是完全虚假的。你不妨说
struct implementation_defined {} bogus;
boost::regex_replace(bogus, re, fmt, boost::match_default | boost::format_all);
并想知道为什么它不会编译。
你应该只有专用的仿函数。你可以当然是凤凰适应你需要的正则表达式函数,但它所做的就是将复杂性税转移到一些语法糖上。
我总是选择一种对于经验丰富的c ++程序员来说更容易理解的更天真的方法,并避免高线操作带来的陷阱²。
然而,如果你好奇,这里有一个指针:
http://www.boost.org/doc/libs/1_63_0/libs/phoenix/doc/html/phoenix/modules/function.html
<强> Live On Coliru 强>
#include <iostream>
#include <boost/regex.hpp>
#include <boost/phoenix.hpp>
#include <boost/spirit/include/lex_lexer.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/lex.hpp>
namespace lex = boost::spirit::lex;
BOOST_PHOENIX_ADAPT_FUNCTION(std::wstring, regex_replace_, boost::regex_replace, 4)
template <typename... T>
struct Lexer : lex::lexer<T...> {
Lexer() {
// the token definition
literal_str = L"\\\"([^\\\\\"]|(\\\\.))*\\\""; // string with escapes
// adding it to the lexer
this->self += literal_str [
lex::_val = regex_replace_(lex::_val,
boost::wregex(L"(\\\\r)|(\\\\n)|(\\\\t)|(\\\\\\\\)|(\\\\\")"),
L"(?1\r)(?2\n)(?3\t)(?4\\\\)(?5\")",
boost::match_default | boost::format_all)
];
}
// the token declaration
lex::token_def<std::wstring, wchar_t> literal_str;
};
int main() {
typedef lex::lexertl::token<std::wstring::const_iterator, boost::mpl::vector<std::wstring, wchar_t>> token_type;
typedef Lexer<lex::lexertl::actor_lexer<token_type>> lexer_type;
typedef lexer_type::iterator_type lexer_iterator_type;
}
¹认为可以在以后调用的组合函数对象
²如果您将此设计为EDSL以供非专家进一步配置,则余额可能会提示,但是您将负责记录您的EDSL以及可以使用它的限制
我们应该说,大脑的精神孩子?