如何将 std::variant 类型与 %type 指令一起使用

How to use std::variant type with %type directive

我正在尝试用 bison 编写一些解析 C 代码的语法。我是野牛的新手,我正在尝试从我在网上找到的例子中学习。我正在写 AST。如果这是我定义的语法(最基本的用例)

declarator
: IDENTIFIER         { $$ = ;}
| declarator '(' ')' { $$ = new functionDecl(); }

现在,当我编译这段代码时,会抛出一条错误消息,提示 'declarator' 没有类型。

我知道我可以使用 %type 声明来定义类型。但我希望 "declarator" 与变体类型相关联:

%code {

class Stmt 
{
   public:
     std::string id;
     Stmt(std::string aId)
     : id(aId)
     {}  
};
typedef std::variant<std::string, Stmt> decl_type;
}

%define api.value.type variant
%token <std::string> IDENTIFIER
%type <decl_type> declarator

我也无法编译这段代码。它抛出 decl_type 未知的错误。我错过了什么?

写的时候

%define api.value.type variant

你告诉 bison 使用它自己的变体类型实现来实现语义值

这在 bison manual 中突出显示的注释中突出显示 警告:

Warning: We do not use Boost.Variant, for two reasons. First, it appeared unacceptable to require Boost on the user’s machine (i.e., the machine on which the generated parser will be compiled, not the machine on which bison was run). Second, for each possible semantic value, Boost.Variant not only stores the value, but also a tag specifying its type. But the parser already “knows” the type of the semantic value, so that would be duplicating the information.

We do not use C++17’s std::variant either: we want to support all the C++ standards, and of course std::variant also stores a tag to record the current type.

(如果您想使用 Bison 变体,请阅读整个部分。)

你可以定义 bison 的语义类型为 std::variant,当然:

%define api.value.type std::variant<std::string, Stmt>

但这可能不是你想要的,因为 bison 对 std::variant 一无所知,它不会做任何事情来帮助你使用访问变量值的语法。通常,正如关于 Bison 变体的页面所指出的,Bison 可以 推断 语法符号的语义值的类型(当然,使用你的 %type 声明),但是如果你不使用 union 或 Bison 变体类型,那么 Bison 只知道该值是 std::variant。如果您碰巧知道它是一种特定类型(例如,因为您知道终端符号的类型),并且您想要使用该类型检查值,则必须使用 std::variant::get , 类似于 .get<NodeList>.

在 Bison 邮件列表上有一些关于改进 Bison 对变体类型的处理的讨论。遗憾的是,我没有详细关注它,所以你可能想自己看看。