我为我的Boost Spirit Lexer写了一个语义 Action ,将字符串中的转义序列转换为它们所代表的含义。它运行完美,我想将其转换为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
。如何获得当前 token 的字符串或一对
wchar_t
迭代器? 最佳答案
我要高呼“为什么”?
这次,有充分的理由。
通常,避免语义 Action :Boost Spirit: "Semantic actions are evil"?。
凤凰 Actor 比专门的函子要复杂得多。它们有一个优点(主要是简单的赋值或内置操作)。但是,如果参与者是任何不平凡的参与者,您将看到复杂性迅速增加,不仅对于人类,而且对于编译器。这将导致
这种情况
不能工作完全没有
问题在于您正在将延迟/延迟参与者与直接调用混合在一起。那永远都行不通。
phoenix::construct<std::wstring>(lex::_start, lex::_end)
的类型不应该是std::wstring
。当然。应该是一个懒惰的 Actor ¹,可以在以后的某个时候使用它来创建std::wstring
。现在我们知道
phoenix::construct<std::wstring>(lex::_start, lex::_end)
(以及为什么)是一个actor类型,现在应该弄清楚为什么对它调用boost::regex_replace
是完全伪造的。你不妨说struct implementation_defined {} bogus;
boost::regex_replace(bogus, re, fmt, boost::match_default | boost::format_all);
想知道为什么它不能编译。
概要:
您可能应该只拥有专用的函子。当然,您可以使Phoenix适应所需的正则表达式功能,但是它所做的只是转移某些语法糖的复杂性税。
我将始终选择更老练的方法,这对于经验丰富的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及其使用限制
³我们应该说,是大脑的灵性 child 吗?
关于c++ - 将Boost Spirit Lex语义 Action 转换为Phoenix-如何访问_val?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43100216/