如何通过%type指令使用std :: variant类型

时间:2019-06-24 20:13:51

标签: c++ bison flex-lexer bisonc++

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

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

现在,当我编译这段代码时,会抛出一条错误消息,说明“声明符”没有类型。

我知道我可以使用%type声明式来定义类型。但我希望将“声明符”与变量类型相关联:

%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是未知的。我想念什么?

1 个答案:

答案 0 :(得分:1)

撰写时

%define api.value.type variant

您要告诉野牛使用自己的变体类型实现来实现语义值。

这在[野牛手册](%define api.value.type变体)中以醒目的标记警告:

  

警告:出于两个原因,我们不使用Boost.Variant。首先,在用户的计算机上(即将在其上编译生成的解析器的计算机,而不是在运行bison的计算机上)要求Boost似乎是不可接受的。其次,对于每个可能的语义值,Boost.Variant不仅存储该值,还存储指定其类型的标记。但是解析器已经“知道”了语义值的类型,因此将复制信息。

     

我们也不使用C ++ 17的std::variant:我们要支持所有C ++标准,当然std::variant还存储一个标记以记录当前类型。

(如果要使用它们,则值得阅读有关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 ,类似于$2.get<NodeList>

在Bison邮件列表中已经进行了一些讨论,以改进Bison对变量类型的处理。可悲的是,我没有详细介绍它,因此您可能想自己看看。