std::shared_ptr 在 Bison 中导致成员错误
std::shared_ptr in Bison causing member error
我正在尝试通过使用 std::shared_ptr
使 bison 的内存效率更高。我不想使用原始指针。我使用节点系统作为解析树,所以我将 YYTYPE
定义为 std::shared_ptr<Node>
。在 运行 它与一些简单的语法之后,我得到了编译错误:
C2039 'blockNode': is not a member of 'std::shared_ptr'
我发现这个 st运行ge 作为等效代码 运行 在 C++ 中工作得很好
std::shared_ptr<Node> test = std::make_shared<BlockNode>();
我错过了什么?
需要
%code requires {
typedef void* yyscan_t;
#include "node.h"
#include <memory>
#define YYSTYPE std::shared_ptr<Node>
}
联盟
%union {
std::shared_ptr<BlockNode> blockNode;
std::shared_ptr<TestNode> testNode;
}
%type <blockNode> input
%type <testNode> expr
语法
%start program
%%
program : input { *result = ; } // <- error here
;
input: '\n' { $$ = std::make_shared<BlockNode>();} // <- error here
;
%%
Node.h
class Node /*: public std::enable_shared_from_this<Node>*/ {
public:
std::string myString;
Node() {}
~Node() { std::cout << "destoryed" << myString << std::endl; }
};
class BlockNode : public Node {
public:
BlockNode() {
myString = "block node";
std::cout << "created" << myString << std::endl;
}
};
首先你应该知道这个设计是行不通的。如果你对 bison 使用默认的 C API,你不能使用不可简单复制的语义类型,因为如果 bison 需要重新分配它,它会按字节复制它的堆栈(我相信还有其他问题需要做在不调用析构函数的情况下覆盖字节)。如果你想使用共享指针,你应该弄清楚如何使用 C++ API,我认为它已经达到某种成熟度(虽然我用得不多)。您可能会对结果更满意。
尽管如此,您的代码还有一些其他问题。
首先,现代野牛应用程序不应该 #define YYSTYPE
,甚至不应该在 %code requires
块内。你应该改用
%define api.value.type { /* SemanticType */ }
如果您这样做了,bison 就会告诉您不能同时使用 %union
声明和固定的 api.value.type
。如果语义类型是一个联合,它就是一个联合。它也不能是 shared_pointer
。既然你似乎希望它是一个成员都是共享指针的联合,那么它就是一个联合,你不想以其他方式定义它。
如果您确实使用了 #define YYSTYPE
,并且还使用了 %union
,那么您会发现 %union
永远不会被应用。 %union
插入 YYSTYPE
的默认定义(如 union YYSTYPE
),但您对 YYSTYPE
的显式定义会覆盖它。但是 bison 不知道您已经这样做了——在 C 编译器实际编译生成的代码之前它不会变得明显——因此它使用您在 %type
声明中提供的标记重写语义值引用。换句话说,当你说 %type <blockNode> input
时,bison 会通过添加字段引用自动更改对 $n
的任何引用,其中引用 input non-terminal
的实例,就好像你已经写了 $n.blockNode
(当然,您不能这样做,因为 bison 已经添加了字段引用)。但是 #define
-overridden YYSTYPE
不是联合,它是 shared_pointer<Node>
,并且 shared_pointer<Node>
没有 blockNode
成员,因为 C++ 编译器错误消息表示。
类似地,在 input
的规则中,%type
声明导致 bison 发出代码,该代码将分配给(不存在的)blockNode
成员。
为了说明我的第一点——您不能将 shared_pointer
用作 C 代码生成器的语义类型或联合成员——我通过应用上述建议“修复”了您的代码(即是,删除 #define YYSTYPE
,并进行或多或少的最小更改以避免其他野牛和编译器错误,从而导致以下 reduced reproducible example:
文件tom.yy
%code requires {
#include "tom_node.h"
#include <memory>
}
%code {
std::shared_ptr<Node> result;
void yyerror(const char* msg) {
std::cerr << msg << '\n';
}
int yylex();
}
%union {
std::shared_ptr<BlockNode> blockNode;
std::shared_ptr<Node> testNode;
}
%type <blockNode> input
%%
program : input { *result = *; /* ?? I don't know the actual intent */ }
input: '\n' { $$ = std::make_shared<BlockNode>();}
文件tom_node.h
#ifndef TOM_NODE_H
#define TOM_NODE_H
#include <iostream>
#include <string>
class Node /*: public std::enable_shared_from_this<Node>*/ {
public:
std::string myString;
Node() {}
~Node() { std::cout << "destroyed" << myString << std::endl; }
};
class BlockNode : public Node {
public:
BlockNode() {
myString = "block node";
std::cout << "created" << myString << std::endl;
}
};
#endif
结果是一系列类似的错误,所有这些错误都与 std::shared_pointer
不是普通类型这一事实有关。这是前几个:
$ bison -o tom.cc tom.yy
$ gcc -Wall -o tom tom.cc -ly
tom.cc:956:9: error: use of deleted function ‘YYSTYPE::YYSTYPE()’
YYSTYPE yylval;
^~~~~~
tom.cc:104:7: note: ‘YYSTYPE::YYSTYPE()’ is implicitly deleted because the default definition would be ill-formed:
union YYSTYPE
^~~~~~~
tom.yy:15:32: error: union member ‘YYSTYPE::blockNode’ with non-trivial ‘constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = BlockNode]’
std::shared_ptr<BlockNode> blockNode;
^~~~~~~~~
tom.yy:16:27: error: union member ‘YYSTYPE::testNode’ with non-trivial ‘constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = Node]’
std::shared_ptr<Node> testNode;
^~~~~~~~
tom.cc: In function ‘int yyparse()’:
tom.cc:985:30: error: use of deleted function ‘YYSTYPE::YYSTYPE()’
YYSTYPE yyvsa[YYINITDEPTH];
^
这是 C++ 联合的一个限制,联合的成员不能有构造函数。
union {
std::shared_ptr<BlockNode> blockNode; //not allowed
std::shared_ptr<Node> *testNode; //allowed
}
所以,在你的情况下,没必要使用shared_ptr,只需
union {
Node *testNode;
}
我正在尝试通过使用 std::shared_ptr
使 bison 的内存效率更高。我不想使用原始指针。我使用节点系统作为解析树,所以我将 YYTYPE
定义为 std::shared_ptr<Node>
。在 运行 它与一些简单的语法之后,我得到了编译错误:
C2039 'blockNode': is not a member of 'std::shared_ptr'
我发现这个 st运行ge 作为等效代码 运行 在 C++ 中工作得很好
std::shared_ptr<Node> test = std::make_shared<BlockNode>();
我错过了什么?
需要
%code requires {
typedef void* yyscan_t;
#include "node.h"
#include <memory>
#define YYSTYPE std::shared_ptr<Node>
}
联盟
%union {
std::shared_ptr<BlockNode> blockNode;
std::shared_ptr<TestNode> testNode;
}
%type <blockNode> input
%type <testNode> expr
语法
%start program
%%
program : input { *result = ; } // <- error here
;
input: '\n' { $$ = std::make_shared<BlockNode>();} // <- error here
;
%%
Node.h
class Node /*: public std::enable_shared_from_this<Node>*/ {
public:
std::string myString;
Node() {}
~Node() { std::cout << "destoryed" << myString << std::endl; }
};
class BlockNode : public Node {
public:
BlockNode() {
myString = "block node";
std::cout << "created" << myString << std::endl;
}
};
首先你应该知道这个设计是行不通的。如果你对 bison 使用默认的 C API,你不能使用不可简单复制的语义类型,因为如果 bison 需要重新分配它,它会按字节复制它的堆栈(我相信还有其他问题需要做在不调用析构函数的情况下覆盖字节)。如果你想使用共享指针,你应该弄清楚如何使用 C++ API,我认为它已经达到某种成熟度(虽然我用得不多)。您可能会对结果更满意。
尽管如此,您的代码还有一些其他问题。
首先,现代野牛应用程序不应该 #define YYSTYPE
,甚至不应该在 %code requires
块内。你应该改用
%define api.value.type { /* SemanticType */ }
如果您这样做了,bison 就会告诉您不能同时使用 %union
声明和固定的 api.value.type
。如果语义类型是一个联合,它就是一个联合。它也不能是 shared_pointer
。既然你似乎希望它是一个成员都是共享指针的联合,那么它就是一个联合,你不想以其他方式定义它。
如果您确实使用了 #define YYSTYPE
,并且还使用了 %union
,那么您会发现 %union
永远不会被应用。 %union
插入 YYSTYPE
的默认定义(如 union YYSTYPE
),但您对 YYSTYPE
的显式定义会覆盖它。但是 bison 不知道您已经这样做了——在 C 编译器实际编译生成的代码之前它不会变得明显——因此它使用您在 %type
声明中提供的标记重写语义值引用。换句话说,当你说 %type <blockNode> input
时,bison 会通过添加字段引用自动更改对 $n
的任何引用,其中引用 input non-terminal
的实例,就好像你已经写了 $n.blockNode
(当然,您不能这样做,因为 bison 已经添加了字段引用)。但是 #define
-overridden YYSTYPE
不是联合,它是 shared_pointer<Node>
,并且 shared_pointer<Node>
没有 blockNode
成员,因为 C++ 编译器错误消息表示。
类似地,在 input
的规则中,%type
声明导致 bison 发出代码,该代码将分配给(不存在的)blockNode
成员。
为了说明我的第一点——您不能将 shared_pointer
用作 C 代码生成器的语义类型或联合成员——我通过应用上述建议“修复”了您的代码(即是,删除 #define YYSTYPE
,并进行或多或少的最小更改以避免其他野牛和编译器错误,从而导致以下 reduced reproducible example:
文件tom.yy
%code requires {
#include "tom_node.h"
#include <memory>
}
%code {
std::shared_ptr<Node> result;
void yyerror(const char* msg) {
std::cerr << msg << '\n';
}
int yylex();
}
%union {
std::shared_ptr<BlockNode> blockNode;
std::shared_ptr<Node> testNode;
}
%type <blockNode> input
%%
program : input { *result = *; /* ?? I don't know the actual intent */ }
input: '\n' { $$ = std::make_shared<BlockNode>();}
文件tom_node.h
#ifndef TOM_NODE_H
#define TOM_NODE_H
#include <iostream>
#include <string>
class Node /*: public std::enable_shared_from_this<Node>*/ {
public:
std::string myString;
Node() {}
~Node() { std::cout << "destroyed" << myString << std::endl; }
};
class BlockNode : public Node {
public:
BlockNode() {
myString = "block node";
std::cout << "created" << myString << std::endl;
}
};
#endif
结果是一系列类似的错误,所有这些错误都与 std::shared_pointer
不是普通类型这一事实有关。这是前几个:
$ bison -o tom.cc tom.yy
$ gcc -Wall -o tom tom.cc -ly
tom.cc:956:9: error: use of deleted function ‘YYSTYPE::YYSTYPE()’
YYSTYPE yylval;
^~~~~~
tom.cc:104:7: note: ‘YYSTYPE::YYSTYPE()’ is implicitly deleted because the default definition would be ill-formed:
union YYSTYPE
^~~~~~~
tom.yy:15:32: error: union member ‘YYSTYPE::blockNode’ with non-trivial ‘constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = BlockNode]’
std::shared_ptr<BlockNode> blockNode;
^~~~~~~~~
tom.yy:16:27: error: union member ‘YYSTYPE::testNode’ with non-trivial ‘constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = Node]’
std::shared_ptr<Node> testNode;
^~~~~~~~
tom.cc: In function ‘int yyparse()’:
tom.cc:985:30: error: use of deleted function ‘YYSTYPE::YYSTYPE()’
YYSTYPE yyvsa[YYINITDEPTH];
^
这是 C++ 联合的一个限制,联合的成员不能有构造函数。
union {
std::shared_ptr<BlockNode> blockNode; //not allowed
std::shared_ptr<Node> *testNode; //allowed
}
所以,在你的情况下,没必要使用shared_ptr,只需
union {
Node *testNode;
}