为什么我不能在语义操作中访问值
Why can I not access the value in a semantic action?
我正在尝试编写一个解析器来使用boost::spirit创建AST。作为第一步,我尝试在AST节点中包装数值。这是我使用的代码:
AST_NodePtr make_AST_NodePtr(const int& i) {
return std::make_shared<AST_Node>(i);
}
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace l = qi::labels;
template<typename Iterator>
struct test_grammar : qi::grammar<Iterator, AST_NodePtr(), ascii::space_type> {
test_grammar() : test_grammar::base_type(test) {
test = qi::int_ [qi::_val = make_AST_NodePtr(qi::_1)];
}
qi::rule<Iterator, AST_NodePtr(), ascii::space_type> test;
};
根据我对文档的理解,q::_1应该包含qi::int_解析的值,但是上面的代码总是在
这一行给我一个错误。invalid initialization of reference of type ‘const int&’ from expression of type ‘const _1_type {aka const boost::phoenix::actor<boost::spirit::argument<0> >}
为什么这不能工作,即使qi::_1应该保存解析值?否则我将如何将输入解析为自定义AST?
你在语义动作中使用了一个规则的函数。
这意味着在构造函数中的编译器将尝试调用带有提供的参数的make_AST_NodePtr
函数:qi::_1
。
Q。为什么这不能工作,即使qi::_1应该保存解析值?
。 qi::_1
不保存解析值。它表示 (is-a-placeholder-for)函数调用
这显然行不通。函数需要一个整数
怎么了?
您需要创建一个"lazy"或"deferred"函数用于语义操作。仅使用预先提供的Boost Phoenix函子,您可以将其拼出:
test = qi::int_ [ qi::_val = px::construct<AST_NodePtr>(px::new_<AST_Node>(qi::_1)) ];
这样就不需要辅助函数了。但结果既丑陋又不理想。所以,让我们做得更好!
使用Phoenix Function包装器
struct make_shared_f {
std::shared_ptr<AST_Node> operator()(int v) const {
return std::make_shared<AST_Node>(v);
}
};
px::function<make_shared_f> make_shared_;
有了这个定义,您可以将语义操作简化为:
test = qi::int_ [ qi::_val = make_shared_(qi::_1) ];
实际上,如果你使它泛型,你可以在许多类型中重用它:
template <typename T>
struct make_shared_f {
template <typename... Args>
std::shared_ptr<T> operator()(Args&&... args) const {
return std::make_shared<T>(std::forward<Args>(args)...);
}
};
px::function<make_shared_f<AST_Node> > make_shared_;
演示下面是一个独立的示例,展示了过程中的一些样式修复:
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <memory>
struct AST_Node {
AST_Node(int v) : _value(v) {}
int value() const { return _value; }
private:
int _value;
};
using AST_NodePtr = std::shared_ptr<AST_Node>;
AST_NodePtr make_AST_NodePtr(const int& i) {
return std::make_shared<AST_Node>(i);
}
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
template<typename Iterator>
struct test_grammar : qi::grammar<Iterator, AST_NodePtr()> {
test_grammar() : test_grammar::base_type(start) {
using boost::spirit::ascii::space;
start = qi::skip(space) [ test ];
test = qi::int_ [ qi::_val = make_shared_(qi::_1) ];
}
private:
struct make_shared_f {
std::shared_ptr<AST_Node> operator()(int v) const {
return std::make_shared<AST_Node>(v);
}
};
px::function<make_shared_f> make_shared_;
//
qi::rule<Iterator, AST_NodePtr()> start;
qi::rule<Iterator, AST_NodePtr(), boost::spirit::ascii::space_type> test;
};
int main() {
AST_NodePtr parsed;
std::string const input ("42");
auto f = input.begin(), l = input.end();
test_grammar<std::string::const_iterator> g;
bool ok = qi::parse(f, l, g, parsed);
if (ok) {
std::cout << "Parsed: " << (parsed? std::to_string(parsed->value()) : "nullptr") << "n";
} else {
std::cout << "Failedn";
}
if (f!=l)
{
std::cout << "Remaining input: '" << std::string(f, l) << "'n";
}
}
打印
Parsed: 42
附加功能:使用BOOST_PHOENIX_ADAPT_FUNCTION
如果你愿意,你可以使用你的自由函数,并按如下方式使用它:
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <memory>
struct AST_Node {
AST_Node(int v) : _value(v) {}
int value() const { return _value; }
private:
int _value;
};
using AST_NodePtr = std::shared_ptr<AST_Node>;
AST_NodePtr make_AST_NodePtr(int i) {
return std::make_shared<AST_Node>(i);
}
BOOST_PHOENIX_ADAPT_FUNCTION(AST_NodePtr, make_AST_NodePtr_, make_AST_NodePtr, 1)
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
template<typename Iterator>
struct test_grammar : qi::grammar<Iterator, AST_NodePtr()> {
test_grammar() : test_grammar::base_type(start) {
using boost::spirit::ascii::space;
start = qi::skip(space) [ test ] ;
test = qi::int_ [ qi::_val = make_AST_NodePtr_(qi::_1) ] ;
}
private:
qi::rule<Iterator, AST_NodePtr()> start;
qi::rule<Iterator, AST_NodePtr(), boost::spirit::ascii::space_type> test;
};
int main() {
AST_NodePtr parsed;
std::string const input ("42");
auto f = input.begin(), l = input.end();
test_grammar<std::string::const_iterator> g;
bool ok = qi::parse(f, l, g, parsed);
if (ok) {
std::cout << "Parsed: " << (parsed? std::to_string(parsed->value()) : "nullptr") << "n";
} else {
std::cout << "Failedn";
}
if (f!=l)
{
std::cout << "Remaining input: '" << std::string(f, l) << "'n";
}
}
相关文章:
- 是否可以访问类数据成员并在析构函数中对它们执行操作?
- 在链接的程序集文件中,我想从 c++ 调用代码访问变量.是否可以在不触发访问冲突的情况下执行此操作?
- 为什么在 C++ 执行删除操作后仍可以访问释放的动态分配的内存
- 如何通过 COM 互操作访问复杂对象的属性?
- 访问新创建的操作时出现问题
- 为什么原子操作需要独家的缓存访问
- 如何在语义操作中访问元组的元素
- 如何创建一个可以对同一类的多个对象进行操作的函数,访问C++中的私有属性
- 我如何在数值求解器中优化大量的副本和访问操作
- 在 CUDA / 推力中,如何在每个操作期间访问矢量元素的邻居?
- 访问类成员的C++操作顺序
- 加法操作是如何加速此内存访问的
- 在编译期间遍历树,并执行访问操作
- Windows安装程序,在C++中访问自定义操作中的自定义属性
- Linux:将统计访问硬盘的操作
- boost::精神访问从语义操作定位迭代器
- STL 向量上的重复操作是否允许"Inherent Parallelism"/改进的内存访问?
- 我可以通过WiX的自定义操作访问.wxl本地化文件中的字符串吗
- 访问智能指针时的自定义操作
- RenderTexture在访问操作(Cocos2d-x)时崩溃