C++ 通过引用在\u错误传递错误\u处理程序结构上提升精神气
我还有另一个关于灵气的拦截器问题 我已经在名为error\u handler的函子结构中实现了错误处理。 通过引用将其传递给语法构造函数(参见Qi的MiniC示例) 然后,我在语法的构造函数中定义了关于错误的C++ 通过引用在\u错误传递错误\u处理程序结构上提升精神气,c++,reference,boost-spirit,boost-spirit-qi,boost-phoenix,C++,Reference,Boost Spirit,Boost Spirit Qi,Boost Phoenix,我还有另一个关于灵气的拦截器问题 我已经在名为error\u handler的函子结构中实现了错误处理。 通过引用将其传递给语法构造函数(参见Qi的MiniC示例) 然后,我在语法的构造函数中定义了关于错误的: typedef boost::phoenix::function<error_handler<> > error_handler_function; on_error<fail>(gr_instruction, error_handle
:
typedef boost::phoenix::function<error_handler<> > error_handler_function;
on_error<fail>(gr_instruction,
error_handler_function(err_handler)(L"Error: Expecting ", _4, _3));
// more on_error<fail>s...
但是,问题仍然存在:on_error()
可用于err_handler
的副本,而不是单个实例
我还尝试了boost::phoenix::ref(err\u handler)
的变体,除了编译错误外,什么都没有
当然,通过引用传递处理程序必须有一个简单的解决方案
如果您有任何意见,我将不胜感激。谢谢您的帮助。是的,默认情况下,phx::bind和phx::function将采用其包装器可调用项的值。不过
比方说,[1],您有一个这样的错误处理程序。。。极简主义的例子:
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "\n";
}
mutable int proof = 0;
};
与往常一样,一个完全集成的示例程序:
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace asmast
{
typedef std::string label;
}
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "\n";
}
mutable int proof = 0;
};
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Skipper>
{
parser() :
parser::base_type(start)
{
using namespace qi;
start = lexeme["Func" >> !(alnum | '_')] > function;
function = gr_identifier
>> "{"
>> -(
gr_instruction
| gr_label
//| gr_vardecl
//| gr_paramdecl
) % eol
> "}";
gr_instruction_names.add("Mov", unused);
gr_instruction_names.add("Push", unused);
gr_instruction_names.add("Exit", unused);
gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
gr_operands = -(gr_operand % ',');
gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];
gr_newline = +( char_('\r')
|char_('\n')
);
gr_label = gr_identifier >> ':' > gr_newline;
#if 1
on_error<fail>(function, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(start, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
#else
auto ll = phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3);
on_error<fail>(function, ll);
on_error<fail>(start, ll);
on_error<fail>(gr_instruction, ll);
#endif
// more on_error<fail>s...
BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
my_error_handler<> err_handler;
private:
qi::symbols<char, qi::unused_type> gr_instruction_names;
qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
qi::rule<It, qi::unused_type()> gr_newline;
qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
};
int main()
{
typedef boost::spirit::istream_iterator It;
std::cin.unsetf(std::ios::skipws);
It f(std::cin), l;
parser<It, qi::blank_type> p;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank);
if (ok) std::cout << "parse success\n";
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
std::cout << "The 'proof' in the err_handler instance is: " << p.err_handler.proof << "\n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'\n";
}
return false;
}
它打印(作为第一行/最后一行)
[1]这不是我第一次想象相关的代码了我记得当时有一个很晚的想法,想检查一下:
当然,
my_error_handler<> err_handler;
phx::function<my_error_handler<> > err_handler_(err_handler);
不会飞行(因为my_error
无法从phx::ref(err_handler)
构造),所以从逻辑上讲,您实际需要做的只是:
namespace P = boost::proto;
phx::function<const phx::actor<P::exprns_::basic_expr<
P::tagns_::tag::terminal,
P::argsns_::term<boost::reference_wrapper<my_error_handler<> > >,
0l>
> > err_handler_;
现在,使用一些C++11,可以编写稍微不那么冗长的代码:
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
我的错误处理程序错误处理程序;
phx::函数err\u handler\u;
请参见使用下面的代码运行它:
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace asmast
{
typedef std::string label;
}
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "\n";
}
mutable int proof = 0;
};
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Skipper>
{
parser() :
parser::base_type(start),
err_handler(),
err_handler_(phx::ref(err_handler))
{
using namespace qi;
start = lexeme["Func" >> !(alnum | '_')] > function;
function = gr_identifier
>> "{"
>> -(
gr_instruction
| gr_label
//| gr_vardecl
//| gr_paramdecl
) % eol
> "}";
gr_instruction_names.add("Mov", unused);
gr_instruction_names.add("Push", unused);
gr_instruction_names.add("Exit", unused);
gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
gr_operands = -(gr_operand % ',');
gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];
gr_newline = +( char_('\r')
|char_('\n')
);
gr_label = gr_identifier >> ':' > gr_newline;
#if 0
on_error<fail>(function, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(start, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
#else
on_error<fail>(function, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(start, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, err_handler_(L"Error: Expecting ", _4, _3));
#endif
// more on_error<fail>s...
BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
private:
qi::symbols<char, qi::unused_type> gr_instruction_names;
qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
qi::rule<It, qi::unused_type()> gr_newline;
qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
};
int main()
{
typedef boost::spirit::istream_iterator It;
std::cin.unsetf(std::ios::skipws);
It f(std::cin), l;
parser<It, qi::blank_type> p;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank);
if (ok) std::cout << "parse success\n";
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
std::cout << "The 'proof' in the err_handler instance is: " << p.err_handler.proof << "\n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'\n";
}
return false;
}
#定义提升(精神)使用(凤凰)
//#定义BOOST_SPIRIT_调试
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间phx=boost::phoenix;
名称空间asmast
{
typedef std::字符串标签;
}
模板结构我的错误处理程序{
my_error_handler()=默认值;
我的错误处理程序(我的错误处理程序常量&)=删除;
模板结构结果{typedef void type;};
模板无效运算符()(T&…)常量{
std::cerr函数;
函数=gr\U标识符
>> "{"
>> -(
gr_指令
|gr_标签
//|格鲁·瓦尔德克尔
//|gr_paramdecl
)%eol
> "}";
gr_指令_名称。添加(“Mov”,未使用);
gr_指令_名称。添加(“推”,未使用);
gr_指令_名称。添加(“退出”,未使用);
gr|U指令=词素[gr|U指令名称>>!(alnum |“”)]>gr|U操作数;
gr_操作数=-(gr_操作数%',');
gr|U identifier=lexeme[alpha>>*(alnum |'"');
gr_操作数=gr_标识符| gr_字符串;
gr_string=lexeme[''''>>*(“\'\'\'\'\'\'\'.\char\'\')>'''];
gr_换行符=+(字符('\r'))
|字符('\n')
);
gr_标签=gr_标识符>>':'>gr_换行符;
#如果0
on_error(函数,phx::bind(phx::ref(err_handler),L“error:Expecting”,_4,_3));
on_error(start,phx::bind(phx::ref(err_handler),L“error:Expecting”,_4,_3));
on_error(gr_指令,phx::bind(phx::ref(err_handler),L“error:Expecting”,_4,_3));
#否则
on_error(函数,err_handler(L“error:Expecting”,_4,_3));
on_错误(开始,错误处理程序(错误:预期的),错误4,错误3);
on_error(gr_指令,err_处理程序(error:Expecting),_4,_3));
#恩迪夫
//更多关于你的错误。。。
BOOST_-SPIRIT_-DEBUG_节点((启动)(函数)(gr_指令)(gr_操作数)(gr_标识符)(gr_操作数)(gr_字符串));
}
我的错误处理程序错误处理程序;
phx::函数err\u handler\u;
私人:
qi::符号gr_指令_名称;
qi::规则开始、函数、gr_指令、gr_操作数、gr_操作数、gr_字符串;
qi::规则gr_新行;
qi::规则gr_标签,gr_标识符;
};
int main()
{
typedef boost::spirit::istream_迭代器It;
std::cin.unsetf(std::ios::skipws);
它是f(标准::cin),l;
语法分析器p;
尝试
{
bool ok=qi::短语解析(f,l,p,qi::blank);
如果(确定)std::非常感谢您的回复和示例。我将在早上的第一件事中尝试。您在前面的示例的基础上继续构建有点可笑:]Spirit确实是一条陡峭的学习曲线;特别是由于它高度依赖于其他boost库,并且很难解码编译器错误,但最终非常值得。再次感谢感谢您的耐心!@namezero Lol。我只是为了节约!我不喜欢从头开始输入随机代码样本:/另外,要小心那里的意见偏见。我得出的结论是,手摇解析器有时更可取。然而,一旦掌握了窍门,Spirit……对于快速原型来说是无法忍受的(并且不喜欢使用Antlr/CoCo/…)。谢谢,这确实有效!我没有偶然发现使用phoenix::bind的示例。至于[1],错误处理程序就像MiniC示例中的一样,只是我没有输出到std::cout。我知道在这个解析器中不使用Spirit会更容易,但是我们遇到了更复杂的问题,所以我认为这将是开始理解库的一个很好的方法。再次感谢!@namezero我并不真正关心sa我必须查找的示例。至少,你说它是有状态的。所以我写了我能想到的最简单的有状态函子:)我刚刚意识到,phx::function
是你的phx::function
思想的明显替代品。见我的新答案。+1.我认为你也可以使用phx::function:type>err\u handler\uu;
。我想我更喜欢简单地把proof
作为初始参考在构造器中进行了优化,但这种方式非常有趣。
Func Ident{
Mov name, "hello"
Push 5
Exit
}
my_error_handler invoked 0
my_error_handler invoked 1
...
The 'proof' in the err_handler instance is: 2
my_error_handler<> err_handler;
phx::function<my_error_handler<> > err_handler_(err_handler);
phx::function<my_error_handler<> > err_handler_(phx::ref(err_handler));
namespace P = boost::proto;
phx::function<const phx::actor<P::exprns_::basic_expr<
P::tagns_::tag::terminal,
P::argsns_::term<boost::reference_wrapper<my_error_handler<> > >,
0l>
> > err_handler_;
on_error<fail>(function, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(start, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, err_handler_(L"Error: Expecting ", _4, _3));
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace asmast
{
typedef std::string label;
}
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "\n";
}
mutable int proof = 0;
};
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Skipper>
{
parser() :
parser::base_type(start),
err_handler(),
err_handler_(phx::ref(err_handler))
{
using namespace qi;
start = lexeme["Func" >> !(alnum | '_')] > function;
function = gr_identifier
>> "{"
>> -(
gr_instruction
| gr_label
//| gr_vardecl
//| gr_paramdecl
) % eol
> "}";
gr_instruction_names.add("Mov", unused);
gr_instruction_names.add("Push", unused);
gr_instruction_names.add("Exit", unused);
gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
gr_operands = -(gr_operand % ',');
gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];
gr_newline = +( char_('\r')
|char_('\n')
);
gr_label = gr_identifier >> ':' > gr_newline;
#if 0
on_error<fail>(function, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(start, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
#else
on_error<fail>(function, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(start, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, err_handler_(L"Error: Expecting ", _4, _3));
#endif
// more on_error<fail>s...
BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
private:
qi::symbols<char, qi::unused_type> gr_instruction_names;
qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
qi::rule<It, qi::unused_type()> gr_newline;
qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
};
int main()
{
typedef boost::spirit::istream_iterator It;
std::cin.unsetf(std::ios::skipws);
It f(std::cin), l;
parser<It, qi::blank_type> p;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank);
if (ok) std::cout << "parse success\n";
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
std::cout << "The 'proof' in the err_handler instance is: " << p.err_handler.proof << "\n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'\n";
}
return false;
}