从 boostspirit 语法获取结果(phoenixpush_back 导致编译错误)
我有以下精神语法。我正在尝试使用标准 push_back(at_c<0>(qi::_val), qi::_1)
在 struct myresult
中创建 AST 节点向量,但是我出现编译错误(见下文)。
typedef vector<ZLS::ASTNode*> vector_astnode_t;
struct myresult {
vector_astnode_t turtle_commands;
};
BOOST_FUSION_ADAPT_STRUCT
(
myresult,
(vector_astnode_t, turtle_commands)
);
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
struct debugprint {
string _name;
debugprint( string n ) : _name(n) {}
void operator()(int const& i, qi::unused_type, qi::unused_type) const {
cout << _name << std::endl;
}
void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const {
cout << _name << std::endl;
}
// todo: more of these for each type
};
template <typename Iterator>
struct lsystem_parser : qi::grammar<Iterator, myresult() > {
lsystem_parser( ZLS::Context* ctx )
: lsystem_parser::base_type(start)
, _ctx( ctx )
{
using qi::char_;
using qi::float_;
using qi::eps;
using qi::lit;
using qi::_1;
using qi::_val;
using phoenix::ref;
using phoenix::push_back;
using phoenix::at_c;
float_parameters = '(' >> (float_ >> *(',' >> float_)) >> ')';
/// turtle grammar ///
draw_forward = ( char_('F') [ _val = new ZLS::ASTDrawForward(_ctx,0)] )
[debugprint("draw_forward")];
move_forward = ( char_('f') [ _val = new ZLS::ASTMoveForward(_ctx,0)] )
[debugprint("move_forward")];
turn_left = ( char_('+') [ _val = new ZLS::ASTTurnLeft(_ctx,0)] )
[debugprint("turn_left")];
turn_right = ( char_('-') [ _val = new ZLS::ASTTurnRight(_ctx,0)] )
[debugprint("turn_right")];
push_state = ( char_('[') [ _val = new ZLS::ASTPushState(_ctx)] )
[debugprint("push_state")];
pop_state = ( char_(']') [ _val = new ZLS::ASTPopState(_ctx) ] )
[debugprint("pop_state")];
turtle_commands = (draw_forward
| move_forward
| turn_left
| turn_right
| push_state
| pop_state);
// >>>> THIS IS WHAT IS CAUSING THE ERROR <<<<<
start = *turtle_commands[ push_back(at_c<0>(qi::_val), qi::_1) ];
}
qi::rule< Iterator, myresult() > start;
qi::rule< Iterator, vector<float> > float_parameters;
qi::rule< Iterator, ZLS::ASTNode* > draw_forward;
qi::rule< Iterator, ZLS::ASTNode* > move_forward;
qi::rule< Iterator, ZLS::ASTNode* > turn_left;
qi::rule< Iterator, ZLS::ASTNode* > turn_right;
qi::rule< Iterator, ZLS::ASTNode* > push_state;
qi::rule< Iterator, ZLS::ASTNode* > pop_state;
qi::rule< Iterator, ZLS::ASTNode* > turtle_commands;
ZLS::Context* _ctx;
};
以下是从 XCode 返回的实际错误:
container.hpp:492: error: no matching function for call to 'std::vector<ZLS::ASTNode*, std::allocator<ZLS::ASTNode*> >::push_back(const boost::fusion::unused_type&)'
stl_vector.h:600: note: candidates are: void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = ZLS::ASTNode*, _Alloc = std::allocator<ZLS::ASTNode*>]
container.hpp:492: error: return-statement with a value, in function returning 'void'
编辑:以下是可编译和运行的修订版 Spirit 语法。有一些细微的变化需要注意,包括使用 phoenix new_
运算符并将以下语义操作添加到 turtle_commands = ... [_val = _1]
template <typename Iterator>
struct lsystem_parser : qi::grammar<Iterator, vector_astnode_t() > {
lsystem_parser( ZLS::Context* ctx )
: lsystem_parser::base_type(start)
, _ctx( ctx )
{
using qi::char_;
using qi::float_;
using qi::eps;
using qi::lit;
using qi::_1;
using qi::_val;
using phoenix::ref;
using phoenix::push_back;
using phoenix::at_c;
using phoenix::new_;
float_parameters = '(' >> (float_ >> *(',' >> float_)) >> ')';
/// turtle grammar ///
draw_forward = ( char_('F') [ _val = new_<ZLS::ASTDrawForward>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("draw_forward")];
move_forward = ( char_('f') [ _val = new_<ZLS::ASTMoveForward>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("move_forward")];
turn_left = ( char_('+') [ _val = new_<ZLS::ASTTurnLeft>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("turn_left")];
turn_right = ( char_('-') [ _val = new_<ZLS::ASTTurnRight>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("turn_right")];
push_state = ( char_('[') [ _val = new_<ZLS::ASTPushState>(_ctx)] )
[debugprint("push_state")];
pop_state = ( char_(']') [ _val = new_<ZLS::ASTPopState>(_ctx) ] )
[debugprint("pop_state")];
turtle_commands = (draw_forward
| move_forward
| turn_left
| turn_right
| push_state
| pop_state)[_val = _1];
start = *turtle_commands >> qi::eps;
}
qi::rule< Iterator, vector_astnode_t() > start;
qi::rule< Iterator, vector<float> > float_parameters;
qi::rule< Iterator, ZLS::ASTNode*() > draw_forward;
qi::rule< Iterator, ZLS::ASTNode*() > move_forward;
qi::rule< Iterator, ZLS::ASTNode*() > turn_left;
qi::rule< Iterator, ZLS::ASTNode*() > turn_right;
qi::rule< Iterator, ZLS::ASTNode*() > push_state;
qi::rule< Iterator, ZLS::ASTNode*() > pop_state;
qi::rule< Iterator, ZLS::ASTNode*() > turtle_commands;
ZLS::Context* _ctx;
};
I have the following spirit grammar. I am trying to create a vector of AST node in struct myresult
using the standard push_back(at_c<0>(qi::_val), qi::_1)
but am getting compile errors (see below).
typedef vector<ZLS::ASTNode*> vector_astnode_t;
struct myresult {
vector_astnode_t turtle_commands;
};
BOOST_FUSION_ADAPT_STRUCT
(
myresult,
(vector_astnode_t, turtle_commands)
);
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
struct debugprint {
string _name;
debugprint( string n ) : _name(n) {}
void operator()(int const& i, qi::unused_type, qi::unused_type) const {
cout << _name << std::endl;
}
void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const {
cout << _name << std::endl;
}
// todo: more of these for each type
};
template <typename Iterator>
struct lsystem_parser : qi::grammar<Iterator, myresult() > {
lsystem_parser( ZLS::Context* ctx )
: lsystem_parser::base_type(start)
, _ctx( ctx )
{
using qi::char_;
using qi::float_;
using qi::eps;
using qi::lit;
using qi::_1;
using qi::_val;
using phoenix::ref;
using phoenix::push_back;
using phoenix::at_c;
float_parameters = '(' >> (float_ >> *(',' >> float_)) >> ')';
/// turtle grammar ///
draw_forward = ( char_('F') [ _val = new ZLS::ASTDrawForward(_ctx,0)] )
[debugprint("draw_forward")];
move_forward = ( char_('f') [ _val = new ZLS::ASTMoveForward(_ctx,0)] )
[debugprint("move_forward")];
turn_left = ( char_('+') [ _val = new ZLS::ASTTurnLeft(_ctx,0)] )
[debugprint("turn_left")];
turn_right = ( char_('-') [ _val = new ZLS::ASTTurnRight(_ctx,0)] )
[debugprint("turn_right")];
push_state = ( char_('[') [ _val = new ZLS::ASTPushState(_ctx)] )
[debugprint("push_state")];
pop_state = ( char_(']') [ _val = new ZLS::ASTPopState(_ctx) ] )
[debugprint("pop_state")];
turtle_commands = (draw_forward
| move_forward
| turn_left
| turn_right
| push_state
| pop_state);
// >>>> THIS IS WHAT IS CAUSING THE ERROR <<<<<
start = *turtle_commands[ push_back(at_c<0>(qi::_val), qi::_1) ];
}
qi::rule< Iterator, myresult() > start;
qi::rule< Iterator, vector<float> > float_parameters;
qi::rule< Iterator, ZLS::ASTNode* > draw_forward;
qi::rule< Iterator, ZLS::ASTNode* > move_forward;
qi::rule< Iterator, ZLS::ASTNode* > turn_left;
qi::rule< Iterator, ZLS::ASTNode* > turn_right;
qi::rule< Iterator, ZLS::ASTNode* > push_state;
qi::rule< Iterator, ZLS::ASTNode* > pop_state;
qi::rule< Iterator, ZLS::ASTNode* > turtle_commands;
ZLS::Context* _ctx;
};
The following is the actual errors returned from XCode:
container.hpp:492: error: no matching function for call to 'std::vector<ZLS::ASTNode*, std::allocator<ZLS::ASTNode*> >::push_back(const boost::fusion::unused_type&)'
stl_vector.h:600: note: candidates are: void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = ZLS::ASTNode*, _Alloc = std::allocator<ZLS::ASTNode*>]
container.hpp:492: error: return-statement with a value, in function returning 'void'
EDIT: Following is a revised spirit grammar that compiles and works. There are a few subtle changes to note including using the phoenix new_
operator and adding the following semantic action to turtle_commands = ... [_val = _1]
template <typename Iterator>
struct lsystem_parser : qi::grammar<Iterator, vector_astnode_t() > {
lsystem_parser( ZLS::Context* ctx )
: lsystem_parser::base_type(start)
, _ctx( ctx )
{
using qi::char_;
using qi::float_;
using qi::eps;
using qi::lit;
using qi::_1;
using qi::_val;
using phoenix::ref;
using phoenix::push_back;
using phoenix::at_c;
using phoenix::new_;
float_parameters = '(' >> (float_ >> *(',' >> float_)) >> ')';
/// turtle grammar ///
draw_forward = ( char_('F') [ _val = new_<ZLS::ASTDrawForward>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("draw_forward")];
move_forward = ( char_('f') [ _val = new_<ZLS::ASTMoveForward>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("move_forward")];
turn_left = ( char_('+') [ _val = new_<ZLS::ASTTurnLeft>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("turn_left")];
turn_right = ( char_('-') [ _val = new_<ZLS::ASTTurnRight>(_ctx, (ZLS::ASTNode*)0)] )
[debugprint("turn_right")];
push_state = ( char_('[') [ _val = new_<ZLS::ASTPushState>(_ctx)] )
[debugprint("push_state")];
pop_state = ( char_(']') [ _val = new_<ZLS::ASTPopState>(_ctx) ] )
[debugprint("pop_state")];
turtle_commands = (draw_forward
| move_forward
| turn_left
| turn_right
| push_state
| pop_state)[_val = _1];
start = *turtle_commands >> qi::eps;
}
qi::rule< Iterator, vector_astnode_t() > start;
qi::rule< Iterator, vector<float> > float_parameters;
qi::rule< Iterator, ZLS::ASTNode*() > draw_forward;
qi::rule< Iterator, ZLS::ASTNode*() > move_forward;
qi::rule< Iterator, ZLS::ASTNode*() > turn_left;
qi::rule< Iterator, ZLS::ASTNode*() > turn_right;
qi::rule< Iterator, ZLS::ASTNode*() > push_state;
qi::rule< Iterator, ZLS::ASTNode*() > pop_state;
qi::rule< Iterator, ZLS::ASTNode*() > turtle_commands;
ZLS::Context* _ctx;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您不能在语义操作中直接使用
operator new
,请使用 phoenix::new_<> 代替。此外,规则的属性是使用函数符号语法指定的。因此,您需要将规则声明更改为:
这是一个附加提示。如果将开始规则更改为:
您可以完全避免语义操作。通过将规则转换为(解析器)序列,您可以利用序列的属性传播规则,从而允许将融合序列的第一个元素(
vector_astnode_tturtle_commands
)直接映射到解析器的第一个元素序列(*turtle_commands
)。我无法编译您的示例,因为它不完整,因此可能隐藏更多问题。
You can't directly use
operator new
inside of semantic actions, use phoenix::new_<> instead.Moreover, attributes for rules are specified using the function notation syntax. Therefore, you'll need to change your rule declarations to:
Here is an additional tip. If you change the start rule to:
you can avoid the semantic action alltogether. By converting the rule into a (parser) sequence you can leverage the attribute propagation rules for sequences, allowing to directly map the first element of your fusion sequence (the
vector_astnode_t turtle_commands
) onto the first element of the parser sequence (the*turtle_commands
).I'm not able to compile your example as it is incomplete, so more problems might be hidden.