我正在尝试用野牛写一些语法来解析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是未知的。我想念什么?
答案 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对变量类型的处理。可悲的是,我没有详细介绍它,因此您可能想自己看看。